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

时间:2016-10-03 18:29:10

标签: c# wpf linq mvvm datagrid

所以我很清楚我的问题,我只是遇到了为它开发解决方案的问题。让我们说我有一个带有数据网格的MVVM WPF应用程序。 ItemSource绑定到ObservableCollection集合。这是通过转换器提供的,因为数据模型相当复杂,但模型复杂性与问题没有任何关系。然后我需要在我的observable集合上使用Linq查询,因为我希望它只显示该集合中的某些项目。

如果我直接从我的转换器返回Linq查询,我会收到错误" ' EditItem'不允许使用此视图。"我意识到发生该错误是因为Linq查询返回了一个IEnumerable集合,DataGrid TwoWay数据绑定不支持该集合。

但是,如果我将其作为新的ObservableCollection返回,我会收到错误" 双向绑定需要Path或XPath。"这是有道理的,因为新集合不是具有访问器和更改器的属性,而且,我们以这种方式丢失了与原始源绑定的数据。

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

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

以下是一些用于演示此问题的代码。

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()方法,我的数据绑定确实适用于现有项目(这是有意义的,因为它只是引用对象的旧实例)。但是,当通过数据网格添加新项目时,应用程序会中断错误&#34; 双向绑定需要Path或XPath。&#34; (这也很有意义,因为它没有引用创建的新列表,而不是旧的可观察集合)。如何制作它以便我仍然可以通过数据网格添加项目以引用新列表上的旧可观察集合?

1 个答案:

答案 0 :(得分:1)

由于View指示VM看起来应该是什么样,因此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>