Question

I need a custom UserControl (StackPanel with Labels, TextBoxes, Buttons, ...) for data input (some therapy) before and after an event. So I want to put that UserControl twice on a Window, and a property says, how the content of some of the labels should look, how some of the buttons should react and the binding of the TextBoxes should be.

In fact there are five different patterns for the therapy, so I need five custom UserControls, which are placed twice on five different Windows. I would like to achieve this mainly with XAML.

That's what I've tried so far:

I created an attached property:

public static class TherapyBeforeAfter
{    
    public static DependencyProperty _BeforeAfter = DependencyProperty.RegisterAttached("BeforeAfter", typeof(string),
        typeof(TherapyBeforeAfter), new FrameworkPropertyMetadata("b", FrameworkPropertyMetadataOptions.AffectsRender,Callback));

    private static void Callback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        d.SetValue(_BeforeAfter, e.NewValue.ToString());
    }

   [AttachedPropertyBrowsableForType(typeof(DependencyObject))]
   [AttachedPropertyBrowsableForChildren]
   public static string GetBeforeAfter(DependencyObject d)
   {
        return (string)d.GetValue(_BeforeAfter);
   }

   public static void SetBeforeAfter(DependencyObject d, string value)
   {
        d.SetValue(_BeforeAfter, value);
   }
}

In a dictionary, I define the needed styles with triggers, for example for a Label:

<Style x:Key="TherapyLabelHeader" TargetType="Label">
<Setter Property="FontSize" Value="16"/>
<Setter Property="Content" Value="Default" />
<Setter Property="Grid.ColumnSpan" Value="2"/>
<Setter Property="Margin" Value="10,0,0,0"/>
<Setter Property="Foreground" Value="DarkRed"/>
      <Style.Triggers>
         <Trigger Property="Namespace:TherapyBeforeAfter.BeforeAfter" Value="b">
           <Setter Property="Content" Value="Therapy before" />
         </Trigger>
         <Trigger Property="Namespace:TherapyBeforeAfter.BeforeAfter" Value="a">
           <Setter Property="Content" Value="Therapy after" />
        </Trigger>
     </Style.Triggers>
</Style>

In the UserControl, let's call it cntTherapy, I set the Style of a Label to the Template above:

<Label Style="{DynamicResource TherapyLabelHeader}" />

In the MainWindow I put the control twice into the XAML-Code and set the value for the attached property:

<Namespace:cntTherapy x:Name="TherapyBefore" Grid.Row="1" Namespace:TherapyBeforeAfter.BeforeAfter="b" />
<Namespace:cntTherapy x:Name="TherapyAfter" Grid.Row="2"   Namespace:TherapyBeforeAfter.BeforeAfter="a" />  

When I run the Window, both labels have the content for the default value of the attached property. So when I set the default value to "a", both labels have the content "Therapy after", if I set the default value to "b", both labels have the content "Therapy before". and if I set the default value to something else ("x" for example), both labels have the default content "Default". When I check the value of the attached property for both UserControls, the value is correct, one UserControl has "a", the other "b".

What am I missing? Is my PropertyChangedCallback method wrong? Or is there another way to achieve this in XAML?

Was it helpful?

Solution

Found a solution for the problem: in the dictionary I was looking for the value for the attached property in the label. Instead the attached property has to be checked for the canvas.

<Style x:Key="TherapyLabelHeader" 
       TargetType="{x:Type Label}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StackPanel}}, Path=(Namespace:TherapyBeforeAfter.BeforeAfter)}" 
                     Value="b" >

            <Setter Property="Content" 
                    Value="before" />
        </DataTrigger>

        <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StackPanel}}, Path=(Namespace:TherapyBeforeAfter.BeforeAfter)}" 
                     Value="a" >
            <Setter Property="Content" 
                    Value="after" />
        </DataTrigger>
    </Style.Triggers>
</Style>

Even the DataBinding can be set this way.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top