Отображение многомерных данных в WPF - PullRequest
2 голосов
/ 21 апреля 2010

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

Ответы [ 5 ]

2 голосов
/ 22 апреля 2010

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

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

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

Corey

Редактировать: (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>

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

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

1 голос
/ 21 апреля 2010

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

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

0 голосов
/ 21 апреля 2010

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

0 голосов
/ 21 апреля 2010

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

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

0 голосов
/ 21 апреля 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>

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

С уважением,

Майк МакОлей

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...