【问题标题】:"Dynamically" Generate a WPF View C# for Plotting with DynamicDataDisplay“动态”生成 WPF 视图 C# 以使用 DynamicDataDisplay 进行绘图
【发布时间】:2014-06-09 23:54:41
【问题描述】:

我正在用 C# 编写一个 WPF 应用程序。此应用程序是使用 MVVM 设计的。

目前,我有一个带有几个复选框的父窗口。使用用户可以检查他们想要的任何框,然后单击“绘图”Button。一旦他们点击“绘图”,就会出现一个新的子窗口,在 单个 图表上显示数据。

所以,如果我只选中了一个复选框,然后单击“绘图”,我将看到一个带有单线的图形。如果我有 2 个复选框选中并单击“绘图”,我将看到相同的单个图形,但上面会有 2 条线。

我目前的实现:

目前,我有一个名为GraphWindowView 的“视图”类。视图显然需要知道要显示哪些数据。所以要做到这一点,我有 GraphWindowView.DatesGraphWindowView.Data 的依赖属性,它们最终会生成 Data(y 轴)与 Dates(x 轴)的图表。

问题:GraphWindowView 的当前实现显然仅限于绘制一组数据(即DataDates)。我想让这个(很多)更具可扩展性,并根据选中的复选框数量来提供任意数量的绘图。我该怎么做呢?我想我需要重新考虑我对依赖属性的使用......

>>> 更新

所以我创建了一个GraphLine 类,它应该代表图表上的一条线。 “图”实际上是GraphWindowPresenter.xaml 类中的ChartPlotter 元素。此外,我为GraphLine 对象指定了DataType,但这就是我所理解的。下一步是什么,我如何实际将数据添加到图表中?以及如何/在哪里创建 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; }
        }
    }

【问题讨论】:

    标签: c# wpf xaml dynamic-data-display


    【解决方案1】:

    WPF 中的大多数此类问题都可以通过仔细使用数据绑定和DataTemplates 来解决,而不是通过数英里的程序代码来解决。一般的想法是您创建一个自定义类,其中包含绘制所有线条所需的所有属性。然后,您将声明一个 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 元素的四个使用属性.但是,您也可以选择将更多属性添加到数据绑定到 StrokeStrokeThicknessFill 属性等。

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


    最终更新>>>

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

    在我开始之前我可以给你一些最后的提示:你控件中的DependencyProperty 应该是ObservableCollection&lt;GraphLine&gt; 类型。在您的控件中,您应该将它们数据绑定到某种ItemsControl,如上所示 - 我更改了其中的Binding Path,因为您应该真正使用RelativeSource Binding 来定位您的情况下的属性(其中YourControlName 是您要在其中绘制 Line 对象的 UserControl 的名称)。

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

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

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

    【讨论】:

    • 感谢您的回答,我刚刚阅读了关于 DataTemplates 的长篇教程,现在我正在尝试理解这种方法。当您说我“创建一个具有绘制线条所需的所有属性的自定义类”时,您的意思是像我的 GraphWindowView 类的 ViewModel 吗?此外,是否会在我的 GraphWindowView.xaml 类或我的 MainWindowView.xaml 类中定义 DataTemplate(使用 .xaml)?我想我了解 DataTemplates 的一般用途,只是在我的特定上下文/场景中不了解。
    • 嘿,非常感谢到目前为止的帮助,我已经更新了我的原始帖子,我已经到了那里,如果你能回复它,那就太棒了。非常感谢到目前为止的帮助!
    • 老实说……回答这些类型的问题,用户不断地添加新的需求并不断地拖拽它们是很烦人的。以后,请将您的所有要求放在开始的问题中。 Stack Overflow 答案作者的工作不是教如何使用特定语言...问题应该有一个狭窄的焦点,例如“任何人都可以看到代码中的错误?”,而不是“谁能教我如何做某事?”原因很简单……网上到处都是学习教程……这个网站没有。
    • 感谢您的所有帮助。我已经阅读了教程,但在我的代码上下文中我不理解它们。不过,您的回答对这个主题有很多启发。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多