0

This is a follow up to this question:

Entity Datagrid : best way to add computed values?

In short I want a column in a datagrid to display the difference of two other columns in the grid. And I want the value of the calculated column to update as I enter values in either of the other columns.

The source of the data is an auto generated entity. So after going through the ADO.NET Entity Model process the top level class that accesses the database is:

public partial class BenchMarkEntities : DbContext
    {
        public BenchMarkEntities()
            : base("name=BenchMarkEntities")
        {            }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public virtual DbSet<BenchmarkDescription> BenchmarkDescriptions { get; set; }
        public virtual DbSet<SecurityDescription> SecurityDescriptions { get; set; }
        public virtual DbSet<Weight> Weights { get; set; }

Here is an example class contained in the DbSet collection:

using System;
using System.Collections.ObjectModel;

public partial class Weight
{
    public int BenchmarkID { get; set; }
    public string Symbol { get; set; }
    public decimal Benchmark_Weight { get; set; }
    public decimal Security_Weight { get; set; }
    public string Symbol_and_BenchmarkID { get; set; }
    public bool Weight_Exists { get; set; }

    public virtual BenchmarkDescription BenchmarkDescription { get; set; }
    public virtual SecurityDescription SecurityDescription { get; set; }
}

In MainWindow I have to instantiate a BenchmarkEntities to be able to perform CRUD operations on the database. The code below was from tutorial. If you have a better method would love to see it.

public partial class MainWindow : Window
{
    private BenchMarkEntities _context = new BenchMarkEntities();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        System.Windows.Data.CollectionViewSource weightViewSource =
          ((System.Windows.Data.CollectionViewSource)(this.FindResource("weightViewSource")));

        _context.Weights.Load();
        // Load data by setting the CollectionViewSource.Source property:
        weightViewSource.Source = _context.Weights.Local;

    }

So as the other question suggested I added a property to the class (Weight in this case). When I run it I get a correct initial value. But the calculated column doesn't update as I enter values in the other columns.

public partial class Weight : INotifyPropertyChanged
{
    public Weight()
    {
        this.PropertyChanged += ActiveWeightPropertyChanged;
    }

    void ActiveWeightPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        switch (e.PropertyName)
        {
            case "Benchmark_Weight":
            case "Security_Weight":
                OnPropertyChanged("DiffValues");
                break;
        }
    }

    public decimal DiffValues
    {
        get
        {
            return Benchmark_Weight - Security_Weight;
        }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    void OnPropertyChanged(string propName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(
                this, new PropertyChangedEventArgs(propName));
    }

    #endregion

}

}

Here is my XAML and the second DataGridTextColumn binds to addtional property I added.

  <DataGrid x:Name="weightDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected" Margin="51,21,54,99" 
                  ItemsSource="{Binding}" EnableRowVirtualization="True" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn x:Name="benchmark_WeightColumn" Width="SizeToHeader" 
                                    Header="Benchmark Weight" Binding="{Binding Benchmark_Weight}"/>
                <DataGridTextColumn x:Name="ActiveWeightColumn" Width="SizeToHeader" Header="ActiveWeight"
                                    Binding="{Binding DiffValues}"/>
                <DataGridTextColumn x:Name="security_WeightColumn" Width="SizeToHeader" Header="Security Weight" Binding="{Binding Security_Weight}"/>
                <DataGridTextColumn x:Name="symbolColumn" Width="SizeToHeader" Header="Symbol" Binding="{Binding Symbol}"/>
                <DataGridCheckBoxColumn x:Name="Weigh_ExistsColumn" Header="Remove" IsThreeState="False" Binding="{Binding Weight_Exists}"/>
            </DataGrid.Columns>
        </DataGrid>

I think I know what to do but not sure its possible.

  1. I need to add and implement the INotifyPropertyChanged to I believe the BenchMarkEntities Class?

  2. Then I need to change the setters for the two properties that will notify DiffValues. Problem with this is those are auto generated.

Or is it that I need to add the PropertyChanged event and its method to MainWindow?

Any help or suggestions?

Thank You

Community
  • 1
  • 1
rsgmon
  • 1,892
  • 4
  • 23
  • 35
  • Would you please add the code of the class that is your data source for the grid? Is it an Observable collection? – rodrigogq Nov 05 '14 at 14:41

2 Answers2

0

Make sure you are following this:

    public partial class MyEntity : INotifyPropertyChanged
    {
        // Methods
    }

    public class MyViewModel : INotifyPropertyChanged
    {
        private ObservableCollection<MyEntity> _listEntities = new ObservableCollection<MyEntity>();
        public ObservableCollection<MyEntity> ListEntities
        {
            get { return this._listEntities; }
            set { /* code here... */}
        }
    }

In this case, you would bind your grid to ListEntities of your instance of MyViewModel. Also, try setting the bind mode to TwoWay.

rodrigogq
  • 1,943
  • 1
  • 16
  • 25
0

you need to raisepropertychanged for the two properties that will notify DiffValues, something like:

public partial class Weight: INotifyPropertyChanged
{
  //.....
  decimal  _benchmarkweight;
  decimal  _securityweight;
  public decimal Benchmark_Weight 
  {
     get{return _benchmarkweight;}
     set{
         _benchmarkweight=value; 
         OnPropertyChanged("Benchmark_Weight ");  
         // OnPropertyChanged("DiffValues");   //don't need if you raise it already in this.PropertyChanged 
        }
  }
  public decimal Security_Weight
  {
     get{return _securityweight;}
     set{
         _securityweight=value; 
         OnPropertyChanged("Security_Weight");  
        // OnPropertyChanged("DiffValues");  //don't need if you raise it already in this.PropertyChanged  
        }
  }

  //.....
}

Edit: Sorry didn't realise this is entity:

Based on the discussion here you need to change the WriteProperty method in the templetes to the following, so that it will generate the property with OnPropertyChanged:

void WriteProperty(string accessibility, string type, string name, string getterAccessibility, string setterAccessibility)
{
#>
    private <#=type#> _<#=name#>;
    <#=accessibility#> <#=type#> <#=name#> 
    { 
        <#=getterAccessibility#>get
        {
            return _<#=name#>;
        } 
        <#=setterAccessibility#>set
        {
            if (value != _<#=name#>)
            {
                _<#=name#> = value;
                OnPropertyChanged("<#=name#>");
            }
        }
    }

<#+
}
Bolu
  • 8,696
  • 4
  • 38
  • 70
  • Thanks for your response and I tried as you suggested above and got a compiler error. Benchmark_Weight and Security_Weight are already declared in the autogenerated file (second code example). As I mentioned at the bottom of my question I don't think I can change these autogenerated properties. – rsgmon Nov 05 '14 at 16:02
  • Thanks @Bolu I'm going to give this a try. I just found a similar (well kinda) answer that also updates the template files. [link]http://stackoverflow.com/questions/11010718/how-to-get-property-change-notifications-with-ef-4-x-dbcontext-generator/12192358#12192358 – rsgmon Nov 05 '14 at 16:23
  • Maybe I just need to use MVVM... I went through the .tt and the Context.tt and WriteProperty isn't there. – rsgmon Nov 05 '14 at 16:32