【发布时间】: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