Click here to Skip to main content
Click here to Skip to main content

Silverlight FluentDataGrid

, 21 Jan 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
Silverlight Fluent DataGrid provides a simple approach for creating complex tables with multi level headers, validation, hierarchy, and summaries support.
Introduction

Almost every application to work with the data we have to work with the tables for display to the user of any data which it has applied. For users familiar applications such pages and comfortable enough, but not always easy to implement a particular display logic for complex data structures such as the customer wants them to be. We give a simple example, let us have the lists A and B, are related by 1: n, each element of the list B contains three attributes - the key, the record type and value, types of records that can be repeated. Suppose we want to display the record of A, so that each row of A list displays all values ​​from the list B, the record type is used as a title 

Students (List A) 

Id

Name

1

John

2

Alex

3

Sara

Marks (List B) 

Id

Student

Category

Value

1

1

C#

5

2

1

Java

3

1

HTML & CSS

4

4

2

C#

4

5

3

Java

3

We need to get the following table:

Id

Name

Marks

C#

Java

HTML & CSS

1

John

5

4

4

2

Alex

4

-

-

3

Sara

-

3

-

Application in which I faced with such a task was developed using the technology of Silverlight. Built-in DataGrid functionality described above is not realized. This led to the development of special control FluentGrid

How it works:

FluentDataGrid - is the control that builds a table based on a custom data source FluentGridSource. Currently, the construction of the table (view) is available only at runtime. FluentGridSource has Fluent-like interface for the formation of rules of construction.

The key source of data is the formation of the class, which will be a "model line." She describes one row of the result table, for our example of such a class might look like

public class ExampleRow : PropertyChangedBase
{
    public ExampleRow(int id, string name, IList<IDynamicElement> marks)
    {
        _id = id;
        _name = name;
        Marks = marks;
    }

    private int _id;
    private string _name;

    [DynamicHeader("Id", false, HorizontalAlignment = HorizontalAlignment.Right)]
    public int Id
    {
        get { return _id; }
        set
        {
            NotifyPropertyChanged(() => Id);
            _id = value;
        }
    }

    [DynamicHeader("Name", false, 
        HorizontalAlignment = HorizontalAlignment.Left, Width = 200)]
    public string Name
    {
        get { return _name; }
        set
        {
            NotifyPropertyChanged(() => Name);
            _name = value;
        }
    }

    public IList<IDynamicElement> Marks { get; set; }
}

public class MarkDynamicElement : PropertyChangedBase, IDynamicElement
{
    private object _value;

    public MarkDynamicElement(DynamicHeader header, object value)
    {
        Header = header;
        Value = value;
    }

    /// <summary>
    /// Header for the value
    /// </summary>
    public DynamicHeader Header { get; set; }

    /// <summary>
    /// Value that will be displayed
    /// </summary>
    public object Value
    {
        get { return _value; }
        set
        {
            _value = value;
            NotifyPropertyChanged(() => Value);
        }
    }
} 

The base class implements the INotifyPropertyChanged PropertyChangedBase. We see that in the line two "static" column Id and Name, attribute DynamicHeader helps us set a cap column. There is also a list of Marks, a "dynamic" of the table, which can be constructed, for example, by using LINQ. Its elements have to implement a special interface IDynamicElement.

In forming a data source, you can add formatting rules AddFromatter (), totals AddSummary (), validation rules for totals AddValidator (), the validation rules of values ​​in table cells AddCellValidator (), and set rules for the formation of the hierarchy. In order to specify the hierarchy, you must specify the property model - key (Id), the property - a reference to the parent element (ParentId) and the property on which to display the hierarchy. 

How to use:  

The first step is defining the control in the XAML file:  

<CurriculumControl Source="{Binding SimpleSampleSource,Mode=TwoWay}" SelectedItem="{Binding SelectedRow, Mode=TwoWay}" />  

Next step is to create a row with the appropriate attributes for the grid as described above. 

Than you should create view model, construct FluentGridSource

DynamicExampleSource = FluentGridSource.CreateFrom(DynamicExampleSource, Repository.GetExampleRows());

Constructing FluentGrisSource may be more complex if you set some validation, totals

ValidationSampleSource = new FluentGridSource(typeof(SimpleRow));
ValidationSampleSource = FluentGridSource.CreateFrom(ValidationSampleSource, Repository.GetSimpleRows());

#region Formatters

ValidationSampleSource
    .SetOptions(true, 50)
    .AddFormatter(new DynamicHeader {Name = "Min", HeaderGroup = new OverallSalaryHeaderGroup()},
                  (row, value) => ((double) value).ToString("c", new CultureInfo("en-us")));
#endregion

#region Summaries

ValidationSampleSource
    .AddSummary(new DynamicHeaderCollection {new DynamicHeader {Name = "Employee name"}}, x => "Total")
    .AddSummary(
        new DynamicHeaderCollection
            {new DynamicHeader {Name = "Min", HeaderGroup = new OverallSalaryHeaderGroup()}},
        delegate(IDictionary<DynamicHeader, IEnumerable> allValues)
            {
                var header = allValues.Keys.Single(x => x.Name == "Min");
                var values = (List<object>) allValues[header];
                return values.Sum(x => (double) x);
            })
    .AddSummary(
        new DynamicHeaderCollection
            {new DynamicHeader {Name = "Max", HeaderGroup = new OverallSalaryHeaderGroup()}},
        delegate(IDictionary<DynamicHeader, IEnumerable> allValues)
            {
                var header = allValues.Keys.Single(x => x.Name == "Max");
                var values = (List<object>) allValues[header];
                return values.Sum(x => (double) x);
            });
#endregion

#region Validations

ValidationSampleSource
    .AddCellValidator(new DynamicHeader { Name = "Min", HeaderGroup = new OverallSalaryHeaderGroup() },
        delegate(object row, object value)
        {
            var simpleRow = (SimpleRow)row;
            var min = (double)value;

            if (min > simpleRow.Max)
                return "Minimum cannot be higher than maximum!";
            if (min < 5000)
                return "Minimum cannot be lower than $5000";

            return null;
        })
    .AddCellValidator(new DynamicHeader { Name = "Max", HeaderGroup = new OverallSalaryHeaderGroup() },
        delegate(object row, object value)
        {
            var simpleRow = (SimpleRow)row;
            var max = (double)value;

            if (max < simpleRow.Min)
                return "Maximum cannot be lower than minimum!";
            if (max > 500000)
                return "Maximum cannot be heigher than $500000";

            return null;
        });

#endregion

 

License

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

Share

About the Author

Ilnur Yusupov
Software Developer
Russian Federation Russian Federation
No Biography provided
Follow on   Twitter

Comments and Discussions

 
QuestionFluent datagrid not working in silverlight PinmemberRupesh Bhavsar20-Dec-13 2:57 
AnswerRe: Fluent datagrid not working in silverlight PinmemberIlnur Yusupov23-Dec-13 21:45 
QuestionDownload link PinmemberMember 976562719-Jan-13 1:05 
Are you able to fix the download link? The link takes me here: http://www.codeproject.com/KB/silverlight/505084/Fluent.zip but then redirects me to a blank page
AnswerRe: Download link PinmemberIlnur Yusupov21-Jan-13 6:17 
GeneralMy vote of 5 Pinmemberiliabest8-Jan-13 17:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411023.1 | Last Updated 21 Jan 2013
Article Copyright 2013 by Ilnur Yusupov
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid