Displaying multidimensional data in WPF

What's the best way to display multidimensional data in WPF? I won't know the size / shape of the data until runtime. Ideally I would like to use data binding, but this is not a strict requirement. I was thinking about some kind of grid, but I don't know how to dynamically bind to data and count the number of rows and columns. Suggestions and examples?

+2


a source to share


5 answers


Sounds like you want an Excel-like interface for editable 2D arrays. For other dimensions, you'll have to come up with tabs or a series of comboboxes.

Check out the WPF Toolkit DataGrid. There is an option to automatically generate columns. Experiment with this.

However, you will have some code to work with other dimensions as the Datagrid can only represent 2D data.

Corey

Edit: (04/28/2010) Here is a working solution.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using Microsoft.Windows.Controls;

namespace WpfApplication2
{
    public partial class MainWindow : Window
    {
    public List<List<object>> TheData { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        // Generate some random data
        Random r = new Random();

        TheData = new List<List<object>>
        {
            new List<object> { r.Next(100), r.Next(100), r.Next(100),r.Next(100) },
            new List<object> {  r.Next(100), r.Next(100), r.Next(100),r.Next(100) },
            new List<object> {  r.Next(100), r.Next(100), r.Next(100) },
            new List<object> {  r.Next(100), r.Next(100), r.Next(100),r.Next(100) },
            new List<object> {  r.Next(100), r.Next(100), r.Next(100),r.Next(100) },
            new List<object> {  r.Next(100), r.Next(100), r.Next(100),r.Next(100), r.Next(100) }
        };

        // Now bind data to the grid
        // We need at least one element
        if (TheData.Count > 0)
        {
            // Find the longest row so we create enough columns
            var max = TheData.Max(c => c.Count);

            for (var i = 0; i < max; i++)
            {
                TheGrid.Columns.Add(
                    new DataGridTextColumn
                    {
                        Header = string.Format("Column: {0:00}", i),
                        Binding = new Binding(string.Format("[{0}]", i))
                    }
                    );
            }
        }

        TheGrid.ItemsSource = TheData;
    }
}

      



}

XAML ...

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit"
    Title="GridTest">
<Grid x:Name="LayoutGrid">
    <toolkit:DataGrid x:Name="TheGrid"
                      AutoGenerateColumns="False"
                      IsReadOnly="False"
                      CanUserAddRows="False"/>
</Grid>

      

Something to note about this approach, if you allow data editing and allow jagged arrays, you will need to create a new list in short strings.

As far as 2D data is concerned, you will need some option to select a different dimension as the datagrid can only represent 2D data.

+2


a source


I think the best solution for you is to just use the TreeView :) if you are using MVVM this is the most striking TreeView tutorial I have found: http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx



Please keep me posted if you need more information.

+1


a source


I did something similar when the data was a list or lists or an array of arrays. Not sure how locked into you the use of multidimensional arrays versus this method for grid data.

This is how I am attached to a list of lists.

        <Resources>
        <DataTemplate x:Key="GridDtInner">
            <TextBlock Text="{Binding YourProperty}"/>
        </DataTemplate>
        <DataTemplate x:Key="GridDtOuter">
            <ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource GridDtInner}" />
        </DataTemplate>     
        </Resources> 
        <ItemsControl  ItemTemplate="{DynamicResource GridDtOuter}" ItemsSource="{Binding YourList, Mode=Default}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
        </ItemsControl>

      

Obviously I've cut everything down for brevity, but I hope this makes sense.

Hello,

Mike Macaulay

0


a source


I did something very similar, but most likely in a completely different industry than what you are working on.

When you say data size / shape, I am assuming that you are not literally talking about circles or squares, but instead say that you have an NxM data matrix and you don’t know what N and M are before doing. I also assume that you want to display some kind of text in each cell of the NxM matrix.

Note that the following XAML has been modified from my code and has not been tested, but I wanted to give you a general idea of ​​how I did it.

        <ListBox Width="300" Height="300" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding Cells}">
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel Width="Auto" Height="Auto" ItemWidth="{Binding CellBoundary}" ItemHeight="{Binding CellBoundary}"/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Width="{Binding CellDiameter}" Height="{Binding CellDiameter}" Text="{Binding CellValue}"></TextBlock>
                </DataTemplate>                    
            </ListBox.ItemTemplate>
        </ListBox>

      

I changed the ListBox ItemsPanel to just be a ListBox. Thus, if you have an NxM matrix (it can also be sparse), you treat it as a vector with NxM cells. Each cell is actually an item in the ListBox.

Then you set the DataTemplate for each ListBox just as a TextBlock, where the size of the TextBlock is the data binding and the displayed value is in CellValue

your Cells element , which is, ObservableCollection<double>

or similar, the database binding before Cells

.

The only thing you have to do at this point in the code is figure out what N and M are and do the necessary math to calculate the size of the ListBox (maybe inside the ViewBox to make it scale) so that the values ​​are displayed accordingly. Obviously you will need to change your hardcoded values ​​and what to do.

This approach seems to be the easiest for me around my brain, so I used it for my stuff.

I should also add that to create a sparse matrix you set CellValue to 0, but you can also use a DataTrigger to make TextBlocks invisible if the value is 0, which gives the illusion of a sparse matrix.

0


a source


I just found a DataGrid in the WPF Toolkit that shows some potential. This at least allows you to select individual cells. I'll post code when I figure out the data binding.

http://wpf.codeplex.com/releases/view/40535
http://windowsclient.net/wpf/wpf35/wpf-35sp1-toolkit-datagrid-feature-walkthrough.aspx

0


a source







All Articles