Отображение многомерных данных в WPF

Каков наилучший способ отображения многомерных данных в WPF? Я не буду знать размер/форму данных до времени выполнения. В идеале я хотел бы использовать привязку данных, но это не является строгим требованием. Я думал о какой-то сетке, но я не знаю, как динамически привязываться к данным и определять количество строк и столбцов. Предложения и примеры, пожалуйста?


person KrisTrip    schedule 20.04.2010    source источник
comment
Уточнение: под размером/формой я подразумеваю MxN, а не круги/квадраты. Я имею дело с данными массива, которые могут быть от 1D до 6D, которые я хочу отобразить в виде таблицы (более того, 2D следует просто последовательно отображать в таблице). Я не имею дело с зубчатыми массивами или разреженными матрицами. Мой вопрос действительно в том, какой хороший элемент управления использовать для реализации этой таблицы.   -  person KrisTrip    schedule 21.04.2010
comment
Еще одно уточнение: мне также нужно, чтобы он действовал как таблица Excel. Например, мне нужно иметь возможность выбрать прямоугольник данных для копирования/вставки из/в него.   -  person KrisTrip    schedule 21.04.2010
comment
Знаете, не рассчитывайте на огромный отклик, если не будете давать баллы за правильные ответы на свой вопрос (вне всяких сомнений, они правильные) :)   -  person Piotr Justyna    schedule 21.04.2010
comment
У меня еще не было возможности их протестировать. Я обязательно поставлю баллы и выберу лучший ответ, как только у меня будет возможность попробовать его. К сожалению, я могу работать над этим только вечером, так как это не является частью моей дневной работы.   -  person KrisTrip    schedule 21.04.2010


Ответы (5)


Звучит так, как будто вам нужен Excel-подобный интерфейс для 2D-массивов с возможностью редактирования. Для других измерений вам придется придумать вкладки или серию выпадающих списков.

Ознакомьтесь с WPF Toolkit DataGrid. Есть возможность автоматически генерировать столбцы. Поэкспериментируйте с этим.

Однако у вас будет некоторый код для работы с другими измерениями, поскольку Datagrid может представлять только 2D-данные.

Кори

Изменить: (28.04.2010) Вот рабочее решение.

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>

Some thing to note about this approach, if you allow editing of data and allow jagged arrays, you will need to new up a new List on the short rows.

Что касается> 2D-данных, вам понадобится какая-то опция для выбора другого измерения, поскольку сетка данных может представлять только 2D-данные.

person CoreyH    schedule 22.04.2010
comment
Это именно то, о чем я говорю! WPF Toolkit DataGrid выглядит многообещающе. - person KrisTrip; 22.04.2010

Я думаю, что лучшее решение для вас — просто использовать TreeView :) Если вы используете MVVM, это самое блестящее руководство по TreeView, которое я нашел: http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx

Пожалуйста, держите меня в курсе, если вам нужна дополнительная информация.

person Piotr Justyna    schedule 21.04.2010
comment
TreeView не является хорошим решением для меня. Это данные массива, которые необходимо отображать в виде таблицы (например, сетка Excel или что-то в этом роде). - person KrisTrip; 21.04.2010
comment
В этом случае у меня есть 2 альтернативы для вас. Во-первых: вы можете шаблонировать древовидное представление, чтобы оно выглядело точно так же, как таблица (я настаиваю на использовании TreeView, потому что его очень легко привязать к иерархическим структурам данных). Во-вторых: вы можете использовать обычную сетку со связанными строками/столбцами или список со связанными шаблонными элементами списка. На вашем месте я бы выбрал первое решение :) С уважением, Петр. - person Piotr Justyna; 21.04.2010
comment
Мне также нужно, чтобы он действовал как таблица Excel. Например, мне нужно иметь возможность выбрать прямоугольник данных для копирования/вставки из/в него. Я не думаю, что TreeView может обрабатывать такие функции. - person KrisTrip; 21.04.2010
comment
Вы будете удивлены ;) У меня есть ощущение, что этот вопрос следует задать снова, но под другим заголовком (например, как может имитировать поведение Excel в моем приложении WPF). Я нашел для вас кое-что, вы можете воспользоваться бесплатной пробной версией: devexpress.com/Products/NET/Controls/WPF/Grid/filter.xml Боюсь, для его реализации использовали обычную сетку. - person Piotr Justyna; 21.04.2010

Я сделал что-то подобное, когда данные были списком или списками или массивом массивов. Не уверен, насколько вы привязаны к использованию многомерных массивов по сравнению с этим методом для данных, подобных сетке.

Вот как я связался со списком списков.

        <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>

Очевидно, я вырезал вещи для краткости, но я надеюсь, что это имеет смысл.

С уважением,

Майк МакОлей

person Brosten Consulting    schedule 21.04.2010

Я делал что-то очень похожее, но, скорее всего, в совершенно другой отрасли, чем та, в которой вы работаете.

Когда вы говорите размер/форма данных, я предполагаю, что вы не имеете в виду буквально круги и квадраты, а вместо этого говорите, что у вас есть матрица данных NxM, и вы не знаете, что такое N и M, пока время выполнения. Я также предполагаю, что вы хотите отображать какой-то текст в каждой ячейке матрицы NxM.

Обратите внимание, что следующий XAML был изменен из моего кода и не тестировался, но я хотел дать вам общее представление о том, как я это сделал.

        <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>

Я изменил ItemsPanel ListBox, чтобы он был просто ListBox. Итак, пока у вас есть матрица NxM (она тоже может быть разреженной), вы рассматриваете ее как вектор с ячейками NxM. Каждая ячейка фактически является элементом в ListBox.

Затем вы устанавливаете DataTemplate для каждого элемента ListBox просто как TextBlock, где размер TextBlock привязан к данным, а отображаемое значение находится в элементе CellValue ваших ячеек, который является ObservableCollection<double> или подобным, привязанным к данным Cells.

Единственное, что вам нужно сделать на этом этапе кода, — это выяснить, что такое N и M, и выполнить необходимые математические действия для расчета размера ListBox (может быть внутри ViewBox, чтобы сделать его масштабируемым), чтобы значения отображаются соответствующим образом. Очевидно, вам нужно будет изменить мои жестко запрограммированные значения на что-то связанное с данными.

Этот подход кажется мне самым простым для понимания, поэтому я использую его для своих целей.

Я также должен добавить, что для создания разреженной матрицы вы установите для CellValue значение 0, но вы также можете использовать DataTrigger, чтобы сделать TextBlocks невидимыми, если значение равно 0, создавая таким образом иллюзию разреженной матрицы.

person Dave    schedule 21.04.2010

Я только что нашел DataGrid в наборе инструментов WPF, который демонстрирует некоторый потенциал. По крайней мере, это позволяет выбирать отдельные ячейки. Я опубликую код, когда выясню привязку данных.
http://wpf.codeplex.com/releases/view/40535
http://windowsclient.net/wpf/wpf35/wpf-35sp1-toolkit-datagrid-feature-walkthrough.aspx

person KrisTrip    schedule 21.04.2010