Visual States in XAML
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SectionHeader">
<VisualState x:Name="SectionHeaderNormal">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1200"/>
</VisualState.StateTriggers>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="txtUser" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource usernameStyle}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="txtName" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource nameStyle}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
I need to create this XAML code programmatically via C# code.
Current code
var vsg = new VisualStateGroup();
var vs = new VisualState();
vs.StateTriggers.Add(new AdaptiveTrigger
{
MinWindowWidth = 1200.0
});
How do I create storyboards and add these properties?
If you want to use the VisualState in code behind, you should be able to add Setter to SetterBaseCollection of the VisualState. Also we should be able to add the VisualState to the VisualStateGroup. Then we can add the VisualStateGroup to our control.
To get the Style in code behind, we should be able to use the FrameworkElement.Resources.
For example:
<Page.Resources>
<Style x:Key="usernameStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="Red" />
</Style>
</Page.Resources>
<Grid Name="MyGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Name="txtUser" Text="555555" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
The code behind:
public MainPage()
{
this.InitializeComponent();
var vsg = new VisualStateGroup();
var vs = new VisualState();
Style appButtonStyle = (Style)this.Resources["usernameStyle"];
vs.StateTriggers.Add(new AdaptiveTrigger
{
MinWindowWidth = 1080
});
vs.Setters.Add(new Setter
{
Target = new TargetPropertyPath
{
Path = new PropertyPath("(TextBlock.Style)"),
Target = txtUser
},
Value = appButtonStyle
});
vsg.States.Add(vs);
VisualStateManager.GetVisualStateGroups(MyGrid).Add(vsg);
}
Related
Thanks for #Justin XL and #grek40 help me so much.
I must apologize for my poor English that troubles everyone so much.
And I think I need to improve this question to help any others in the furture.
Here is the newest:
I need to make a square button like this:
My programme is a fullscreen programme that different device has different window's size.
So my square button should be can resizeable also beaucase I want to make a Reactive UI.
And now how can I make a square button?
Thank you.
It's perfectly fine to have pure UI logic like this live inside its code-behind. I'd even argue it's more efficient in most cases.
In your example, it's super easy to square your Rectangle with the following code
XAML
<Border x:Name="MyBorder"
Grid.Column="1"
Grid.Row="1"
SizeChanged="MyBorder_SizeChanged">
<Rectangle x:Name="MyRectangle"
Fill="LightBlue" />
</Border>
Code-behind
private void MyBorder_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (MyBorder.ActualWidth > MyBorder.ActualHeight)
{
MyRectangle.Width = MyRectangle.Height = MyBorder.ActualHeight;
}
else if (MyBorder.ActualWidth < MyBorder.ActualHeight)
{
MyRectangle.Height = MyRectangle.Height = MyBorder.ActualWidth;
}
}
But can we improve this? Since you want a square Button, it makes most sense to create a SquareButton and insert it straight into your Grid.
So the XAML can be simplified to a much more readable version below
<local:SquareButton Grid.Column="1" Grid.Row="1" />
Then you just need to implement the custom control like the following
SquareButton class
[TemplatePart(Name = PART_Root, Type = typeof(Border))]
[TemplatePart(Name = PART_ContentHost, Type = typeof(Border))]
public sealed class SquareButton : Button
{
private const string PART_Root = "Root";
private const string PART_ContentHost = "ContentHost";
public SquareButton()
{
DefaultStyleKey = typeof(SquareButton);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
var root = (Border)GetTemplateChild(PART_Root);
var contentHost = (Border)GetTemplateChild(PART_ContentHost);
root.SizeChanged += (s, e) =>
{
if (root.ActualWidth > root.ActualHeight)
{
contentHost.Width = contentHost.Height = root.ActualHeight;
}
else if (root.ActualWidth < root.ActualHeight)
{
contentHost.Height = contentHost.Height = root.ActualWidth;
}
};
}
}
SquareButton Style inside Themes/Generic.xaml
<Style TargetType="local:SquareButton">
<Setter Property="Background"
Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
<Setter Property="Foreground"
Value="{ThemeResource SystemControlForegroundBaseHighBrush}" />
<Setter Property="BorderBrush"
Value="{ThemeResource SystemControlForegroundTransparentBrush}" />
<Setter Property="BorderThickness"
Value="{ThemeResource ButtonBorderThemeThickness}" />
<Setter Property="Padding"
Value="8,4,8,4" />
<Setter Property="HorizontalAlignment"
Value="Stretch" />
<Setter Property="VerticalAlignment"
Value="Stretch" />
<Setter Property="FontFamily"
Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight"
Value="Normal" />
<Setter Property="FontSize"
Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals"
Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SquareButton">
<Border x:Name="Root">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="ContentHost" />
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<PointerUpThemeAnimation Storyboard.TargetName="ContentHost" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentHost"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlBackgroundBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightTransparentBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<PointerDownThemeAnimation Storyboard.TargetName="ContentHost" />
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentHost"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SystemControlDisabledTransparentBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="ContentHost" Background="{TemplateBinding Background}">
<ContentPresenter x:Name="ContentPresenter"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTransitions="{TemplateBinding ContentTransitions}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw" />
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Hope this helps!
Use the Rectangle.Stretch property:
<Rectangle Fill="Red" Stretch="Uniform"></Rectangle>
I think this answers the actual question of creating a rectangle where width and height are the same and the rectangle is stretched to the available space.
In terms of binding, a MultiBinding on both Width and Height with an IMultiValueConverter implementation that returns the minimum of all input values might work. However, it's only needed for controls that don't provide automated stretching.
You can use attached properties to set the same width/height for a given limit:
public static class SquareSize
{
public static double GetWidthLimit(DependencyObject obj)
{
return (double)obj.GetValue(WidthLimitProperty);
}
public static void SetWidthLimit(DependencyObject obj, double value)
{
obj.SetValue(WidthLimitProperty, value);
}
public static readonly DependencyProperty WidthLimitProperty = DependencyProperty.RegisterAttached(
"WidthLimit", typeof(double), typeof(SquareSize),
new FrameworkPropertyMetadata(double.PositiveInfinity, new PropertyChangedCallback(OnWidthLimitChanged)));
private static void OnWidthLimitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UpdateSize(d, (double)e.NewValue, GetHeightLimit(d));
}
public static double GetHeightLimit(DependencyObject obj)
{
return (double)obj.GetValue(HeightLimitProperty);
}
public static void SetHeightLimit(DependencyObject obj, double value)
{
obj.SetValue(HeightLimitProperty, value);
}
public static readonly DependencyProperty HeightLimitProperty = DependencyProperty.RegisterAttached(
"HeightLimit", typeof(double), typeof(SquareSize),
new FrameworkPropertyMetadata(double.PositiveInfinity, new PropertyChangedCallback(OnHeightLimitChanged)));
private static void OnHeightLimitChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UpdateSize(d, GetWidthLimit(d), (double)e.NewValue);
}
private static void UpdateSize(DependencyObject d, double widthLimit, double heightLimit)
{
double resultSize = Math.Min(widthLimit, heightLimit);
d.SetCurrentValue(FrameworkElement.WidthProperty, resultSize);
d.SetCurrentValue(FrameworkElement.HeightProperty, resultSize);
}
}
Use with appropriate xmlns namespace
<Border x:Name="border" Grid.Column="1" Grid.Row="1">
<Rectangle
Fill="Red"
local:SquareSize.WidthLimit="{Binding ElementName=border,Path=ActualWidth}"
local:SquareSize.HeightLimit="{Binding ElementName=border,Path=ActualHeight}"/>
</Border>
A solution involving a custom control as wrapper for square-spaced content:
public class SquareContentControl : ContentControl
{
protected override Size ArrangeOverride(Size arrangeBounds)
{
var sizeLimit = Math.Min(arrangeBounds.Width, arrangeBounds.Height);
if (VisualChildrenCount > 0)
{
var child = GetVisualChild(0) as UIElement;
if (child != null)
{
child.Arrange(new Rect(new Point((arrangeBounds.Width - sizeLimit) / 2, (arrangeBounds.Height - sizeLimit) / 2), new Size(sizeLimit, sizeLimit)));
return arrangeBounds;
}
}
return base.ArrangeOverride(arrangeBounds);
}
protected override Size MeasureOverride(Size constraint)
{
var sizeLimit = Math.Min(constraint.Width, constraint.Height);
if (VisualChildrenCount > 0)
{
var child = GetVisualChild(0) as UIElement;
if (child != null)
{
child.Measure(new Size(sizeLimit, sizeLimit));
return child.DesiredSize;
}
}
return base.MeasureOverride(constraint);
}
}
Usage:
<Border x:Name="border" Grid.Column="1" Grid.Row="1">
<local:SquareContentControl>
<Rectangle Fill="Red"/>
</local:SquareContentControl>
</Border>
EDIT 2017/8/17 only works on WPF, not UWP.
Using Minimum Converter:
public class MinConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double result = double.NaN;
if (values != null)
{
try
{
result = values.Cast<double>().Aggregate(double.PositiveInfinity, (a, b) => Math.Min(a, b));
}
catch (Exception)
{
result = double.NaN;
}
}
return result;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
Then in your xaml set the Rectangle Height to match parent's Border Min(ActualHeight, ActualWidth). And the Rectangle Width can just bind to Rectangle's ActualHeight
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.1*"></RowDefinition>
<RowDefinition Height="0.8*"></RowDefinition>
<RowDefinition Height="0.1*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
<ColumnDefinition Width="0.8*"></ColumnDefinition>
<ColumnDefinition Width="0.1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Border x:Name="Bd" Grid.Column="1" Grid.Row="1">
<Rectangle x:Name="R"
Width="{Binding Path=ActualHeight, Mode=OneWay, RelativeSource={RelativeSource Self}}">
<Rectangle.Height>
<MultiBinding Converter="converter:MinConverter">
<Binding ElementName="Bd" Path="ActualHeight"/>
<Binding ElementName="Bd" Path="ActualWidth"/>
</MultiBinding>
</Rectangle.Height>
</Rectangle>
</Border>
</Grid>
How can i make such alist of checkboxes, that they are left aligned to the button, from where it opens, and provide a opening and closing Animation, like in the Alarm & Clock App in Windows 10? I tried with Popups and Flyouts, but there isnt the same effect.
It looks that this Control in the Alarm & Clock App is actually expanded from a ComboBox control.
So we can use a ComboBox to do this, for example:
<ComboBox x:Name="comboBox" VerticalAlignment="Center" HorizontalAlignment="Stretch" ItemsSource="{x:Bind comboitems}"
PlaceholderText="{x:Bind contenttext, Mode=OneWay}" DropDownClosed="comboBox_DropDownClosed" SelectionChanged="comboBox_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding dayofweek}" IsChecked="{Binding ischecked, Mode=TwoWay}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
To show the selected days on the ComboBox is a little complex, we can do this work in the code behind:
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
private ObservableCollection<comboItem> comboitems = new ObservableCollection<comboItem>();
private string _contenttext;
public string contenttext
{
get
{
return _contenttext;
}
set
{
if (value != _contenttext)
{
_contenttext = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public MainPage()
{
this.InitializeComponent();
this.Loaded += MainPage_Loaded;
}
private int daycount;
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
showdays();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
comboitems.Clear();
comboitems.Add(new comboItem { dayofweek = "Sunday", ischecked = false });
comboitems.Add(new comboItem { dayofweek = "Monday", ischecked = true });
comboitems.Add(new comboItem { dayofweek = "Tuesday", ischecked = true });
comboitems.Add(new comboItem { dayofweek = "Wednesday", ischecked = true });
comboitems.Add(new comboItem { dayofweek = "Thursday", ischecked = true });
comboitems.Add(new comboItem { dayofweek = "Friday", ischecked = true });
comboitems.Add(new comboItem { dayofweek = "Saturday", ischecked = false });
}
private void comboBox_DropDownClosed(object sender, object e)
{
showdays();
}
private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
comboBox.SelectedIndex = -1;
}
private void showdays()
{
contenttext = null;
daycount = 0;
for (int i = 0; i < comboBox.Items.Count(); i++)
{
comboItem item = comboBox.Items.ElementAt(i) as comboItem;
if (item.ischecked)
{
contenttext = contenttext + item.dayofweek.Substring(0, 3) + ", ";
daycount++;
}
}
if (daycount != 0)
{
if (daycount == 2 && contenttext == "Sun, Sat, ")
{
contenttext = "Weekends";
}
else if (daycount == 5 && contenttext == "Mon, Tue, Wed, Thu, Fri, ")
{
contenttext = "Weekdays";
}
else if (daycount == 7)
{
contenttext = "Every day";
}
else
{
contenttext = contenttext.TrimEnd(' ', ',');
}
}
else
{
contenttext = "Only once";
}
}
}
And the comboItem class by my side is like this:
public class comboItem : INotifyPropertyChanged
{
public string dayofweek { get; set; }
private bool _ischecked;
public bool ischecked
{
get
{
return _ischecked;
}
set
{
if (value != _ischecked)
{
_ischecked = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Maybe you can find another easier way to convert days to specific string, eventually my method works here.
Update:
Here is the whole modified template style of the ComboBox, you can also edit the template by your self.
<Style TargetType="ComboBox">
<Setter Property="Padding" Value="12,5,0,7" />
<Setter Property="MinWidth" Value="{ThemeResource ComboBoxThemeMinWidth}" />
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}" />
<Setter Property="Background" Value="{ThemeResource SystemControlBackgroundAltMediumLowBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumLowBrush}" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="TabNavigation" Value="Once" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto" />
<Setter Property="ScrollViewer.IsVerticalRailEnabled" Value="True" />
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
<Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<CarouselPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="32" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlPageBackgroundAltMediumBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseMediumBrush}" />
</ObjectAnimationUsingKeyFrames>
<!--<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="PlaceholderTextBlock">
<DiscreteObjectKeyFrame KeyTime="0" Value="LightBlue" />
</ObjectAnimationUsingKeyFrames>-->
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundListMediumBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="HeaderContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="PlaceholderTextBlock">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="DropDownGlyph">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="HighlightBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightTransparentBrush}" />
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="HighlightBackground" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="PlaceholderTextBlock">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="DropDownGlyph">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseMediumHighBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="FocusedPressed">
<Storyboard>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="HighlightBackground" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="PlaceholderTextBlock">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="DropDownGlyph">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseMediumHighBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused" />
<VisualState x:Name="PointerFocused" />
<VisualState x:Name="FocusedDropDown">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="PopupBorder">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="DropDownStates">
<VisualState x:Name="Opened">
<Storyboard>
<SplitOpenThemeAnimation ClosedTargetName="ContentPresenter" OffsetFromCenter="{Binding TemplateSettings.DropDownOffset, RelativeSource={RelativeSource Mode=TemplatedParent}}" OpenedTargetName="PopupBorder" OpenedLength="{Binding TemplateSettings.DropDownOpenedHeight, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
</Storyboard>
</VisualState>
<VisualState x:Name="Closed">
<Storyboard>
<SplitCloseThemeAnimation ClosedTargetName="ContentPresenter" OffsetFromCenter="{Binding TemplateSettings.DropDownOffset, RelativeSource={RelativeSource Mode=TemplatedParent}}" OpenedTargetName="PopupBorder" OpenedLength="{Binding TemplateSettings.DropDownOpenedHeight, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="HeaderContentPresenter" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" FontWeight="{ThemeResource ComboBoxHeaderThemeFontWeight}" FlowDirection="{TemplateBinding FlowDirection}" Margin="{ThemeResource ComboBoxHeaderThemeMargin}" Visibility="Collapsed" x:DeferLoadStrategy="Lazy" />
<Border x:Name="Background" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.ColumnSpan="2" Grid.Row="1" />
<Border x:Name="HighlightBackground" BorderBrush="{ThemeResource SystemControlHighlightBaseMediumLowBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{ThemeResource SystemControlHighlightListAccentLowBrush}" Grid.ColumnSpan="2" Opacity="0" Grid.Row="1" />
<ContentPresenter x:Name="ContentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Grid.Row="1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Grid.ColumnSpan="2">
<TextBlock x:Name="PlaceholderTextBlock" Foreground="{ThemeResource SystemControlForegroundAccentBrush}" Text="{TemplateBinding PlaceholderText}" />
</ContentPresenter>
<!--<FontIcon x:Name="DropDownGlyph" AutomationProperties.AccessibilityView="Raw" Grid.Column="1" Foreground="{ThemeResource SystemControlForegroundBaseMediumHighBrush}" FontSize="12" FontFamily="{ThemeResource SymbolThemeFontFamily}" Glyph="" HorizontalAlignment="Right" IsHitTestVisible="False" Margin="0,10,10,10" Grid.Row="1" VerticalAlignment="Center" />-->
<Popup x:Name="Popup">
<Border x:Name="PopupBorder" BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}" BorderThickness="{ThemeResource ComboBoxDropdownBorderThickness}" Background="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" HorizontalAlignment="Stretch" Margin="0,-1,0,-1">
<ScrollViewer x:Name="ScrollViewer" AutomationProperties.AccessibilityView="Raw" BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" Foreground="{ThemeResource SystemControlForegroundBaseHighBrush}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" MinWidth="{Binding TemplateSettings.DropDownContentMinWidth, RelativeSource={RelativeSource Mode=TemplatedParent}}" VerticalSnapPointsType="OptionalSingle" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" VerticalSnapPointsAlignment="Near" ZoomMode="Disabled">
<ItemsPresenter Margin="{ThemeResource ComboBoxDropdownContentMargin}" />
</ScrollViewer>
</Border>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
It's just remove the FontIcon inside this control and make the TextBlock's ColumnSpan = 2, and change it's foreground to SystemControlForegroundAccentBrush. If you want to modify it by your self, you can open the Document OutLine, find this ComboBox, right click on it, then choose Edit Template then Edit a Copy, so you will get the default template of ComboBox:
I have a form for adding an item. The item requires an author which could be search, in which the component for the author was a search box. Also included a code in which the background of the search box will turn red when empty otherwise white. Also have a list for suggestion. When the time I select an author in the suggestions, the search box don't turn it's color. But when I hover the search box, that's the only time it goes to the costumed color. No user want's to hover the search box every time just to see if it is valid or not.
Here's a sample code:
XAML
<SearchBox x:Name="SearchBoxColor" SearchHistoryEnabled="False" SuggestionsRequested="SearchBoxColor_SuggestionsRequested" QueryChanged="SearchBoxColor_QueryChanged" QuerySubmitted="SearchBoxColor_QuerySubmitted" Background="White" />
<Button Content="Turn Color"Click="ButtonColor_Click" />
CS
private void SearchBoxColor_SuggestionsRequested(SearchBox sender, SearchBoxSuggestionsRequestedEventArgs args) {
// When this event is called the background will change instantly
ChangeSearchBoxColor();
}
private void SearchBoxColor_QueryChanged(SearchBox sender, SearchBoxQueryChangedEventArgs args) {
// When this event is called the background will change instantly
ChangeSearchBoxColor();
}
private void SearchBoxColor_QuerySubmitted(SearchBox sender, SearchBoxQuerySubmittedEventArgs args) {
// When this event is called the background will change instantly
ChangeSearchBoxColor();
}
private void ButtonColor_Click(object sender, RoutedEventArgs e) {
// When this event is called the background will change only when the search box is hovered
ChangeSearchBoxColor();
}
private void ChangeSearchBoxColor() {
SearchBoxColor.Background = new SolidColorBrush(Colors.Red);
}
You can achieve this with code-behind on your view which would set the background to the red color you're looking for however I'd recommend using the Behaviors SDK, which you can reference in your 8.1 project, to set a VisualState on the control if the text is invalid. You can do this as follows:
Action:
public class SearchBoxTextErrorVisualStateAction : DependencyObject, IAction
{
public static readonly DependencyProperty ErrorVisualStateProperty = DependencyProperty.Register(
"ErrorVisualState",
typeof(string),
typeof(SearchBoxTextErrorVisualStateAction),
new PropertyMetadata(string.Empty));
public string ErrorVisualState
{
get
{
return (string)this.GetValue(ErrorVisualStateProperty);
}
set
{
this.SetValue(ErrorVisualStateProperty, value);
}
}
public static readonly DependencyProperty ValidVisualStateProperty =
DependencyProperty.Register(
"ValidVisualState",
typeof(string),
typeof(SearchBoxTextErrorVisualStateAction),
new PropertyMetadata(string.Empty));
public string ValidVisualState
{
get
{
return (string)this.GetValue(ValidVisualStateProperty);
}
set
{
this.SetValue(ValidVisualStateProperty, value);
}
}
public object Execute(object sender, object parameter)
{
var searchBox = sender as SearchBox;
if (searchBox != null)
{
VisualStateManager.GoToState(
searchBox,
string.IsNullOrWhiteSpace(searchBox.QueryText) ? this.ErrorVisualState : this.ValidVisualState,
true);
}
return parameter;
}
}
XAML example:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.Resources>
<Color x:Key="AppErrorColor">#FFD32F2F</Color>
<SolidColorBrush x:Key="ThemeErrorShade" Color="{ThemeResource AppErrorColor}" />
<Style x:Key="SearchBoxStyle" TargetType="SearchBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="SearchBox">
<Grid x:Name="SearchBoxGrid">
...
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="SearchBoxGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding Background, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="SearchBoxBorder">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding BorderBrush, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="SearchButton">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="SearchBoxGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SearchBoxDisabledBackgroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="SearchBoxBorder">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SearchBoxDisabledBorderThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="SearchButton">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SearchBoxDisabledTextThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="SearchTextBox">
<DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ErrorStates">
<VisualState x:Name="TextInvalid">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="SearchBoxGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ThemeErrorShade}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="TextValid">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="SearchBoxGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding Background, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="SearchBoxBorder">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding BorderBrush, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="SearchButton">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
...
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<SearchBox Style="{StaticResource SearchBoxStyle}">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Loaded">
<core:EventTriggerBehavior.Actions>
<actions:SearchBoxTextErrorVisualStateAction ErrorVisualState="TextInvalid" ValidVisualState="TextValid" />
</core:EventTriggerBehavior.Actions>
</core:EventTriggerBehavior>
<core:EventTriggerBehavior EventName="QueryChanged">
<core:EventTriggerBehavior.Actions>
<actions:SearchBoxTextErrorVisualStateAction ErrorVisualState="TextInvalid" ValidVisualState="TextValid" />
</core:EventTriggerBehavior.Actions>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</SearchBox>
</Grid>
Due to the limits of answers, I can't paste the entirety of the XAML but you want to add the default SearchBox to your view, in the design window, right click it and go to 'Edit Template -> Edit a copy'. It will create a copy of the default style in which you can replace the root Grid's VisualStateGroups with the ones above.
Edit: The reason for firing the action on the Loaded event is so that you can enable the color change when the control is brought into view and not just when the text changes.
I have a C# WPF Page and on it I have placed several small images that I want to act like check boxes (I have my own custom images for hover and selected states).
I am manually changing the images like so:
<Image x:Name="Image_Custom" Source="/Images/checkcircle_off.png" Width="16" Height="16" HorizontalAlignment="Left" Margin="30,107,0,0" VerticalAlignment="Top" MouseEnter="Image_Custom_MouseEnter" MouseLeave="Image_Custom_MouseLeave" MouseUp="Image_Custom_MouseUp" MouseLeftButtonDown="Image_Custom_MouseLeftButtonDown"/>
private void Image_Custom_MouseEnter(object sender, MouseEventArgs e)
{
if (_selected == false)
{
var uriSource = new Uri("/Images/checkcircle_hover.png", UriKind.Relative);
Image_Custom.Source = new BitmapImage(uriSource);
}
}
private void Image_Custom_MouseLeave(object sender, MouseEventArgs e)
{
if (_selected == false)
{
var uriSource = new Uri("/Images/checkcircle_off.png", UriKind.Relative);
Image_Custom.Source = new BitmapImage(uriSource);
}
}
private void Image_Custom_MouseUp(object sender, MouseButtonEventArgs e)
{
if (_selected)
{
var uriSource = new Uri("/Images/checkcircle_off.png", UriKind.Relative);
Image_Custom.Source = new BitmapImage(uriSource);
_selected = false;
}
else
{
var uriSource = new Uri("/Images/checkcircle_on.png", UriKind.Relative);
Image_Custom.Source = new BitmapImage(uriSource);
_selected = true;
}
}
private void Image_Custom_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (_selected)
{
var uriSource = new Uri("/Images/checkcircle_off.png", UriKind.Relative);
Image_Custom.Source = new BitmapImage(uriSource);
_selected = false;
}
else
{
var uriSource = new Uri("/Images/checkcircle_on.png", UriKind.Relative);
Image_Custom.Source = new BitmapImage(uriSource);
_selected = true;
}
}
This works but is very cumbersome and I will have up to 20 check boxes.
How can I create a custom XAML Style that I can use for each image or something similar.
EDIT:
I have used the following style to handle the hover over:
<Page.Resources>
<Style TargetType="Image" x:Key="checkBoxStyle">
<Setter Property="Source" Value="/Images/checkcircle_off.png"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Source" Value="/Images/checkcircle_hover.png"/>
</Trigger>
</Style.Triggers>
</Style>
</Page.Resources>
<Image x:Name="Image_Custom" Style="{StaticResource checkBoxStyle}" Width="16" Height="16" HorizontalAlignment="Left" Margin="30,107,0,0" VerticalAlignment="Top" MouseEnter="Image_Custom_MouseEnter" MouseLeave="Image_Custom_MouseLeave" MouseUp="Image_Custom_MouseUp" MouseLeftButtonDown="Image_Custom_MouseLeftButtonDown"/>
But I dont know how to handle the clicked event. How can I do this?
EDIT 2
I have did the following:
<Style TargetType="{x:Type CheckBox}" x:Key="myCheckBoxStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Image x:Name="checkBoxImage" Source="/Images/checkcircle_off.png"></Image>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="checkBoxImage" Property="Source" Value="/Images/checkcircle_on.png"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="checkBoxImage" Property="Source" Value="/Images/checkcircle_off.png"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="checkBoxImage" Property="Source" Value="/Images/checkcircle_hover.png"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<CheckBox Content="My CheckBox" Style="{StaticResource myCheckBoxStyle}" Width="16" Height="16" Foreground="white" FontSize="16" HorizontalAlignment="Left" Margin="30,242,0,0" VerticalAlignment="Top" />
The correct images appear when hovered, checked and unchecked.
But I noticed that the Content has disappeared ("My Checkbox") and also I only want the hover state to appear when its not checked, how can I do that?
In WPF you generally look for a control that has the functionality you need and then you make it look like you want. So if you want CheckBox functionality then you use CheckBox control and change its Template to be what you want. So you can create Style for CheckBox that will set your custom Template
<Window.Resources>
<Style TargetType="{x:Type CheckBox}" x:Key="myCheckboxStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<StackPanel Orientation="Horizontal">
<Image x:Name="checkboxImage" Source="normal.png" Width="32"/>
<ContentPresenter/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="checkboxImage" Property="Source" Value="checked.png"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="False"/>
</MultiTrigger.Conditions>
<Setter TargetName="checkboxImage" Property="Source" Value="hover.png"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
and then just use it on any CheckBox
<CheckBox Style="{StaticResource myCheckboxStyle}" Content="ABC"/>
and you'll have all CheckBox functionality with your custom looks
If you override CheckBox and create a specific style this will look like this:
public class MyCheckBox : CheckBox
{
#region ImageNormal
/// <summary>
/// ImageNormal Dependency Property
/// </summary>
public static readonly DependencyProperty ImageNormalProperty =
DependencyProperty.Register("ImageNormal", typeof(ImageSource), typeof(MyCheckBox),
new FrameworkPropertyMetadata((ImageSource)null));
/// <summary>
/// Gets or sets the ImageNormal property. This dependency property
/// indicates ....
/// </summary>
public ImageSource ImageNormal
{
get { return (ImageSource)GetValue(ImageNormalProperty); }
set { SetValue(ImageNormalProperty, value); }
}
#endregion
#region ImageChecked
/// <summary>
/// ImageChecked Dependency Property
/// </summary>
public static readonly DependencyProperty ImageCheckedProperty =
DependencyProperty.Register("ImageChecked", typeof(ImageSource), typeof(MyCheckBox),
new FrameworkPropertyMetadata((ImageSource)null));
/// <summary>
/// Gets or sets the ImageChecked property. This dependency property
/// indicates ....
/// </summary>
public ImageSource ImageChecked
{
get { return (ImageSource)GetValue(ImageCheckedProperty); }
set { SetValue(ImageCheckedProperty, value); }
}
#endregion
//... other image properties removed for simplicity
static MyCheckBox()
{
//Override base class style
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCheckBox), new FrameworkPropertyMetadata(typeof(MyCheckBox)));
}
}
Associated XAML Style:
<Style TargetType="{x:Type local:MyCheckBox}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="grdNormal">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="grdMouseOver">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="grdPressed">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="grdNormal">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
<VisualStateGroup x:Name="CheckStates">
<VisualState x:Name="Checked">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imgUnchecked1">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imgChecked1">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imgUnchecked2">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imgChecked2">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imgUnchecked3">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imgChecked3">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unchecked"/>
<VisualState x:Name="Indeterminate"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid x:Name="grdNormal">
<Image x:Name="imgUnchecked1" Source="{Binding ImageNormal, RelativeSource={RelativeSource TemplatedParent}}"/>
<Image x:Name="imgChecked1" Visibility="Collapsed" Source="{Binding ImageNormal, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
<Grid x:Name="grdMouseOver" Visibility="Collapsed">
<Image x:Name="imgUnchecked2" Source="{Binding ImageMouseOver, RelativeSource={RelativeSource TemplatedParent}}"/>
<Image x:Name="imgChecked2" Visibility="Collapsed" Source="{Binding ImageMouseOverChecked, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
<Grid x:Name="grdPressed" Visibility="Collapsed">
<Image x:Name="imgUnchecked3" Source="{Binding ImagePressed, RelativeSource={RelativeSource TemplatedParent}}"/>
<Image x:Name="imgChecked3" Visibility="Collapsed" Source="{Binding ImagePressedChecked, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I have an animation that animates a Canvas by turning it 360 degrees indefinitely (it basically spins). What I want is for this animation to start when the control is shown and then stop when the control is hidden. I figured I could tie this in, somehow, to the VisualStateManager. I have seen an example of fading in and out controls here which could work but I just dont know how to use VSM to start and stop the storyboard
<Canvas.Resources>
<Storyboard x:Name="spinnerBoard">
<DoubleAnimation
Storyboard.TargetName="SpinnerRotate"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:01.3"
RepeatBehavior="Forever" />
</Storyboard>
</Canvas.Resources>
<Canvas.RenderTransform>
<RotateTransform x:Name="SpinnerRotate" Angle="0" />
</Canvas.RenderTransform>
Example VSM
<VisualState x:Name="Show">
<Storyboard>
<!-- Start the story board here -->
</Storyboard>
</VisualState>
<VisualState x:Name="Hide">
<Storyboard>
<!-- Stop the story board here -->
</Storyboard>
</VisualState>
A global answer of your different questions :
ExtendedVisualStateManager.GoToElementState returns false in Silverlight
Default binding to UserControl for custom DP
You can do something like this :
Use a template control that extend ContentControl to play with
IsEnabled of content (prevent action during waiting) ;
Create a DP IsWaiting that switch your control visual state ;
Create the two states in XAML : Use DoubleAnimation with RepeatBehavior="Forever"
After you can add a overlay and a Waiting message dependency property like the busy indicator control...
I use a picture for the Waiting visual part but you can use a canvas, grid etc...
C#
[TemplateVisualState(GroupName = "WaitGroup", Name = WaitSpinner.IsWaitingStateName)]
[TemplateVisualState(GroupName = "WaitGroup", Name = WaitSpinner.NotWaitingStateName)]
public class WaitSpinner : ContentControl
{
#region States names
internal const String IsWaitingStateName = "IsWaitingState";
internal const String NotWaitingStateName = "NotWaitingState";
#endregion States names
public bool IsWaiting
{
get { return (bool)GetValue(IsWaitingProperty); }
set { SetValue(IsWaitingProperty, value); }
}
public static readonly DependencyProperty IsWaitingProperty =
DependencyProperty.Register("IsWaiting", typeof(bool), typeof(WaitSpinner), new PropertyMetadata(false, OnIsWaitingPropertyChanged));
private static void OnIsWaitingPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
WaitSpinner waitSpinner = (WaitSpinner)sender;
waitSpinner.ChangeVisualState(true);
}
public WaitSpinner()
{
DefaultStyleKey = typeof(WaitSpinner);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
ChangeVisualState(false);
}
protected virtual void ChangeVisualState(bool useTransitions)
{
VisualStateManager.GoToState(this, IsWaiting ? IsWaitingStateName : NotWaitingStateName, useTransitions);
}
}
Xaml :
<VisualStateGroup x:Name="WaitGroup">
<VisualState x:Name="NotWaitingState" >
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Control.IsEnabled)" Storyboard.TargetName="content">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Boolean>True</System:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="IsWaitingState">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="WaitPart">
<DiscreteObjectKeyFrame KeyTime="0:0:0.200" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)" Storyboard.TargetName="WaitPart" To="360" RepeatBehavior="Forever" Duration="0:0:1" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Control.IsEnabled)" Storyboard.TargetName="content">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Boolean>False</System:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<!-- ............. -->
<ContentControl
IsTabStop="False"
x:Name="content"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Foreground="{TemplateBinding Foreground}"
ScrollViewer.HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
ScrollViewer.VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"/>
<Image Source="CirclePicture.png"
x:Name="WaitPart"
RenderTransformOrigin="0.5,0.5"
Width="16"
Height="16"
Visibility="Collapsed"
IsHitTestVisible="False">
<Image.RenderTransform>
<RotateTransform />
</Image.RenderTransform>
</Image>