0

I am writing a WPF application in C#. This application is design using MVVM.

Currently, I have a parent window with a few check boxes. Use user can check whichever boxes they want and then click the "plot" Button. Once they click "plot", a new child window comes up displaying the data on a single graph.

So, if I have only 1 check box checked, and then click "plot", I will see a graph with a single line on it. If I have 2 check boxes check and click "plot", I will see the same single graph, but it will have 2 lines on it.

My current Implementation:

Currently, I have a "view" class called GraphWindowView. The view obviously needs to know of which data to show. So to do that, I have dependency properties GraphWindowView.Dates and GraphWindowView.Data which ultimatley produces a graph of Data (y axis) vs. Dates (x axis).

Question: This current implementation of GraphWindowView is obviously restricted to only being able to graph one set of data (i.e. Data vs. Dates). I would like to make this (a lot) more extensible and have an arbitrary number of plots available depending on how much check boxes are checked. How would I go about doing this? I think I need to rethink my use of dependency properties...

>>> UPDATE

So I made a GraphLine class which should represent a line on the graph. The "graph" is actually a ChartPlotter element in the GraphWindowPresenter.xaml class. Additionally, I specified a DataType for the GraphLine objects, but that is all I understand. What are the next steps to this, how do I actually add the data to the graph? And how/where do I make instances of GraphLine to populate the ChartPlotter element? Sorry I am pretty lost on this, even after reading quite a few tutorials. Thanks for all the help so far, I really appreciate it!

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; }
        }
    }
4

1 回答 1

2

WPF 中的大多数此类问题都可以通过仔细使用数据绑定和DataTemplates 来解决,而不是通过数英里的程序代码来解决。一般的想法是您创建一个自定义类,其中包含绘制所有线条所需的所有属性。然后,您将声明 aDataTemplate来定义如何对各种属性进行数据绑定,可能有点像这样:

<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元素的四个使用属性。但是,您也可以选择将更多属性添加到绑定到StrokeStrokeThicknessFill属性的数据中。

至于你应该在哪里定义DataTemplate,它应该在应用它的项目的范围内。如果您想在一个视图中使用它,请将其放在该UserControl.Resources视图的部分中。但是,如果您想使用相同的DataTemplate,那么您应该将其放入文件的Application.Resources部分,App.xaml因为它们Resources在应用程序范围内可用。


最后更新>>>

正如我在评论中所指出的,教用户如何使用 WPF 绝对超出了本网站的范围,所以我不会这样做。要了解DataTemplates,您应该阅读 MSDN 上的数据模板概述页面。当您对某事不了解时,MSDN 应该始终是您搜索答案的首选。

在我走之前,我可以给你一些最后的提示:DependencyProperty你控制的应该是类型ObservableCollection<GraphLine>。在您的控件中,您应该将它们数据绑定到某种类型,ItemsControl如上所示 - 我更改了Binding Path它,因为您应该真正使用 aRelativeSource Binding在您的情况下定位属性(您要绘制对象YourControlName的名称在哪里) .UserControlLine

最后,在您的视图模型(与包含UserControl绘制线条的新视图的视图链接)中,您需要一个集合属性来与 中的集合进行数据绑定,UserControl假设命名为YourGraphLineCollectionInViewModel

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

正是在这个视图模型中,您将GraphLine类的实例添加到YourGraphLineCollectionInViewModel集合中,只要您Binding Path按照此处所示设置了您的 s,它们就会出现在您的 UI 中的ItemsControl. 我假设您知道如何正确设置您的DataContext- 如果不知道,您可以轻松地找到如何在线进行设置。

于 2014-06-10T11:22:22.223 回答