Click here to Skip to main content
15,899,126 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi All,

I'm about 2 months new to C# and WPF. I am trying to solve the following situation that I need to accomplish. Any help would be appreciated.

The scenario is what I need to achieve as follows:

1) If I have a Single Data Model object that has one or more properties, I need to display the properties as when they change - I have no issue with this as I am binding the properties using INotifyPropertyChanged

2) If I have a Composite Data Model, it is made up of two or more of the Single Data Model objects. If there are 3 properties in the Single Data Model such as Name, Score, Rank, then there are also 3 same properties in the Composite Data Model. However, the property values of those in the Composite Data Model are dependent on any change in value of those in the Single Data Model

Both Models implement INotifyPropertyChanged and IBaseModel (see the List<ibasemodel> below in my source code)

For instance, if:

SDM1 (Single Data Model): [Name=Man, Score=50, Rank=5]
SDM2 (Single Data Model): [Name=Woman, Score=70, Rank=8]

The CDM (Composite Data Model) for this should be the following:

CDM : [Name=Man/Women, Score=(70+50)/2, Rank=(8-5).

3) In my Data Grid, I should see:

Man 50 5
Woman 70 8
Man/Woman 60 3

4) Now, if tomorrow, the Score for SDM1 (Man) should change to 30, my CDM should recalculate the value for Score to (70+30/2) and update the Data Grid display for:

Man/Woman 50 3

5) If again, SDM2 (Woman) the Rank changes to 10, my CDM should change to (10-5)

Man/Woman 50 5

The main problem I have having is the following:
a. How can I create any dependency on the SMD's such that if any property changes in it, it should trigger a a re-calculation in the CMD for those specific properties and change the property value in the data grid.

I know that I can use the Observer pattern and register the CMD as an Observer and the properties in the SDM's as Subjects and have the CMD properties observe the specific properties of the subject (SDM1 and SMD2).

However, what I'm seeing is that simply assigning the value of set method in the CDM for Score to the following is not enough to trigger any such change to the WPF

C#
// WPF Data Grid - Binding SPREAD
private double _score;
public double Score
{
    get
    {
        Debug.WriteLine(this.ToString() + ": Score - (GET) - [_score=" + _score+ "]");
        return _score;
    }
    set
    {
        Debug.WriteLine(this.ToString() + ": Score - (SET) - [value=" + value + "]");
        this._score= (sdm1.Score - sdm2.Score)/2;
        OnPropertyChanged("Score");
    }
}



I have a simple Data Grid as follows:

XML
<UserControl x:Class="ValueModelTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
        Height="350" Width="503">
    <UserControl.Resources>
        <ResourceDictionary>
            <CollectionViewSource x:Key="MyDataSource"/>
        </ResourceDictionary>
    </UserControl.Resources>

    <DockPanel Name="DP" LastChildFill="False">
        <dg:DataGrid x:Name="DG" ItemsSource="{Binding Source={StaticResource MyDataSource}}"
                     HeadersVisibility="Column"
                     CanUserAddRows="True"
                     AutoGenerateColumns="False">
            <dg:DataGrid.Columns>
                <dg:DataGridTextColumn Header="Name"
                                       Binding="{Binding NAME}"
                                       Width="150">
                </dg:DataGridTextColumn>

                <dg:DataGridTextColumn Header="A"
                                       Binding="{Binding Score}"
                                       Width="150">
                </dg:DataGridTextColumn>

                <dg:DataGridTextColumn Header="B"
                                       Binding="{Binding Rank}"
                                       Width="150">
                </dg:DataGridTextColumn>

            </dg:DataGrid.Columns>
        </dg:DataGrid>
    </DockPanel>

</UserControl>


In my MainView.xaml.cs, I have the following:

C++
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;

using System.Windows.Markup;
using System.Diagnostics;

namespace ValueModelTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : UserControl
    {
        // MyModel and MyCompositeModel
        public MyDataModel s2Model;
        public MyDataModel s5Model;
        public MyCompositeModel scModel;

        // Contains all the Main DataModel - Grid
        private static List<IBaseModel> dataSource;
        // DataModel Structure in the XAML
        private static CollectionViewSource dataViewSource;

        // Main
        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = this;

            // Initialize the Data once the WPF Grid Display is initialized
            InitializeData();
        }

        // Load the data into the Grid
        public void InitializeData()
        {
            try
            {
                Debug.WriteLine(this.ToString() + ":InitializeData");

                // DataList Initialize
                dataSource = new List<IBaseModel>();

                // Create the MyModel(2)
                s2Model = new MyModel();
                s2Model.NAME = "Man";
                s2Model.Score= 50;
                s2Model.Rank= 5;
                dataSource.Add(s2Model);

                // Create another MyModel(5)
                s5Model = new MyModel();
                s5Model.NAME = "Woman";
                s5Model.Score= 70;
                s5Model.Rank= 8;
                dataSource.Add(s5Model);

                // Create the Composite MyCompositeModel (Man/Woman)
                scModel = new MyCompositeModel (1, s2Model, s5Model);
                scModel.NAME = s2Model.NAME + "/" + s5Model.NAME;
                dataSource.Add(scModel);

                // Get a handle on the Data Source in the WPF
                dataViewSource = (CollectionViewSource)FindResource("MyDataSource");

                //Populate the WPF Data
                dataViewSource.Source = dataSource;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(this.ToString() + ": InitializeData Error - " + ex.StackTrace.ToString());
            }

            Debug.WriteLine("ValueModelTest: - Testing");
        }
    }
}
Posted

1 solution

Hi I may have misunderstood the question. But you should concider using
ObservableCollection<IBaseModel>
instead of
List<IBaseModel>
when presenting data to the UI, because the ObservableCollection also implements the notification properties notifying changes in the list.

Hope it helps :-)
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900