views:

34

answers:

2

Hi all. I have a custom ClockFace UserControl which has properties to allow colors, font and hands (as a Path objects) to be changed. This is used in custom TimePicker and Clock UserControls. In these parent controls, the ClockFace properties can be set on the ClockFace object in xaml just fine. What I'm trying to do is expose these ClockFace properties so that they can be set on these two parent controls (eg. the Clock and TimePicker objects). I thought that making them Attached properties would do the trick, so I tried with one of the colour properties.

public static readonly DependencyProperty HourTicksBrushProperty = DependencyProperty.RegisterAttached("HourTicksBrush", typeof(Brush), typeof(ClockFace), new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender));
public static void SetHourTicksBrush(DependencyObject element, Brush value)
{
    element.SetValue(HourTicksBrushProperty, value);
}
public static Brush GetHourTicksBrush(DependencyObject element)
{
    return (Brush)element.GetValue(HourTicksBrushProperty);
}

I can use this attached property in the xaml where the Clock is with: (Controls is the xml namespace)

<Controls:Clock Controls:ClockFace.HourTicksBrush="Aqua" />

It compiles just fine, but although the default value (Brushes.Black) from the attached HourTicksBrushProperty shows, the value set on the parent Clock control (Aqua) never fire the above methods or change the colour. Am I missing something?

To be clear, I would like to be able to use the above xaml on a parent control to set the HourTicksBrush property of a child ClockFace control.

Any help would be much appreciated.

A: 

Use something like:

public static readonly DependencyProperty HourTicksBrushProperty = DependencyProperty.RegisterAttached("HourTicksBrush", typeof(Brush), typeof(ClockFace), new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender));


public static Brush HourTicksBrush
{
    get { return (Brush)GetValue(HourTicksBrushProperty); }
    set { SetValue(HourTicksBrushProperty); }
}

and something like this in the XAML

<Controls:Clockface.HourTicks Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=HourTicksBrush}/>

I'm not sure whether to use TemplatedParent or Self in the RelativeSource

Maarten Van Genechten
I may have explained incorrectly. I have updated the xaml that I use. I have no problem with the xaml... it's just that setting the value doesn't trigger the SetHourTicksBrush method in ClockFace and so doesn't update the Brush.
Sheridan
In the code you posted is nothing that asks for triggering
Maarten Van Genechten
But why is the Brush property not updating when set on a parent control although it does when set on the actual ClockFace control? Or changing the question slightly... how can I achieve this?
Sheridan
+1  A: 

Those "get" and "set" methods in your attached property class are actually just convenience methods for your own codebehind. The XAML parser ignores these, calling element.SetValue itself. If you want to respond to a setter, you have to provide a property changed handler to the FrameworkPropertyMetadata

public static readonly DependencyProperty HourTicksBrushProperty = DependencyProperty.RegisterAttached(
    "HourTicksBrush", 
    typeof(Brush), 
    typeof(ClockFace), 
    new FrameworkPropertyMetadata(
        Brushes.Black, 
        FrameworkPropertyMetadataOptions.AffectsRender,
        HourTicksBrushChanged));

public static void SetHourTicksBrush(DependencyObject element, Brush value)
{
    element.SetValue(HourTicksBrushProperty, value); //not always called
}
public static Brush GetHourTicksBrush(DependencyObject element)
{
    return (Brush)element.GetValue(HourTicksBrushProperty); //not always called
}
private static void HourTicksBrushChanged(DependencyObject sender, somethingsomethingArgs args){
    // do stuff with sender and args.NewValue here
}
Rob Fonseca-Ensor
Sorry to everyone because my question omiited the fact that I wanted to catch the incoming values in the code behind. Extra kudos to Rob for guessing that's what I was after. Many thanks Rob.
Sheridan
I had the same problem a while back so it was an easy guess :)
Rob Fonseca-Ensor