【问题标题】:How to bind a Linq result to a WPF DataGrid while keeping two way binding MVVM如何将 Linq 结果绑定到 WPF DataGrid,同时保持两种方式绑定 MVVM
【发布时间】:2017-02-11 18:48:32
【问题描述】:

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

如果我直接从转换器返回 Linq 查询,我会收到错误“'EditItem' is not allowed for this view.”我意识到发生该错误是因为 Linq 查询返回一个 IEnumerable集合,DataGrid TwoWay 数据绑定不支持。

但是,如果我将它作为新的 ObservableCollection 返回,我会收到错误“双向绑定需要 Path 或 XPath。”这是有道理的,因为新集合不是具有访问器的属性,并且mutators,此外,我们以这种方式失去了与原始源的数据绑定。

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

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

这里有一些代码来演示这个问题。

XAML 数据网格:

<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。”而中断(这也是有道理的,因为它没有引用创建的新列表,不是旧的可观察集合)。如何做到这一点,以便我仍然可以通过数据网格添加项目以在新列表上引用旧的 observable 集合?

【问题讨论】:

    标签: c# wpf linq mvvm datagrid


    【解决方案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>
    

    【讨论】:

    • 此解决方案不起作用,因为您要从所有数据网格从中绘制的数据源中永久删除项目。我只想将它们从视图本身中删除。
    猜你喜欢
    • 2021-03-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-06
    • 2018-02-07
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多