#c# #wpf #binding #code-behind
#c# #wpf #привязка #код за
Вопрос:
Я хочу связать свои элементы управления с моей моделью представления в WPF и автоматически обновлять элементы управления данными при обновлении моей базы данных. Я реализовал модель представления, которая имеет некоторые List<myClass>
свойства и получает данные из базы данных, которые будут сохранены в этих свойствах. Затем я привязываю свой источник элементов управления к этим свойствам. Все в порядке, но когда я получаю новые данные из базы данных и сохраняю их в этих свойствах, данные элементов управления не обновляются. Как я могу исправить это программно?
Это мой код:
public partial class MainWindow : Window
{
ListOfPerson personList1 = new ListOfPerson();
ListOfPerson personList2 = new ListOfPerson();
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
personList1.People.Add(new Person { PersonName = "test1" });
personList2.People.Add(new Person { PersonName = "test2" });
dg.AutoGenerateColumns = false;
PropertyPath prop = new PropertyPath("PersonName");
Binding bind = new Binding();
bind.Mode = BindingMode.TwoWay;
bind.Path = prop;
dg.Columns.Add(new DataGridTextColumn { Header = "Name", Binding = bind });
dg.ItemsSource = personList1.People;
}
public void Refresh()
{
personList1.People = personList2.People;
}
private void btn_Refresh_Click(object sender, RoutedEventArgs e)
{
Refresh();
}
}
public class Person : INotifyPropertyChanged
{
private string name;
public Person()
{
}
public Person(string value)
{
this.name = value;
}
public string PersonName
{
get { return name; }
set
{
name = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
public class ListOfPerson : INotifyPropertyChanged
{
private List<Person> people = new List<Person>();
public List<Person> People
{
get
{
return people;
}
set
{
people = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Комментарии:
1. В случае, если вы собираетесь добавлять элементы в a
List<Person>
после того, как они были назначены свойству People для ListOfPerson, вам следует использовать ObservableCollection вместо List .2. Резервуары. Но я использую наблюдаемую коллекцию, и у нее тоже есть эта проблема.
Ответ №1:
Вы назначаете свой ItemsSource
напрямую, это не является привязкой.
dg.ItemsSource = personList1.People;
Refresh
Однако, вы заменяете People
коллекцию personList1
.
personList1.People = personList2.People;
Источник элементов по-прежнему содержит ссылку на старую коллекцию, поскольку вы назначили ее напрямую. Вместо этого вы могли бы добавить привязку, которая заметила бы, что источник элементов изменился с помощью реализации уведомления об изменении свойства ListOfPerson
для People
свойства. Это должно сработать:
Binding itemsSourceBinding = new Binding
{
Source = personList1,
Path = new PropertyPath("People")
};
BindingOperations.SetBinding(dg, DataGrid.ItemsSourceProperty, itemsSourceBinding);
Это только один из вариантов обработки этого сценария. Другой вариант — использовать только один ObservableCollection<T>
экземпляр, который вы Clear
и заполняете снова или изменяете между ними (если вы замените его новым экземпляром, подобным списку в вашем коде, вы столкнетесь с той же проблемой, что и выше). Он реализует INotifyCollectionChanged
интерфейс и уведомляет об изменениях, таких как автоматическое добавление, удаление или вставка элементов, что, в свою очередь, обновляет пользовательский интерфейс.
Комментарии:
1.
PropertyPath("personList1.People")
будет работать только тогда, когда personList1 является общедоступным свойством. Вместо этого вы можете использовать его в качестве источника сPropertyPath("People")
помощью .2. @Clemens Спасибо, вы правы, я упустил из виду, что списки пользователей на самом деле являются полями.
3.
Source = personList1.People
не будет вызвано PropertyChanged.4. @thatguy Танки. Итак, мне нужно создать новую привязку для каждого элемента управления в приложении, которое использует совместное свойство? Я проверяю, что если после
personList1.People = personList2.People;
Я пользуюсьdg.ItemsSource = personList1.People;
, все будет в порядке. Но я хочу решение, которое не нужно реализовывать для каждого элемента управления. Я использую INotifyCollectionChanged, но он работает плохо.5. @MaryamHeydari Без привязки обновление свойств работать не будет. Конечно, переназначение
ItemsSource
в этом случае работает, потому что вы назначаете другой экземпляр списка.