【问题标题】:DataGrid bound to BindingList (or ObservableCollection) does not update绑定到 BindingList(或 ObservableCollection)的 DataGrid 不更新
【发布时间】:2017-03-27 10:02:57
【问题描述】:

我在 SO 上尝试了很多解决方案,但没有一个适合我。 DataGrid 永远不会更新。

我有一个类 (UserTab) 从 UserControl 继承,带有 XAML,还有一个类带有数据 (TableController)。

XAML(用户标签):

<local:BaseTab.Resources>
        <ResourceDictionary>
            <controller:TableController x:Key="tablecontroller" />
        </ResourceDictionary>
</local:BaseTab.Resources>

<DataGrid x:Name="dataGrid"
          IsReadOnly="True"
          ItemsSource="{Binding Path=FilteredEntries, Source={StaticResource tablecontroller}}"
          SelectionUnit="Cell"
          AutoGenerateColumns="False">
          <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding id}"
                                    Header="{StaticResource id}" />
                <DataGridTextColumn Binding="{Binding name}"
                                    Header="{StaticResource name}" />
                <DataGridTextColumn Binding="{Binding desc}"
                                    Header="{StaticResource desc}" />
          </DataGrid.Columns>
</DataGrid>

我也尝试过更改ModeUpdateSourceTrigger

表格控制器

public class TableController : INotifyPropertyChanged
{
    private IList<entry> _allEntries;
    private BindingList<entry> _filteredEntries = new BindingList<entry>();

    public IList<entry> AllEntries
    {
        get
        {
            return _allEntries;
        }
        set
        {
            _allEntries = value;
        }
    }
    public BindingList<entry> FilteredEntries
    {
        get
        {
            return _filteredEntries;
        }
        set
        {
            _filteredEntries = value;
            NotifyPropertyChanged("FilteredEntries");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private void LoadData()
    {
        using (var dbContext = new InventarDBEntities())
        {
            AllEntries = dbContext.entry.OrderBy(x => x.name).ToList();
            //FilteredEntries = new BindingList<entry>(AllEntries);
        }
    }

    public void TestMethod()
    {
        foreach (entry entry in AllEntries)
        {
            FilteredEntries.Add(entry);
        }
    }
}

以后的FilteredEntries 只包含AllEntries 的子列表。我使用此代码来测试绑定。首先FilteredEntries 是空的,DataGrid 也是空的。单击按钮并触发 TestMethod 时,FilteredEntries 包含条目,但 DataGrid 仍然为空。我也试过ObservableCollection 并在UserTab.xaml.cs 中创建一个属性,只是从TableController 转发FilteredEntries。没有任何效果。

更新: 似乎第一个 Binding 不起作用,因为当我通过代码设置 ItemSource 时,它​​会在更改列表时更新。

【问题讨论】:

  • 只是一个提示:在使用 ICollectionView 和内置过滤器逻辑时,您不需要两个列表。您可以将所有条目放在一个列表中,而您查看的只会显示过滤后的条目。
  • FilteredEntries 应该是 ObservableCollection 而不是 BindingList。您应该在 AllEntries 属性的设置器中调用 NotifyPropertyChanged 方法。
  • 但是 ICollectionView 没有一些好的方法/属性。是否可以将 ICollectionView 绑定到 dataGrid?
  • ICollectionView?我说的是 ObservableCollection 类型。请参考我的回答。

标签: c# wpf xaml data-binding datagrid


【解决方案1】:

FilteredEntries属性的类型改为ObservableCollection&lt;entry&gt;,并在AllEntries属性的setter中调用NotifyPropertyChanged方法:

public class TableController : INotifyPropertyChanged
{
    private IList<entry> _allEntries;
    private ObservableCollection<entry> _filteredEntries = new ObservableCollection<entry>();

    public IList<entry> AllEntries
    {
        get
        {
            return _allEntries;
        }
        set
        {
            _allEntries = value;
            NotifyPropertyChanged("AllEntries");
        }
    }
    public ObservableCollection<entry> FilteredEntries
    {
        get
        {
            return _filteredEntries;
        }
        set
        {
            _filteredEntries = value;
            NotifyPropertyChanged("FilteredEntries");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private void LoadData()
    {
        using (var dbContext = new InventarDBEntities())
        {
            AllEntries = dbContext.entry.OrderBy(x => x.name).ToList();
            //FilteredEntries = new BindingList<entry>(AllEntries);
        }
    }

    public void TestMethod()
    {
        foreach (entry entry in AllEntries)
        {
            FilteredEntries.Add(entry);
        }
    }
}

那行不通。它必须是具有约束力而不是更新的东西。当我将 dataGrid 的 dataContext 设置为 TableController.FilteredEntries 时,它可以工作并显示所有更新

当然,您必须将DataGridDataContext 或其任何父元素设置为TableController 类的实例才能绑定到它。

我不知道您为什么要尝试绑定到资源。您不应将 TableController 添加为资源,而应将其设置为元素的 DataContext

<local:BaseTab.DataContext>
    <controller:TableController />
</local:BaseTab.Resources>

<DataGrid x:Name="dataGrid"
      IsReadOnly="True"
      ItemsSource="{Binding Path=FilteredEntries}"
      SelectionUnit="Cell"
      AutoGenerateColumns="False">
...

或者:

<DataGrid x:Name="dataGrid"
          IsReadOnly="True"
          ItemsSource="{Binding Path=FilteredEntries}"
          SelectionUnit="Cell"
          AutoGenerateColumns="False">
    <DataGrid.DataContext>
        <controller:TableController />
    </DataGrid.DataContext>
    ...
</DataGrid>

【讨论】:

  • 那行不通。它必须是具有约束力而不是更新的东西。当我将 dataGrid 的 dataContext 设置为 TableController.FilteredEntries 时,它可以工作并显示所有更新。
  • 当然你需要将DataContext设置为一个TableController的实例,并设置这个特定实例的属性。请参阅我编辑的答案。
  • 是的,它是这样工作的,谢谢。但我无法为整个 UserControl 设置 DataContext。
  • 为什么不呢?然后设置DataGrid的DataContext。
  • 谢谢!按预期工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-20
  • 2021-08-31
  • 2016-09-13
  • 2021-11-15
  • 1970-01-01
  • 1970-01-01
  • 2017-11-21
相关资源
最近更新 更多