【问题标题】:WPF. Assigning a value to the DataContext property doesn't change the value of the bound propertyWPF。为 DataContext 属性赋值不会改变绑定属性的值
【发布时间】:2020-08-11 09:46:49
【问题描述】:

为 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); }
    }
  }

仅用于从绑定中获取值。

我使用下面的代码来获取每条记录的绑定属性的值。

  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",
                                  typeof(object),
                                  typeof(BindValueReader),
                                  new PropertyMetadata(null));

    public object Value
    {
      get { return GetValue(ValueProperty); }
      set { SetValue(ValueProperty, 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')

【问题讨论】:

  • BindValueReader 是个怪物。你做的事情感觉不对。最糟糕的是 - 我无法理解您要解决的原始问题。你是在重新发明 wpf 中的 wpf 绑定吗???只需将多个目标绑定到同一个源,设置一次DataContext,然后请阅读有关 MVVM 的信息。
  • Assigning a value to the DataContext property doesn't change the value of the bound property. DataContext 不应该以这种方式改变。设置数据上下文一次并将绑定根更改为数据上下文中的可绑定属性。

标签: c# wpf binding datacontext


【解决方案1】:

您正在尝试对收入属性求和。

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

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

虽然这不是使用 WPF 的好方法,但您应该研究 MVVM,定义一个实现 inotifypropertychanged 的​​类作为行视图模型。将 itemssource 绑定到 this 的 observablecollection。然后使用绑定的集合和命名的属性。

【讨论】:

  • 这只是一个例子。实际上,我在 DataGrid 中有一个 DataGridBoundColumn,我需要计算该列的总和。我需要编写一个通用函数来计算任何 DataGrid 中任何列的总和。我正在尝试使用 DataGridBoundColumn.Binding 属性来实现这样的功能。
  • 但是绑定是一个毫无意义的开销@DmitryB。你也可以。按索引或名称引用 datarowview 列并将其汇总。要么。您可以引用 datarowview 列,创建绑定,从绑定中获取值,然后对其求和。绑定没有意义。
猜你喜欢
  • 1970-01-01
  • 2016-10-28
  • 2018-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-18
相关资源
最近更新 更多