VisualStateManager not working inside Button.ContentTemplate UWP - xaml

I have been struggling with this for a few days now unable to find solution after lot of effort. This is the code where I'm facing the issue. SO I have a ItemsControl where each element is Button and each Button has an Image and TextBlock. On hovering over Button I could see the Background of Button being changed to Red as expected. But I'm unable to change the Foreground of TextBlock to Green. Any help in this regard is highly appreciated
<ControlTemplate x:Key="ButtonTemplate" TargetType="ContentControl">
<Grid Background="Transparent" x:Name="Mini">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="Mini.Background" Value="Red" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="MiniContent" />
</Grid>
</ControlTemplate>
<DataTemplate x:Key="ListItemTemplate" x:DataType="local:DataModel">
<Button
Template="{StaticResource ButtonTemplate}">
<Button.ContentTemplate>
<DataTemplate x:DataType="local:DataModel">
<UserControl>
<Grid >
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="Value.Foreground" Value="Green" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<TextBlock x:Name="Value"
Foreground="Yellow"
Text="{x:Bind DisplayName, Mode=OneWay}"/>
<Image
Width="16"
Source="{x:Bind ImageBitmap, Mode=OneWay}"/>
</Grid>
</UserControl>
</DataTemplate>
</Button.ContentTemplate>
</Button>
</DataTemplate>
<ItemsControl
ItemTemplate="{StaticResource ListItemTemplate}"
ItemsSource="{x:Bind DataModelVector, Mode=OneWay}" />

You need something to actually transition between the VisualStates, the PointerOver state isn't triggered automatically. The easiest way would be to factor the content of your DataTemplate into its own file (UserControl with markup and code-behind) and handle pointer events in code to transition between visual states using VisualStateManager.GoToState.
You could also create a reusable "StateTrigger" for transitioning any control into a "PointerOver" visual state, but often some code-behind is simpler.

Related

XAML VisualStateManager and RelativePanel

I am loocking to do a responsive desing on my uwp project.
The idea is on PC get my StackPanel_ListViews below the StackPanel_CommandBar.
And on mobile get my StackPanel_CommandBar below the StackPanel_ListViews.
Both StackPanels are inside of a Pivot.
This is my code:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualState x:Name="Mobile">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="StackPanel_CommandBar.(RelativePanel.Below)" Value="StackPanel_ListViews"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pc">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="800"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="StackPanel_ListViews.(RelativePanel.Below)" Value="StackPanel_CommandBar"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel>
<controls:PageHeader x:Name="pageHeader" RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
RelativePanel.AlignTopWithPanel="True" Text="Tittle">
</controls:PageHeader>
<Pivot x:Name="MainPivot">
<PivotItem>
<RelativePanel>
<StackPanel Orientation="Vertical" x:Name="StackPanel_CommandBar" RelativePanel.AlignLeftWithPanel="True" RelativePanel.AlignRightWithPanel="True">
</StackPanel>
<StackPanel Orientation="Vertical" x:Name="StackPanel_ListViews" RelativePanel.Below="StackPanel_CommandBar" RelativePanel.AlignLeftWithPanel="True" RelativePanel.AlignRightWithPanel="True">
</StackPanel>
</RelativePanel>
</PivotItem>
</Pivot>
</StackPanel>
StackPanel_ListViews is a stackpanel contains 2 ListViews.
StackPanel_CommandBar is a stackpanel contains a CommandBar.
Using this code I have no results, and using a above and below I am geting a circular error.
What I am doing wrong, how I can get it work as I say above?
Any help is appreciated.
I think you've made a tiny mistake here by your second StackPanel "StackPanel_ListViews".
You've set RelativePanel.Below="StackPanel_CommandBar" at first, but when the layout is rendered, at the very beginning, the window's width is 0, this will cause conflicts with the Setter in your <VisualState x:Name="Mobile">, and throw an exception. You can just remove this RelativePanel.Below="StackPanel_CommandBar" code and it will works fine.

Adaptive trigger doesn't work in a user control

I'm working on a UWP app. I'm already using adaptive triggers to adapt my xaml depending on the width of the window, and it works.. only in a Page.
Now I want to do the same for the xaml of a User Control, and it's not working .. Yet I put the VisualStateManager to root grid of the user control.
Is there a difference ?
Here's the code of my user control :
<UserControl
x:Class=.....>
<UserControl.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator"/>
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.DataContext>
<Binding Path="MyUserControlVM" Source="{StaticResource Locator}"/>
</UserControl.DataContext>
<Grid x:Name="LayoutRoot" Background="white">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Narrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="LastName.Foreground" Value="Red" />
<Setter Target="LastName.Fontsize" Value="10" />
<Setter Target="FirstName.Foreground" Value="Red"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Normal">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="600" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="LastName.Foreground" Value="Red" />
<Setter Target="LastName.Fontsize" Value="25" />
<Setter Target="FirstName.Foreground" Value="Red"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Wide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1000"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="LastName.Foreground" Value="Red" />
<Setter Target="FirstName.Foreground" Value="Red"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Listbox>
...
</ListBox>
<TextBlock x:Name="lblNoData" Grid.ColumnSpan="2" Text="No Data" Visibility="{Binding NoDataVisible, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<ProgressRing x:Name="prLoading" Width="60" Height="60" Foreground="Blue" IsActive="{Binding InitializationNotifier.IsNotCompleted}" />
</Grid>
("LastName" and "FirstName" are textblocks in the DataTemplate of my listbox. I'm just trying to put my text in red in order to see when the triggers work)
And I call the user control in a simple page like this :
<Grid x:Name="LayoutRoot" Background="{StaticResource white}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="0,0,0,10">
...
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="10,0">
<UC:MyUserControl/>
</Grid>
</Grid>
I don't understand why this code won't work. Thank you in advance for your help !
("LastName" and "FirstName" are textblocks in the DataTemplate of my listbox. I'm just trying to put my text in red in order to see when the triggers work)
You can refer to my another answer here, as I said in that answer, when the controls are placed in the DataTemplate, they becomes the visual structure of your data objects. I think there is no clean way to do this work only in the xaml code, Data Binding here is your friend.
From your code I can see that you want to change the Foreground (but all to Red?) and the FontSize of the TextBlocks inside of the DataTemplate depending on the window's size. So you can bind these two proprieties to the window's size, or you can use ItemsControl.ItemTemplateSelector to select different template when the window's size is changed.

Drag-and-Drop UWP vs Button Style

I have a question that is me to leave upset. I want to drag and drop an item in a listview and I can not do when I have a style applied to my item. Only I can do and is working perfectly when I have no style (MyButtonStyle) applied / or do not have this image in style. When I have style (MyButtonStyle), ItemDragStarting event is not called.
Another situation: I have tapped associated event, and when I apply this style crashes. I do not understand what the problem is, can someone help me?
Thank you:
Code MainPage:
<ListView x:Name="MyListView" ItemsSource="{x:Bind _ObservableCollection}" Style="{StaticResource MyListViewStyle}" SelectionMode="None" CanDragItems="True" DragItemsStarting="MyListView_OnDragItemsStarting">
<ListView.ItemTemplate>
<DataTemplate>
<Button Tapped="Item_Tapped" Style="{StaticResource MyButtonStyle}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
XAML Style code:
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{StaticResource MyColor1}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="ButtonContent" Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="ButtonContent" To="{StaticResource MyColor2}"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
Duration="00:00:00.1"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<PointerDownThemeAnimation TargetName="ButtonContent"/>
<ColorAnimation Storyboard.TargetName="ButtonContent" To="{StaticResource MyColor3}"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
Duration="00:00:00.1"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Image Width="200" Height="200">
<Image.Source>
<BitmapImage UriSource="{Binding MyImage, Mode=OneTime}" />
</Image.Source>
</Image>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The best solution for you would be to not use a Button at all. Use IsItemClickEnabled property and ItemClick event on the ListView instead, then put your image in the ItemContainerStyle. It will fix your drag and drop issues, focus problems and result in better performance.

How fadeout element in dataTemplate when mouse clicked its containter? My idea throw always exception

This code throw always exception. Is a way to get TextBox (x:Name = "MyBox") to hide (fadeout) when we click in its container (here ListViewItem)? What's wrong with my code?
<ListView x:Name="ListViewMy" IsItemClickEnabled="True" ItemsSource="{Binding list, Mode=TwoWay}" HorizontalAlignment="Left" Height="223" Margin="240,350,0,0" VerticalAlignment="Top" Width="582" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Grid x:Name="GridMy">
<ContentPresenter x:Name="MyContentPresenter">
<ContentPresenter.ContentTemplate>
<DataTemplate x:Key="DataTemplate">
<Grid Background="#FF25C1D1" Margin="-30,0,0,0" x:Name="GridBlue">
<TextBox x:Name="MyBox" HorizontalAlignment="Left" Margin="135,0,0,0" TextWrapping="Wrap" Text="{Binding}" VerticalAlignment="Top" Width="352" Height="81" Background="{x:Null}" BorderBrush="#FF25C1D1" FontFamily="Segoe WP Semibold" FontSize="32" FontWeight="Bold" Foreground="White"/>
</Grid>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed" >
<Storyboard>
<FadeOutThemeAnimation TargetName="MyBox" Duration="0:0:5"></FadeOutThemeAnimation>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
The problem with your code is that your animation, in the ControlTemplate for ListViewItem, should only target other elements within the ControlTemplate for ListViewItem. The DataTemplate won't work here because x:Name="MyBox" won't resolve. DataTemplates are reusable pieces of UI so Name expansion is skipped on them.
A good way to achieve your scenario is to target the animation to the ContentPresenter that is in fact part of your ControlTemplate, i.e.:
<FadeOutThemeAnimation TargetName="MyContentPresenter" Duration="0:0:5" />

Silverlight 4 - How can I change button background color when focused with an Implicit button style?

I'm having a great deal of difficulty trying to achieve something that should be trivial. I'm using an Implicit Button Style defined in a global XAML resource file. I just want to change the background color of the focused button to red with a ColorAnimation. I've tried a number of different combinations in Storyboard.TargetProperty and Storyboard.TargetName and nothing has worked. How can I achieve this?
Thanks in advance.
<Style TargetType="Button" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="grid" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused" >
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="Button" From="Green" To="Red" Duration="00:00:01" />
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
...
Since I don't have the rest of your Style I made this with two Borders and a ContentPresenter. This animates the Background of the Button from Green to Red once focused.
<Style TargetType="Button" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="grid" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<ColorAnimation Storyboard.TargetName="border"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
From="Green"
To="Red"
Duration="0:0:1" />
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border BorderBrush="Transparent" BorderThickness="1" CornerRadius="4">
<Border x:Name="border" Background="White" BorderBrush="Black" BorderThickness="1" CornerRadius="4">
</Border>
</Border>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Width="Auto"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Some good answers here:
Style the MouseOver on a Silverlight/WPF button
http://forums.silverlight.net/forums/p/186402/427878.aspx