简体   繁体   中英

WPF. Assigning a value to the DataContext property doesn't change the value of the bound property

Assigning a value to the DataContext property doesn't change the value of the bound property.

I need to get the value of a bound property multiple times for each record in a table to calculate the sum value for a column in a DataGrid.

For this I use a special dummy FrameworkElement object.

The object code looks like this:

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

It is only used to get the value from the binding.

I use the following code to get the value of the bound property for each record.

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

it works correctly but is rather slow.

When I try to optimize the code like this

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

it stops working.

I can't figure out why.

Here is the complete program code:

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

}

Debug Output:

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')

You're trying to sum the income property.

You can do that by working with the column in the datarowview you obtain rather than by using binding.

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

This is not a good way to work with WPF though and you should look into MVVM, define a class that implements inotifypropertychanged as a row viewmodel. Bind itemssource to an observablecollection of this. Then work with the bound collection and the named property.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM