GridView's ItemContainerStyle and selection states - xaml

I'm trying to change the appearance of gridview items when they are selected.
(Before, I used a trick with an IsSelected property in the ViewModel object bound to the containing grid and a bool-to-color converter, but I recognize that it is bad)
To do so, I do:
<GridView ItemContainerStyle="{StaticResource GridViewItemContainerStyle}" ...> ...
and
<Style x:Key="GridViewItemContainerStyle" TargetType="GridViewItem">
<Setter Property="Background" Value="Red" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewItem">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Background)" Storyboard.TargetName="itemGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="Black"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="UnselectedSwiping"/>
<VisualState x:Name="UnselectedPointerOver"/>
<VisualState x:Name="Selecting"/>
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Grid.Background)" Storyboard.TargetName="itemGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="White"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="SelectedSwiping"/>
<VisualState x:Name="Unselecting"/>
<VisualState x:Name="Unselected"/>
<VisualState x:Name="SelectedUnfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid ... x:Name="itemGrid">
<!-- HERE MY DATA TEMPLATE -->
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When I run the app, the items are Black (as in the "normal" state). But selecting them does not turn them into White. Where am I wrong?
Moreover, it there a way to set "ItemContainerStyle" without having it to "overwrite" the "ItemTemplate" ???

You DataTemplate should be inside the ItemTemplate property of the GridView element in your page's XAML. Make a separate XAML file (ResourceDictionary), for example CustomStyles.xaml. Reference it in App.xaml like this:
<Application.Resources>
<!-- Application-specific resources -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="PathToCustomStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
You can find on MSDN the default template for GridViewItem (http://msdn.microsoft.com/en-us/library/windows/apps/xaml/jj709915.aspx), under the Default style section (second, longer XAML).
Copy that and paste it into CustomStyles.xaml. Just give it some key like:
<Style TargetType="GridViewItem" x:Key="CustomGridViewItemStyleWithWhiteSelectionBackground">...
As you can see, Selected visual state changes the opacity of three targets, SelectionBackground, SelectedBorder and SelectedCheckMark. So, these elements are not visible in Normal state because their opacity is zero. Find those three elements down below, and change their properties if needed. For the background change the Fill property of the SelectionBackground rectangle:
<Rectangle x:Name="SelectionBackground"
Margin="4"
Fill="White"
Opacity="0" />
Now, when the selection occurs, this element's opacity will be changed to 1 and since you set it's Fill to be white, the background of the selected item will be white. And don't forget to reference this style in the definition of the GridView:
<GridView ItemContainerStyle="{StaticResource CustomGridViewItemStyleWithWhiteSelectionBackground}" ...>
<GridView.ItemTemplate>
<DataTemplate>
...define your template here...
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Edit:
This is the expanded style XAML, probably more suitable for some more complicated style changes. If you want to change only the background, you should take the first style from that MSDN link above under the Default style section, and just edit this (and give it some style key, so you don't overwrite the default one):
SelectedBackground="{ThemeResource ListViewItemSelectedBackgroundThemeBrush}"

Related

VisualState Storyboard.TargetName in UWP

I'm new to working with VisualStates and wondered how to set a Storyboard.TargetName to the control that is being styled ?
I hope the following snippet will make my question a little clearer.
<Style x:Key="AppBarBtnStyle" TargetType="AppBarButton">
<Setter Property="BorderBrush" Value="Gray"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="AppBarButton">
<Grid x:Name="Root"
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Flash">
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="WHAT GOES HERE TO TARGET THE BORDERBRUSH SET PREVIOUSLY ABOVE" Storyboard.TargetProperty="(BorderBrush).(SolidColorBrush.Color)" Duration="0:0:1">
how to set a Storyboard.TargetName to the control that is being styled ?
It seems like you want to animate the <Setter> which property is BorderBrush. Actually when a Style is used to define a control template, the TargetType of the Style element and the TargetType of the ControlTemplate element for its Control.Template setter should always use the same value.Details please reference Styles and templates section of Setter class.
For example, the BorderBrush property you can find it in Grid control which named Root inside the AppBarButton styles and templates.
<Grid
x:Name="Root"
MinWidth="{TemplateBinding MinWidth}"
MaxWidth="{TemplateBinding MaxWidth}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
So that you can met your requierements by setting the Storyboard.TargetName to Root element for the color animation here.
<VisualState x:Name="Normal">
<Storyboard>
<ColorAnimationUsingKeyFrames
Storyboard.TargetName="Root"
Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)"
Duration="0:0:5">
<LinearColorKeyFrame KeyTime="00:00:02" Value="Blue" />
<DiscreteColorKeyFrame KeyTime="00:00:2.5" Value="Yellow" />
</ColorAnimationUsingKeyFrames>
<PointerUpThemeAnimation Storyboard.TargetName="OverflowTextLabel" />
</Storyboard>
</VisualState>

XAML Windows Phone 8.1 Button should change backgroundImage

I know this kind of question have been asked a lot. But I couldn't solve it by my own.
The challenge to achieve is a simple button without any styling except a changing background image for several states (default, pressed and hover).
The code I've done so far is in my App.xaml file:
<Style x:Key="likeActionButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="HoverBackground"
Storyboard.TargetProperty = "Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="PressedBackground"
Storyboard.TargetProperty = "Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border>
<Grid>
<Image Source="Assets/ActionsIcons/like-action.png"></Image>
<Image x:Name="HoverBackground" Source="Assets/ActionsIcons/like-action-onHover.png" Visibility="Collapsed"></Image>
<Image x:Name="PressedBackground" Source="Assets/ActionsIcons/like-action-on-pressed.png" Visibility="Collapsed"></Image>
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
[Calling the button style from somewhere]
<Button Style="{StaticResource likeActionButton}"/>
So this XAML code seems to do nothing because there is no image at all..
Cheers,
Chris
It looks like an initial slash is needed to accurately path the location of the image because the image is not relative to the current xaml path.
Change
Source="Assets/ActionsIcons/like-action-on-pressed.png"
to the root of the package with
Source="/Assets/ActionsIcons/like-action-on-pressed.png"
It does not look likes these are dynamic databound images. Dynamic images need ms-appx:/// because they are not declared in xaml and need a special nomenclature to be properly pathed.
I believe the advice to add ms-appx:/// works because it is providing a proper path which can be resolved, but is superfluous if a / is just added to the path.
For a better understanding read How to load file resources (XAML) (Windows)

Is it possible to style BorderThickness of RadioButton?

I'd like to change the BorderThickness of a RadioButton. Is this possible?
This is what I've got so far:
<Style TargetType="RadioButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderThickness" Storyboard.TargetName="Border">
<DiscreteObjectKeyFrame KeyTime="0" Value="6" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<!-- ... -->
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I read this post but somehow it's not working for me because:
The name "ThicknessAnimation" does not exist in the namespace "http://schemas.microsoft.com/client/2007"
Any ideas?
To answer your question: yes, it is possible to style the BorderThickness of the RadioButton control.
In what context do you want to change the BorderThickness?
In order to have one particular button show a thicker border just set the property accordingly:
<RadioButton x:Name="MyNiceFoobarButton" BorderThickness="6"/>
If you want all your RadioButtons to have a thicker border you have to use a Style:
<Style TargetType="RadioButton">
<Setter Property="BorderThickness" Value="6"/>
</Style>
[Edit]
And if you want your button to show a thicker border only while a paticular VisualState is active you have to overwrite the ControlTemplate and specify all VisualStates with their corresponding animations.

Windows Store Apps: change the background of GridViewItem on PointerOver

I have a gridview thats' bound to the following model
class Item
{
string Title;
string ImagePath
string ImagePathPressed;
}
where ImagePath & ImagePathPressed are paths to images within the app.
now I want my grid View Item to change it's background when the mouse is over from the value in ImagePath to that in ImagePathPressed
how to achive this ?
it would be better if you make these variables as properties and also implement INotifyPropertyChanged on your class. And on your mouseOver event of gridView change the ImagePath to that of ImagePathPressed it will reflect the change in ImagePath.i think on your mouseover event you can get the on which item is your mouse pointer reside.
Following this link to get guideline to implement Style for GridViewItem
http://msdn.microsoft.com/en-us/library/windows/apps/jj709915.aspx
You should implement your class members as Bindable Properties then implement PointerOver state as guideline in above link.
I suggest that you should create two images (one for normal state and other one for hover state)
For example:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewItem">
<Border x:Name="OuterContainer">
<Grid>
<Image x:Name="NormalImage" Source="{Binding ImagePath}"/>
<Image x:Name="PressImage" Source="{Binding ImagePathPressed}" Opacity="0"/>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="PressImage"
Storyboard.TargetProperty="Opacity"
Duration="0"
To="1" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">...
OK, I got it
I implemented a control template like this:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewItem">
<Border x:Name="OuterContainer" Tag={Binding}>
<Border.Resources>
<!-- Define brush resources for both states-->
<ImageBrush x:Key="MouseOverBrush" ImageSource="{Binding Tag.ImagePathPressed, ElementName=OuterContainer}" Stretch="None" />
<ImageBrush x:Key="DefaultBrush" ImageSource="{Binding Tag.ImagePath, ElementName=OuterContainer}" Stretch="None" />
</Border.Resources>
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ReorderHintContent" >
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource MouseOverBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
.
.
.
<Grid x:Name="ReorderHintContent" Tag="{Binding}" DataContext="{Binding}" >
<Grid.Background>
<!-- Default background-->
<ImageBrush x:Name="BGBrush" ImageSource="{Binding Tag.ImagePath, ElementName=ReorderHintContent}" Stretch="None" Opacity="0" />
</Grid.Background>
I had to set the Tag for both the border and the Grid in order to have access to the properties of the model

Windows Phone 7 - Setting style for specific control within selected ListBoxItem

let's say i have something like this:
<Grid>
<ListBox x:Name="list"
ItemsSource="{Binding SomeCollection, Mode=TwoWay}"
SelectedItem="{Binding SomeItem, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="first" Text="{Binding SomeProperty}" />
<TextBlock x:Name="second" Text="{Binding OtherProperty}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Now, how do i alter some style property (f.ex. FontSize) of only the TextBlock called "second" when a ListBoxItem gets selected? If i'd like to set the FontSize for all ListBoxItem's contents, then i'd have no problem. That scenario is quite well documented here and elsewhere on the web.
I will not give you an exact solution, but a good point to start with: check out the file
C:\Program Files\Microsoft SDKs\Windows Phone\vX.Y\Design\System.Windows.xaml
you have to adjust X.Y to 7.0/7.1 along with your setup. There you will find exactly the same Control-Templates that are being used all the basic UI Controls of the WP7/Silverlight. Open it in VisualStudio-or-whateverelse and search for:
<Style TargetType="ListBoxItem">
(... and immediatelly following ~40 lines of xaml)
ah well, since I've opened that file, here's that
<!--x:Key="PhoneListBoxItem"-->
<Style TargetType="ListBoxItem">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Padding" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="LayoutRoot" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver" />
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TransparentBrush}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="ContentContainer" Storyboard.TargetProperty="Opacity" Duration="0" To=".5" />
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected"/>
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentContainer" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneAccentBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentControl x:Name="ContentContainer" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" Foreground="{TemplateBinding Foreground}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This is the complete style for your DEFAULT ListBoxItem - the thing you want to alter. Skim through the code and note the 'ContentPresenter' and preceding 'VisualStateGroup x:Name="SelectionStates"'.
ContentPresenter is the thing that will show your DataTemplate for the item.
VisualStates in that group define the changes from the normal state that should occur if a "selected state" is fired of on an list element.
Once the "selection state" diminishes, the element returns to the unselected state automatically and his visuals follow. Note also that the Unselected visual state does not enforce any changes - so it preserves your plain DataTemplate style.
The last thing to notice is that this is a style for ListBoxItem, and not for your data-item, nor your data-template. Your DataTemplate is never touched, it is directly displayed by the ContentPresenter. The ListBox wraps all your items in "ListBoxItem" instances, then displays those ListBoxItems and applies that style to them.
IMHO, this is the point you will have to work with.
You may want to copy&alter this style to your needs, and then set your ListBox.ItemContainerStyle to that new style. One of the ways is:
<YourPage.Resources>
<Style x:Key="mylistboxitemoverride" .....
........
</Style>
</YourPage.Resources>
...
...
<ListBox ......... ItemContainerStyle="{StaticResource mylistboxitemoverride}"
...
...
</ListBox>
Now, the trick is to modify the 'Selected' VisualState, and make it alter not the Foreground (doing that would restyle both your TextBoxes!), but some other property which will affect only one of your txbs. Unfortunatelly, that may be harder/uglier. I don't at that moment any idea how to make it "prettier" than hard-replacing the ContentPresenter with your DataTemplate and referencing your exact leaf-textbox in the VisualState like that:
<Style .... TargetType="ListBoxItem">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Padding" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="LayoutRoot" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver" />
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TransparentBrush}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="SECOND" Storyboard.TargetProperty="Opacity" Duration="0" To=".5" /> <!-- #### RETARGETTED -->
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected"/>
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SECOND" Storyboard.TargetProperty="Foreground"> <!-- #### RETARGETTED -->
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneAccentBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<!-- #### INLINED YOUR DATATEMPLATE -->
<StackPanel Orientation="Vertical"
Margin="{TemplateBinding Padding}"
DataContext="{TemplateBinding Content}"> <!-- #### careful with the bindings. the DataCtx may be needed or is spurious. do check that! -->
<TextBlock Text="{Binding SomeProperty}" /> <!-- #### referenced from nowhere, so I removed the name -->
<TextBlock x:Name="SECOND" Text="{Binding OtherProperty}" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This should be almost what you want, or at least very close to it. I have not tested it, you may need to tinker with proper data-binding (I've included a DataContent=binding:Content, but that's a quick guess) and probably you will want to add your own animations. I think you have now tons of bits to experiment with. Have fun!
Set the Style on the TextBlock to a Style that does what you want.
<DataTemplate>
<TextBlock x:Name="first" Style="{StaticResource Header}" Text="{Binding SomeProperty}" />
<TextBlock x:Name="second" Style="{StaticResource Info}" Text="{Binding OtherProperty}" />
</DataTemplate>
one way to achieve this is, create an extended ListBox class with a SecondText dependency property in it. Then just use Blend to generate a normal ListBox style, change the targat type to my ExtendedListBox.
In this style, add another TextBlock control and set its Text TemplateBinding to the SecondText. You just need to alter this TextBlock's font size in the selected visual state.
Also, rather than extending the ListBox, you might be able to create an attached property SecondText and just TemplateBinding to it directly, but I haven't tested this method yet.
Hope this can get you started with. :)