Как использовать привязку данных в WPF C #?

#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 в этом случае работает, потому что вы назначаете другой экземпляр списка.