更改WPF图表工具包图例中显示的颜色

时间:2014-01-22 20:32:16

标签: c# wpf mvvm charts

我有以下样式删除数据点并为我的线系列图

随机生成线条颜色
<Style x:Key="LineDataPointStyle" 
        TargetType="ChartingToolkit:LineDataPoint">
    <Setter Property="Foreground" Value="DarkGreen"/>
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="Width" Value="NaN"/>
    <Setter Property="Height" Value="NaN"/>
    <Setter Property="Background" 
            Value="{Binding RelativeSource={RelativeSource Self}, 
                            Converter={StaticResource ColorBrushConverter}}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ChartingToolkit:LineDataPoint">
                <Grid x:Name="Root" Opacity="0"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

转换器位于:

public class ColorToBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, 
        object parameter, System.Globalization.CultureInfo culture)
    {
        return new SolidColorBrush(Utils.GenerateRandomColor());
    }

    public object ConvertBack(object value, Type targetType, 
        object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

以随机颜色生成线条,但图例是不同的颜色;要么是由库本身自动生成,要么是通过样式模板调用我的转换器。

Shown

如何让图例打印出正确的颜色?

2 个答案:

答案 0 :(得分:1)

我做了类似的事情,我生成了颜色变化的图,但是这些颜色是从首选列表中随机选择的(我有黑色背景,有些颜色在黑色上不能很好地工作)。我从后面的代码设置颜色,我不确定这是你可以做的事情。

在你的情况下,我会尝试这样的事情:

//If you declare your style in a resource dictionary, get that resource first

ResourceDictionary resD = (ResourceDictionary)Application.LoadComponent(new Uri("ResourcesPlot\\ResourceDictionaryPlot.xaml", UriKind.Relative));

//The actual style


Style lineDataPointStyle= (Style)resD["LineDataPointStyle"];

//Set the color
lineDataPointStyle.Setters.Add(new Setter(BackgroundProperty, Utils.GenerateRandomColor()));

希望这有效。

编辑:

对于图例,我使用了这个(我有一个额外的复选框用于显示/隐藏某个图表)

<Style x:Key="CustomLegendItemStyle" TargetType="{x:Type chartingToolkit:LegendItem}">
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="chartingToolkit:LegendItem">
                    <StackPanel Orientation="Horizontal">
                        <CheckBox VerticalAlignment="Center" Margin="3" IsChecked="true" Checked="DisplaySeries_Checked" Unchecked="DisplaySeries_Unchecked"/>
                        <!--<Rectangle VerticalAlignment="Center" Width="8" Height="8" Fill="{DynamicResource MyBackgroundDiode1}" Stroke="{Binding BorderBrush}" StrokeThickness="1" Margin="5,5,5,5" />-->
                        <chartingToolkit:LegendItem VerticalAlignment="Center" Content="{TemplateBinding Content}" />

                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

答案 1 :(得分:1)

注意:是Killercam问题的答案,已被问及here。回答这个问题特别适合他的赏金,所以应他的要求我在这里发表。

在这个答案中,Button控件用于演示使用模板。

<强> Part I. Binding in ControlTemplate

如果要在ControlTemplate中使用 Binding ,则应使用以下构造:

<ControlTemplate TargetType="{x:Type SomeControl}">
    <Rectangle Fill="{TemplateBinding Background}" />

引自MSDN

  

TemplateBinding是模板场景绑定的优化形式,类似于使用{Binding RelativeSource={RelativeSource TemplatedParent}}.构建的绑定

Notes about using TemplateBinding

TemplateBinding在模板外或VisualTree属性之外不起作用,因此您甚至无法在模板的触发器中使用TemplateBinding。此外,当应用于Freezable时,TemplateBinding不起作用(主要是出于人为原因),例如 - VisualBrush。在这种情况下,可以像这样使用Binding:

<FreezableControl Property="{Binding RelativeSource={RelativeSource TemplatedParent},
                                     Path=Background}" />

此外,您始终可以使用TemplateBinding的替代方法:

<Rectangle Fill="{Binding RelativeSource={RelativeSource TemplatedParent},
                          Path=Background}" />

作为另一种可能性,您还可以尝试以下方法:

<Rectangle Fill="{Binding Background, 
                          RelativeSource={RelativeSource AncestorType={x:Type SomeControl}}, 
                          Path=Background}" />

<强> Part II. Notes about your version

在您的情况下,这可能会导致ControlTemplate中的名称冲突,因为您已经使用Binding背景是为了边框。因此,请为Border删除此绑定,或使用其他属性(例如Tag附加依赖项属性)来绑定背景颜色。< / p>

Example of using

取而代之的是ChartingToolkit控件,作为基础Button控件,因为它更容易展示这种样式的概念。

<强> Solution 1: using Tag

<Window.Resources>
    <Style x:Key="TestButtonStyle" TargetType="{x:Type Button}">
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="IsTabStop" Value="False" />

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <!-- Here we are set Tag for Border Background -->
                    <Border Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}" 
                            BorderThickness="{TemplateBinding BorderThickness}">

                        <Grid>
                            <Rectangle Width="24" 
                                       Height="24" 
                                       Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background}" 
                                       Stroke="{TemplateBinding BorderBrush}" />

                            <ContentPresenter Content="{TemplateBinding Content}" 
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<Grid>
    <Button Name="TestButton"
            Style="{StaticResource TestButtonStyle}"
            Content="Test"
            HorizontalContentAlignment="Center"
            VerticalContentAlignment="Center"
            Tag="Green"
            Background="Aquamarine"
            Width="100"
            Height="100" />
</Grid>

Output

enter image description here

此处针对Rectangle,设置两种颜色:默认为Rectangle,标记为Border。我认为这不是一个好的解决方案,这就是原因:

  • 如果Border和Rectangle需要设置不同的值,例如:Background,BorderThickness,BorderBrush等,则Tag是不够的。

  • 使用一个名称属性必须明确其目的,一个名称“标记”我们什么都没说。

这些缺点可以归结为我们应该找到一个替代方案,作为替代方案,我使用带有附加依赖属性的扩展类。

Extender class ButtonExt.cs

public static class ButtonExt
{
    #region RectangleBackground Property

    public static readonly DependencyProperty RectangleBackgroundProperty;

    public static void SetRectangleBackground(DependencyObject DepObject, Brush value)
    {
        DepObject.SetValue(RectangleBackgroundProperty, value);
    }

    public static Brush GetRectangleBackground(DependencyObject DepObject)
    {
        return (Brush)DepObject.GetValue(RectangleBackgroundProperty);
    }

    #endregion

    #region RectangleBorderBrush Property

    public static readonly DependencyProperty RectangleBorderBrushProperty;

    public static void SetRectangleBorderBrush(DependencyObject DepObject, Brush value)
    {
        DepObject.SetValue(RectangleBorderBrushProperty, value);
    }

    public static Brush GetRectangleBorderBrush(DependencyObject DepObject)
    {
        return (Brush)DepObject.GetValue(RectangleBorderBrushProperty);
    }

    #endregion       

    #region Button Constructor

    static ButtonExt()
    {
        #region RectangleBackground

        PropertyMetadata BrushPropertyMetadata = new PropertyMetadata(Brushes.Transparent);

        RectangleBackgroundProperty = DependencyProperty.RegisterAttached("RectangleBackground",
                                                            typeof(Brush),
                                                            typeof(ButtonExt),
                                                            BrushPropertyMetadata);

        #endregion

        #region RectangleBorderBrush

        RectangleBorderBrushProperty = DependencyProperty.RegisterAttached("RectangleBorderBrush",
                                                            typeof(Brush),
                                                            typeof(ButtonExt),
                                                            BrushPropertyMetadata);

        #endregion
    }

    #endregion
}

MainWindow.xaml

<Window.Resources>
    <Style x:Key="TestButtonExtensionStyle" TargetType="{x:Type Button}">
        <Setter Property="Width" Value="80" />
        <Setter Property="Height" Value="80" />
        <Setter Property="Background" Value="Green" />
        <Setter Property="BorderBrush" Value="Pink" />
        <Setter Property="BorderThickness" Value="4" />

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border Background="{TemplateBinding Background}" 
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">

                        <Grid>
                            <Rectangle Fill="{TemplateBinding PropertiesExtension:ButtonExt.RectangleBackground}" 
                                       Stroke="{TemplateBinding PropertiesExtension:ButtonExt.RectangleBorderBrush}"
                                       Width="30" 
                                       Height="30" />

                            <ContentPresenter Content="{TemplateBinding Content}" 
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<Grid>
    <Button Style="{StaticResource TestButtonExtensionStyle}"
            PropertiesExtension:ButtonExt.RectangleBackground="Aquamarine"
            PropertiesExtension:ButtonExt.RectangleBorderBrush="Black"
            Content="Test" />
</Grid>

Output

enter image description here

<强> Part III. Setting values for dependency properties

创建并注册附加依赖项属性时,必须声明Set和Get方法与他合作:

public static void SetRectangleBackground(DependencyObject DepObject, Brush value)
{
    DepObject.SetValue(RectangleBackgroundProperty, value);
}

public static Brush GetRectangleBackground(DependencyObject DepObject)
{
    return (Brush)DepObject.GetValue(RectangleBackgroundProperty);
}

然后与他们合作将如下:

Set

ButtonExt.SetRectangleBackground(MyButton, Brushes.Red);

Get

Brush MyBrush = ButtonExt.GetRectangleBackground(MyButton);

但在我们的案例中,并非如此简单。当我使用附加的依赖属性问题时,更新值不是。但在我们的例子中,属性在模板中,在我的情况下,没有更新Button。我尝试在Binding和属性声明Mode=TwoWay中设置UpdateSourceTrigger=PropertyChangedGetBindingExpression().UpdateTarget(),但它没用。

请注意,对于属性设置 new 值,并且模板中的通知不是,该属性已更新。也许我错了,你会工作,或者可能是专门制作的,例如为了避免内存泄漏。

在任何情况下,最好不要直接更新依赖项属性,并将Model的属性绑定到它,并在ViewModel中设置值。

示例:

<Button Style="{StaticResource TestButtonExtensionStyle}"
        adp:ButtonExt.RectangleBackground="{Binding Path=Model.RectBackground,
                                                    Mode=TwoWay, 
                                                    UpdateSourceTrigger=PropertyChanged}"
        adp:ButtonExt.RectangleBorderBrush="{Binding Path=Model.RectBorderBrush,
                                                     Mode=TwoWay, 
                                                     UpdateSourceTrigger=PropertyChanged}" />

其中RectBackgroundRectBorderBrush实现了INotifyPropertyChanged接口。

在这种情况下,请不要使用依赖项属性,并使用DataTemplate作为控件。 DataTemplate非常适合MVVM,非常灵活和动态。

例如,使用DataTemplate,您可以看到我的答案:

Make (create) reusable dynamic Views

One ViewModel for UserControl and Window or separate ViewModels

相关问题