如何将Linq结果绑定到WPF DataGrid,同时保持双向绑定MVVM

问题描述:

所以我理解我的问题相当好,我只是有问题开发解决方案。假设我有一个带有数据网格的MVVM WPF应用程序。 ItemSource绑定到一个集合ObservableCollection。由于数据模型相当复杂,这是通过转换器提供的,但模型复杂性与问题无关。然后我需要在我的可观察集合上使用Linq查询,因为我希望它只显示该集合中的某些项目。如何将Linq结果绑定到WPF DataGrid,同时保持双向绑定MVVM

如果我直接从我的转换器返回LINQ查询,我得到的错误“‘EditItem’不允许这种观点。”我意识到发生的错误,因为LINQ查询返回IEnumerable集合,这是不支持DataGrid TwoWay数据绑定。但是,如果我将它作为新的ObservableCollection返回,则会出现错误“双向绑定需要Path或XPath。”“这很有意义,因为新集合不是具有访问器和增变器的属性, ,我们以这种方式丢失了与原始源的数据绑定。

所以这里的问题是我如何只返回我需要从转换器中的项目,以这种方式保持我的数据绑定到原始源,并允许双向绑定?

我不确定是否需要以下内容,但可能值得关注此应用程序的背景。此应用程序在选项卡控件中动态生成了选项卡,并且每个选项卡项都包含这些DataGrid中的一个。这些数据网格用相同的对象集合来填充,只是每个对象都有一个不同的过滤器,这取决于它包含在哪个标签中(这一切都与绑定到模型中)。转换器在那里很重要,因为向任何数据网格添加项目都需要一些额外的编码。

下面是一些代码来演示这个问题。

的XAML的DataGrid:

<DataGrid IsReadOnly="False"> 
    <DataGrid.ItemsSource> 
     <MultiBinding Converter="{StaticResource MyObjectCollectionDataGridConverter}" UpdateSourceTrigger="PropertyChanged"> 
      <Binding Path="StateManager.MyObjectCollection" Mode="TwoWay"/> 
      <Binding Mode="OneWay"/> 
     </MultiBinding> 
    </DataGrid.ItemsSource> 
</DataGrid> 

的C#转换

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
{ 
    string header = ((MyObjectType)values[1]).Name; 

    // Returning as a Linq query: 
    // return ((ObservableCollection<MyObject>)values[0]).Where(c => c.Type.Name == header); 

    // Returning as a new Observable Collection 
    return new ObservableCollection<MyObject>(((ObservableCollection<MyObject>)values[0]).Where(c => c.Type.Name == header)); 
} 

感谢您的帮助!

编辑

好了,我也发现,通过使用LINQ查询方法时,通过调用ToList()方法,我的数据绑定并保持现有项目(这是有道理的,因为它只是引用对象的旧实例)。但是,当通过数据网格添加新项目时,应用程序中断时出现错误“双向绑定需要Path或XPath。”(这也是有意义的,因为它没有引用创建的新列表,而不是旧的可观察集合)。我该如何做到这一点,以便我仍然可以通过数据网格添加项目,以便通过新列表引用旧的可观察集合?

由于View支配虚拟机应该看起来像你的MyObject应该遵循这个规则。

你想扩展你的MyObject类来包含标志,不管项目是否可见。

这是你的RowViewModel的外观:

public class MyObject : INotifyPropertyChanged 
{ 
    private string _name; 
    public string Name 
    { 
     get { return _name; } 
     set 
     { 
      _name = value; 
      OnPropertyChanged(); 
     } 
    } 

    private bool _isEnabled; 
    public bool IsEnabled 
    { 
     get { return _isEnabled; } 
     set 
     { 
      _isEnabled = value; 
      OnPropertyChanged(); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public void OnPropertyChanged([CallerMemberName] string propName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); 
    } 
} 

这里是你将如何处理它在转换器:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
{ 
    string header = ((MyObject)values[1]).Name; 
    foreach (var item in (ObservableCollection<MyObject>)values[0]) 
     item.IsEnabled = item.Name == header; 

    return values[0]; 
} 

当然要公开启用旗标DataTemplate XAML:

<DataGrid IsReadOnly="False" AutoGenerateColumns="False"> 
    <DataGrid.ItemsSource> 
    <MultiBinding Converter="{StaticResource MyObjectCollectionDataGridConverter}" UpdateSourceTrigger="PropertyChanged"> 
     <Binding Path="StateManager.MyObjectCollection" Mode="TwoWay"/> 
     <Binding Mode="OneWay"/> 
    </MultiBinding> 
    </DataGrid.ItemsSource> 
    <DataGrid.Columns> 
      <DataGridTemplateColumn> 
       <DataGridTemplateColumn.CellTemplate> 
        <DataTemplate> 
         <TextBox Text="Hello" IsEnabled="{Binding IsEnabled}"/> 
        </DataTemplate> 
       </DataGridTemplateColumn.CellTemplate> 
      </DataGridTemplateColumn> 
    </DataGrid.Columns> 
</DataGrid> 
+0

此解决方案不起作用,因为您要永久移除数据源中的项目所有的数据网格都是从中绘制的。我只想从视图中删除它们。 – Chris

+0

@Goody Gotcha,检查更新的答案。 – Karolis