Change DependencyProperty on the ControlTemplate - xaml

I have a Button with two different images - one for normal state and one - for PointerOver state:
public sealed class MyButtonTwo : Button
{
public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register(
"ImageSource", typeof (ImageSource), typeof (MyButtonTwo), new PropertyMetadata(default(ImageSource)));
public ImageSource ImageSource
{
get { return (ImageSource) GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
public static readonly DependencyProperty ImageSource2Property = DependencyProperty.Register(
"ImageSource2", typeof (ImageSource), typeof (MyButtonTwo), new PropertyMetadata(default(ImageSource)));
public ImageSource ImageSource2
{
get { return (ImageSource) GetValue(ImageSource2Property); }
set { SetValue(ImageSource2Property, value); }
}
I am using this property in the Control Template in the Style:
<Image x:Name="Image"
Source="{TemplateBinding ImageSource}" />
In the style I can change the properties of the MyButton:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="FullGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="White"/>
But I can not change my dependency property such way:
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Storyboard.TargetName="Image">
<DiscreteObjectKeyFrame KeyTime="0" Value="{TemplateBinding ImageSource2}"/>
Only one way I have found is to add two different Images on the Template and change Visibility of them.
May be there is any better way?

It works with a regular Binding instead of a TemplateBinding:
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source"
Storyboard.TargetName="Image">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{Binding ImageSource2,
RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</ObjectAnimationUsingKeyFrames>

Related

Uwp image scaling

I am trying to scale images in gridview items using RenderTransform. Scaling
performed successfully but scaled image is in behind the gridview items. how to bring it to front.
<VisualState x:Name="PointerOver">
<Storyboard >
<DoubleAnimation Duration="0" Storyboard.TargetName="BorderRectangle"
Storyboard.TargetProperty="Opacity" To="1" />
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="contentborderscale"
Storyboard.TargetProperty="ScaleY" >
<DiscreteObjectKeyFrame KeyTime="0" Value="2" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentborderscale"
Storyboard.TargetProperty="ScaleX">
<DiscreteObjectKeyFrame KeyTime="0" Value="2" />
</ObjectAnimationUsingKeyFrames>
<PointerUpThemeAnimation Storyboard.TargetName="ContentPresenter" />
</Storyboard>
</VisualState>
In short, you want to scale the Container of the GridViewItem.
I check my answer to GridView selectedItem Popup
(Method 2)
Method 2: On Pointer Hover
XAML Part
<GridView Height="200">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:ItemSource">
<Grid Width="100" Height="100" PointerEntered="GridView_PointerEntered" PointerExited="GridView_PointerExited">
<!-- Content -->
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid VerticalAlignment="Center" HorizontalAlignment="Center"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
C# Part
FrameworkElement lastPopUpElement = null;
private void GridView_PointerEntered(object sender, PointerRoutedEventArgs e)
{
lastPopUpElement = VisualTreeHelper.GetParent(VisualTreeHelper.GetParent(sender as FrameworkElement) as FrameworkElement) as FrameworkElement;
Canvas.SetZIndex(lastPopUpElement, 1);
lastPopUpElement.Scale(scaleX: 1.5f, scaleY: 1.5f, centerX: 50, centerY: 50, easingType: EasingType.Sine).Start();
}
private void GridView_PointerExited(object sender, PointerRoutedEventArgs e)
{
if (lastPopUpElement != null)
{
Canvas.SetZIndex(lastPopUpElement, 0);
lastPopUpElement.Scale(centerX: 50, centerY: 50, easingType: EasingType.Sine).Start();
}
}
Sample Output

UWP Derived Button With Flyout: Binding within the Style

General: in a Style for a custom control, is it possible to bind to another DependencyProperty (e.g. MySecondProperty) value from within a <Setter Property="MyFirstProperty">?
For what purpose? To accomplish the following:
1.) Derive some MyButton : Button control, which has an additional List<string> FlyoutSource dependency property on it.
2.) Define a MyButtonStyle, which has a <Setter Property="Flyout"> element defining the Button.Flyout property (since MyButton : Button).
The Flyout will have a ListView in it, whose ItemsSource must bind to MyButton.FlyoutSource
<Style TargetType="local:MyButton" x:Key="MyButtonStyle">
<Setter Property="Background" Value="Green"/>
<Setter Property="Flyout">
<Setter.Value>
<Flyout>
<!-- &&&&&&& THE FOLLOWING LINE DOES NOT WORK PROPERLY &&&&&&& -->
<ListView ItemsSource="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=FlyoutSource}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Flyout>
</Setter.Value>
</Setter>
</Style>
How would I like to use the solution:
<local:MyButton
FlyoutSource="{x:Bind FlyoutSourceList, Mode=TwoWay}"
Style="{StaticResource MyButtonStyle}">
</local:MyButton
More Detail: the MyButton class:
public class MyButton : Button
{
public MyButton()
{
this.DefaultStyleKey = typeof(Button);
}
public static DependencyProperty FlyoutSourceProperty = DependencyProperty.Register(
"FlyoutSource", typeof(List<string>), typeof(MyButton),
new PropertyMetadata(null, new PropertyChangedCallback(OnFlyoutSourceChanged)));
public List<string> FlyoutSource
{
get { return (List<string>)GetValue(FlyoutSourceProperty); }
set { SetValue(FlyoutSourceProperty, value); }
}
public static void OnFlyoutSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
Debug.WriteLine("");
}
}
You actually don't need to subclass Button to do this, just make FlyoutSource an attached property.
You can't use RelativeSource mode TemplatedParent here because it is not within a ControlTemplate.
It seems that the only way for the flyout content to obtain information from it's attached element is through DataContext inheritance. I could only come up with this, but it involves a lot of binding gymnastics. I don't recommend it.
public class ViewProps
{
public static object GetFlyoutListSource(DependencyObject obj)
{
return (object)obj.GetValue(FlyoutListSourceProperty);
}
public static void SetFlyoutListSource(DependencyObject obj, object value)
{
obj.SetValue(FlyoutListSourceProperty, value);
}
public static readonly DependencyProperty FlyoutListSourceProperty =
DependencyProperty.RegisterAttached("FlyoutListSource", typeof(object), typeof(ViewProps), new PropertyMetadata(null));
}
<Grid x:Name="MyGrid">
<Grid.Resources>
<Style x:Key="FlyoutButton" TargetType="Button">
<Setter Property="Flyout">
<Setter.Value>
<Flyout>
<ListView ItemsSource="{Binding (local:ViewProps.FlyoutListSource)}"/>
</Flyout>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Button
Style="{StaticResource FlyoutButton}"
Content="Button"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
local:ViewProps.FlyoutListSource="{Binding ElementName=MyGrid, Path=DataContext.ItemsSource}"/>
</Grid>
If you want to subclass Button, then you can do something like this.
ListFlyoutButton.cs
public sealed class ListFlyoutButton : Button
{
public object ItemsSource
{
get { return (object)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(object), typeof(ListFlyoutButton), new PropertyMetadata(null));
public ListFlyoutButton()
{
this.DefaultStyleKey = typeof(ListFlyoutButton);
}
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
((FrameworkElement)((Flyout)Flyout).Content).DataContext = this;
}
}
Themes\Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="***">
<Style TargetType="local:ListFlyoutButton">
<Setter Property="Background" Value="{ThemeResource ButtonBackground}" />
<Setter Property="Foreground" Value="{ThemeResource ButtonForeground}" />
<Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
<Setter Property="Padding" Value="8,4,8,4" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="FocusVisualMargin" Value="-3" />
<Setter Property="Flyout">
<Setter.Value>
<Flyout>
<ListView ItemsSource="{Binding ItemsSource}"/>
</Flyout>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ListFlyoutButton">
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<PointerDownThemeAnimation Storyboard.TargetName="RootGrid" />
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundDisabled}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<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" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
MainPage.xaml
<local:ListFlyoutButton Content="Button" ItemsSource="{Binding Items}"/>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
DataContext = new
{
Items = new[] { "Apple", "Banana" },
};
}
}
It would be nice if we didn't have to duplicate the entire default Button style.

(UWP) How to make the password reveal button always visible and make it work always in a PasswordBox

I am using a PasswordBox in my UWP application where I want to show the password reveal button always. Also, when pressed it should work as expected and should show the passord.
I have modified this default style of the PasswordBox control to set the visibility of Password Reveal button to true. It works and the button is always visible now. But the problem is the password reveal functionality only works when the password is cleared and typed from starting.
<Style x:Key="PasswordBoxStyle" TargetType="PasswordBox">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="PasswordBox">
<Grid Background="Transparent">
<Grid.Resources>
<Style x:Name="RevealButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="ButtonLayoutGrid" BorderBrush="{ThemeResource TextBoxButtonBorderThemeBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{ThemeResource TextBoxButtonBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="GlyphElement"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAccentBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonLayoutGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAccentBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="GlyphElement"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltChromeWhiteBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ButtonLayoutGrid"
Storyboard.TargetProperty="Opacity"
To="0"
Duration="0" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<TextBlock x:Name="GlyphElement"
Foreground="{ThemeResource SystemControlForegroundChromeBlackMediumBrush}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontStyle="Normal"
FontSize="16"
Text=""
FontFamily="{ThemeResource SymbolThemeFontFamily}"
AutomationProperties.AccessibilityView="Raw"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundElement"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledTransparentBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledChromeDisabledLowBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledChromeDisabledLowBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Normal">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BorderElement">
<DiscreteObjectKeyFrame KeyTime="0" Value="Gray"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderThickness" Storyboard.TargetName="BorderElement">
<DiscreteObjectKeyFrame KeyTime="0" Value="0.5"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="BackgroundElement">
<DiscreteObjectKeyFrame KeyTime="0" Value="White"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BorderElement">
<DiscreteObjectKeyFrame KeyTime="0" Value="Gray"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderThickness" Storyboard.TargetName="BorderElement">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="BackgroundElement">
<DiscreteObjectKeyFrame KeyTime="0" Value="White"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="BorderElement">
<DiscreteObjectKeyFrame KeyTime="0" Value="Gray"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderThickness" Storyboard.TargetName="BorderElement">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="BackgroundElement">
<DiscreteObjectKeyFrame KeyTime="0" Value="White"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ButtonStates">
<VisualState x:Name="ButtonVisible">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RevealButton"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="ButtonCollapsed" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border x:Name="BackgroundElement"
Grid.Row="1"
Background="{TemplateBinding Background}"
Margin="{TemplateBinding BorderThickness}"
Opacity="{ThemeResource TextControlBackgroundRestOpacity}"
Grid.ColumnSpan="2"
Grid.RowSpan="1"/>
<Border x:Name="BorderElement"
Grid.Row="1"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Grid.ColumnSpan="2"
Grid.RowSpan="1"/>
<ContentPresenter x:Name="HeaderContentPresenter"
x:DeferLoadStrategy="Lazy"
Visibility="Collapsed"
Grid.Row="0"
Foreground="{ThemeResource SystemControlForegroundBaseHighBrush}"
Margin="0,0,0,8"
Grid.ColumnSpan="2"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
FontWeight="Normal" />
<ScrollViewer x:Name="ContentElement"
Grid.Row="1"
HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
Margin="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
IsTabStop="False"
ZoomMode="Disabled"
AutomationProperties.AccessibilityView="Raw"/>
<ContentControl x:Name="PlaceholderTextContentPresenter"
Grid.Row="1"
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
Margin="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
IsTabStop="False"
Grid.ColumnSpan="2"
Content="{TemplateBinding PlaceholderText}"
IsHitTestVisible="False"/>
<Button x:Name="RevealButton"
Grid.Row="1"
Style="{StaticResource RevealButtonStyle}"
BorderThickness="{TemplateBinding BorderThickness}"
Margin="{ThemeResource HelperButtonThemePadding}"
IsTabStop="False"
Grid.Column="1"
Visibility="Visible"
FontSize="{TemplateBinding FontSize}"
VerticalAlignment="Stretch"
MinWidth="34" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Please notice that I have changed below style for Reveal Password button to have the visibility set to true (it is collapsed by default):
<Button x:Name="RevealButton"
Grid.Row="1"
Style="{StaticResource RevealButtonStyle}"
BorderThickness="{TemplateBinding BorderThickness}"
Margin="{ThemeResource HelperButtonThemePadding}"
IsTabStop="False"
Grid.Column="1"
Visibility="Visible"
FontSize="{TemplateBinding FontSize}"
VerticalAlignment="Stretch"
MinWidth="34" />
This is by design, you can refer to PasswordBox:
The password reveal button is shown only when the PasswordBox receives focus for the first time and a character is entered. If the PasswordBox loses focus and then regains focus, the reveal button is not shown again unless the password is cleared and character entry starts over.
By default it behaves like so, even you make the RevealButton visible always, the problem now is this Button doesn't work properly.
The official recommended method is to create a similar UI for example a CheckBox to let a user switch the reveal mode. I've also noticed that you changed the default ToggleButton to Button in the style, if you insist to use this Button for switching the reveal mode, you can for example code in behind like this:
public Page21()
{
this.InitializeComponent();
this.Loaded += Page21_Loaded;
}
private Button RevealButton;
private void Page21_Loaded(object sender, RoutedEventArgs e)
{
RevealButton = FindChildOfType<Button>(passwordbox);
RevealButton.Tapped += RevealButton_Tapped;
RevealButton.ClickMode = ClickMode.Press;
RevealButton.Click += RevealButton_Click;
RevealButton.RightTapped += RevealButton_RightTapped;
}
private void RevealButton_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
Debug.WriteLine("RevealButton_RightTapped");
passwordbox.PasswordRevealMode = PasswordRevealMode.Hidden;
}
private void RevealButton_Tapped(object sender, TappedRoutedEventArgs e)
{
Debug.WriteLine("RevealButton_Tapped");
passwordbox.PasswordRevealMode = PasswordRevealMode.Hidden;
}
private void RevealButton_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine("RevealButton_Click");
passwordbox.PasswordRevealMode = PasswordRevealMode.Visible;
}
public static T FindChildOfType<T>(DependencyObject root) where T : class
{
var queue = new Queue<DependencyObject>();
queue.Enqueue(root);
while (queue.Count > 0)
{
DependencyObject current = queue.Dequeue();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(current); i++)
{
var child = VisualTreeHelper.GetChild(current, i);
var typedChild = child as T;
if (typedChild != null)
{
return typedChild;
}
queue.Enqueue(child);
}
}
return null;
}
The basic idea here is firstly get the RevealButton inside the PasswordBox, then change the ClickMode of RevealButton so will the Click event be fired when the Button is being pressed, by default the Tapped/ RightTapped event of Button will be fired when the pointer is released, finally you can change the PasswordRevealMode in these two events. Tapped event works fine on PC, but on mobile, I used RightTapped for the point released of Button.
You can make the button always be visible by simply finding the button and setting its visibility to Visibility.Visible. I assume the button in the default template uses TemplateBinding and its visibility is not programmatically toggled because setting its visibility directly would break any existing bindings, such as the aforementioned.
I use the following extension method to find the button:
public static T GetChildOfType<T>(this DependencyObject Object) where T : DependencyObject
{
if (Object == null)
return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(Object); i++)
{
var Child = VisualTreeHelper.GetChild(Object, i);
var Result = (Child as T) ?? GetChildOfType<T>(Child);
if (Result != null) return Result;
}
return null;
}
Then, when the PasswordBox loads, do this:
private void OnLoaded(object sender, RoutedEventArgs e)
{
var RevealButton = (sender as PasswordBox).GetChildOfType<Button>();
if (RevealButton != null)
RevealButton.Visibility = Visibility.Visible;
}
You can define a generic ContentControl class to subclass PasswordBox, if you wish; otherwise, just attach the above Loaded event to each instance.
There's a drawback, though: After losing focus, the button no longer has the ability to toggle the visibility of the password despite being visible. It is unclear why.

Create ControlTemplate with Attached Property

I am essentially trying to create a Button with an image background and border that changes color based off if it is hovered, clicked or default state. I will several of these types of buttons, and I want to have a ControlTemplate defined that I can reuse and change the ImageSource. Here is what I have so far, but for some reason the TemplateBinding doesn't seem to work. The buttons have no background image set.
Template:
<ControlTemplate x:Name="SkillIconTemplate" TargetType="Button">
<Border CornerRadius="10" BorderThickness="2" Margin="5">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition To="MouseOver" GeneratedDuration="0:0:0.1"/>
<VisualTransition To="Pressed" GeneratedDuration="0:0:0.1"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color"
To="Yellow" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color"
To="Black"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border.BorderBrush>
<SolidColorBrush x:Name="BorderBrush" Color="White"/>
</Border.BorderBrush>
<Border.Background>
<ImageBrush ImageSource="{TemplateBinding local:SkillIcon.IconImageSource}"/>
</Border.Background>
</Border>
</ControlTemplate>
Buttons:
<Button x:Name="skillIcon0" Width="75" Height="75" ClickMode="Press" local:SkillIcon.IconImageSource="ms-appx:/data/images/icons/skill_icon_0.png" Template="{StaticResource SkillIconTemplate}"/>
<Button x:Name="skillIcon1" Width="75" Height="75" ClickMode="Press" local:SkillIcon.IconImageSource="ms-appx:/data/images/icons/skill_icon_1.png" Template="{StaticResource SkillIconTemplate}"/>
…
Property Code:
public abstract class SkillIcon : DependencyObject
{
public static readonly DependencyProperty IconImageSourceProperty = DependencyProperty.RegisterAttached(
"IconImageSource",
typeof(ImageSource),
typeof(SkillIcon),
new PropertyMetadata(GetIconImage(0))
);
public static ImageSource GetIconImageSource(DependencyObject obj)
{
return (ImageSource)obj.GetValue(IconImageSourceProperty);
}
public static void SetIconImageSource(DependencyObject obj, ImageSource value)
{
obj.SetValue(IconImageSourceProperty, value);
}
/// <summary>
/// Gets the image source for the button
/// </summary>
public static ImageSource GetIconImage(int index)
{
Uri source = new Uri(string.Format("ms-appx:/data/images/icons/skill_icon_{0}.png", index), UriKind.RelativeOrAbsolute);
return new BitmapImage() { UriSource = source };
}
}
Usage in code:
SkillIcon.SetIconImageSource(skillIcon0, SkillIcon.GetIconImage(0));
I ended up binding the background of the Button to the background of the border:
<ControlTemplate x:Name="SkillIconTemplate" TargetType="Button">
<Border CornerRadius="10" BorderThickness="2" Margin="5" Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition To="MouseOver" GeneratedDuration="0:0:0.05"/>
<VisualTransition To="Pressed" GeneratedDuration="0:0:0.05"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color"
To="Yellow" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color"
To="Black"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border.BorderBrush>
<SolidColorBrush x:Name="BorderBrush" Color="White"/>
</Border.BorderBrush>
</Border>
</ControlTemplate>

DataTrigger in WinRT?

I was able to find EventTrigger in the WinRT reference, however, I wasn't able to find DataTrigger. I wasn't able to use it in an application either.
Can anyone confirm that DataTrigger is really missing in WinRT? Is EventTrigger the only trigger available in WinRT?
DataTrigger is not currently supported in WinRT XAML.
Addendum by Mike Brown
The DataTrigger API has been replaced with the VisualStateManager a similar API to Data Triggers was provided by the Blend SDK for Silverlight. Since the Attached Behavior Pattern works in WinRT, it is possible to do the same.
What about this project that seems implement triggers in WinRT : http://winrttriggers.codeplex.com/
I don't know when it changed but i have DataTriggerBehavior and GoToStateAction combining them should solve your problem...
namespace imports
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
ViewSateManager place on root element
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Common">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0" To="Online">
<Storyboard>
<ColorAnimation Duration="0" To="Lime" Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="Name" />
</Storyboard>
</VisualTransition>
<VisualTransition GeneratedDuration="0" To="Offline">
<Storyboard>
<ColorAnimation Duration="0" To="Red" Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="Name" />
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Online" />
<VisualState x:Name="Offline" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding Active}" Value="True">
<Core:GoToStateAction StateName="Online" />
</Core:DataTriggerBehavior>
<Core:DataTriggerBehavior Binding="{Binding Active}" Value="False">
<Core:GoToStateAction StateName="Offline" />
</Core:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
I implemented an alternate workaround that may work for you. Steps:
Create a UserControl (either from scratch or inheriting) so you can write some code-behind C# into the control.
Create a DependencyProperty in the codebehind for the databinding you want to trigger on.
Use the DependencyProperty's PropertyChangedCallback method to implement do what you need to do in code to the control.
Bind the DependencyProperty in XAML to the data you want to trigger on.
It's not as clean as a DataTrigger, but it's not too much worse and it works well (for me at least).
Declaration in XAML (DataContext is already set to a viewmodel object):
<local:PlayButton IsPlaying="{Binding IsPlaying}"/>
Example DependencyProperty that triggers storyboards to change state:
// Use this to implement storyboard changing in W8 since triggers are not supported
public static readonly DependencyProperty IsPlayingProperty = DependencyProperty.Register(
"IsPlaying",
typeof(bool),
typeof(PlayButton),
new PropertyMetadata(null,
new PropertyChangedCallback(OnIsPlayingChanged)
));
private static void OnIsPlayingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PlayButton pb = (PlayButton)d;
bool isPlaying = (bool)e.NewValue;
if (isPlaying == false)
pb.GotoPlay.Begin();
else
pb.GotoPause.Begin();
}
public bool IsPlaying
{
get { return (bool)GetValue(IsPlayingProperty); }
set { SetValue(IsPlayingProperty, value); }
}
you can use VisualState instead of object.Triggers in Windows 8 Here is the code
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<!--Take one half second to transition to the PointerOver state.-->
<VisualTransition To="PointerOver" GeneratedDuration="0:0:0.5"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="ButtonBrush"
Storyboard.TargetProperty="Color" To="Red" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.Background>
<SolidColorBrush x:Name="ButtonBrush" Color="Green"/>
</Grid.Background>
</Grid>
</ControlTemplate>