2
votes

Solution: Please look at Ilan answer!

I am currently working on some CustomControls and this is one of them. Depending on the DirectionProperty i want to change the direction of the linearGradientBrush with the DataTrigger. I am not really able to get it working and hope for your help.

It looks like the DataTrigger isn't really able to get the Value or the Direction. Thanks in advance SanHolo

EDIT: Doing it like that i get an error:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='CustomControlLibrary.ColoredProgress', AncestorLevel='1''. BindingExpression:Path=Direction; DataItem=null; target element is 'ColoredProgress' (Name=''); target property is 'NoTarget' (type 'Object')

C#

using System.Windows;
using System.Windows.Controls;

namespace CustomControlLibrary
{
    public class ColoredProgress : Control
    {
        public enum colorDirection { Increase, Decrease }

        private static DependencyProperty ProgressProperty =
            DependencyProperty.Register("Progress", typeof(double), typeof(ColoredProgress), new PropertyMetadata(0.00));

        private static DependencyProperty DirectionProperty =
            DependencyProperty.Register("Direction", typeof(colorDirection), typeof(ColoredProgress), new PropertyMetadata(colorDirection.Increase));

        public double Progress
        {
            get { return (double)GetValue(ProgressProperty); }
            set { SetValue(ProgressProperty, converter(value)); }
        }

        public colorDirection Direction
        {
            get { return (colorDirection)GetValue(DirectionProperty); }
            set { SetValue(DirectionProperty, value); }
        }

        public ColoredProgress()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ColoredProgress), new FrameworkPropertyMetadata(typeof(ColoredProgress)));
            this.Loaded += ColoredProgress_Loaded;
        }

        private void ColoredProgress_Loaded(object sender, RoutedEventArgs e)
        {
            double height = (double)GetValue(ColoredProgress.ActualHeightProperty);
            SetValue(ProgressProperty, height - (height * Progress));
        }

        //takes a double between 0-1 (percent of the ProgressBar) and converts it to the value needed in the design
        private double converter(double percentage)
        {
            double height = (double)GetValue(ColoredProgress.ActualHeightProperty);
            return height - (height * percentage);
        }
    }
}

XAML

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CustomControlLibrary">

    <Style TargetType="{x:Type local:ColoredProgress}">

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ColoredProgress}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            RenderTransformOrigin="0.5, 0.5"
                            DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ColoredProgress}}}">

                        <Grid x:Name="PART_Bar">
                            <Grid Background="Transparent" Panel.ZIndex="1">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                </Grid.RowDefinitions>
                                <Rectangle Fill="{TemplateBinding Background}" Height="{Binding Path=Progress, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                            </Grid>

                            <Grid Panel.ZIndex="0">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="*" x:Name="increase"/>
                                    <RowDefinition Height="0" x:Name="decrease"/>
                                </Grid.RowDefinitions>
                                <Rectangle Grid.Row="0">
                                    <Rectangle.Fill>
                                        <LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
                                            <GradientStop Color="Yellow" Offset="0.0" />
                                            <GradientStop Color="Red" Offset="1.0" />
                                        </LinearGradientBrush>
                                    </Rectangle.Fill>
                                </Rectangle>
                                <Rectangle Grid.Row="1">
                                    <Rectangle.Fill>
                                        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                                            <GradientStop Color="Yellow" Offset="0.0" />
                                            <GradientStop Color="Red" Offset="1.0" />
                                        </LinearGradientBrush>
                                    </Rectangle.Fill>
                                </Rectangle>
                            </Grid>
                        </Grid>
                    </Border>

                    <ControlTemplate.Triggers>
                        <DataTrigger Binding="{Binding Path=Direction, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ColoredProgress}}}" Value="colorDirection.Decrease">
                            <Setter TargetName="increase" Property="Height" Value="0"/>
                            <Setter TargetName="decrease" Property="Height" Value="*"/>
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>
2

2 Answers

1
votes

please use the regular triggers:

                <ControlTemplate TargetType="{x:Type local:ColoredProgress}">
                ...

                <ControlTemplate.Triggers>
                    <Trigger Property="Direction" Value="Decrease">
                        <Setter TargetName="increase" Property="Height" Value="0"/>
                        <Setter TargetName="decrease" Property="Height" Value="*"/>
                    </Trigger>
                    <Trigger Property="Direction" Value="Increase">
                        <Setter TargetName="increase" Property="Height" Value="*"/>
                        <Setter TargetName="decrease" Property="Height" Value="0"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>

As I understand the data trigger go to the DataContext to check for the value, since you've defined a Direction as a dependency property of your control you, can get the value directly. More over you can't point the data context because you haven't any property in you data context that can provide you with the value you need. That is why you get the binding expression error. Let me know if you need more explanation.

Regards.

0
votes

I haven't run your code, but I suppose your problem is that your value binding in the DataTrigger is not set correctly to the Enum value you expect.

Try this: (Note the new Value binding)

<ControlTemplate.Triggers>
    <DataTrigger Binding="{Binding Path=Direction, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ColoredProgress}}}" 
                 Value="{x:Static local:colorDirection.Decrease}">
        <Setter TargetName="increase" Property="Height" Value="0"/>
        <Setter TargetName="decrease" Property="Height" Value="*"/>
    </DataTrigger>
</ControlTemplate.Triggers>

I suppose it should work, but I didn't check the rest of the code, so feel free to update your progress in here.