"Динамически" Создайте WPF View C# для печати с DynamicDataDisplay

Я пишу приложение WPF на C#. Это приложение разработано с использованием MVVM.

В настоящее время у меня есть родительское окно с несколькими флажками. Пользователь может установить флажки, которые захотят, а затем нажать "Сюжет". Button, Как только они нажимают "заговор", появляется новое дочернее окно, отображающее данные на одном графике.

Таким образом, если у меня установлен только один флажок, а затем нажмите "Сюжет", я увижу график с одной линией на нем. Если у меня есть 2 флажка, отмеченных галочкой, и я нажму "сюжет", я увижу один и тот же график, но на нем будет 2 строки.

Моя текущая реализация:

В настоящее время у меня есть класс "view" под названием GraphWindowView, Очевидно, что представление должно знать, какие данные показывать. Так что для этого у меня есть свойства зависимости GraphWindowView.Dates а также GraphWindowView.Data который в конечном итоге производит график Data (ось у) против Dates (ось х).

Вопрос: это текущая реализация GraphWindowView очевидно, ограничивается возможностью графического представления только одного набора данных (т.е. Data против Dates). Я хотел бы сделать это (намного) более расширяемым и иметь произвольное количество доступных графиков в зависимости от того, сколько флажков установлено. Как бы я поступил так? Я думаю, что мне нужно переосмыслить свое использование свойств зависимости...

>>> ОБНОВЛЕНИЕ

Итак, я сделал GraphLine класс, который должен представлять линию на графике. "График" на самом деле ChartPlotter элемент в GraphWindowPresenter.xaml учебный класс. Кроме того, я указал DataType для GraphLine объекты, но это все, что я понимаю. Каковы следующие шаги к этому, как я на самом деле добавить данные в график? И как / где я делаю экземпляры GraphLine заселить ChartPlotter элемент? Извините, я довольно запутался в этом, даже после того, как прочитал немало учебников. Спасибо за всю помощь до сих пор, я действительно ценю это!

GraphWindowView.xaml

<Window x:Class="BMSVM_Simulator.View.GraphWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ViewModel="clr-namespace:BMSVM_Simulator.ViewModel"
        xmlns:d3="http://research.microsoft.com/DynamicDataDisplay/1.0"
        x:Name="ThisGraphWindowInstance"
        Title="Plot" Height="500" Width="750"
        Icon="../res/qualcomm_q_icon.ico.ico"
        MinWidth="400" MinHeight="300">

    <Window.DataContext>
        <ViewModel:GraphWindowPresenter/>
    </Window.DataContext>

    <d3:ChartPlotter Name="plotter" Margin="10,10,20,10">
        <d3:ChartPlotter.HorizontalAxis>
            <d3:HorizontalIntegerAxis Name="dateAxis"/>
        </d3:ChartPlotter.HorizontalAxis>
        <d3:ChartPlotter.VerticalAxis>
            <d3:VerticalIntegerAxis Name="countAxis"/>
        </d3:ChartPlotter.VerticalAxis>

        <d3:Header FontFamily="Arial" Content="{Binding ElementName=ThisGraphWindowInstance, Path=title}"/>
        <d3:VerticalAxisTitle FontFamily="Arial" Content="{Binding ElementName=ThisGraphWindowInstance, Path=yAxis}"/>
        <d3:HorizontalAxisTitle FontFamily="Arial" Content="{Binding ElementName=ThisGraphWindowInstance, Path=xAxis}"/>
    </d3:ChartPlotter>

    <Window.Resources>
        <DataTemplate DataType="{x:Type ViewModel:GraphLine}">
            <!--WHAT GOES HERE-->
        </DataTemplate>
    </Window.Resources>

</Window>

GraphLine.cs

namespace BMSVM_Simulator.ViewModel
    {
        class GraphLine
        {
            public string xAxis                     { get; private set; }
            public string yAxis                     { get; private set; }
            public string title                     { get; private set; }
            public string legend                    { get; private set; }
            public EnumerableDataSource<int> data   { get; private set; }
            public EnumerableDataSource<int> dates  { get; private set; }
        }
    }

1 ответ

Решение

Большинство из этих типов проблем в WPF могут быть решены путем некоторого осторожного использования привязки данных и DataTemplateс, а не мили процедурного кода. Общая идея заключается в том, что вы создаете пользовательский класс со всеми свойствами, которые необходимы для рисования всех ваших линий. Затем вы объявите DataTemplate чтобы определить, как различные свойства должны быть связаны с данными, возможно, что-то вроде этого:

<DataTemplate DataType="{x:Type YourXamlNamespacePrefix:GraphLine}">
    <Line X1="{Binding X1}" Y1="{Binding Y1}" X2="{Binding X2}" Y2="{Binding Y2}" />
</DataTemplate>

Затем вы создаете коллекцию пользовательских экземпляров классов, а данные связывают ее с каким-либо элементом управления коллекцией, например ItemsControl и каждый из них будет автоматически отображен в правильном месте:

<ItemsControl ItemsSource="{Binding YourGraphLineCollection, RelativeSource={
    RelativeSource AncestorType={x:Type YourXamlNamespacePrefix:YourControlName}}}" />

Добро пожаловать в мощный мир связывания данных WPF и DataTemplates.


ОБНОВЛЕНИЕ >>>

Пользовательский класс для привязки данных к Line элементы не является моделью представления. Думайте об этом как о классе типа данных, для которого вы объявите DataTemplate как тот, что выше. Когда я сказал, что он должен иметь все необходимые свойства, если вы посмотрите на приведенный выше пример, вы увидите, что ему нужно по крайней мере четыре double свойства к данным привязываются к четырем используемым свойствам Line элемент. Однако вы также можете добавить дополнительные свойства к привязке данных к Stroke, StrokeThickness или же Fill свойства например.

Что касается того, где вы должны определить DataTemplate, оно должно быть в пределах объема предметов, к которым оно применено. Если вы хотите использовать его в одном представлении, поместите его в UserControl.Resources раздел этого взгляда. Однако, если вы хотите использовать тот же DataTemplateтогда вы должны положить его в Application.Resources раздел App.xaml файл, потому что те Resources доступны широкое применение.


ЗАКЛЮЧИТЕЛЬНОЕ ОБНОВЛЕНИЕ >>>

Как отмечалось в моем комментарии, обучение пользователей тому, как использовать WPF, определенно выходит за рамки этого веб-сайта, поэтому я не буду этого делать. Узнать о DataTemplates, вы должны прочитать страницу Обзор шаблонов данных на MSDN. Когда вы ничего не знаете, MSDN всегда должен быть вашим первым местом для поиска ответов.

Я могу дать вам несколько последних советов, прежде чем я уйду: DependencyProperty в вашем контроле должно быть типа ObservableCollection<GraphLine>, Внутри вашего контроля, вы должны связать их с каким-то ItemsControl как показано выше - я изменил Binding Path в нем, потому что вы действительно должны использовать RelativeSource Binding найти недвижимость в вашей ситуации (где YourControlName это имя твоего UserControl где вы хотите нарисовать Line объекты).

Наконец, в вашей модели представления (которая связана с представлением, которое содержит ваши новые UserControl который рисует линии), вам понадобится свойство коллекции для привязки данных с коллекцией в UserControlскажем, по имени YourGraphLineCollectionInViewModel:

<YourXamlNamespacePrefix:YourControlName YourGraphLineCollection="{Binding 
    YourGraphLineCollectionInViewModel}" />

Именно в этой модели представления вы добавляете экземпляры вашего GraphLine класс в YourGraphLineCollectionInViewModel Коллекция и до тех пор, пока вы создали Binding PathКак показано здесь, они появятся в вашем пользовательском интерфейсе в пределах ItemsControl, Я предполагаю, что вы знаете, как правильно настроить DataContext - если нет, вы можете легко узнать, как это сделать в Интернете.

Другие вопросы по тегам