Home Forums WPF controls Xceed DataGrid for WPF StatFunctions with DisplayMemberBinding

Viewing 8 posts - 1 through 8 (of 8 total)
  • Author
    Posts
  • User (Old forums)
    Member
    Post count: 23064
    #25912 |

    Hello,

    I have a problem with stat functions when using the DisplayMemberBinding binding.
    First some code:

    // data item class
    public class DataItem
    {
    private string _name;
    private int _value;

    public string Name
    {
    get { return _name; }
    set { _name = value; }
    }

    public int Value
    {
    get { return _value; }
    set { _value = value; }
    }

    public DataItem(string name, int value)
    {
    _name = name;
    _value = value;
    }
    }

    // data row class
    public class DataRow
    {
    private DataItem _first;
    private DataItem _second;

    public DataItem First
    {
    get { return _first; }
    set { _first = value; }
    }

    public DataItem Second
    {
    get { return _second; }
    set { _second = value; }
    }
    }

    // data creation
    private List<DataRow> CreateData()
    {
    List<DataRow> dataSource = new List<DataRow>();
    for (int ix = 0; ix < 10; ix++)
    {
    DataItem first = new DataItem(string.Format(“First_Name_{0}”, ix), ix);
    for (int iz = 0; iz < 10; iz++)
    {
    DataRow dr = new DataRow();
    DataItem second = new DataItem(string.Format(“Second_Name_{0}”, iz), iz);
    dr.First = first;
    dr.Second = second;
    dataSource.Add(dr);
    }
    }
    return dataSource;
    }

    // adding the columns
    private static void AddColumns(DataGridControl grid)
    {
    Column col = new Column();
    col.FieldName = “FirstName”;
    col.Title = “First Name”;
    Binding b = new Binding(“First.Name”);
    col.DisplayMemberBinding = b;
    grid.Columns.Add(col);

    col = new Column();
    col.FieldName = “FirstValue”;
    col.Title = “First value”;
    b = new Binding(“First.Value”);
    col.DisplayMemberBinding = b;
    grid.Columns.Add(col);

    col = new Column();
    col.FieldName = “SecondName”;
    col.Title = “Second Name”;
    b = new Binding(“Second.Name”);
    col.DisplayMemberBinding = b;
    grid.Columns.Add(col);

    col = new Column();
    col.FieldName = “SecondValue”;
    col.Title = “Second Value”;
    b = new Binding(“Second.Value”);
    col.DisplayMemberBinding = b;
    grid.Columns.Add(col);
    }

    // this is how I am adding the collection view
    private static DataGridCollectionView CreateDataGridCollectionView(List<DataRow> dataSource)
    {
    DataGridCollectionView view = new DataGridCollectionView(dataSource, typeof(DataRow));

    // grouping
    DataGridGroupDescription desc = new DataGridGroupDescription();
    desc.PropertyName = “First”;
    view.GroupDescriptions.Add(desc);

    // stat functions
    StatFunction sum = new SumFunction();
    sum.ResultPropertyName = “RESULT_SUM”;
    sum.SourcePropertyName = “SecondValue”;
    view.StatFunctions.Add(sum);

    return view;
    }

    And now the issue. I am creating a GroupHeaderFooterItemTemplate that contains a StatRow with one StatCell, that shall display the sum calculated by the sum function added previously.

    TableView table = grid.View as TableView;
    if (table != null)
    {
    GroupLevelConfiguration glConfig = new GroupLevelConfiguration();
    glConfig.InitiallyExpanded = false;

    GroupHeaderFooterItemTemplate hfTemplate = new GroupHeaderFooterItemTemplate();
    hfTemplate.VisibleWhenCollapsed = true;
    MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(“<DataTemplate><xcdg:StatRow Height=\”20\” Background=\”#3FB0C4DE\”><xcdg:StatCell FieldName=\”SecondValue\” ResultPropertyName=\”RESULT_SUM\” ResultConverterParameter=\”F2\”/></xcdg:StatRow></DataTemplate>”));
    ParserContext pc = new ParserContext();
    pc.XmlnsDictionary.Add(“”, “http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;);
    pc.XmlnsDictionary.Add(“x”, “http://schemas.microsoft.com/winfx/2006/xaml&#8221;);
    pc.XmlnsDictionary.Add(“xcdg”, “http://schemas.xceed.com/wpf/xaml/datagrid&#8221;);

    DataTemplate dt = (DataTemplate)XamlReader.Load(ms, pc);
    hfTemplate.Template = dt;
    glConfig.Headers.Add(hfTemplate);
    table.GroupLevelConfigurations.Add(glConfig);
    }

    I think it all shall work – field name is always set to SecondValue, the same is true for the SourcePropertyName of the SumFunction used. The problem is that it seems that either the sum function does not calculate the values, or the stat cell cannot display it… Do you maybe know why I have a problem here?
    Or maybe someone could give me a working example where you’re using a little bit more complex data sources where (where you have to bind to a property of an object being a property) where the stat function works?

    Thanks in advance!


    mYsZa

    Imported from legacy forums. Posted by Michal (had 4565 views)

    User (Old forums)
    Member
    Post count: 23064

    Hi,

    I’m having a similar kind of problem.

    As a work around I’m trying a facade class that does not use nested properties:

    For example:

    Instead of Prop1.SubPropA, Prop2.SubPropB, I made a facade object with only SubPropA and SubPropB that delegates to the correct objects.

    This seems to allow the stat functions to work, but I haven’t figured out how to get them to update automatically.

    Even though my facade implements INotifyPropertyChanged and I can watch it fire, the stats don’t update unless I re-group.

    If I find out anything helpful info I’ll post it here.

    Rich

    Imported from legacy forums. Posted by Richard (had 492 views)

    User (Old forums)
    Member
    Post count: 23064

    I was able to get an example like yours to work. A facade class is not needed in your case or my case.

    Here’s a working test case based on your example:

    <hr>
    <b>Data Class</b>
    <hr>

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Windows.Data;

    namespace StatFuncNestedPropProblem
    {
    // data item class
    public class TestDataItem : INotifyPropertyChanged
    {

    private TestDataItem()
    {
    }

    public TestDataItem(string name, int value)
    {
    m_name = name;
    m_value = value;
    m_creationDate = DateTime.Now;

    }

    private string m_name;
    public string Name
    {
    get { return m_name; }
    set
    {
    m_name = value;
    OnPropertyChanged(“Name”);
    }
    }

    private int m_value;
    public int Value
    {
    get { return m_value; }
    set
    {
    m_value = value;
    OnPropertyChanged(“Value”);
    }
    }

    private DateTime m_creationDate;
    public DateTime CreationDate
    {
    get { return m_creationDate; }
    set
    {
    m_creationDate = value;
    OnPropertyChanged(“CreationDate”);
    }
    }

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

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
    }

    // data row class
    public class TestDataRow : INotifyPropertyChanged
    {

    private TestDataRow() { }

    public TestDataRow(string firstName, int firstValue, string secondName, int secondValue)
    {
    m_first = new TestDataItem(firstName, firstValue);
    m_second = new TestDataItem(secondName, secondValue);
    }

    private TestDataItem m_first;
    public TestDataItem First

    {
    get { return m_first; }
    set
    {
    m_first = value;
    OnPropertyChanged(“First”);
    }
    }

    private TestDataItem m_second;
    public TestDataItem Second
    {
    get { return m_second; }
    set
    {
    m_second = value;
    OnPropertyChanged(“Second”);
    }
    }
    void OnPropertyChanged(string propertyName)
    {
    if (PropertyChanged != null)
    {
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
    }

    public class NestedPropertyExample
    {
    static public List<TestDataRow> TestDataRowTestData
    {

    get
    {

    string[] firstObjGroups = new string[] { “Group 1”, “Group 2” };
    string[] secondObjGroups = new string[] { “Group A”, “Group B”, “Group C” };
    List<TestDataRow> list = new List<TestDataRow>();

    foreach (string g1 in firstObjGroups)
    {
    for (int i = 1; i < 4; i++)
    {
    foreach (string g2 in secondObjGroups)
    {
    for (int j = 1; j < 4; j++)
    {
    list.Add(new TestDataRow(g1, i, g2, j));
    }
    }
    }
    }

    return list;
    }
    }
    }

    }

    <hr>
    <b>Window XAML</b>
    <hr>
    <Window x:Class=”StatFuncNestedPropProblem.Window1″
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;
    xmlns:xcdg=”http://schemas.xceed.com/wpf/xaml/datagrid&#8221;
    xmlns:local=”clr-namespace:StatFuncNestedPropProblem” Title=”Window1″ Height=”300″
    Width=”300″>

    <Window.Resources>

    <xcdg:DataGridCollectionViewSource x:Key=”m_dgcvs_test” Source=”{Binding Source={x:Static local:NestedPropertyExample.TestDataRowTestData}}”>

    <xcdg:DataGridCollectionViewSource.StatFunctions>
    <xcdg:AverageFunction SourcePropertyName=”First.Value”
    ResultPropertyName=”AverageUnitCost” />
    </xcdg:DataGridCollectionViewSource.StatFunctions>
    </xcdg:DataGridCollectionViewSource>

    <xcdg:StatResultConverter x:Key=”StatValueConverter” />

    </Window.Resources>

    <Grid>
    <xcdg:DataGridControl x:Name=”m_testGrid” AutoCreateColumns=”False” Grid.Row=”1″
    ItemsSource=”{Binding Source={StaticResource m_dgcvs_test}}”>

    <xcdg:DataGridControl.Columns>
    <xcdg:Column FieldName=”First.Name” Title=”First Name” />
    <xcdg:Column FieldName=”First.Value” Title=”First Value” />
    <xcdg:Column FieldName=”Second.Name” Title=”Second Name” />
    <xcdg:Column FieldName=”Second.Value” Title=”Second Value” />
    </xcdg:DataGridControl.Columns>

    <xcdg:DataGridControl.View>
    <xcdg:TableView>
    <xcdg:TableView.GroupLevelConfigurations>

    <xcdg:GroupLevelConfiguration InitiallyExpanded=”False”>
    <xcdg:GroupLevelConfiguration.Footers>
    <xcdg:GroupHeaderFooterItemTemplate
    VisibleWhenCollapsed=”True”>
    <DataTemplate>
    <xcdg:StatRow Background=”AliceBlue”>

    <xcdg:StatCell FieldName=”First.Value”
    ResultPropertyName=”AverageFirstValue” SDJXCEED@20

    Imported from legacy forums. Posted by Richard (had 915 views)

    User (Old forums)
    Member
    Post count: 23064

    I should, while I can get the nested properties to work find, I have not determine how to have the statistics automatically update when the data changes.

    If I change the data, the stats will update only when I un-group and then re-group.

    I’m not sure why.

    Imported from legacy forums. Posted by Richard (had 858 views)

    User (Old forums)
    Member
    Post count: 23064

    Hello,

    Thank you for your help.
    I’ll try to deeply investigate the code you’ve sent and if I have any questions I am back here 🙂


    Michal

    Imported from legacy forums. Posted by Michal (had 4286 views)

    User (Old forums)
    Member
    Post count: 23064

    Hey Guys
     
    I can’t get this to work using the example above. Actually I already had a very similar example that I cant get to work. Its strange columns seem to be able to reference nested properties. For example this works when an item bound to the column has a nested ‘value’ property.

    <xcdg:Column FieldName=”Exposure.Value” Title=”Exposure Value” />

    however the stat function doesn’t seem to be able to work with this, eg:

    <xcdg:SumFunction  ResultPropertyName=”Exposure_Sum” SourcePropertyName=”Exposure.Value”/>

    and then in the footer: <xcdg:StatCell FieldName=”Exposure.Value” ResultPropertyName=”Exposure_Sum”/>
    Ideally I’d just like to have a column bound to Exposure and let its template binding work out the actual nested property. This is because I have tracking with the Exposure object that a style uses to change the background color of a cell (as suggested in other forum postings). However I don’t know how the stat function would then work.

    Do i have to write a custom function that knows about my custom type inorder to do calculations on my custom types? **cry**

    Imported from legacy forums. Posted by Keith (had 775 views)

    User (Old forums)
    Member
    Post count: 23064

    Problem solved…

    I implemented a custom function like done on this thread http://xceed.com/CS/forums/thread/10844.aspx

    Basically I have a custom type that wraps a decimal and store other contextual related information relating to the actual number, I can now bind my grid column to my custom type, use template binding to get the value I want from my type and finally use the new function below to add it up… sweet.

        public class AmountSumFunction : SumFunction
        {
            private Amount _sum = new Amount();
            protected Amount Sum
            {
                get { return _sum; }
            }

            protected override void Reset()
            {
                _sum = new Amount();
            }

            protected override void Accumulate(object[] values)
            {
                foreach (object obj in values)
                {
                    _sum.Value += ((Amount)obj).Value;
                }
            }

            protected override void AccumulateChildResult(StatResult childResult)
            {
                _sum.Value += ((Amount)childResult.Value).Value;
            }

            protected override StatResult GetResult()
            {
                return new StatResult(_sum);
            }
        }

    Imported from legacy forums. Posted by Keith (had 784 views)

    User (Old forums)
    Member
    Post count: 23064

    i am working on the same problem and now tried this proposed solution with custom statfunctions – this workaround works. you have to know that the same statfunction for the same sourceproperty is called only once. in my case i have to derive a statfunction class for each SourcePropertyName.

    do anyone have experience with linq queries on objects an xceed wpf grid. my idea is to make a  flat structure with a linq query on my deep structure. if i bind my linq query my datagrid is readonly and i have no chance to make it editable. i am looking for an example…

    thanks, markus

     

    Imported from legacy forums. Posted by maxthewolf (had 1414 views)

Viewing 8 posts - 1 through 8 (of 8 total)
  • You must be logged in to reply to this topic.