How to Bind to Another Control Property in WPF

MoonKnight

I am using the WPF Charting ToolKit via the namespaces:

xmlns:ChartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:VisualizationToolkit="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit"

I have a chart control in which I generate a random color for each time a Lineseries plot is undertaken. I remove the data point markers and colorize using the following style

<Style x:Key="LineDataPointStyle" 
        TargetType="ChartingToolkit:LineDataPoint">
    <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>

The LineSeries is defined via

<ChartingToolkit:LineSeries Title="{Binding DisplayName}" 
                            AnimationSequence="FirstToLast"
                            SnapsToDevicePixels="True" 
                            DataPointStyle="{StaticResource LineDataPointStyle}"
                            ItemsSource="{Binding Data}"
                            IndependentValueBinding="{Binding X}"
                            DependentValueBinding="{Binding Y}"/>

Now, this works fine but the legend markers display a different color to the random one I generate for the LineSeries. I want the same color to be displayed for the legend item for the LineSeries and the Lineseries itself. So, I have styled the legend item as below

<Style x:Key="TestSuiteLegendItemStyle" 
      TargetType="{x:Type ChartingToolkit:LegendItem}">
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="Template">
       <Setter.Value>
          <ControlTemplate TargetType="{x:Type ChartingToolkit:LegendItem}">
             <Border Background="{TemplateBinding Background}" 
                     BorderBrush="{TemplateBinding BorderBrush}" 
                     BorderThickness="{TemplateBinding BorderThickness}">
                <StackPanel Orientation="Horizontal">
                   <Rectangle Width="8" 
                              Height="8" 
                              Fill="{Binding Background}" 
                              Stroke="{Binding BorderBrush}" 
                              StrokeThickness="1" Margin="0,0,3,0" />
                   <VisualizationToolkit:Title Content="{TemplateBinding Content}" />
                </StackPanel>
             </Border>
          </ControlTemplate>
       </Setter.Value>
    </Setter>
</Style>

My question is how can I 'bind' the Rectangle.Fill in the TestSuiteLegendItemStyle style so that it is the same color as the LineSeries as set by the LineDataPointStyle defined above?*

Thanks for your time.


Edit. I have tried setting a DependencyProperty that holds the Background color of my plot as suggested below via

<Style x:Key="LineDataPointStyle" 
        TargetType="ChartingToolkit:LineDataPoint">
    ...
    <Setter Property="Background" 
            Value="{Binding RelativeSource={RelativeSource Self}, 
                            Converter={StaticResource ColorBrushConverter}}"/>
    ...
</Style>

Where the I have ammended the converter (as marked) so that I can store the randomly generated background color and then use this in my legend

public class ColorToBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, 
        object parameter, System.Globalization.CultureInfo culture)
    {
        Brush b = new SolidColorBrush(Utils.GenerateRandomColor());
        MultiChartExtensions.BackgroundBrushProperty = b; <= how to set the dependency property?
        return b;
    }

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

where the Dependency Property (DP) is defined as

public static readonly DependencyProperty BackgroundBrushProperty;
public static void SetBackgroundBrush(DependencyObject DepObject, Brush value)
{
    DepObject.SetValue(BackgroundBrushProperty, value);
}

public static Brush GetBackgroundBrush(DependencyObject DepObject)
{
    return (Brush)DepObject.GetValue(BackgroundBrushProperty);
}

I would then look to set the legend background via this DP via

<Style x:Key="TestSuiteLegendItemStyle" 
      TargetType="{x:Type ChartingToolkit:LegendItem}">
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="Template">
       <Setter.Value>
          <ControlTemplate TargetType="{x:Type ChartingToolkit:LegendItem}">
             <Border Background="{TemplateBinding Background}" 
                     BorderBrush="{TemplateBinding BorderBrush}" 
                     BorderThickness="{TemplateBinding BorderThickness}">
                <StackPanel Orientation="Horizontal">
                   <Rectangle Width="8" 
                              Height="8" 
                              Fill="{Binding MultiChart:MultiChartExtensions.BackgroundBrushProperty}" 
                              Stroke="{Binding BorderBrush}" 
                              StrokeThickness="1" Margin="0,0,3,0" />
                   <VisualizationToolkit:Title Content="{TemplateBinding Content}" />
                </StackPanel>
             </Border>
          </ControlTemplate>
       </Setter.Value>
    </Setter>
</Style>

Any help with this would be appreciated...

Anatoliy Nikolaev

Part I. Binding in ControlTemplate

If you want to use Binding in a ControlTemplate, you should use following construction:

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

Quoted from MSDN:

A TemplateBinding is an optimized form of a Binding for template scenarios, analogous to a Binding constructed with {Binding RelativeSource={RelativeSource TemplatedParent}}.

Notes about using TemplateBinding

TemplateBinding doesn’t work outside a template or outside its VisualTree property, so you can’t even use TemplateBinding inside a template’s trigger. Furthermore, TemplateBinding doesn’t work when applied to a Freezable (for mostly artificial reasons), for example - VisualBrush. In such cases it is possible to use Binding like this:

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

Also, you can always use an alternative for TemplateBinding:

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

As another possibility, you can also try the following:

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

Part II. Notes about your version

In your case, this may cause a conflict of names in the ControlTemplate, because you already are using Binding background is for Border. Therefore, remove it this Binding for a Border, or use another property, such as Tag or attached dependency property for binding Background color.

Example of using

Instead ChartingToolkit controls, took as a basis Button control, because it's easier to demonstrate the idea of ​​this styles.

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

Here for Rectangle, set two colors: default for Rectangle, in Tag for Border. I do not find this a good solution, and here's why:

  • If a Border and Rectangle need to set different values, such as: Background, BorderThickness, BorderBrush, etc. one Tag is not enough.

  • With one name property must be clearly its purpose, one name "Tag" us to nothing says.

Of these disadvantages can be concluded that we should find an alternative, as an alternative I use a extender-class with the attached dependency properties.

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

When you create and register your attached dependency property, you must declare the Set and Get methods to work with him:

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

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

Then work with them will be as follows:

Set

ButtonExt.SetRectangleBackground(MyButton, Brushes.Red);

Get

Brush MyBrush = ButtonExt.GetRectangleBackground(MyButton);

But in our case, it's not so simple. When I used the attached dependency property problems in updating values ​​were not. But in our case, the property is in the template, and in my case there was no update Button. I tried to set Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, in Binding and in the property declaration, GetBindingExpression().UpdateTarget(), but it was useless.

Note that for the property setting a new value, and notification from the template is not, that the property has been updated. Maybe I'm wrong, and you have will work, or maybe it's made specifically, for example to avoid memory leaks.

In any case, it is better not to update the dependency property directly, and bind to it the property of the Model and in the ViewModel to set the value.

Example:

<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}" />

where RectBackground and RectBorderBrush implement the INotifyPropertyChanged interface.

As an alternative in this case, do not use dependency properties and use the DataTemplate for the control. DataTemplate ideal for MVVM, very flexible and dynamic.

For example, work with DataTemplate, you can see my answers:

Make (create) reusable dynamic Views

One ViewModel for UserControl and Window or separate ViewModels

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

How to bind a property of control to another control's property

From Dev

How to bind a property of control to another control's property

From Dev

How to bind a property to the property of another class (with no UI Control)?

From Dev

How to bind a property to the property of another class (with no UI Control)?

From Dev

How do I bind a WPF control's margin to a property?

From Dev

How to Bind an another Control on the Setter Value Property by using a Trigger?

From Dev

Bind a property to another property of a custom control

From Dev

Bind to wpf custom control dependency property for tooltip?

From Dev

Bind WPF user control property inside code

From Dev

bind a value having dependency property from one class to another class textbox control in wpf

From Dev

How to bind control to object property?

From Dev

How to bind control to object property?

From Dev

How to bind an object from one window to another control in another window in wpf? (c#)

From Dev

How to bind user control property to other property?

From Dev

In Wpf GridView how can i bind a control to another inside one Item

From Dev

WPF Bind property to another element property by the element's name

From Dev

How to resize control according to another control ? (WPF)

From Dev

WPF: Custom control property was already registered by another custom control error

From Dev

How to bind data to a control's Visibility property

From Dev

How to bind data to a control's Visibility property

From Dev

How to parse a json object property to bind it to a control

From Dev

WPF DataGrid, How to bind property on custom DataGridColumn

From Dev

Can't bind DataGridTextColumn property from another thread (WPF)

From Dev

WPF: Bind Tab Control

From Dev

WPF: Bind Tab Control

From Dev

How to bind to a control's property which is inside control template?

From Dev

how to access property of a custom control in XAML WPF

From Dev

Bind control to escaped property?

From Dev

Start a WPF animation when a property on another control has changed

Related Related

  1. 1

    How to bind a property of control to another control's property

  2. 2

    How to bind a property of control to another control's property

  3. 3

    How to bind a property to the property of another class (with no UI Control)?

  4. 4

    How to bind a property to the property of another class (with no UI Control)?

  5. 5

    How do I bind a WPF control's margin to a property?

  6. 6

    How to Bind an another Control on the Setter Value Property by using a Trigger?

  7. 7

    Bind a property to another property of a custom control

  8. 8

    Bind to wpf custom control dependency property for tooltip?

  9. 9

    Bind WPF user control property inside code

  10. 10

    bind a value having dependency property from one class to another class textbox control in wpf

  11. 11

    How to bind control to object property?

  12. 12

    How to bind control to object property?

  13. 13

    How to bind an object from one window to another control in another window in wpf? (c#)

  14. 14

    How to bind user control property to other property?

  15. 15

    In Wpf GridView how can i bind a control to another inside one Item

  16. 16

    WPF Bind property to another element property by the element's name

  17. 17

    How to resize control according to another control ? (WPF)

  18. 18

    WPF: Custom control property was already registered by another custom control error

  19. 19

    How to bind data to a control's Visibility property

  20. 20

    How to bind data to a control's Visibility property

  21. 21

    How to parse a json object property to bind it to a control

  22. 22

    WPF DataGrid, How to bind property on custom DataGridColumn

  23. 23

    Can't bind DataGridTextColumn property from another thread (WPF)

  24. 24

    WPF: Bind Tab Control

  25. 25

    WPF: Bind Tab Control

  26. 26

    How to bind to a control's property which is inside control template?

  27. 27

    how to access property of a custom control in XAML WPF

  28. 28

    Bind control to escaped property?

  29. 29

    Start a WPF animation when a property on another control has changed

HotTag

Archive