1

I'm using some buttons with templated content

e.g.

button.Template = (ControlTemplate)FindResource("StatusEmpty");

In the same code behind file is a (global) field named currentNumber

private int currentNumber = 1;
    public int CurrentNumber
    {
        get
        {
            return currentNumber;
        }
    }

These templates are defined in a merged RessourceDictionary

<ControlTemplate x:Key="BinStatusEmpty" TargetType="Button">
    <Border x:Name="border"  BorderBrush="LightGray" CornerRadius="8,8,8,8" Margin="3" >
        <Border.Background>
            <LinearGradientBrush>
                <GradientStop Offset="0" Color="white"></GradientStop>
                <GradientStop Offset="1" Color="LightGray"></GradientStop>
            </LinearGradientBrush>
        </Border.Background>
        <ContentPresenter Content = "{TemplateBinding Content}" 
           HorizontalAlignment = "Center" VerticalAlignment = "Center"  
                             TextBlock.FontSize="40"/>
    </Border>
    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="BorderBrush" Value="Blue" TargetName="border" />
            <Setter Property="BorderThickness" Value="4" TargetName="border" />
        </Trigger>

        <DataTrigger Binding="{Binding currentNumber, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" Value="{TemplateBinding Content}" >
            <Setter Property="BorderBrush" Value="Blue" TargetName="border" />
            <Setter Property="BorderThickness" Value="4" TargetName="border" />
        </DataTrigger>

    </ControlTemplate.Triggers>
</ControlTemplate>

What I Want is a data trigger which changes the border defined in the template dynamic based on the current c# variable.

There are currently two problems: 1) The binding

{Binding currentNumber, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}

doesn't find my variable

BindingExpression path error: 'currentNumber' property not found on 'object' ''MainWindow' (Name='xMainWindow')'. BindingExpression:Path=currentNumber; DataItem='MainWindow' (Name='xMainWindow'); target element is 'BinButton' (Name=''); target property is 'NoTarget' (type 'Object')

2) I can't bind

{TemplateBinding Content}

as value of the datatrigger.

Thanks a lot

René

Rene
  • 70
  • 6

1 Answers1

1

You should bind to the property CurrentNumber (with a capital 'C') and not to the backing field currentNumber.

But you cannot bind the Value property of a DataTrigger to something. This is not supported:

Using binding for the Value property of DataTrigger condition

You will need to use a converter:

namespace WpfApplication1
{
    public class MultiConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            int CurrentNumber = (int)values[0];
            object content = values[1];

            return CurrentNumber.ToString() == content.ToString();
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
}

XAML:

<ControlTemplate x:Key="BinStatusEmpty" TargetType="Button"
                 xmlns:local="clr-namespace:WpfApplication1">
    <ControlTemplate.Resources>
        <local:MultiConverter x:Key="conv" />
    </ControlTemplate.Resources>
    <Border x:Name="border" BorderBrush="LightGray" CornerRadius="8,8,8,8" Margin="3" >
        <Border.Background>
            <LinearGradientBrush>
                <GradientStop Offset="0" Color="white"></GradientStop>
                <GradientStop Offset="1" Color="LightGray"></GradientStop>
            </LinearGradientBrush>
        </Border.Background>
        <ContentPresenter Content = "{TemplateBinding Content}" 
                                  HorizontalAlignment = "Center" VerticalAlignment = "Center"  
                                TextBlock.FontSize="40"/>
    </Border>
    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="BorderBrush" Value="Blue" TargetName="border" />
            <Setter Property="BorderThickness" Value="4" TargetName="border" />
        </Trigger>
        <DataTrigger Value="True">
            <DataTrigger.Binding>
                <MultiBinding Converter="{StaticResource conv}">
                    <Binding Path="CurrentNumber" RelativeSource="{RelativeSource FindAncestor, AncestorType=Window}" />
                    <Binding Path="Content" RelativeSource="{RelativeSource Self}" />
                </MultiBinding>
            </DataTrigger.Binding>
            <Setter Property="BorderBrush" Value="Blue" TargetName="border" />
            <Setter Property="BorderThickness" Value="4" TargetName="border" />
        </DataTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>
Community
  • 1
  • 1
mm8
  • 163,881
  • 10
  • 57
  • 88
  • It's working for the static case, but how can I achieve the trigger is fired when the value of CurrentNumber changes? Thanks – Rene May 18 '17 at 12:28
  • @Rene: You will need to implement the INotifyPropertyChanged interface and raise the PropertyChanged event whenever the CurrentNumber property is set to a new value: https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx – mm8 May 18 '17 at 12:39