Hello I have a problem accessing User Control Properties. My User Control Looks like this:
<UserControl.Resources>
<Style x:Key="CheckBoxStyle1" TargetType="{x:Type CheckBox}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<ControlTemplate.Resources>
<Storyboard x:Key="OnChecking">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="25"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OnUnchecking">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<ThicknessAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="slider" Storyboard.TargetProperty="(FrameworkElement.Margin)">
<SplineThicknessKeyFrame KeyTime="00:00:00.3000000" Value="1,1,1,1"/>
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Border Name="Border">
<DockPanel x:Name="dockPanel">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" ContentTemplate="{TemplateBinding ContentTemplate}" RecognizesAccessKey="True" VerticalAlignment="Center"/>
<Grid Width="50" x:Name="grid">
<TextBlock Text="ON" TextWrapping="Wrap" FontWeight="Bold" FontSize="12" HorizontalAlignment="Right" Margin="0,0,3,0"/>
<TextBlock HorizontalAlignment="Left" Margin="2,0,0,0" FontSize="12" FontWeight="Bold" Text="OFF" TextWrapping="Wrap"/>
<Border HorizontalAlignment="Left" x:Name="slider" Width="23" BorderThickness="1,1,1,1" CornerRadius="3,3,3,3" RenderTransformOrigin="0.5,0.5" Margin="1,1,1,1">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1"/>
<SkewTransform AngleX="0" AngleY="0"/>
<RotateTransform Angle="0"/>
<TranslateTransform X="0" Y="0"/>
</TransformGroup>
</Border.RenderTransform>
<Border.BorderBrush>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#FF4490FF" Offset="1"/>
</LinearGradientBrush>
</Border.BorderBrush>
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF8AB4FF" Offset="1"/>
<GradientStop Color="#FFD1E2FF" Offset="0"/>
</LinearGradientBrush>
</Border.Background>
</Border>
</Grid>
</DockPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource OnUnchecking}" x:Name="OnUnchecking_BeginStoryboard"/>
</Trigger.ExitActions>
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource OnChecking}" x:Name="OnChecking_BeginStoryboard"/>
</Trigger.EnterActions>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<CheckBox x:Name="CheckBox1" HorizontalAlignment="Center"
Style="{DynamicResource CheckBoxStyle1}"
VerticalAlignment="Center"
Checked="CheckBox1_OnChecked"
Unchecked="CheckBox1_OnUnchecked"/>
</Grid>
And in the code behind(some of a great number of getters/setters):
public new Brush Background
{
get
{
var border = CheckBox1.Template.LoadContent() as Border;
return border == null ? Brushes.White : border.Background;
}
set
{
var border = CheckBox1.Template.LoadContent() as Border;
if (border == null) return;
border.Background = value;
}
}
public new Thickness BorderThickness
{
get
{
var border = CheckBox1.Template.LoadContent() as Border;
return border == null ? new Thickness(0) : border.BorderThickness;
}
set
{
var border = CheckBox1.Template.LoadContent() as Border;
if (border == null) return;
border.BorderThickness = value;
}
}
public new Brush BorderBrush
{
get
{
var border = CheckBox1.Template.LoadContent() as Border;
return border == null ? Brushes.Transparent : border.BorderBrush;
}
set
{
var border = CheckBox1.Template.LoadContent() as Border;
if (border == null) return;
border.BorderBrush = value;
}
}
And also i use it in another window like this(SliderOnOff is the name of my control):
<switch:SliderOnOff x:Name="SliderOnOff"
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsEnabled="True"
Background="Green"
BorderThickness="10"
BorderBrush="HotPink"
IsChecked="True"
BorderRadius="5"
Checked="SliderOnOff_OnChecked"
UnChecked="SliderOnOff_OnUnChecked">
</switch:SliderOnOff>
I thought it works fine, because setting properties in xaml leaded to changing in properties of control.
BUT!!!!!!
When I try to change it programmatically ( Slider.Background = Brushes.HotPink; ), nothing happens, it doesnt change. Also this part of properties doesnt work at all(none in xaml, none in code):
public CornerRadius BorderRadius
{
get
{
var border = CheckBox1.Template.LoadContent() as Border;
return border == null ? new CornerRadius(0) : border.CornerRadius;
}
set
{
var border = CheckBox1.Template.LoadContent() as Border;
if (border == null) return;
border.CornerRadius = new CornerRadius(value.TopLeft,value.TopRight,value.BottomRight,value.BottomLeft);
}
}
Can you help me with it?
I think your ui hast to be informed about the changes.
Have a look at: http://www.codeproject.com/Articles/42536/List-vs-ObservableCollection-vs-INotifyPropertyCha
Your class must implement INotifyPropertyChanged, and within your "set" part you have to raise that event.
like:
public class MainViewModel : ViewModelBase, INotifyPropertyChanged
{
public KeyInfo SelectedKeyInfo
{
get
{
return _SelectedKeyInfo;
}
set
{
_SelectedKeyInfo = value;
OnPropertyChanged("SelectedKeyProducts");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
Related
I want to add a new "Activated" state to a WPF Button and I want to avoid re-creating a control from scratch.
This new state is linked to the IsActivated dependency property and must change the background color of the Button. Here is the truth table of the interaction between the IsEnabled and IsActivated dependency properties:
I wrote a class extending from Button, created dependency properties, and in the callback of IsActivated, I computed the visual state of the button.
The issue is that the ButtonBase type already manages the visual state through the ChangeVisualState function, which cannot be overridden.
After managing callbacks of both dependency properties, the interaction between IsActivated and IsEnabled works as intended, but clicking on the button, or putting the mouse over the button overrides the Activated visual state.
Is this possible to accomplish this with visual states, or should I use simple triggers?
The code of the Control so far:
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace OrganizationName.BasicControls.Primitive
{
public class MultiStateButton : Button
{
static MultiStateButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiStateButton), new FrameworkPropertyMetadata(typeof(MultiStateButton)));
IsEnabledProperty.OverrideMetadata(typeof(MultiStateButton), new FrameworkPropertyMetadata(propertyChangedCallback: IsEnabledCallback));
}
internal void ChangeVisualState(bool useTransitions)
{
if (!IsEnabled)
{
VisualStateManager.GoToState(this, "Disabled", useTransitions);
}
else if (IsActivated)
{
VisualStateManager.GoToState(this, "Activated", useTransitions);
}
else if (IsPressed)
{
VisualStateManager.GoToState(this, "Pressed", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Normal", useTransitions);
}
}
#region IsEnabled override
private static void IsEnabledCallback(DependencyObject o, DependencyPropertyChangedEventArgs args)
{
MultiStateButton multiStateButton = o as MultiStateButton;
if (multiStateButton == null) return;
multiStateButton.ChangeVisualState(true);
}
#endregion IsEnabled override
#region DP IsActivated
public bool IsActivated
{
get { return (bool)GetValue(IsActivatedProperty); }
set { SetValue(IsActivatedProperty, value); }
}
private static void IsActivatedCallback(DependencyObject o, DependencyPropertyChangedEventArgs args)
{
MultiStateButton multiStateButton = o as MultiStateButton;
if (multiStateButton == null) return;
multiStateButton.ChangeVisualState(true);
}
private readonly static FrameworkPropertyMetadata IsActivatedMetadata = new FrameworkPropertyMetadata
{
PropertyChangedCallback = IsActivatedCallback,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
public static readonly DependencyProperty IsActivatedProperty =
DependencyProperty.Register("IsActivated", typeof(bool), typeof(MultiStateButton), IsActivatedMetadata);
#endregion DP IsActivated
}
}
The default style of the button:
<sys:Double x:Key="ButtonCornerRadiusValue">5</sys:Double>
<CornerRadius x:Key="ButtonCornerRadius"
TopLeft="{StaticResource ButtonCornerRadiusValue}"
BottomLeft="{StaticResource ButtonCornerRadiusValue}"
TopRight="{StaticResource ButtonCornerRadiusValue}"
BottomRight="{StaticResource ButtonCornerRadiusValue}"/>
<CornerRadius x:Key="ButtonCornerRadiusLeft"
TopLeft="{StaticResource ButtonCornerRadiusValue}"
BottomLeft="{StaticResource ButtonCornerRadiusValue}"/>
<CornerRadius x:Key="ButtonCornerRadiusRight"
TopRight="{StaticResource ButtonCornerRadiusValue}"
BottomRight="{StaticResource ButtonCornerRadiusValue}"/>
<CornerRadius x:Key="ButtonCornerRadiusTop"
TopRight="{StaticResource ButtonCornerRadiusValue}"
TopLeft="{StaticResource ButtonCornerRadiusValue}"/>
<CornerRadius x:Key="ButtonCornerRadiusBottom"
BottomLeft="{StaticResource ButtonCornerRadiusValue}"
BottomRight="{StaticResource ButtonCornerRadiusValue}"/>
<Style x:Key="{x:Type primitives:MultiStateButton}"
TargetType="{x:Type primitives:MultiStateButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type primitives:MultiStateButton}">
<Border TextBlock.Foreground="{TemplateBinding Foreground}"
x:Name="Border"
CornerRadius="{StaticResource ButtonCornerRadius}"
Background="White"
BorderThickness="1">
<Border.Effect>
<DropShadowEffect Color="#CDD5E3"
ShadowDepth="0"
BlurRadius="13"
Direction="0"/>
</Border.Effect>
<Border.BorderBrush>
<RadialGradientBrush Center="0.5,0.5"
RadiusY="1"
RadiusX="5"
GradientOrigin="0.5,0.5">
<RadialGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="Transparent"
Offset="0" />
<GradientStop Color="Transparent"
Offset="0.5" />
<GradientStop Color="{StaticResource BorderPushedColor}"
Offset="0.8" />
<GradientStop Color="{StaticResource BorderPushedColor}"
Offset="1" />
</GradientStopCollection>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Border.BorderBrush>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Border.Width)"
Storyboard.TargetName="LeftBorder"
Duration="00:00:00"
To="10"/>
<DoubleAnimation Storyboard.TargetProperty="(Border.Width)"
Storyboard.TargetName="RightBorder"
Duration="00:00:00"
To="10"/>
<DoubleAnimation Storyboard.TargetProperty="(Border.Height)"
Storyboard.TargetName="TopBorder"
Duration="00:00:00"
To="10"/>
<DoubleAnimation Storyboard.TargetProperty="(Border.Height)"
Storyboard.TargetName="BottomBorder"
Duration="00:00:00"
To="10"/>
<DoubleAnimation Storyboard.TargetProperty="(Border.Effect).(DropShadowEffect.BlurRadius)"
Storyboard.TargetName="Border"
Duration="00:00:00"
To="10"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.Background)"
Storyboard.TargetName="Border">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SkyblueLight}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Activated">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.Background)"
Storyboard.TargetName="Border">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ReflexBlue}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Background="Transparent">
<ContentPresenter Margin="2"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="True"/>
<Border BorderThickness="0"
Width="0"
HorizontalAlignment="Left"
CornerRadius="{StaticResource ButtonCornerRadiusLeft}"
x:Name="LeftBorder">
<Border.Background>
<LinearGradientBrush StartPoint="1,0.5" EndPoint="0,0.5">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="Transparent"/>
<GradientStop Offset="1" Color="#D9DDE4"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
</Border>
<Border BorderThickness="0"
Width="0"
HorizontalAlignment="Right"
CornerRadius="{StaticResource ButtonCornerRadiusRight}"
x:Name="RightBorder">
<Border.Background>
<LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="Transparent"/>
<GradientStop Offset="1" Color="#D9DDE4"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
</Border>
<Border BorderThickness="0"
Height="0"
VerticalAlignment="Top"
CornerRadius="{StaticResource ButtonCornerRadiusTop}"
x:Name="TopBorder">
<Border.Background>
<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="Transparent"/>
<GradientStop Offset="1" Color="#D9DDE4"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
</Border>
<Border BorderThickness="0"
Height="0"
VerticalAlignment="Bottom"
CornerRadius="{StaticResource ButtonCornerRadiusBottom}"
x:Name="BottomBorder">
<Border.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0" Color="Transparent"/>
<GradientStop Offset="1" Color="#D9DDE4"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Border.Background>
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When it comes to adding a simple visual state to an existing control, I typically avoid creating a subclass and instead use attached properties.
When it comes to implementing a new visual state for an existing control, you don't have to use the VisualStateManager at all. Especially if you aren't using animations.
I recommend using Triggers instead.
If you want to continue to use your MultiStateButton control, you can simply do something like this:
<ControlTemplate ...>
...
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsEnabled" Value="True" />
<Condition Property="IsActivated" Value="True" />
</MultiTrigger.Conditions>
<Setter TargetName="Border" Property="Background" Value="{StaticResource ReflexBlue}" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
However, if you don't need to keep using MultiStateButton, I would keep your custom button style, and control template, and use an attached property class to add the new property.
public static class MultiStateButtonProperties
{
public static readonly DependencyProperty IsActivatedProperty = DependencyProperty.RegisterAttached("IsActivated", typeof(bool), typeof(MultiStateButtonProperties), new FrameworkPropertyMetadata(false));
public static bool GetIsActivated(DependencyObject obj)
{
return (bool)obj.GetValue(IsActivatedProperty);
}
public static void SetIsActivated(DependencyObject obj, bool value)
{
obj.SetValue(IsActivatedProperty, value);
}
}
Then, in your style's control template, you can use a MultiTrigger like the one above and do something like this:
<ControlTemplate ...>
...
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsEnabled" Value="True" />
<Condition Property="ap:MultiStateButtonProperties.IsActivated" Value="True" />
</MultiTrigger.Conditions>
<Setter TargetName="Border" Property="Background" Value="{StaticResource ReflexBlue}" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I hope this helps.
I'm received the exception Type reference cannot find type named '{clr-namespace:Dashboard.View}DashBoardColors at runtime.
I have a static class with my colors:
namespace Dashboard.View
{
public static class DashBoardColors
{
public static readonly Color TargetColor = Color.FromRgb(200, 240, 255);
public static readonly SolidColorBrush Red = new SolidColorBrush(Color.FromRgb(255, 0, 0));
public static readonly SolidColorBrush Stale = new SolidColorBrush(Color.FromRgb(200, 200, 200));
public static readonly SolidColorBrush Target = new SolidColorBrush(TargetColor);
public static readonly SolidColorBrush Dragging = new SolidColorBrush(Color.FromRgb(200, 255, 200));
public static readonly SolidColorBrush Good = Dragging;
}
}
My resource dictionary:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:Dashboard.View">
<Style x:Key="AnimatedSwitch" TargetType="{x:Type ToggleButton}">
<Setter Property="Foreground" Value="Silver" />
<Setter Property="Background" Value="Silver" />
<Setter Property="BorderBrush" Value="Silver" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Viewbox Stretch="Uniform" Width="40">
<Canvas Name="Layer_1" Width="20" Height="20">
<Ellipse Canvas.Left="0" Width="20" Height="20" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="0.5"/>
<Ellipse Canvas.Left="15" Width="20" Height="20" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="0.5"/>
<Border Canvas.Left="10" Width="15" Height="20" Name="rect416927" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,0.5,0,0.5"/>
<Ellipse x:Name="ellipse" Canvas.Left="0" Width="20" Height="20" Fill="White" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="0.3">
<Ellipse.RenderTransform>
<TranslateTransform X="0" Y="0" />
</Ellipse.RenderTransform>
<Ellipse.BitmapEffect>
<DropShadowBitmapEffect Softness="0.1" ShadowDepth="0.7" Direction="270" Color="#BBBBBB"/>
</Ellipse.BitmapEffect>
</Ellipse>
</Canvas>
</Viewbox>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.15"
Storyboard.TargetName="ellipse"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="{x:Static view:DashBoardColors.TargetColor}" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard FillBehavior="Stop">
<ColorAnimation Duration="0:0:0.3"
Storyboard.TargetName="ellipse"
Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="White" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And my usage within the usercontrol:
Included the namespace:
xmlns:view="clr-namespace:Dashboard.View"
Merged the dictionary:
<UserControl.Resources>
<ResourceDictionary x:Key="Styles">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Dashboard;component/View/Styles/AnimatedStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Applied the style:
<ToggleButton Style="{StaticResource AnimatedSwitch}" Height="20" x:Name="DateSelectToggle" />
The problem is in setting the following:
To="{x:Static view:DashBoardColors.TargetColor}"
Oops,
I had the build action on View/Styles/AnimatedStyles.xaml set to resource which means that namespace needed to include the assembly, if it is not current:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:Dashboard.View;assembly=Dashboard">
Or set the build action to Page and now it works.
I am working on an MVVM application and I would like to have a ProgressBar that smoothly animates to it's new value when that property changes. I have seen several answers to this question using c# but I'd prefer to do it all inside the template. The problem I'm having is setting up and targeting the event and storyboard properly. Here is what I have currently:
The progress bar-
The style- (just the triggers)
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="RangeBase.ValueChanged">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="???????"
Storyboard.TargetProperty="Value"
To="???????" Duration="0:0:5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
I took the trigger code from here: http://msdn.microsoft.com/en-us/library/system.windows.controls.progressbar(v=vs.110).aspx.
How do I set the TargetName to the template itself so that it applies to all the controls which use this template? How do I set "To" to the incoming Value? There appears to be a way to grab the "Binding" value but I have Value and Max both bound on the progressbar element. How would it know what to use?
Here is the whole template for reference:
<Style x:Key="ProgressStyle" TargetType="{x:Type ProgressBar}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<Grid MinHeight="14" MinWidth="20">
<Border x:Name="BaseRectangle" Background="{StaticResource BaseColor}" CornerRadius="10,0,10,0"></Border>
<Border x:Name="GlassRectangle" CornerRadius="10,0,10,0" Background="{StaticResource GlassFX}" Panel.ZIndex="10"></Border>
<Border x:Name="animation" CornerRadius="10,0,10,0" Opacity=".7" Background="{Binding Path=Foreground, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Left"></Border>
<Border x:Name="PART_Indicator" CornerRadius="10,0,10,0" Background="{Binding Path=Foreground, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Left"></Border>
<Border x:Name="PART_Track" BorderThickness="1" CornerRadius="10,0,10,0" BorderBrush="Black"></Border>
<Border x:Name="BordeCabeceraSombra" BorderThickness="2" CornerRadius="10,0,10,0" BorderBrush="DarkGray" Opacity=".2" Margin="1,1,1,0"></Border>
<Label x:Name="Progress" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontWeight="Bold" Foreground="White" Opacity=".7" Content="{Binding Path=Value, RelativeSource={RelativeSource TemplatedParent}}"></Label>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="RangeBase.ValueChanged">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="???????"
Storyboard.TargetProperty="Value"
From="???????" To="???????" Duration="0:0:5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<Trigger Property="IsIndeterminate" Value="True">
<Setter Property="Visibility" TargetName="Progress" Value="Hidden"></Setter>
<Setter Property="Background" TargetName="PART_Indicator">
<Setter.Value>
<MultiBinding>
<MultiBinding.Converter>
<wintheme:ProgressBarHighlightConverter/>
</MultiBinding.Converter>
<Binding Source="{StaticResource GlowFXProgressAnimated}"/>
<Binding Path="ActualWidth" ElementName="BaseRectangle"/>
<Binding Path="ActualHeight" ElementName="BaseRectangle"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value=".5"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Any help would be appreciated!
I think its better way.
You can create behavior to do this. (MVVM WPF)
Create class:
class ProgresBarAnimateBehavior : Behavior<ProgressBar>
{
bool _IsAnimating = false;
protected override void OnAttached()
{
base.OnAttached();
ProgressBar progressBar = this.AssociatedObject;
progressBar.ValueChanged += ProgressBar_ValueChanged;
}
private void ProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (_IsAnimating)
return;
_IsAnimating = true;
DoubleAnimation doubleAnimation = new DoubleAnimation
(e.OldValue, e.NewValue, new Duration(TimeSpan.FromSeconds(0.3)), FillBehavior.Stop);
doubleAnimation.Completed += Db_Completed;
((ProgressBar)sender).BeginAnimation(ProgressBar.ValueProperty, doubleAnimation);
e.Handled = true;
}
private void Db_Completed(object sender, EventArgs e)
{
_IsAnimating = false;
}
protected override void OnDetaching()
{
base.OnDetaching();
ProgressBar progressBar = this.AssociatedObject;
progressBar.ValueChanged -= ProgressBar_ValueChanged;
}
}
And simply usage:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:b="clr-namespace:YOURNAMESPACE.Behaviors"
<ProgressBar Height="7"
Value="{Binding LoadingValue}">
<i:Interaction.Behaviors>
<b:ProgresBarAnimateBehavior />
</i:Interaction.Behaviors>
</ProgressBar>
I never actually found a solution to this. I ended up just writing my own control. This isn't technically an answer to the question, but I figure I may as well post it. If someone is looking for an animating progress control for MVVM this may help.
namespace Card_System.Controls
{
/// <summary>
/// Interaction logic for StatProgressBar.xaml
/// </summary>
public partial class StatProgressBar : UserControl
{
private double _trackWidth;
private bool _isAnimate;
private bool _isRefresh;
public StatProgressBar()
{
InitializeComponent();
var descriptor = DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, typeof(Border));
if (descriptor != null)
{
descriptor.AddValueChanged(TrackBorder, ActualWidth_ValueChanged);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private double _barValueSet;
public double BarValueSet
{
get { return _barValueSet; }
set
{
_barValueSet = value;
OnPropertyChanged("BarValueSet");
_isAnimate = true;
AnimateWidth();
}
}
public double BarValueDesired
{
get { return (double)GetValue(BarValueProperty); }
set { SetValue(BarValueProperty, value); }
}
public static readonly DependencyProperty BarValueProperty =
DependencyProperty.Register("BarValueDesired", typeof(double), typeof(StatProgressBar), new UIPropertyMetadata(0.0d, new PropertyChangedCallback(BarValueDesired_PropertyChanged)));
public double BarMaximum
{
get { return (double)GetValue(BarMaximumProperty); }
set { SetValue(BarMaximumProperty, value); }
}
public static readonly DependencyProperty BarMaximumProperty =
DependencyProperty.Register("BarMaximum", typeof(double), typeof(StatProgressBar), new UIPropertyMetadata(0.0d));
public static void BarValueDesired_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Set BarValue to the value of BarValueDesired BEFORE it was just changed.
((StatProgressBar)d).BarValueSet = (double)e.OldValue;
}
public Brush BarColor
{
get { return (Brush)GetValue(BarColorProperty); }
set { SetValue(BarColorProperty, value); }
}
public static readonly DependencyProperty BarColorProperty =
DependencyProperty.Register("BarColor", typeof(Brush), typeof(StatProgressBar), new UIPropertyMetadata(Brushes.White, new PropertyChangedCallback(BarColor_PropertyChanged)));
public static void BarColor_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((StatProgressBar)d).BarFill.Background = (Brush)e.NewValue;
}
private void ActualWidth_ValueChanged(object a_sender, EventArgs a_e)
{
_trackWidth = TrackBorder.ActualWidth;
_isRefresh = true;
AnimateWidth();
}
public void AnimateWidth()
{
if (_isAnimate && _isRefresh)
{
double StartPoint = new double();
double EndPoint = new double();
double PercentEnd = new double();
double PercentStart = new double();
PercentStart = BarValueSet / BarMaximum;
StartPoint = _trackWidth * PercentStart;
PercentEnd = BarValueDesired / BarMaximum;
EndPoint = _trackWidth * PercentEnd;
DoubleAnimation animation = new DoubleAnimation(StartPoint, EndPoint, TimeSpan.FromSeconds(3));
this.BarFill.BeginAnimation(Border.WidthProperty, animation);
}
else return;
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
}
And here is the XAML:
<Grid>
<Grid MinHeight="14" MinWidth="20">
<Border x:Name="BaseRectangle" Background="{StaticResource BaseColor}" CornerRadius="0,0,0,0"/>
<Border x:Name="TrackBorder" BorderThickness="1" CornerRadius="0,0,0,0" BorderBrush="Black" Panel.ZIndex="20"/>
<Border x:Name="BarFill" HorizontalAlignment="Left" Opacity=".7" Background="White"/>
<Border x:Name="GlassOverlay" CornerRadius="0,0,0,0" Background="{StaticResource GlassFX}" Panel.ZIndex="10"/>
<Border x:Name="GlassOverlayBorder" BorderThickness="4" CornerRadius="0,0,0,0" BorderBrush="DarkGray" Opacity=".2" Panel.ZIndex="12"/>
</Grid>
I know this question is solved, but I found a really good implementation that doesn't require creating a UserControl. It imitates the "barber pole effect" and works right out of the box:
<SolidColorBrush x:Key="ProgressBarBorderBrush" Color="Transparent" />
<SolidColorBrush x:Key="ProgressBarBackgroundBrush" Color="White" />
<SolidColorBrush x:Key="ProgressBarTrackBackgroundBrush" Color="#63D055" />
<Style x:Key="{x:Type ProgressBar}" TargetType="{x:Type ProgressBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<local:ClippingBorder x:Name="BorderBackground" CornerRadius="3" BorderThickness="0"
BorderBrush="{StaticResource ProgressBarBorderBrush}"
Background="{StaticResource ProgressBarBackgroundBrush}">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Determinate" />
<VisualState x:Name="Indeterminate" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="PART_Track" Margin="0" BorderThickness="0" CornerRadius="3" />
<Border x:Name="PART_Indicator" Margin="0" BorderThickness="0" CornerRadius="3" HorizontalAlignment="Left"
Background="{StaticResource ProgressBarTrackBackgroundBrush}" ClipToBounds="True">
<Border x:Name="DiagonalDecorator" Width="5000">
<Border.Background>
<DrawingBrush TileMode="Tile" Stretch="None" Viewbox="0,0,1,1" Viewport="0,0,36,34" ViewportUnits="Absolute">
<DrawingBrush.RelativeTransform>
<TranslateTransform X="0" Y="0" />
</DrawingBrush.RelativeTransform>
<DrawingBrush.Drawing>
<GeometryDrawing Brush="#48C739" Geometry="M0,0 18,0 36,34 18,34 Z" />
</DrawingBrush.Drawing>
</DrawingBrush>
</Border.Background>
<Border.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Border.Background).(DrawingBrush.RelativeTransform).(TranslateTransform.X)"
From="0" To=".36" RepeatBehavior="Forever" Duration="0:0:18" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
</Border>
</Border>
</Grid>
</local:ClippingBorder>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Simply edit speed and colors to your liking.
If buttons are dynamically added in wpf from code behind how can you add tooltips to them or text to the actual button?
This is what you would do in windows forms but I dont think you can do it in wpf:
partial class Window1
{
void button3Click(object sender, RoutedEventArgs e)
{
//toolTip1.SetToolTip(this.button1, "My button1");
MessageBox.Show("action 3");
}
void button2Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("action 2");
}
void button1Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("action 1");
}
public Window1()
{
this.InitializeComponent();
populateButtons();
//ToolTip toolTip1 = new ToolTip();
//// Set up the delays for the ToolTip.
//toolTip1.AutoPopDelay = 5000;
//toolTip1.InitialDelay = 1000;
//toolTip1.ReshowDelay = 500;
//// Force the ToolTip text to be displayed whether or not the form is active.
//toolTip1.ShowAlways = true;
}
public void populateButtons()
{
int xPos;
int yPos;
Random ranNum = new Random();
foreach (var routedEventHandler in new RoutedEventHandler[] { button1Click, button2Click, button3Click })
{
Button foo = new Button();
Style buttonStyle = Window.Resources["CurvedButton"] as Style;
int sizeValue = 100;
foo.Width = sizeValue;
foo.Height = sizeValue;
xPos = ranNum.Next(200);
yPos = ranNum.Next(250);
//canvas1.HorizontalAlignment = HorizontalAlignment.Left;
//canvas1.VerticalAlignment = VerticalAlignment.Top;
//canvas1.Margin = new Thickness(xPos, yPos, 0, 0);
foo.HorizontalAlignment = HorizontalAlignment.Left;
foo.VerticalAlignment = VerticalAlignment.Top;
foo.Margin = new Thickness(xPos, yPos, 0, 0);
foo.Style = buttonStyle;
foo.Click += routedEventHandler;
LayoutRoot.Children.Add(foo);
}
}
}
}
As for adding text im not sure?
Here is the xaml:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xml:lang="en-US"
x:Class="DynamicButtons.Window1"
x:Name="Window"
Title="Dynamic Buttons"
Width="840" Height="600" Icon="shape_group.png">
<Window.Resources>
<Style x:Key="CurvedButton" BasedOn="{x:Null}" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ControlTemplate.Resources>
<Storyboard x:Key="OnMouseMove1">
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFFFFFFF"/>
<SplineColorKeyFrame KeyTime="00:00:00.3000000" Value="#7CE1DBDB"/>
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="1.66"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="1.66"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OnMouseLeave1">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<SplineDoubleKeyFrame KeyTime="00:00:00.8000000" Value="1.78"/>
<SplineDoubleKeyFrame KeyTime="00:00:01" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<SplineDoubleKeyFrame KeyTime="00:00:00.8000000" Value="1.78"/>
<SplineDoubleKeyFrame KeyTime="00:00:01" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OnClick1">
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)">
<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FFFFFFFF"/>
<SplineColorKeyFrame KeyTime="00:00:00.3000000" Value="#BFA0D1E2"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Grid>
<Rectangle RenderTransformOrigin="1,1" Fill="#3FFFFFFF" Stroke="{x:Null}" RadiusX="11" RadiusY="11" x:Name="rectangle">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1"/>
<SkewTransform AngleX="0" AngleY="0"/>
<RotateTransform Angle="0"/>
<TranslateTransform X="0" Y="0"/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="ButtonBase.Click">
<BeginStoryboard x:Name="OnClick1_BeginStoryboard" Storyboard="{StaticResource OnClick1}"/>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<BeginStoryboard x:Name="OnMouseLeave1_BeginStoryboard" Storyboard="{StaticResource OnMouseLeave1}"/>
</EventTrigger>
<EventTrigger RoutedEvent="FrameworkElement.Loaded"/>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<BeginStoryboard x:Name="OnMouseMove1_BeginStoryboard" Storyboard="{StaticResource OnMouseMove1}"/>
</EventTrigger>
<Trigger Property="IsFocused" Value="True"/>
<Trigger Property="IsDefaulted" Value="True"/>
<Trigger Property="IsMouseOver" Value="True"/>
<Trigger Property="IsPressed" Value="True"/>
<Trigger Property="IsEnabled" Value="False"/>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFF3F3F3" Offset="0"/>
<GradientStop Color="#FFEBEBEB" Offset="0.5"/>
<GradientStop Color="#FFDDDDDD" Offset="0.5"/>
<GradientStop Color="#E1CDCDCD" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded"/>
</Window.Triggers>
<Window.Background>
<LinearGradientBrush EndPoint="0.484,0.543" StartPoint="0.478,0.009">
<GradientStop Color="Gray" Offset="1"/>
<GradientStop Color="DarkGray" Offset="0"/>
</LinearGradientBrush>
</Window.Background>
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Canvas Height="282" HorizontalAlignment="Left" Margin="12,12,0,0" Name="canvas1" VerticalAlignment="Top" Width="343" />
</Grid>
</Window>
Have you tried to use the Tooltip-Property?
You can assign a ToolTip to the ToolTip property of the Button and set the Content property to the text you want to display:
ToolTip t = new ToolTip();
t.Content = "Something helpful";
Button b = new Button;
b.Content = "Hover over me";
b.ToolTip = t;
If you want to make the button show up apparently you have to add it to the panel it should belong to - which I assume is the canavs:
// add the button to the canvas
canvas1.Children.Add(b);
// set the position of the button on the canvas
Canvas.SetLeft(b, 20);
Canvas.SetTop(b, 20);
How to register DependencyProperty on Rectangle fill, so i can change the color
dynamically?
<UserControl.Resources>
<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle Stroke="Black">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF48B6E4" Offset="0.013"/>
<GradientStop Color="#FF091D8D" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True"/>
<Trigger Property="IsDefaulted" Value="True"/>
<Trigger Property="IsMouseOver" Value="True"/>
<Trigger Property="IsPressed" Value="True"/>
<Trigger Property="IsEnabled" Value="False"/>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<Button Style="{DynamicResource ButtonStyle1}"/>
<TextBlock
x:Name="NodeName"
x:FieldModifier="public"
Text="Property"
Margin="8"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextWrapping="Wrap"
TextAlignment="Center"
FontFamily="Segoe Print"
FontWeight="Bold"
Foreground="White"
FontSize="40"/>
</Grid>
Why don't you bind Fill to the Background property of the Button:
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle Stroke="Black" Fill="{TemplateBinding Background}" />
...
</Grid>
...
</ControlTemplate>
and then set Background like this:
<Button Style="{DynamicResource ButtonStyle1}">
<Button.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF48B6E4" Offset="0.013"/>
<GradientStop Color="#FF091D8D" Offset="1"/>
</LinearGradientBrush>
</Button.Background>
</Button>
If you have your own dependency property called MyProperty registered in your UserControl, you can bind it this way:
...
<Rectangle Stroke="Black" Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Parent.Parent.MyProperty}" />
...
No other changes are needed.
This binds the Fill property to parent of parent of the control to which the style is assigned, in your case the UserControl itself.
Using this method you can not only bind it to properties of a UserControl, but also to other controls' properties.
I would create a dependency property on your YourUserControl view, something like this (I removed some of your markup for brevity):
<UserControl.Resources>
<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle Stroke="Black" Fill="{TemplateBinding Background}">
</Rectangle>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Grid x:Name="LayoutRoot">
<Button Style="{DynamicResource ButtonStyle1}" Background="{Binding DynamicColor}"/>
</Grid>
Then in YourUserControl.xaml.cs you could create your dependency property:
private My_ViewModel _viewModel
{
get { return this.DataContext as My_ViewModel; }
}
public LinearGradientBrush DynamicColor
{
get { return (string)GetValue(DynamicColorProperty); }
set { SetValue(DynamicColorProperty, value); }
}
public static readonly DependencyProperty DynamicColorProperty =
DependencyProperty.Register("DynamicColor", typeof(LinearGradientBrush), typeof(YourUserControl),
new PropertyMetadata(new PropertyChangedCallback(OnDynamicColorPropertyChanged)));
private static void OnDynamicColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((YourUserControl)d).OnTrackerInstanceChanged(e);
}
protected virtual void OnDynamicColorPropertyChanged(DependencyPropertyChangedEventArgs e)
{
this._viewModel.DynamicColor = e.NewValue;
}
public class My_ViewModel : INotifyPropertyChanged
{
public LinearGradientBrush DynamicColor
{
get { return dynamicColor; }
set
{
if(dynamicColor != value)
{
dynamicColor = value;
OnPropertyChanged("DynamicColor");
}
}
}
private LinearGradientBrush dynamicColor;
}
This approach gives you complete control over the DynamicColor property's value as well as allows you to be able to unit test the behavior effectively.