Search code examples
c#wpfxamldata-bindingstyles

How to bind property to style of the rectangle in a UserControl in WPF


I have a rectangle with a style definded in < Rectangle.Style> but the data binding within the style is not working? How to fix the problem?

if I override the rectangle, it works (but the animation does not work). but if I moved it to the style it does not work any more.

<UserControl x:Class="MyProject.WPF.Controls.UI_MovingLine"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:AutinPower.WPF.Controls"
             mc:Ignorable="d" 
             Height="8" Width="auto">

    <Rectangle x:Name="rectangleLine" Width="auto" Height="auto" Margin="0">
        <Rectangle.Style>
            <Style TargetType="{x:Type Rectangle}">
                <Setter Property="RenderTransform">
                    <Setter.Value>
                        <RotateTransform Angle="0" />
                    </Setter.Value>
                </Setter>
                <Setter Property="Fill">
                    <Setter.Value>
                        <VisualBrush TileMode="Tile" Viewport="0,0,10,8" ViewportUnits="Absolute" Viewbox="0,0,8,8" ViewboxUnits="Absolute">
                            <VisualBrush.Transform>
                                <TranslateTransform X="0" Y="0" />
                            </VisualBrush.Transform>
                            <VisualBrush.Visual>
                                <Grid x:Name="gridMoving">
                                    <Polygon x:Name="polygonMovingBack" Fill="{Binding LineBackColor}" Points="0,0 8,0 8,8 0,8" />
                                    <Polygon x:Name="polygonMoving" Fill="{Binding LineBackgroundColor}" Points="{Binding IndicationShape}" />
                                </Grid>
                            </VisualBrush.Visual>
                        </VisualBrush>
                    </Setter.Value>
                </Setter>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding AnimationStart}" Value="Start">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard x:Name="StartAnimation">
                                <Storyboard>
                                    <DoubleAnimation 
                                    From="0" 
                                    To="10" 
                                    RepeatBehavior="Forever"
                                    Storyboard.TargetProperty="(Rectangle.Fill).(VisualBrush.Transform).(TranslateTransform.X)" 
                                    Duration="0:0:0.1" />
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding AnimationStart}" Value="Stop">
                        <DataTrigger.EnterActions>
                            <StopStoryboard x:Name="StopAnimation" BeginStoryboardName="StartAnimation"/>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Rectangle.Style>
    </Rectangle>
</UserControl>

code behind

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using MyProject.Enum;

namespace MyProject.WPF.Controls
{
    /// <summary>
    /// Interaction logic for UI_MovingLine.xaml
    /// </summary>
    public partial class UI_MovingLine : UserControl, INotifyPropertyChanged
    {
        #region properties
        public PointCollection IndicationPoints
        {
            get
            {
                return (PointCollection)GetValue(IndicationPointsProperty);
            }
            set
            {
                SetValue(IndicationPointsProperty, value);
            }
        }
        public SolidColorBrush LineBackgroundColor
        {
            get
            {
                return (SolidColorBrush)GetValue(LineBackgroundColorProperty);
            }
            set
            {
                SetValue(LineBackgroundColorProperty, value);
            }
        }
        public SolidColorBrush LineBackColor
        {
            get
            {
                return (SolidColorBrush)GetValue(LineBackColorProperty);
            }
            set
            {
                SetValue(LineBackColorProperty, value);
            }
        }
        public PowerSystem.TransmitLineStatus TransmitLineStatus { get => _transmitLineStatus; set => _transmitLineStatus = value; }
        public string AnimationStart {
            get => _animationStart;
            set {
                _animationStart = value;
                NotifyPropertyChanged("AnimationStart");
            } }
        public Action<object[]> NotifyUI { get; set; }
        #endregion

        #region fields
        private PowerSystem.TransmitLineStatus _transmitLineStatus;
        private Storyboard _storyboard;
        private string _animationStart;
        #endregion

        public UI_MovingLine()
        {
            InitializeComponent();
            rectangleLine.DataContext = this;
            //gridMoving.DataContext = this;
            //polygonMoving.DataContext = this;
            AnimationStart = "Start";
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        public static readonly DependencyProperty IndicationPointsProperty
            = DependencyProperty.Register("IndicationPoints", typeof(PointCollection), typeof(UI_MovingLine), new PropertyMetadata(new PointCollection(new List<Point> { new Point(0, 0), new Point(4, 0), new Point(8, 4), new Point(4, 8), new Point(0, 8), new Point(4, 4) })/*, new PropertyChangedCallback(OnIndicationPointsChanged)*/));

        public static readonly DependencyProperty LineBackgroundColorProperty
            = DependencyProperty.Register("LineBackgroundColor", typeof(SolidColorBrush), typeof(UI_MovingLine), new PropertyMetadata(new SolidColorBrush(Colors.Gray)/*, new PropertyChangedCallback(OnLineBackgroundColorChanged)*/));

        public static readonly DependencyProperty LineBackColorProperty
            = DependencyProperty.Register("LineBackColor", typeof(SolidColorBrush), typeof(UI_MovingLine), new PropertyMetadata(new SolidColorBrush(Colors.Gray)/*, new PropertyChangedCallback(OnLineBackColorChanged)*/));

        public static readonly DependencyProperty AnimationStartProperty
            = DependencyProperty.Register("AnimationStart", typeof(string), typeof(UI_MovingLine), new PropertyMetadata("Stop"/*, new PropertyChangedCallback(AnimationStartChanged)*/));

        public void LineMovingToNomal()
        {
            try
            {
                IndicationPoints = new PointCollection(new List<Point> { new Point(0, 0), new Point(4, 0), new Point(8, 4), new Point(4, 8), new Point(0, 8), new Point(4, 4) });
                LineBackgroundColor = new SolidColorBrush(Colors.DodgerBlue);
                LineBackColor = new SolidColorBrush(Colors.White);

                AnimationStart = "Start";
            }
            catch
            {
            }
        }
}

data-binding within the Style should work properly


Solution

  • It seems there is no solution for this... I have to work around by defining different styles and apply them accordingly. I'm quite sure it's not the recommended way to do this, but at least it works for me at this moment. I hope anyone who know how to solve this problem can generously post your answers here.

    My current solution/work around is (click to see the images): xmal code behind