This article has been localized into German by the community.
Reaktion auf Änderungen
Bisher haben wir in diesem Tutorial hauptsächlich Bindungen zwischen UI-Elementen und bestehenden Klassen erstellt, aber in realen Anwendungen sind Sie natürlich an Ihre eigenen Datenobjekte gebunden. Das ist genauso einfach, aber wenn Sie damit anfangen, werden Sie vielleicht etwas entdecken, das Sie enttäuscht: Änderungen werden nicht automatisch übernommen, wie in früheren Beispielen. Wie Sie in diesem Artikel erfahren werden, brauchen Sie ein wenig zusätzliche Arbeit, um dies zu erreichen, aber zum Glück macht WPF dies ziemlich einfach.
Auf Änderungen in der Datenquelle reagieren
Es gibt zwei verschiedene Szenarien, die Sie beim Umgang mit Datenquellenänderungen möglicherweise behandeln möchten: Änderungen an der Liste der Elemente und Änderungen an den gebundenen Eigenschaften in jedem der Datenobjekte. Wie man damit umgeht, hängt davon ab, was Sie tun und was Sie erreichen wollen, aber WPF kommt mit zwei sehr einfachen Lösungen, die Sie verwenden können: Die ObservableCollection und die INotifyPropertyChanged Schnittstelle.
Das folgende Beispiel zeigt, wieso wir hier zweierlei Konzepte brauchen:
<Window x:Class="WpfTutorialSamples.DataBinding.ChangeNotificationSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ChangeNotificationSample" Height="150" Width="300">
<DockPanel Margin="10">
<StackPanel DockPanel.Dock="Right" Margin="10,0,0,0">
<Button Name="btnAddUser" Click="btnAddUser_Click">Add user</Button>
<Button Name="btnChangeUser" Click="btnChangeUser_Click" Margin="0,5">Change user</Button>
<Button Name="btnDeleteUser" Click="btnDeleteUser_Click">Delete user</Button>
</StackPanel>
<ListBox Name="lbUsers" DisplayMemberPath="Name"></ListBox>
</DockPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
namespace WpfTutorialSamples.DataBinding
{
public partial class ChangeNotificationSample : Window
{
private List<User> users = new List<User>();
public ChangeNotificationSample()
{
InitializeComponent();
users.Add(new User() { Name = "John Doe" });
users.Add(new User() { Name = "Jane Doe" });
lbUsers.ItemsSource = users;
}
private void btnAddUser_Click(object sender, RoutedEventArgs e)
{
users.Add(new User() { Name = "New user" });
}
private void btnChangeUser_Click(object sender, RoutedEventArgs e)
{
if(lbUsers.SelectedItem != null)
(lbUsers.SelectedItem as User).Name = "Random Name";
}
private void btnDeleteUser_Click(object sender, RoutedEventArgs e)
{
if(lbUsers.SelectedItem != null)
users.Remove(lbUsers.SelectedItem as User);
}
}
public class User
{
public string Name { get; set; }
}
}
Probieren Sie es selbst aus und sehen Sie, wie nichts in der Benutzeroberfläche aktualisiert wird, obwohl Sie der Liste etwas hinzufügen oder den Namen eines der Benutzer ändern. Das Beispiel ist ziemlich einfach, mit einer Benutzer-Klasse, die den Namen des Benutzers behält, einer Listbox zum Anzeigen und einigen Schaltflächen, um sowohl die Liste als auch ihren Inhalt zu manipulieren. Die ItemsSource der Liste ist einer simple Liste von einigen Benutzern zugeordnet, die wir im Fenster-Konstruktor anlegen. Das Problem ist, dass keine der Tasten zu funktionieren scheint. Lassen Sie uns das in zwei einfachen Schritten beheben.
Änderungen in der Datenquellen-Liste mitbekommen
Der erste Schritt besteht darin, das UI dazu zu bringen, auf Änderungen in der Listenquelle (ItemsSource) zu reagieren, z.B. wenn wir einen Benutzer hinzufügen oder löschen. Was wir brauchen, ist eine Liste, die alle Ziele über Änderungen an ihrem Inhalt informiert, und zum Glück bietet WPF eine Art von Liste, die genau das tut. Sie heißt ObservableCollection, und man benutzt es wie eine normale List<T>, nur mit ein paar wenigen Unterschieden.
Im letzten Beispiel, das Sie unten finden, haben wir einfach die List<User> durch eine ObservableCollection<User> ersetzt - das ist alles! Dadurch funktionieren die Schaltflächen "Hinzufügen" und "Löschen", aber für die Schaltfläche "Name ändern" wird nichts unternommen, da die Änderung auf dem gebundenen Datenobjekt selbst und nicht auf der Quellliste stattfindet - im zweiten Schritt werden wir uns jedoch darum kümmern.
Änderungen in den Datenobjekten mitbekommen
Der zweite Schritt ist die Implementierung der Schnittstelle INotifyPropertyChanged durch unsere Benutzer-Klasse. Dadurch sind unsere User-Objekte in der Lage, die UI-Schicht über Änderungen ihrer Eigenschaften zu informieren. Das ist etwas umständlicher, als nur den Listentyp zu ändern, wie wir es oben getan haben, aber es ist immer noch einer der einfachsten Wege, diese automatischen Updates durchzuführen.
Das abschließende, funktionsfähige Beispiel
Mit den beiden obigen Änderungen bekommen wir nun ein Beispiel, das auf Änderungen in der Datenquelle reagieren wird. Es sieht so aus:
<Window x:Class="WpfTutorialSamples.DataBinding.ChangeNotificationSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ChangeNotificationSample" Height="135" Width="300">
<DockPanel Margin="10">
<StackPanel DockPanel.Dock="Right" Margin="10,0,0,0">
<Button Name="btnAddUser" Click="btnAddUser_Click">Add user</Button>
<Button Name="btnChangeUser" Click="btnChangeUser_Click" Margin="0,5">Change user</Button>
<Button Name="btnDeleteUser" Click="btnDeleteUser_Click">Delete user</Button>
</StackPanel>
<ListBox Name="lbUsers" DisplayMemberPath="Name"></ListBox>
</DockPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace WpfTutorialSamples.DataBinding
{
public partial class ChangeNotificationSample : Window
{
private ObservableCollection<User> users = new ObservableCollection<User>();
public ChangeNotificationSample()
{
InitializeComponent();
users.Add(new User() { Name = "John Doe" });
users.Add(new User() { Name = "Jane Doe" });
lbUsers.ItemsSource = users;
}
private void btnAddUser_Click(object sender, RoutedEventArgs e)
{
users.Add(new User() { Name = "New user" });
}
private void btnChangeUser_Click(object sender, RoutedEventArgs e)
{
if(lbUsers.SelectedItem != null)
(lbUsers.SelectedItem as User).Name = "Random Name";
}
private void btnDeleteUser_Click(object sender, RoutedEventArgs e)
{
if(lbUsers.SelectedItem != null)
users.Remove(lbUsers.SelectedItem as User);
}
}
public class User : INotifyPropertyChanged
{
private string name;
public string Name {
get { return this.name; }
set
{
if(this.name != value)
{
this.name = value;
this.NotifyPropertyChanged("Name");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if(this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
Zusammenfassung
Wie Sie sehen können, ist die Implementierung von INotifyPropertyChanged ziemlich einfach, aber es erzeugt ein wenig zusätzlichen Code für Ihre Klassen und fügt ein wenig zusätzliche Logik zu Ihren Eigenschaften hinzu. Dies ist der Preis, den Sie zahlen müssen, wenn Sie sich an Ihre eigenen Klassen binden und die Änderungen sofort in der Benutzeroberfläche widerspiegeln wollen. Natürlich müssen Sie INotifyPropertyChanged nur im Setter der Eigenschaften aufrufen, an die Sie binden - der Rest kann so bleiben, wie er ist.
Hingegen ist die ObservableCollection sehr einfach zu verwenden - Sie müssen diesen speziellen Listentyp einfach nur dann verwenden, wenn Ihr Bindungsziel über Änderungen benachrichtigt werden soll.