在 XAML 中设置 WPF OxyPlot PlotViews 的样式

Posted

技术标签:

【中文标题】在 XAML 中设置 WPF OxyPlot PlotViews 的样式【英文标题】:Styling WPF OxyPlot PlotViews in XAML 【发布时间】:2017-08-20 02:44:15 【问题描述】:

在设置 OxyPlot 绘图视图时,您可以通过各种控件显式定义绘图,或通过绑定到 PlotModel 来设置它。

因此,在第一种情况下,两个 LineSeries 对象的图的 XAML 可能类似于

<oxy:Plot Title="Some plot">
    <oxy:Plot.Axes>
        <oxy:LinearAxis Position="Left" />
        <oxy:LinearAxis Position="Bottom" />
    </oxy:Plot.Axes>
    <oxy:Plot.Series>
        <oxy:LineSeries ItemsSource="Binding ActualSeriesData1" DataFieldX="X" DataFieldY="Y"/>
        <oxy:LineSeries ItemsSource="Binding ActualSeriesData2" DataFieldX="X" DataFieldY="Y"/>
    </oxy:Plot.Series>
</oxy:Plot>

具有非常薄的视图模型。另一方面,在第二种情况下,我只会有类似

<oxy:PlotView Model="Binding SomePlotModel" />

并在视图模型中构建实际绘图。两种设置各有利弊,但我发现当我事先知道我真正想要绘制的内容时,第一种方法通常效果更好,而第二种方法允许对绘图内容进行动态更改。

我的问题如下:对于第一种情况,我知道如何为所有绘图添加一般样式。例如,如果我想让它们看起来像 Seaborn,我会添加类似

<x:Array Type="Color" x:Key="SeabornColors">
    <Color>#4c72b0</Color>
    <Color>#55a868</Color>
    <Color>#c44e52</Color>
    <Color>#8172b2</Color>
    <Color>#ccb974</Color>
    <Color>#64b5cd</Color>
</x:Array>
<Style TargetType="oxy:Plot">
    <Setter Property="PlotAreaBackground" Value="#EBEBF2" />
    <Setter Property="PlotAreaBorderThickness" Value="0" />
    <Setter Property="TitleFont" Value="Segoe UI" />
    <Setter Property="TitleFontWeight" Value="Normal" />
    <Setter Property="DefaultColors" Value="StaticResource SeabornColors"/>
</Style>
<Style TargetType="oxy:LinearAxis">
    <Setter Property="TicklineColor" Value="White" />
    <Setter Property="MajorGridlineColor" Value="White" />
    <Setter Property="MinorGridlineColor" Value="White" />
    <Setter Property="ExtraGridlineColor" Value="White" />
    <Setter Property="AxislineColor" Value="White" />
    <Setter Property="TitleColor" Value="Black" />
    <Setter Property="TextColor" Value="Black" />
    <Setter Property="Font" Value="Segoe UI" />
    <Setter Property="TitleFont" Value="Segoe UI" />
    <Setter Property="TickStyle" Value="None" />
    <Setter Property="MajorGridlineStyle" Value="Solid" />
</Style>

致我的ResourceDictionary。如何在第二种情况下达到相同的效果,即使用oxy:PlotView?我可以使用&lt;Style TargetType="oxy:PlotView" /&gt; 设置一些常规样式属性,但是我将如何设置所有LineSeries 的样式,比如Series 中的Model 中的Model 中的PlotView

【问题讨论】:

我也遇到过同样的问题,我能够解决的唯一方法是使用后面的代码来设置 PlotModels 上的属性。它仍然将设计与逻辑分开,但遗憾的是没有使用 XAML 或样式。 @Herman:有没有一种直接的方法可以适用于应用程序中的所有 PlotModel?这是将其设置为样式的好处之一。 我能想到的最好方法是为每种样式创建一个以 PlotModel 作为参数的方法,然后遍历所有绘图模型并为每个 PlotModel 调用该方法。从理论上讲,您可以在一个窗口中找到所有 PlotViews 并提取 PlotModel,但在我的情况下,我的 ViewModel 已经有一个绘图模型数组,因此更简单。 我认为你的问题不够具体。每当使用 PlotView / PlotModel / Plot 时,没有什么能阻止您重新使用 XAML 资源,无论是作为 StaticResource 还是通过代码隐藏中的 Application.Current.Resources["SomeResourceKey"]。但请记住,可能存在不兼容的类型,例如,ColorOxyColor 之间。而且在OxyPlot.Wpf.LinearAxisOxyPlot.Axes.LinearAxis之间...... @RobL 取决于项目的类型;因为这个特别是关于 WPF,我们会做xmlns:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"。我不知道在Xamarin.Forms 中调用了哪些相关类型,但如果它没有Plot,我猜你会使用你在Xamarin.Forms 中使用的任何东西。 【参考方案1】:

我没有通过所有的 cmets,但其中一些似乎已经包含解决方案的链接。我有一个示例,我正在使用 MVVM 方法并更改这些设置。它应该有帮助:

在 MainWindow.xaml 中:

<oxy:PlotView Name="TestView" Model="Binding plotModel" Grid.Row="0" Grid.Column="1" />

在我的 MainWindowViewModel.cs 中:

private PlotModel m_plotModel;
public PlotModel plotModel

    get  return m_plotModel; 
    set => SetAndRaisePropertyChanged(ref m_plotModel, value);


public UserControlOscilloViewModel()

    var signalAxis = new CategoryAxis()
    
        Position = AxisPosition.Left,
        Minimum = 0,
        MinimumMinorStep = 1,
        AbsoluteMinimum = 0,
        TicklineColor = OxyColors.Transparent,
    ;
    var timeAxis = new LinearAxis()
    
        Position = AxisPosition.Bottom,
        Minimum = 0,
        MinimumMajorStep = 1,
        AbsoluteMinimum = 0,
    ;

    plotModel = new PlotModel();            
    plotModel.Axes.Add(signalAxis);
    plotModel.Axes.Add(timeAxis);

然后,当您刷新模型时,如果需要,您可以像这样访问您的轴:

CategoryAxis signalAxis = (CategoryAxis)plotModel.Axes.ElementAt(0);
LinearAxis timeAxis = (LinearAxis)plotModel.Axes.ElementAt(1);

并像这样添加系列:

var series = new LineSeries

    Color = OxyColors.SeaShell,
    LineStyle = LineStyle.Dash
;
foreach (DataPoint p in ListOfPoints)

    series.Points.Add(p);

plotModel.Series.Add(series);
plotModel.InvalidatePlot(true);

我并没有完全解决您的问题,但我认为您可以通过这样做访问所有需要的对象/成员。我还简化了我的代码以提高清晰度,我希望这样做时我没有破坏任何东西......

【讨论】:

嗯,是的,我不确定我是否跟随;我遇到的主要问题是应用程序中所有PlotModels 的样式;为个人设置样式很简单,最终我选择了@Herman 建议的或多或少的解决方案,创建了一种方法来设置给定PlotModel 的样式,并确保每个相关的都调用该方法。不理想,但它可以完成工作。

以上是关于在 XAML 中设置 WPF OxyPlot PlotViews 的样式的主要内容,如果未能解决你的问题,请参考以下文章

在 WPF/xaml 中设置静态日期时间

在 WPF/xaml 中设置静态日期时间

WPF - 为啥在 XAML 中设置 Binding BindableObject.Text 时 SetProperty() 不触发 CanExecute?

使用 MvvmCross 时如何在 WPF App.xaml 中设置资源? (MaterialDesignInXamlToolkit)

WPF:一旦我在代码中设置了一个属性,它就会永远忽略 XAML 绑定......我该如何防止这种情况发生?

在 WPF 中使用数据绑定时,OxyPlot 不刷新