2017-02-07 70 views
6

Jestem nowicjuszem w MVVM i utknąłem przy wiązaniu danych. Mam przycisk na mojej stronie widoku, który dynamicznie tworzy pola tekstowe, ale nie widzę jak wiążę te pola tekstowe z moją listą w ViewModel.Wiązanie dynamicznego pola tekstowego z listą

Moim zdaniem mam:

<Button x:Name="btWebsite" Grid.ColumnSpan="2" Width="50" Height="50" Click="btWebsite_Click" Margin="23,245,259,202"> 
     <StackPanel x:Name="pnWebsiteButton" Orientation="Horizontal"> 
      <Image x:Name="imgWebsite" Source= "Images/webIcon.jpg" Stretch="Fill" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
     </StackPanel> 
    </Button> 
    <GroupBox x:Name="grpWebsite" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="73,245,0,0" Grid.ColumnSpan="2" Height="51" Width="170" BorderBrush="{x:Null}" BorderThickness="0"> 
     <ScrollViewer x:Name="pnScrollWebsite" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="0,0,0,-6"> 
      <StackPanel x:Name="pnWebsite" Orientation="Vertical" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="1,2,0,0" VerticalAlignment="Top" IsEnabled="True"> 

      </StackPanel> 
     </ScrollViewer> 
    </GroupBox> 

Kod za przycisku to:

private void btWebsite_Click(object sender, RoutedEventArgs e) 
{ 
    var newTextBox = new TextBox(); 
    newTextBox.Text = "type the website address..."; 
    newTextBox.Foreground = Brushes.Gray; 
    newTextBox.Width = 150; 
    newTextBox.Name = "txtWebsite" + iWebsites; 
    pnWebsite.Children.Add(newTextBox); 
    pnWebsite.RegisterName(newTextBox.Name, newTextBox); 

    iWebsites++; 
} 

W moim ViewModel mam:

public List<string> Websites 
{ 
    get { return _websites; } 
    set 
    { 
     if (value != _websites) 
     { 
      _websites = value; 
      OnPropertyChanged("Websites"); 
     } 
    } 
} 

walczę, aby zobaczyć, jak Dostaję textbox witryny na listę viewmodel. Dziękujemy za pomoc

+1

znacznie lepiej użyć 'ItemsControl "związany z kolekcją witryn internetowych:' '. Uczyń strony internetowe 'ObservableCollection ', dodaj ciąg do kolekcji - i będzie wyświetlany w widoku – ASh

+0

Możesz chcieć rzucić okiem przez [pokój czatu WPF] (http://chat.stackoverflow.com/rooms/18165/wpf) .. koncentrujemy się na MVVM zastosowanej do WPF. Uwaga: Będziesz potrzebował co najmniej 15 powtórzeń. –

+0

Dzięki, ale mam tylko 11 powtórzeń, więc nie mogę wysłać tam –

Odpowiedz

1

Usuń program obsługi zdarzeń z poziomu kodu: btWebsite_Click.

Modyfikowanie XAML tak:

<Button x:Name="btWebsite" Grid.ColumnSpan="2" Width="50" Height="50" Command="{Binding AddNewStringCommand}" Margin="23,245,259,202"> 
     <StackPanel x:Name="pnWebsiteButton" Orientation="Horizontal"> 
      <Image x:Name="imgWebsite" Source= "Images/webIcon.jpg" Stretch="Fill" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
     </StackPanel> 
</Button> 
<GroupBox x:Name="grpWebsite" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="73,245,0,0" Grid.ColumnSpan="2" Height="51" Width="170" BorderBrush="{x:Null}" BorderThickness="0"> 
    <ScrollViewer x:Name="pnScrollWebsite" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="0,0,0,-6"> 
     <StackPanel x:Name="pnWebsite" Orientation="Vertical" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="1,2,0,0" VerticalAlignment="Top" IsEnabled="True"> 

      <ItemsControl ItemsSource="{Binding Websites}"> 
       <ItemsControl.ItemTemplate> 
        <DataTemplate> 
         <TextBox Text="{Binding Mode=TwoWay}"/> 
        </DataTemplate> 
       </ItemsControl.ItemTemplate> 
      </ItemsControl> 

     </StackPanel> 
    </ScrollViewer> 
</GroupBox> 

Trzeba zmodyfikować ViewModel również:

public ObservableCollection<string> Websites { get; set; } 

public ICommand AddNewStringCommand => new RelayCommand(AddNewString); 

private void AddNewString() 
{ 
    Websites.Add(string.Empty); 
} 

Zamiast RelayCommand można użyć dowolnego realizację ICommand. Używam na przykład MVVMLight.

Jak widać, główne różnice:

  • Zamiast obsługi zdarzenia Click, istnieje komenda Oprawa w przycisku.
  • Zamiast generować nowe kontrolki z kodu, istnieje ItemsControl, który tworzy za każdym razem, gdy mamy nowy element w kolekcji.
  • Nowa właściwość Tekst TextBox jest powiązana z nowym elementem.

Aktualizacja:

popełniłem błąd, ObservableCollection nie pracuje bezpośrednio z TextBox.

Wydaje trzeba coś dodatkowo:

public class Website 
{ 
    public string Name { get; set; } 
} 

modyfikować ViewModel tak:

public ObservableCollection<Website> Websites { get; set; } = new ObservableCollection<Website>(); 

public ICommand AddNewStringCommand => new RelayCommand(AddNewString); 

private void AddNewString() 
{ 
    Websites.Add(new Website {Name = "new website"}); 
} 

A ItemsTemplate tak:

<ItemsControl.ItemTemplate> 
    <DataTemplate> 
     <StackPanel > 
      <TextBox Text="{Binding Name, Mode=TwoWay}"/> 
     </StackPanel> 
    </DataTemplate> 
</ItemsControl.ItemTemplate> 
+0

Dziękuję, to wygląda dobrze. Zaimplementowałem Twoją sugestię, ale teraz nowe pole tekstowe nie jest wyświetlane na stronie. –

+0

@TheresaFerguson Dodałem trochę aktualizacji, ponieważ testowałem i nie działało poprawnie. – jannagy02

+0

Dziękuję bardzo. wszystko działa teraz :-) –