dynamically added buttons (tooltips and text) - c#

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);

Related

Manage a new visual state in buttons

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.

Execute Animation DataTrigger with binding to Command

I tried to execute animation with DataTrigger but it don't reise up.
Program don't throw any exception and errors.
Can someone explain why animation don't Start ?
Here is my storyboard
<Storyboard x:Key="storyboard2" AutoReverse="True" RepeatBehavior="Forever" Duration="00:01:00">
<DoubleAnimation Storyboard.TargetProperty="(Rectangle.RenderTransform).(ScaleTransform.ScaleX)" Storyboard.Target="{Binding Source={x:Reference RectangleScaleFrom}}" To="4" From="1"/>
<DoubleAnimation Storyboard.TargetProperty="(Rectangle.RenderTransform).(ScaleTransform.ScaleY)" Storyboard.Target="{Binding Source={x:Reference RectangleScaleFrom}}"
From="4" To="1"/>
</Storyboard>"
Here Is DataTrigger to start and Stop Animation
<DataTrigger Binding="{Binding RunAnimation}" Value="True" x:Key="Start">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="BeginScaleFrom" Storyboard="{StaticResource storyboard2}"/>
<!--<BeginStoryboard x:Name="BeginScaleTo" Storyboard="{StaticResource storyboard2}"/>-->
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding RunAnimation}" Value="False" x:Key="Stop">
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="BeginScaleFrom"/>
<!--<StopStoryboard BeginStoryboardName="BeginScaleTo"/>-->
</DataTrigger.ExitActions>
</DataTrigger>
Here is Button
<ToggleButton Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="50,20,50,30" FontSize="20" x:Name="StartButton" Style="{StaticResource StartStopButtonStyle}" Width="100" Height="50" Command="{Binding StartAnimation}">
</ToggleButton>
And Command to start
private bool _StartAnim = false;
public bool RunAnimation
{
get => _StartAnim;
set
{
_StartAnim = value;
RaisePropertyChanged(nameof(RunAnimation));
}
}
public RelayCommand StartAnimation { get; private set; }
public MainViewModel()
{
StartAnimation = new RelayCommand(() => RunAnimation = !RunAnimation);
}
Something like this should work:
<Window.Resources>
<Storyboard x:Key="storyboard2">
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX"
To="4" From="1" AutoReverse="True"
RepeatBehavior="Forever" Duration="00:00:10"/>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY"
From="4" To="1" AutoReverse="True"
RepeatBehavior="Forever" Duration="00:00:10"/>
</Storyboard>
</Window.Resources>
<Rectangle Width="100" Height="100" Fill="Red">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RunAnimation}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="BeginScaleFrom"
Storyboard="{StaticResource storyboard2}"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="BeginScaleFrom"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>

Get Set User Control Properties in WPF

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));
}
}

Auto-complete box with drop-down

The AutoCompleteBox is pretty great, but one feature it lacks is a click-to-drop-down all the available options. You can come close by setting MinimumPrefixLength=0 -- that way, the user can get the complete drop-down list by deleting the text. This has a couple of limitations, though:
if there is no text to begin with, then the user would have to enter some text and delete it (non-intuitive and inconvenient)
the click-and-keypress sequence seems like suboptimal UX.
How would you tweak this control to make it drop down the complete list of options, when the user clicks on the control (or, also fine, a button to the right)?
It seems I have disappointed #HighCore. So far I tried adding a button to the control template, which triggers opening the Popup. The drawback to this approach is that, if there is text entered, then the list will be filtered per the normal filtering rules. Now, you could clear the text, thus removing the filter, but this has another side effect: de-selecting the currently selected item (in contrast to a ComboBox, whose drop-down you can open without de-selecting). So ... what now? Temporarily remove the filter, and restore it when the popup is closed or the user types anything else?
I built a control like that, the approach I used was to inherit from the AutoComboBox control and remove the filter when the dropdown opens.
EDIT
Code has been updated to include missing resources.
Code is:
public class AutoCompleteComboBox : AutoCompleteBox
{
/// <summary>
/// Occurs when drop down toggle button is clicked.
/// </summary>
public event EventHandler ToggleButtonClick;
private object _holdSelectedItem;
private AutoCompleteFilterMode _holdFilterMode;
/// <summary>
/// Identifies the DisplayMemberPath dependency property.
/// </summary>
public static readonly DependencyProperty DisplayMemberPathProperty = DependencyProperty.Register("DisplayMemberPath", typeof(string), typeof(AutoCompleteComboBox), new PropertyMetadata(string.Empty, DisplayMemberPath_PropertyChanged));
/// <summary>
/// Gets or sets the name or path of the property
/// that is displayed for each the data item in the control.
/// </summary>
public string DisplayMemberPath
{
get { return (string)GetValue(DisplayMemberPathProperty); }
set { SetValue(DisplayMemberPathProperty, value); }
}
private static void DisplayMemberPath_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var accb = (AutoCompleteComboBox)d;
accb.ValueMemberPath = e.NewValue.ToString();
}
/// <summary>
/// Identifies the MaxLength dependency property.
/// </summary>
public static readonly DependencyProperty MaxLengthProperty = DependencyProperty.Register("MaxLength", typeof(int), typeof(AutoCompleteComboBox), null);
/// <summary>
/// Gets or sets the maximum number of characters allowed for user input.
/// </summary>
public int MaxLength
{
get { return (int)GetValue(MaxLengthProperty); }
set { SetValue(MaxLengthProperty, value); }
}
/// <summary>
/// Gets or sets a collection used to generate the content of the control.
/// </summary>
public new IEnumerable ItemsSource
{
get { return GetValue(ItemsSourceProperty) as IEnumerable; }
set
{
SetValue(SelectedItemProperty, null);
SetValue(ItemsSourceProperty, value);
Dispatcher.BeginInvoke(() => SetValue(TextProperty, string.Empty));
_holdSelectedItem = null;
}
}
/// <summary>
/// Initializes a new instance of the AutoCompleteComboBox control.
/// </summary>
public AutoCompleteComboBox()
{
StreamResourceInfo sri = Application.GetResourceStream(new Uri("/UI.Controls;component/AutoCompleteComboBox.xaml", UriKind.Relative));
var sr = new StreamReader(sri.Stream);
Style = (Style)XamlReader.Load(sr.ReadToEnd());
DropDownClosed += AutoCompleteComboBox_DropDownClosed;
DropDownOpened += AutoCompleteComboBox_DropDownOpened;
}
/// <summary>
/// Called when the template's tree is generated.
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var toggle = (ToggleButton)GetTemplateChild("PopupToggleButton");
toggle.Click += DropDownToggle_Click;
var lb = (ListBox)GetTemplateChild("Selector");
lb.DisplayMemberPath = DisplayMemberPath;
_holdFilterMode = FilterMode;
TextChanged += AutoCompleteComboBox_TextChanged;
SelectionChanged += new SelectionChangedEventHandler(AutoCompleteComboBox_SelectionChanged);
}
private void AutoCompleteComboBox_DropDownClosed(object sender, RoutedPropertyChangedEventArgs<bool> e)
{
if (SelectedItem == null && _holdSelectedItem != null && SelectedItem != _holdSelectedItem && ItemsSource.Cast<object>().Contains(_holdSelectedItem))
{
SelectedItem = _holdSelectedItem;
}
_holdSelectedItem = null;
FilterMode = _holdFilterMode;
}
private void AutoCompleteComboBox_DropDownOpened(object sender, RoutedPropertyChangedEventArgs<bool> e)
{
var lb = (ListBox)GetTemplateChild("Selector");
ScrollViewer sv = lb.GetScrollHost();
if (sv != null)
{
sv.ScrollToTop();
}
if (SelectedItem != null)
{
lb.SelectedItem = SelectedItem;
_holdSelectedItem = SelectedItem;
}
}
private void DropDownToggle_Click(object sender, RoutedEventArgs e)
{
IsDropDownOpen = !IsDropDownOpen;
if (ToggleButtonClick != null)
{
ToggleButtonClick(this, e);
}
if (IsDropDownOpen)
{
_holdFilterMode = FilterMode;
FilterMode = AutoCompleteFilterMode.None;
((TextBox)GetTemplateChild("Text")).SelectAll();
}
Focus();
}
private void AutoCompleteComboBox_TextChanged(object sender, RoutedEventArgs e)
{
if (IsDropDownOpen)
{
if (FilterMode == AutoCompleteFilterMode.None && FilterMode != _holdFilterMode)
{
FilterMode = _holdFilterMode;
}
ScrollViewer sv = ((ListBox)GetTemplateChild("Selector")).GetScrollHost();
if (sv != null)
{
sv.ScrollToTop();
}
}
}
private void AutoCompleteComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!IsDropDownOpen && SelectedItem == null)
{
Text = string.Empty;
}
}
}
<Setter Property="Height" Value="24" />
<Setter Property="MinimumPopulateDelay" Value="1" />
<Setter Property="IsTextCompletionEnabled" Value="False" />
<Setter Property="MinimumPrefixLength" Value="0" />
<Setter Property="MaxDropDownHeight" Value="300" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Padding" Value="2" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#FF000000" />
<Setter Property="Background" Value="#FFFFFFFF" />
<Setter Property="Foreground" Value="#FF000000" />
<Setter Property="MinWidth" Value="45" />
<Setter Property="FilterMode" Value="Contains" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ctrls:AutoCompleteComboBox">
<Grid >
<Grid.Resources>
<Style x:Name="comboToggleStyle" TargetType="ToggleButton">
<Setter Property="Foreground" Value="#FF333333"/>
<Setter Property="Background" Value="#FF1F3B53"/>
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFA3AEB9" Offset="0"/>
<GradientStop Color="#FF8399A9" Offset="0.375"/>
<GradientStop Color="#FF718597" Offset="0.375"/>
<GradientStop Color="#FF617584" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="BackgroundOverlay" Storyboard.TargetProperty="Opacity" To="1"/>
<ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" To="#7FFFFFFF"/>
<ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" To="#CCFFFFFF"/>
<ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" To="#F2FFFFFF"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="BackgroundOverlay2" Storyboard.TargetProperty="Opacity" To="1"/>
<DoubleAnimation Duration="0" Storyboard.TargetName="Highlight" Storyboard.TargetProperty="(UIElement.Opacity)" To="1"/>
<ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" To="#E5FFFFFF"/>
<ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" To="#BCFFFFFF"/>
<ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" To="#6BFFFFFF"/>
<ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" To="#F2FFFFFF"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled" />
</VisualStateGroup>
<VisualStateGroup x:Name="CheckStates">
<VisualState x:Name="Checked">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="BackgroundOverlay3" Storyboard.TargetProperty="(UIElement.Opacity)" To="1"/>
<DoubleAnimation Duration="0" Storyboard.TargetName="Highlight" Storyboard.TargetProperty="(UIElement.Opacity)" To="1"/>
<DoubleAnimation Duration="0" Storyboard.TargetName="BackgroundGradient2" Storyboard.TargetProperty="(UIElement.Opacity)" To="1"/>
<ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient2" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" To="#E5FFFFFF"/>
<ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient2" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" To="#BCFFFFFF"/>
<ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient2" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" To="#6BFFFFFF"/>
<ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient2" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" To="#F2FFFFFF"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Unchecked"/>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Visibility" Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="Background" RadiusX="3" RadiusY="3" Fill="{TemplateBinding Background}" StrokeThickness="{TemplateBinding BorderThickness}" Stroke="{TemplateBinding BorderBrush}"/>
<Rectangle x:Name="BackgroundOverlay" Opacity="0" RadiusX="3" RadiusY="3" Fill="#FF448DCA" StrokeThickness="{TemplateBinding BorderThickness}" Stroke="#00000000"/>
<Rectangle x:Name="BackgroundOverlay2" Opacity="0" RadiusX="3" RadiusY="3" Fill="#FF448DCA" StrokeThickness="{TemplateBinding BorderThickness}" Stroke="#00000000"/>
<Rectangle x:Name="BackgroundGradient" RadiusX="2" RadiusY="2" StrokeThickness="1" Margin="{TemplateBinding BorderThickness}" Stroke="#FFFFFFFF">
<Rectangle.Fill>
<LinearGradientBrush StartPoint=".7,0" EndPoint=".7,1">
<GradientStop Color="#FFFFFFFF" Offset="0" />
<GradientStop Color="#F9FFFFFF" Offset="0.375" />
<GradientStop Color="#E5FFFFFF" Offset="0.625" />
<GradientStop Color="#C6FFFFFF" Offset="1" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Opacity="0" x:Name="BackgroundOverlay3" RadiusX="3" RadiusY="3" Fill="#FF448DCA" StrokeThickness="{TemplateBinding BorderThickness}" Stroke="#00000000"/>
<Rectangle Opacity="0" x:Name="BackgroundGradient2" RadiusX="2" RadiusY="2" StrokeThickness="1" Margin="{TemplateBinding BorderThickness}" Stroke="#FFFFFFFF">
<Rectangle.Fill>
<LinearGradientBrush StartPoint=".7,0" EndPoint=".7,1">
<GradientStop Color="#FFFFFFFF" Offset="0" />
<GradientStop Color="#F9FFFFFF" Offset="0.375" />
<GradientStop Color="#E5FFFFFF" Offset="0.625" />
<GradientStop Color="#C6FFFFFF" Offset="1" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle x:Name="Highlight" RadiusX="2" RadiusY="2" Opacity="0" IsHitTestVisible="false" Stroke="#FF6DBDD1" StrokeThickness="1" Margin="{TemplateBinding BorderThickness}" />
<ContentPresenter
x:Name="contentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}"/>
<Rectangle x:Name="FocusVisualElement" RadiusX="3.5" Margin="1" RadiusY="3.5" Stroke="#FF6DBDD1" StrokeThickness="1" Visibility="Collapsed" IsHitTestVisible="false" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="CommonValidationToolTipTemplate" TargetType="ToolTip">
<Grid x:Name="Root" Margin="5,0" RenderTransformOrigin="0,0" Opacity="0">
<Grid.RenderTransform>
<TranslateTransform x:Name="Translation" X="-25" />
</Grid.RenderTransform>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="OpenStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0" />
<VisualTransition To="Open" GeneratedDuration="0:0:0.2">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Translation" Storyboard.TargetProperty="X" To="0" Duration="0:0:0.2">
<DoubleAnimation.EasingFunction>
<BackEase Amplitude=".3" EasingMode="EaseOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.2" />
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Closed">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="0" Duration="0" />
</Storyboard>
</VisualState>
<VisualState x:Name="Open">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Translation" Storyboard.TargetProperty="X" To="0" Duration="0" />
<DoubleAnimation Storyboard.TargetName="Root" Storyboard.TargetProperty="Opacity" To="1" Duration="0" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border Margin="4,4,-4,-4" Background="#052A2E31" CornerRadius="5" />
<Border Margin="3,3,-3,-3" Background="#152A2E31" CornerRadius="4" />
<Border Margin="2,2,-2,-2" Background="#252A2E31" CornerRadius="3" />
<Border Margin="1,1,-1,-1" Background="#352A2E31" CornerRadius="2" />
<Border Background="#FFDC000C" CornerRadius="2">
<TextBlock UseLayoutRounding="false" Foreground="White" Margin="8,4,8,4" MaxWidth="250" TextWrapping="Wrap" Text="{Binding (Validation.Errors)[0].ErrorContent}" />
</Border>
</Grid>
</ControlTemplate>
</Grid.Resources>
<TextBox x:Name="Text" VerticalContentAlignment="Center" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Foreground="{TemplateBinding Foreground}" MaxLength="{TemplateBinding MaxLength}" />
<ToggleButton x:Name="PopupToggleButton" Width="24" HorizontalAlignment="Right" Style="{StaticResource comboToggleStyle}" Margin="1" >
<Path x:Name="BtnArrow" Height="4" Width="8" Stretch="Uniform" Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z " HorizontalAlignment="Center">
<Path.Fill>
<SolidColorBrush x:Name="BtnArrowColor" Color="#FF333333"/>
</Path.Fill>
</Path>
</ToggleButton>
<Border x:Name="ValidationErrorElement" Visibility="Collapsed" BorderBrush="#FFDB000C" BorderThickness="1" CornerRadius="1">
<ToolTipService.ToolTip>
<ToolTip x:Name="validationTooltip" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Template="{StaticResource CommonValidationToolTipTemplate}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<ToolTip.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsHitTestVisible">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<system:Boolean>true</system:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ToolTip.Triggers>
</ToolTip>
</ToolTipService.ToolTip>
<Grid Height="12" HorizontalAlignment="Right" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12" Background="Transparent">
<Path Fill="#FFDC000C" Margin="1,3,0,0" Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" />
<Path Fill="#ffffff" Margin="1,3,0,0" Data="M 0,0 L2,0 L 8,6 L8,8" />
</Grid>
</Border>
<Popup x:Name="Popup">
<ListBox x:Name="Selector" SelectionMode="Single" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" MaxHeight="{TemplateBinding MaxDropDownHeight}" />
</Popup>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="PopupStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0" To="PopupOpened" />
<VisualTransition GeneratedDuration="0:0:0" To="PopupClosed" />
</VisualStateGroup.Transitions>
<VisualState x:Name="PopupOpened">
</VisualState>
<VisualState x:Name="PopupClosed">
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ValidationStates">
<VisualState x:Name="Valid" />
<VisualState x:Name="InvalidUnfocused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="InvalidFocused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationErrorElement" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="validationTooltip" Storyboard.TargetProperty="IsOpen">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<system:Boolean>True</system:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
I worked out one approach. The basic idea is to overlay a button, either in a modified control template, or just flung on top of the view (I'll use the latter here for brevity's sake). The button thing does three things:
Clear the text (in order to restore the complete unfiltered list)
Set IsDropDownOpen = true to open the Popup
Restore the selected item to the ListBox template child
So basically, I have a setup like this:
<Grid>
<mycontrols:ExtendedAutoCompleteBox x:Name="autoCompleteBox" ... />
<Button HorizontalAlignment="Right" Click="Button_Click">
<Path Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z "
Fill="Black" Stretch="Uniform"
Width="8" Height="4"
/>
</Button>
</Grid>
The purpose of subclassing AutoCompleteBox is just to get access to the template child:
public class ExtendedAutoCompleteBox : AutoCompleteBox
{
private ListBox _listBox;
public override void OnApplyTemplate()
{
_listBox = GetTemplateChild("Selector") as ListBox;
}
public void ShowAllOptions()
{
var selectedItem = SelectedItem;
Text = "";
IsDropDownOpen = true;
_listBox.SelectedItem = selectedItem;
UpdateLayout();
_listBox.ScrollIntoView(selectedItem);
}
}
And so the button click will just call this "ShowAllOptions":
private void Button_Click(object sender, RoutedEventArgs e)
{
autoCompleteBox.ShowAllOptions();
}
It's not perfect -- for some reason the keyboard controls get screwy after clicking the button (if you press enter on an item, it does not select the item, but clears it instead) -- but it is better than nothing.
So just to illustrate what it does: let's say you have an item "x" selected, and you click the arrow button, then you will see the complete list:

C# WPF pausing an animated window with storyboard

I am making a C# wpf application with Visual Studio 2012. Here is the toast like notification. It is animated to go off by 4 seconds. It I get the mouse over this I want to pause the animation.
How can I achieve that ?
<Window x:Class="Exmaple.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
Title="Notification Popup" Width="300" SizeToContent="Height"
WindowStyle="None" AllowsTransparency="True" Height="Auto" Background="Transparent">
<Grid x:Name="abc" RenderTransformOrigin="0,1" Height="Auto" Width="300" Margin="0,0,0,0" MouseEnter="Grid_MouseEnter_1" >
<!-- Notification area -->
<Border BorderThickness="1" Background="#FF2D2D30" BorderBrush="Black" CornerRadius="0" Margin="0,0,0,0">
<!--StackPanel Margin="20"-->
<TextBlock x:Name="textblocknotify" TextWrapping="Wrap" Height="Auto" Margin="5" Foreground="White">
</TextBlock>
<!--CheckBox Content="Checkable" Margin="5 5 0 5" /-->
<!--Button Content="Clickable" HorizontalAlignment="Center" /-->
<!--/StackPanel-->
</Border>
<!-- Animation -->
<Grid.Triggers >
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard Completed="Storyboard_Completed_1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="0:0:4.5" Value="1"/>
<SplineDoubleKeyFrame KeyTime="0:0:5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard Completed="Storyboard_Completed_1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.1" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="0:0:4.5" Value="1"/>
<SplineDoubleKeyFrame KeyTime="0:0:5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Grid.RenderTransform>
<ScaleTransform ScaleY="1" />
</Grid.RenderTransform>
</Grid>
Code behind this
public partial class Window1 : Window
{
public Window1(String s)
{
InitializeComponent();
textblocknotify.Text = s;
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() =>
{
var workingArea = System.Windows.SystemParameters.WorkArea;
var transform = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice;
var corner = transform.Transform(new Point(workingArea.Right, workingArea.Bottom));
this.Left = corner.X - this.ActualWidth - 10;
this.Top = corner.Y - this.ActualHeight-30;
}));
//this.Close();
}
private void Storyboard_Completed_1(object sender, EventArgs e)
{
this.Close();
}
private void Grid_MouseEnter_1(object sender, MouseEventArgs e)
{
//don't know what to do
}
You can use the PauseStoryboard Class and the UIElement.MouseEnter Event to pause a running Animation. Equally, if you want the Animation to resume when the mouse is no longer over the control, then you can use the ResumeStoryboard Class and the UIElement.MouseLeave Event. Here is a simple example to demonstrate:
<Button Content="Click Me">
<Button.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Name="OpacityStoryboard">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.Opacity)"
From="0" To="1" RepeatBehavior="Forever" AutoReverse="True" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<PauseStoryboard BeginStoryboardName="OpacityStoryboard" />
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeave">
<ResumeStoryboard BeginStoryboardName="OpacityStoryboard" />
</EventTrigger>
</Button.Triggers>
</Button>

Categories