"Динамически" Создайте 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 и DataTemplate
s.
ОБНОВЛЕНИЕ >>>
Пользовательский класс для привязки данных к Line
элементы не является моделью представления. Думайте об этом как о классе типа данных, для которого вы объявите DataTemplate
как тот, что выше. Когда я сказал, что он должен иметь все необходимые свойства, если вы посмотрите на приведенный выше пример, вы увидите, что ему нужно по крайней мере четыре double
свойства к данным привязываются к четырем используемым свойствам Line
элемент. Однако вы также можете добавить дополнительные свойства к привязке данных к Stroke
, StrokeThickness
или же Fill
свойства например.
Что касается того, где вы должны определить DataTemplate
, оно должно быть в пределах объема предметов, к которым оно применено. Если вы хотите использовать его в одном представлении, поместите его в UserControl.Resources
раздел этого взгляда. Однако, если вы хотите использовать тот же DataTemplate
тогда вы должны положить его в Application.Resources
раздел App.xaml
файл, потому что те Resources
доступны широкое применение.
ЗАКЛЮЧИТЕЛЬНОЕ ОБНОВЛЕНИЕ >>>
Как отмечалось в моем комментарии, обучение пользователей тому, как использовать WPF, определенно выходит за рамки этого веб-сайта, поэтому я не буду этого делать. Узнать о DataTemplate
s, вы должны прочитать страницу Обзор шаблонов данных на 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
- если нет, вы можете легко узнать, как это сделать в Интернете.