WPF将值分配给DataContext属性不会更改bound属性的值

问题描述

将值分配给DataContext属性不会更改绑定属性的值。

我需要为表中的每个记录多次获取绑定属性的值,以计算DataGrid中列的总和。

为此,我使用了一个特殊的虚拟FrameworkElement对象。

目标代码如下:

  public class BindValueReader : FrameworkElement
  {
    public static readonly DependencyProperty ValueProperty =
      DependencyProperty.Register("Value",typeof(object),typeof(BindValueReader),new PropertyMetadata(null));

    public object Value
    {
      get { return GetValue(ValueProperty); }
      set { SetValue(ValueProperty,value); }
    }
  }

它仅用于从绑定中获取值。

我使用以下代码获取每个记录的bound属性值。

  Decimal sumVal = 0;
  foreach (DataRowView rowView in view)
  {
    BindValueReader valueReader = new BindValueReader();
    valueReader.DataContext = rowView;
    valueReader.SetBinding(BindValueReader.ValueProperty,bdn);
    if (valueReader.Value != null)
      sumVal += (Decimal)valueReader.Value;
  }

它可以正常工作,但是速度很慢。

当我尝试优化这样的代码

  Binding bdn = new Binding("Income");

  BindValueReader valueReader = new BindValueReader();
  valueReader.SetBinding(BindValueReader.ValueProperty,bdn);

  DataView view = dataTable.DefaultView;
  Decimal sumVal = 0;

  foreach (DataRowView rowView in view)
  {
    valueReader.DataContext = rowView;
    if (valueReader.Value != null)
      sumVal += (Decimal)valueReader.Value;
  }

它停止工作。

我不知道为什么。

这是完整的程序代码:

XAML:

<Window x:Class="EhLibTestApp.TestWindow1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:EhLibTestApp"
        mc:Ignorable="d"
        Title="TestWindow1" Height="450" Width="800">
    <Grid>
    <StackPanel HorizontalAlignment="Stretch" Height="63" VerticalAlignment="Top" Orientation="Horizontal" >
      <Button Content="Button" Width="87" Margin="10" Click="Button_Click"/>
    </StackPanel>

  </Grid>
</Window>

CS:

using System;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Data;
using System.Diagnostics;

namespace EhLibTestApp
{
  /// <summary>
  /// Interaction logic for TestWindow1.xaml
  /// </summary>
  public partial class TestWindow1 : Window
  {
    public TestWindow1()
    {
      InitializeComponent();
    }

    private void Button_Click(object sender,RoutedEventArgs e)
    {
      DataTable dataTable = new DataTable();
      dataTable.Columns.Add("EmployeeID",typeof(Int32));
      dataTable.Columns.Add("LastName",typeof(String));
      dataTable.Columns.Add("Income",typeof(System.Decimal));

      dataTable.Rows.Add(1,"Davolio",100);
      dataTable.Rows.Add(2,"Fuller",100);
      dataTable.Rows.Add(3,"Leverling",100);
      dataTable.Rows.Add(4,"Peacock",DBNull.Value);

      Debug.WriteLine("");
      Debug.WriteLine("Test1");
      Test1(dataTable);

      Debug.WriteLine("");
      Debug.WriteLine("Test2");
      Test2(dataTable);
    }

    private void Test1(DataTable dataTable)
    {
      Binding bdn = new Binding("Income");
      DataView view = dataTable.DefaultView;

      int ticks = Environment.TickCount;
      Decimal sumVal = 0;
      foreach (DataRowView rowView in view)
      {
        BindValueReader valueReader = new BindValueReader();
        valueReader.DataContext = rowView;
        valueReader.SetBinding(BindValueReader.ValueProperty,bdn);
        if (valueReader.Value != null)
          sumVal += (Decimal)valueReader.Value;
      }

      Debug.WriteLine("Sum of Income = " + sumVal.ToString());
      Debug.WriteLine("Ticks = " + (Environment.TickCount - ticks).ToString());
    }

    private void Test2(DataTable dataTable)
    {
      Binding bdn = new Binding("Income");

      BindValueReader valueReader = new BindValueReader();
      valueReader.SetBinding(BindValueReader.ValueProperty,bdn);

      DataView view = dataTable.DefaultView;
      Decimal sumVal = 0;
      int ticks = Environment.TickCount;

      foreach (DataRowView rowView in view)
      {
        valueReader.DataContext = rowView;
        if (valueReader.Value != null)
          sumVal += (Decimal)valueReader.Value;
      }

      Debug.WriteLine("Sum of Income = " + sumVal.ToString());
      Debug.WriteLine("Ticks = " + (Environment.TickCount - ticks).ToString());
    }
  }

  public class BindValueReader : FrameworkElement
  {
    public static readonly DependencyProperty ValueProperty =
      DependencyProperty.Register("Value",value); }
    }
  }

}

调试输出:

Test1
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=Income; DataItem='DataRowView' (HashCode=22689808); target element is 'BindValueReader' (Name=''); target property is 'Value' (type 'Object')
Sum of Income = 300
Ticks = 16

Test2
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=Income; DataItem=null; target element is 'BindValueReader' (Name=''); target property is 'Value' (type 'Object')
Sum of Income = 0
Ticks = 0
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=Income; DataItem='DataRowView' (HashCode=22689808); target element is 'BindValueReader' (Name=''); target property is 'Value' (type 'Object')

解决方法

您要对收入属性进行求和。

您可以通过使用获取的数据行视图中的列而不是使用绑定来做到这一点。

foreach (DataRowView rowView in view)
{
   var val = rowView["Income"];
   if (val != null)
   {
      sumVal += (Decimal)val;
   }
}

这不是使用WPF的好方法,您应该研究MVVM,定义一个实现将inotifypropertychanged更改为行视图模型的类。将项目源绑定到此项目的可观察集合。然后使用绑定的集合和命名的属性。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...