Click here to Skip to main content
15,881,600 members
Home / Discussions / WPF
   

WPF

 
GeneralRe: WPF DataGrid uses a lot of memory, or is slow to scroll Pin
Leif Simon Goodwin25-Jun-18 3:30
Leif Simon Goodwin25-Jun-18 3:30 
GeneralRe: WPF DataGrid uses a lot of memory, or is slow to scroll Pin
Leif Simon Goodwin25-Jun-18 3:43
Leif Simon Goodwin25-Jun-18 3:43 
GeneralRe: WPF DataGrid uses a lot of memory, or is slow to scroll Pin
Pete O'Hanlon25-Jun-18 4:52
mvePete O'Hanlon25-Jun-18 4:52 
GeneralRe: WPF DataGrid uses a lot of memory, or is slow to scroll Pin
Gerry Schmitz23-Jun-18 4:30
mveGerry Schmitz23-Jun-18 4:30 
GeneralRe: WPF DataGrid uses a lot of memory, or is slow to scroll Pin
Leif Simon Goodwin25-Jun-18 3:19
Leif Simon Goodwin25-Jun-18 3:19 
GeneralRe: WPF DataGrid uses a lot of memory, or is slow to scroll Pin
Gerry Schmitz25-Jun-18 5:48
mveGerry Schmitz25-Jun-18 5:48 
GeneralRe: WPF DataGrid uses a lot of memory, or is slow to scroll Pin
Leif Simon Goodwin25-Jun-18 21:47
Leif Simon Goodwin25-Jun-18 21:47 
QuestionDisplaying a grid of mixed controls from tabular data: solved Pin
Leif Simon Goodwin6-Jun-18 4:04
Leif Simon Goodwin6-Jun-18 4:04 
NB: The solution is at the end.

We need to configure a hard ware device, which provides configuration settings as tabular data. There are lots of different sets of tabular data. We want to display a given table in a view, so that the user can edit the fields. All fields in a given row have the same kind of data e.g. integer. However, one row might display integers, another might display a combo box, and another a check box. The problem is how to automatically create the WPF view and view model code.

The nature of the data in each table is defined in an XML file. Unfortunately for one table the number of columns is defined by a value in another table which is only known at run-time.

Thus we can create some tables at build time, but one must be created at run-time.

I created a parser which generates the WPF view and view model for each table of data. This parser can be run at run-time to generate view and view model source code, which is then compiled at run-time, and displayed. So far so good. This works well with one exception, as the number of fields is almost always modest.

Unfortunately one table has ~120,000 cells, and the resulting view model will not run as the number of controls exceeds the maximum allowed by WPF. The view will display and looks good. Clearly having so many properties in a view model is a tad ridiculous and crude.

So, we need a more elegant solution, and one which allows the values to be displayed in a table with cells all nicely aligned.

The view model contains a list of field objects, each of which provides data in the correct format for the corresponding table cell e.g. "true" and "false" for tick box. Is it possible to create a DataGrid, such that it gets its data from my table of fields, and displays the correct kind of control dependent on the nature of the data (which my field object knows)? Thus row 0 might be tick boxes, row 1 edit boxes, and row 2 combo boxes?

==================================================================

Solution:
I came across some example code that almost solved our problem, and with some changes it does the job in my demo application which I will explain below in case anyone finds this useful. The link is as follows:

WPF DataGrid and binding to matrix of objects using UserControl per cell[^]

The first step is to declare some data templates in the XAML:

C#
<DataTemplate x:Key="LabelDataTemplate">
            <Label Margin="2" Content="{Binding Text}" Background="White"/>
        </DataTemplate>
        <DataTemplate x:Key="TextDataTemplate">
            <TextBox Margin="2" Text="{Binding Text}" Foreground="Green" Height="20"/>
        </DataTemplate>
        <DataTemplate x:Key="ComboBoxDataTemplate">
            <ComboBox Margin="2" Text="{Binding ComboText}" ItemsSource="{Binding Values}" Foreground="Red" Height="20" VerticalAlignment="Center"/>
        </DataTemplate>
        <DataTemplate x:Key="CheckBoxDataTemplate">
            <CheckBox Margin="2" IsChecked="{Binding IsChecked}" Foreground="Red" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </DataTemplate>


The data grid is very basic:

C#
<DataGrid Grid.Row="2" Name="_dataGrid2" ItemsSource="{Binding Matrix}" AlternationCount="2" AutoGenerateColumns="False" Style="{StaticResource styleDataGridNoSelection}" HeadersVisibility="None">


The style simply makes it look nice for our usage. The key point is the binding to Matrix, which is a matrix of nodes:

C#
namespace WpfGridDemo.Model
{
    public class Node
    {
        public NodeType Type { get; set; }
        public string Text { get; set; }
        public bool IsChecked { get; set; }
        public string ComboText { get; set; }
        public List<string> Values { get; set; }
    }
}


The type indicates whether it is text, a combo box, a checkbox or a label. In real code this would be better as a polymorphic base class, but since this was a quick demo, the above is good enough.

A Row class wraps an array of nodes and represents a row from the matrix:

C#
namespace WpfGridDemo
{
    public class Row
    {
        private string name;
        //private string[] values;
        private Model.Node[] values;

        public string Name { get { return name; } }
        public Model.Node[] Values { get { return values; } }
        public int Index { get; set; }

        const int constColumnCount = 40;
    }
}


And the Matrix is defined in the view model as an array of rows:

C#
private Row[] _matrix;
        public Row[] Matrix { get { return _matrix; } }

So it is just a 2D matrix of rows.

In the main window class I set up the binding between the matrix nodes and data grid:

C#
public MainWindow()
        {
            InitializeComponent();

            MainViewModel viewModel = new MainViewModel();
            DataContext = viewModel;

            for (int i = 0; i < 40; i++)
            {
                DataGridTemplateColumn col = new DataGridTemplateColumn();
                //col.Header = i.ToString();

                FrameworkElementFactory fef = new FrameworkElementFactory(typeof(ContentPresenter));
                Binding binding = new Binding();
                fef.SetBinding(ContentPresenter.ContentProperty, binding);
                GridDataTemplateSelector gridDataTemplateSelector = new GridDataTemplateSelector();
                gridDataTemplateSelector.LabelDataTemplate = Resources["LabelDataTemplate"] as DataTemplate;
                gridDataTemplateSelector.TextDataTemplate = Resources["TextDataTemplate"] as DataTemplate;
                gridDataTemplateSelector.CheckBoxDataTemplate = Resources["CheckBoxDataTemplate"] as DataTemplate;
                gridDataTemplateSelector.ComboBoxDataTemplate = Resources["ComboBoxDataTemplate"] as DataTemplate;
                fef.SetValue(ContentPresenter.ContentTemplateSelectorProperty, gridDataTemplateSelector);

                binding.Path = new PropertyPath("Values[" + i + "]");
                DataTemplate dataTemplate = new DataTemplate();
                dataTemplate.VisualTree = fef;
                col.CellTemplate = dataTemplate;

                _dataGrid2.Columns.Add(col);
            }
        }


A key point is the DataTemplateSelector which tells the grid which data template to use for a given cell.

C#
class GridDataTemplateSelector : DataTemplateSelector
    {
        public DataTemplate LabelDataTemplate { get; set; }
        public DataTemplate TextDataTemplate { get; set; }
        public DataTemplate CheckBoxDataTemplate { get; set; }
        public DataTemplate ComboBoxDataTemplate { get; set; }

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            Model.Node node = item as Model.Node;
            if (node != null)
            {
                if (node.Type == Model.NodeType.Label)
                {
                    return LabelDataTemplate;
                }
                if (node.Type == Model.NodeType.Text)
                {
                    return TextDataTemplate;
                }
                if (node.Type == Model.NodeType.CheckBox)
                {
                    return CheckBoxDataTemplate;
                }
                if (node.Type == Model.NodeType.ComboBox)
                {
                    return ComboBoxDataTemplate;
                }
            }
            return TextDataTemplate;
        }
    }


I'm quite certain I would not have solved this without the online code I found. Hopefully I can put this into a little demo project in a short article as I feel it is useful.

modified 8-Jun-18 3:33am.

AnswerRe: Displaying a grid of mixed controls from tabular data Pin
Pete O'Hanlon7-Jun-18 4:06
mvePete O'Hanlon7-Jun-18 4:06 
AnswerRe: Displaying a grid of mixed controls from tabular data Pin
Gerry Schmitz7-Jun-18 7:01
mveGerry Schmitz7-Jun-18 7:01 
GeneralRe: Displaying a grid of mixed controls from tabular data Pin
Leif Simon Goodwin14-Jun-18 21:36
Leif Simon Goodwin14-Jun-18 21:36 
QuestionWPF Toolkit PropertyGrid Pin
Kevin Marois5-Jun-18 4:30
professionalKevin Marois5-Jun-18 4:30 
SuggestionRe: WPF Toolkit PropertyGrid Pin
Richard Deeming5-Jun-18 9:30
mveRichard Deeming5-Jun-18 9:30 
GeneralRe: WPF Toolkit PropertyGrid Pin
Kevin Marois5-Jun-18 10:24
professionalKevin Marois5-Jun-18 10:24 
GeneralRe: WPF Toolkit PropertyGrid Pin
Richard Deeming6-Jun-18 1:21
mveRichard Deeming6-Jun-18 1:21 
QuestionStyle Problem Pin
Kevin Marois9-May-18 12:03
professionalKevin Marois9-May-18 12:03 
AnswerRe: Style Problem Pin
Mycroft Holmes9-May-18 14:25
professionalMycroft Holmes9-May-18 14:25 
QuestionDataGrid Template Column Binding Pin
Kevin Marois9-May-18 5:05
professionalKevin Marois9-May-18 5:05 
AnswerRe: DataGrid Template Column Binding Pin
Nathan Minier9-May-18 7:15
professionalNathan Minier9-May-18 7:15 
GeneralRe: DataGrid Template Column Binding Pin
Kevin Marois9-May-18 9:48
professionalKevin Marois9-May-18 9:48 
GeneralRe: DataGrid Template Column Binding Pin
Nathan Minier10-May-18 1:04
professionalNathan Minier10-May-18 1:04 
QuestionDataGrid DataGridCheckBoxColumn Property Change Not Firing Pin
Kevin Marois2-May-18 6:52
professionalKevin Marois2-May-18 6:52 
AnswerRe: DataGrid DataGridCheckBoxColumn Property Change Not Firing Pin
Richard Deeming2-May-18 8:40
mveRichard Deeming2-May-18 8:40 
GeneralRe: DataGrid DataGridCheckBoxColumn Property Change Not Firing Pin
Kevin Marois2-May-18 9:46
professionalKevin Marois2-May-18 9:46 
QuestionWPF NIC counters Pin
Member 138058691-May-18 13:33
Member 138058691-May-18 13:33 

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

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