2014-07-25 10 views
7

Wciąż wspinam się na strome wzgórze WPF! Dlatego chcę utworzyć interfejs użytkownika, który pozwala użytkownikowi dynamicznie dodawać pole tekstowe. W tym celu nacisnęli przycisk.Dynamiczne dodawanie TextBox za pomocą przycisku w ramach MVVM

Udało mi się utworzyć to za pomocą kodu, ale chcę przejść do struktury MVVM, więc nie mam żadnego kodu w widoku. Próbowałem ICommand i ObservableCollection, ale brakuje mi czegoś i nie wiem gdzie. Oto mój prosty przykład.

XAML: Bardzo prosty z jednym przyciskiem dodającym wiersz.

<Window x:Class="WPFpractice072514.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:WPFpractice072514" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid Name="mymy" > 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto" /> 
      <RowDefinition Height="Auto" /> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="Auto" /> 
      <ColumnDefinition Width="Auto" /> 
     </Grid.ColumnDefinitions> 
     <Button Grid.Column="0" Grid.Row="0" Name="ButtonUpdateArtist" 
       Content="Add TextBox" Click="ButtonAddTexboxBlockExecute" /> 

    </Grid> 
</Window> 

C# Code Behind

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

namespace WPFpractice072514 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     #region members 
     int count = 0; 
     #endregion 

     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private void ButtonAddTexboxBlockExecute(Object Sender, RoutedEventArgs e) 
     { 
      TextBox t = new TextBox(); 
      t.Height = 20; 
      t.Width = 20; 
      t.Name = "button"; 

      RowDefinition rowDef1; 
      rowDef1 = new RowDefinition(); 
      mymy.RowDefinitions.Add(rowDef1); 

      ColumnDefinition colDef1; 
      colDef1 = new ColumnDefinition(); 
      mymy.ColumnDefinitions.Add(colDef1); 
      ++count; 

      mymy.Children.Add(t); 

      Grid.SetColumn(t, 1); 
      Grid.SetRow(t, count); 

     } 
    } 
} 

pytania: Jaki kod (XAML i C#) muszę być w stanie poruszać się metodę z kodem tyłu i do viewmodel?

Czy można użyć poleceń do dynamicznego dodawania pola tekstowego?

Zakładam, że pola tekstowe muszą być przechowywane w kontenerze, w którym to przypadku jest siatka. Ale jeśli używam MVVM, czy muszę zawierać pola tekstowe w widoku listy lub innym kontenerze używającym ItemsSource?

+0

To nie jest MVVM, z powodu którego prawdopodobnie walczysz. W MVVM, miałbym ViewModel z publicznie obserwowalną właściwością kolekcji modeli związanych z ItemsControl. Posiadałbym DataTemplate dla typu modelu. I będę miał ICommand powiązane z przyciskiem. Po kliknięciu przycisku polecenie uruchamia się w modelu widoku, do którego dodaję nowy model do kolekcji. Interfejs użytkownika automatycznie doda interfejs użytkownika dla elementu za pomocą DataTemplate. Właśnie dlatego robimy MVVM - to proste. To, co robisz, to formularze systemu Windows.Jeśli chcesz tworzyć formularze, zrób to. – Will

Odpowiedz

11

Wykonaj kroki i gotowe:

  1. Zastosowanie ItemsControl i wiążą to ItemsSource do pewnego zbioru (najlepiej ObservableCollection) w Twojej ViewModel.
  2. Zdefiniuj ItemTemplate dla ItemsControl z zawartością TextBox.
  3. Utwórz ICommand w ViewModel i powiąż go z przyciskiem.
  4. Po wykonaniu polecenia dodaj element do kolekcji, a zobaczysz, że TextBox zostanie dodany automatycznie.

XAML:

<StackPanel> 
    <Button Content="Add TextBox" Command="{Binding TestCommand}"/> 
    <ItemsControl ItemsSource="{Binding SomeCollection}"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <TextBox Text="{Binding Path=.}"/> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</StackPanel> 

ViewModel:

public class MainWindowViewModel : INotifyPropertyChanged 
{ 
    public ObservableCollection<string> SomeCollection { get; set; } 
    public ICommand TestCommand { get; private set; } 

    public MainWindowViewModel() 
    { 
     SomeCollection = new ObservableCollection<string>(); 
     TestCommand = new RelayCommand<object>(CommandMethod); 
    } 

    private void CommandMethod(object parameter) 
    { 
     SomeCollection.Add("Some dummy string"); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    protected void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

RelayCommand:

public class RelayCommand<T> : ICommand 
{  
    readonly Action<T> _execute = null; 
    readonly Predicate<T> _canExecute = null; 

    public RelayCommand(Action<T> execute) 
     : this(execute, null) 
    { 
    }  

    public RelayCommand(Action<T> execute, Predicate<T> canExecute) 
    { 
     if (execute == null) 
      throw new ArgumentNullException("execute"); 

     _execute = execute; 
     _canExecute = canExecute; 
    } 

    public bool CanExecute(object parameter) 
    { 
     return _canExecute == null ? true : _canExecute((T)parameter); 
    }  

    public event EventHandler CanExecuteChanged 
    { 
     add { CommandManager.RequerySuggested += value; } 
     remove { CommandManager.RequerySuggested -= value; } 
    } 

    public void Execute(object parameter) 
    { 
     _execute((T)parameter); 
    } 
} 

Uwaga - Zakładam, że wiesz jak podłączyć Widok z ViewModel przez ustawienie DataContext aby magia wiązania do pracy.

+1

Dzięki. Wow, nigdy by nie pomyślał o używaniu kolekcji "manekinów" do tworzenia kontrolek interfejsu użytkownika. Jedną z trudnych części uczenia się WPF jest po prostu znalezienie właściwości, jakie przedmioty mogą z nich korzystać i do czego służą. – user1181337

+0

Dokładnie WPF jest bardziej napędzany danymi, podczas gdy WinForms to więcej technologii opartej na interfejsie użytkownika. –

0
[link][1] 

class TestViewModel : BindableBase 
    { 
     private TestModel testModel; 

     public ICommand AddCommand { get; private set; } 
     public TestViewModel(StackPanel stkpnlDynamicControls) 
     { 
      testModel = new TestModel(); 
      TestModel.stkPanel = stkpnlDynamicControls; 
      AddCommand = new DelegateCommand(AddMethod); 
     } 
     public TestModel TestModel 
     { 
      get { return testModel; } 
      set { SetProperty(ref testModel, value); } 
     } 
     private void AddMethod() 
     { 
      Label lblDynamic = new Label() 
      { 
       Content = "This is Dynamic Label" 
      }; 
      TestModel.stkPanel.Children.Add(lblDynamic); 
     } 
    } 
+1

Ogólnie dobrym zwyczajem jest podanie pewnych wyjaśnień za pomocą kodu. Możesz edytować swoją odpowiedź, aby dodać więcej informacji. – Theresa

Powiązane problemy