【问题标题】:Updating target for DataGridColumn bound to DataRow through converter通过转换器更新绑定到 DataRow 的 DataGridColumn 的目标
【发布时间】:2017-08-01 11:15:28
【问题描述】:

此问题与https://stackoverflow.com/questions/42611351/cannot-bind-to-additional-properties-on-typed-datarow有关

我现在所做的是使用转换器来填充数据网格列,其中包含我从键入的数据行中的其他字段计算的值。初始更新一切正常。当我更改计算值所依赖的行值之一时,问题就出现了。我不知道如何更新计算的目标。

这里是 XAML...

<Window.Resources>
    <local:FullNameConverter x:Key="FullNameConverter"/>
</Window.Resources>
<Grid>
    <DataGrid ItemsSource="{Binding TableA}" AutoGenerateColumns="False" >
            <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Name}"  Width="30*" Header="Name" SortDirection="Ascending" />
            <DataGridTextColumn Header="Value" Width="30*" Binding="{Binding Value}"/>
            <DataGridTextColumn Header="Full Name" Width="30*" 
                                Binding="{Binding Converter={StaticResource FullNameConverter}}" IsReadOnly="True"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

这是后面的代码...

public partial class BindingBench : Window
{
    SimplyDataSet _dataSet = new SimplyDataSet();
    public BindingBench()
    {
        InitializeComponent();
        _dataSet.TableA.Columns.Add(new DataColumn("FullName",typeof(string)));
        SimplyDataSet.TableARow arow = _dataSet.TableA.AddTableARow("Z", 0.0);
        arow = _dataSet.TableA.AddTableARow("X", 1.0);
        arow = _dataSet.TableA.AddTableARow("Y", 2.0);
        DataContext = this;
    }
    public DataTable TableA
    {
        get { return _dataSet.TableA; }
    }
}

这是转换器...

public class FullNameConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        DataRowView rv = value as DataRowView;
        if(rv != null)
        {
            SimplyDataSet.TableARow row = rv.Row as SimplyDataSet.TableARow;
            if (row != null)
            {
                return row.Name + "=" + row.Value;
            }
        }
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

最后是类型化的数据集...

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="SimplyDataSet"  targetNamespace="http://tempuri.org/SimplyDataSet.xsd" xmlns:mstns="http://tempuri.org/SimplyDataSet.xsd" xmlns="http://tempuri.org/SimplyDataSet.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:msprop="urn:schemas-microsoft-com:xml-msprop" attributeFormDefault="qualified" elementFormDefault="qualified">
<xs:annotation>
<xs:appinfo source="urn:schemas-microsoft-com:xml-msdatasource">
  <DataSource DefaultConnectionIndex="0" FunctionsComponentName="QueriesTableAdapter" Modifier="AutoLayout, AnsiClass, Class, Public" SchemaSerializationMode="IncludeSchema" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
    <Connections />
    <Tables />
    <Sources />
  </DataSource>
</xs:appinfo>
</xs:annotation>
<xs:element name="SimplyDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:EnableTableAdapterManager="true" msprop:Generator_DataSetName="SimplyDataSet" msprop:Generator_UserDSName="SimplyDataSet">
<xs:complexType>
  <xs:choice minOccurs="0" maxOccurs="unbounded">
    <xs:element name="TableA" msprop:Generator_TableClassName="TableADataTable" msprop:Generator_TableVarName="tableTableA" msprop:Generator_TablePropName="TableA" msprop:Generator_RowDeletingName="TableARowDeleting" msprop:Generator_RowChangingName="TableARowChanging" msprop:Generator_RowEvHandlerName="TableARowChangeEventHandler" msprop:Generator_RowDeletedName="TableARowDeleted" msprop:Generator_UserTableName="TableA" msprop:Generator_RowChangedName="TableARowChanged" msprop:Generator_RowEvArgName="TableARowChangeEvent" msprop:Generator_RowClassName="TableARow">
      <xs:complexType>
        <xs:sequence>
          <xs:element name="Name" msprop:Generator_ColumnVarNameInTable="columnName" msprop:Generator_ColumnPropNameInRow="Name" msprop:Generator_ColumnPropNameInTable="NameColumn" msprop:Generator_UserColumnName="Name" type="xs:string" minOccurs="0" />
          <xs:element name="Value" msprop:Generator_ColumnVarNameInTable="columnValue" msprop:Generator_ColumnPropNameInRow="Value" msprop:Generator_ColumnPropNameInTable="ValueColumn" msprop:Generator_UserColumnName="Value" type="xs:double" minOccurs="0" />
        </xs:sequence>
      </xs:complexType>
    </xs:element>
  </xs:choice>
</xs:complexType>
  </xs:element>
</xs:schema>

注意事项:

  1. 这是一套完整的代码。您看不到 TableA 或 AddTableARow 实现的原因是有一个工具 (XSD) 可以生成代码来实现数据集。我也可以添加这个生成的代码,但即使对于像这个这样的小数据集,它也很庞大,而且不是很有帮助。
  2. 在我看来,我提交的这两个相关问题的基本问题是 DataGridColumn 通过 DataRowView 绑定到 DataRow。我正在向底层 DataRow 添加内容,但无法修改 DataRowView 的行为。因此,在我看来,DataSet 从根本上与 MVVM 不兼容。但是,我似乎找不到任何意见认为应该避免使用 DataSet 来支持其他东西。
  3. 我已经尝试了多种方法来更新计算单元格,包括 DataRowView.BeginEdit()/EndEdit()、在 DataRow 上实现 INotifyPropertyChanged 等。
  4. 我可以通过刷新数据源来更新计算列。这不是解决方案!我可以忍受更新一行中的所有单元格,但不能更新每个单元格。

欢迎任何想法或建议。

【问题讨论】:

    标签: c# wpf mvvm datagrid strongly-typed-dataset


    【解决方案1】:

    我不熟悉您的 SimplyDataSet 类,但我建议绑定到 CollectionViewSource 并将您的 DataSet 分配给 CollectionViewSource.Source 使用 CollectionViewSource 作为代理,它实现 INotifyPropertyChanged 以正确更新您的UI,并保持与底层数据源的连接。

    public partial class BindingBench : Window
    {
        CollectionViewSource dbViewsource = new CollectionViewSource();
        SimplyDataSet _dataSet = new SimplyDataSet();
        public BindingBench()
        {
            InitializeComponent();
            _dataSet.TableA.Columns.Add(new DataColumn("FullName", typeof(string)));
            SimplyDataSet.TableARow arow = _dataSet.TableA.AddTableARow("Z", 0.0);
            arow = _dataSet.TableA.AddTableARow("X", 1.0);
            arow = _dataSet.TableA.AddTableARow("Y", 2.0);
            dbViewsource.Source = _dataSet  //This could possibly be _dataSet.GetDefaultView()
            DataContext = dbViewSource.View;
        }
        public DataTable TableA
        {
            get { return _dataSet.TableA; }
        }
    }
    

    可以在此处找到更深入的示例: https://msdn.microsoft.com/en-us/library/dd547149.aspx

    【讨论】:

    • 是的,我知道如何绑定到 CollectionViewSource。我使用类型化 DataSet 的原因是它提供的不仅仅是 CollectionViewSource。特别是它有一个模式设计器,您可以使用它来设置表和关系。简单地说,使用类型化 DataSet 进行编码是在不同的抽象级别上操作的。它比使用一堆 ObservableCollection 类和启用 INotifyPropertyChanged 的​​对象要高效得多。所以令我惊讶的是,微软似乎正在放弃类型化的 DataSet。 UWP 不支持数据集。我认为这是一个明确的信号。
    • 我不能不同意您的互动,但在我看来,CollectionViewSource 仍然是您对数据的“视图”,而您的 DatSet 是“模型”。并且 INotifyProperty 是代表您实现的,因此您可以保持 DataSet 原样(不像在 POCO 类模型上那样显式实现 INotifyPropertyChanged)您不会丢失任何绑定功能,所以我不确定问题在哪里。我对这个主题有点不理解,但这是我的理解。
    • 公平点。我稍微修改了您的代码以使其正常工作。问题是一样的。我更改了值,但全名列没有得到更新。我还没有深入研究这一点,但我认为 CollectionViewSource.View 将只是表创建的 DataView 之上的另一层。所以我认为这没有帮助,但我会进一步研究。
    • 如果它仍然无法正常工作,我会提出这个问题.. 您的 SimplyDataSet 是否正确扩展了 DataSet?我将挖掘一个仅使用 DataSet 的工作示例,我们可以尝试将 SimplyDataSet 插入等式
    • SimplyDataSet 是一个类型化的数据集。看到上面的 XML 代码了吗?那是类型化的数据集。要使用它,请执行此操作。创建一个 C# 项目并添加一个数据集。您将获得一个空白模式设计器。现在右键单击数据集并使用 XML 编辑器打开。您将看到空数据集的 XML。粘贴上面的 XML,您将拥有我正在使用的内容。
    猜你喜欢
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 2011-02-09
    • 2011-09-12
    • 2017-12-18
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    相关资源
    最近更新 更多