I am trying to change the rowstyle for a datagrid to change the background color when a row is selected(not the row background but the color of the selection rectangle, which by default is a bit too shiny for my application). However the behaviour i'm seeing on applying to style to the grid is that all the rows are getting shrinked together like a folded venetian blind. This is the style that i have written:
<Style x:Key="DataGridRowStyle" TargetType="sdk:DataGridRow">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="sdk:DataGridRow">
<sdk:DataGrid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal Selected">
<Storyboard>
<ColorAnimation
Storyboard.TargetName="ButtonBrush"
Storyboard.TargetProperty="Color"
To="Red" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</sdk:DataGrid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Can someone tell me what's going on here? tbh I havn't really understood how the visual states work and kind of just shooting in the dark.
Thanks
Checking the template for the DataGrid (check here) the background color (that blue) is hard coded in the template. When the row is selected all that happens is that a rectangle becomes visible (Opacity=1). Sadly have to say that you have to re-template the whole DataGridRow... in the provided link you'll find all you might need for this.
In the template look for some code like this:
<Rectangle x:Name="BackgroundRectangle" Grid.RowSpan="2" Grid.ColumnSpan="2" Opacity="0" Fill="#FFBADDE9"/>
Related
When styling controls that have a ContentPresenter (like GridViewItem), and it has a bunch of visual states like Focused, Unfocused, PointerFocused, Disabled etc. Is there a proper way to pass the active visual state down through to the DataTemplate? IOW, is there a nice way for any UI in the DataTemplate to react to the same visual states as its parent (GridViewItem as an example, but would want a solution for any ControlTemplate that uses a ContentPresenter really)? Ex)
<DataTemplate>
<UserControl>
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<!-- These states are copied from the ControlTemplate,
but obviously don't work by default. -->
<VisualState x:Name="Focused" />
<VisualState x:Name="Unfocused" />
<VisualState x:Name="PointerFocused" />
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="foo.Fill" Value="Red" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="foo" />
</Grid>
</UserControl>
</DataTemplate>
My initial naive approach would be to extend ContentPresenter and add a custom property like ActiveVisualState then call VisualStateManager.GoToState((Control)contentPresentorChild, ActiveVisualState, true);. Then use that presenter in the GridViewItem template style (or whatever control I was styling). But I feel like there should be a better, more natural and not so specific, way to achieve this.
We cannot see where you put your ContentPresenter and we also cannot see where you modified your template. So it's not clear what you want.
But if your simply want to modify a property value based on different state. why not just change the status from the setter like this:
<VisualState.Setters>
<Setter Target="NameofYourContentPresenter.(UIElement.Opacity)"
Value="0.5" />
</VisualState.Setters>
For customized property you just need to specify it from your XAML.
In UWP, every time a ListViewItem is selected, a storyboard is triggered to give the user the feeling the component is reacting to the pressure of a touch. That storyboard also changes the ListViewItem's background color until it gets released.
I have designed a UserControl which uses a ListView internally but would like to override this behavior as it doesn't really fit the application's proposed design.
Bellow are the VisualStateGroups I tried to apply both to the ListView through its ControlTemplate and to ListViewItem through its DataTemplate definition as the former attempt failed.
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver" />
<VisualState x:Name="Pressed" />
<VisualState x:Name="PointerOverPressed" />
<VisualState x:Name="Disabled" />
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused" />
<VisualState x:Name="UnFocused" />
<VisualState x:Name="PointerFocused" />
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselecting" />
<VisualState x:Name="Unselected" />
<VisualState x:Name="UnselectedPointerOver" />
<VisualState x:Name="UnselectedSwiping" />
<VisualState x:Name="Selecting" />
<VisualState x:Name="Selected" />
<VisualState x:Name="SelectedSwiping" />
<VisualState x:Name="SelectedUnfocused" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
One possibility could be to bind the root grid of the DataTemplate to the ItemsContainer so that I could override the default behavior every time an item was selected. But I am not that versed in XAML and couldn't figure out the proper way of doing this by myself.
This uses the ListViewItemPresenter as I am sure you have discovered. And, I am sure you have discovered that it is not template-able. The purpose of this more encapsulated approach is purely performance. As a result, items in a ListView are measurably faster to render. However, it does mean that when you want to change it, you are sort of stuck. Does it mean you cannot change it to use your own presenter and unwind the performance improvements? Does it mean you will have a lot of custom code? Yes. Does it means it is not possible? No. Does it mean it is a good idea? Well. I don't know how to answer that one. But, at least you know why it appears to be a brick wall.
It took some time, but in the end it was simpler than expected. I just had to add a ControlTemplate targeting the ListViewItem, which I didn't before as I was stuck fiddling with the ControlTemplate of the ListView.
As we do not declare the ListViewItem directly, the way is to use ListView.ItemContainerStyle. The final result is as follows:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ListViewItemPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
As you can see, an empty ListViewItemPresenter is good enough to override most of the default behavior. I couldn't get rid of the pressing animation, but I'm happy with the current results.
I added a ProgressBar to my application and I wanted it to have a transparent background, so I did it like this:
<ProgressBar IsIndeterminate="True" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<ProgressBar.Background>
<SolidColorBrush Color="Black" Opacity="0.5" />
</ProgressBar.Background>
</ProgressBar>
And in the Preview Window everything looks fine, however, when I run my app, the Background is simply not there. The solution I found to this is to put the ProgressBar in a Grid and set the Background property in the Grid, but since the Preview shows it right, and the property is there, shouldn't it work?
UPDATE:
Based on #Chris W. suggestion, I tried to override the default style of the ProgressBar element, like so:
<ProgressBar IsIndeterminate="True" Background="#FF000000" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="50">
<ProgressBar.Style>
<Style TargetType="ProgressBar">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ProgressBar">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Indeterminate">
<Storyboard RepeatBehavior="Forever">
<DoubleAnimation Storyboard.TargetName="DeterminateRoot"
Storyboard.TargetProperty="Opacity"
To="0.5"
Duration="0" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ProgressBar.Style>
</ProgressBar>
But still, no juice.
Need to get rid of two (2) StoryBoard Animations
Document Outline > Right Click Progress Bar > Edit Template -> Edit A Copy
<!--
<FadeOutThemeAnimation Storyboard.TargetName="DeterminateRoot"/>
<DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="DeterminateRoot"/>
-->
And as #ricochete suggested if using Opacity = 1 change up the Z-Order of DeterminateRoot to be on top of the EllipseGrid
<Border x:Name="DeterminateRoot" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" MinHeight="{TemplateBinding MinHeight}">
<Rectangle x:Name="ProgressBarIndicator" Fill="{TemplateBinding Foreground}" HorizontalAlignment="Left" Margin="{TemplateBinding Padding}"/>
</Border>
<Grid x:Name="EllipseGrid" Opacity="0">
<!-- ... more XAML Style -->
<Grid Background="#FFFF0000">
<ProgressBar IsIndeterminate="True" Style="{StaticResource ProgressBarStyle1}" Height="50" >
<ProgressBar.Background>
<SolidColorBrush Color="Black" Opacity="0.5"/>
</ProgressBar.Background>
</ProgressBar>
</Grid>
If you go look at the default template you'll see at the bottom of the template the Background only has a TemplateBinding in one spot for x:Name="DeterminateRoot" so that's the only place you'd see your color set from the Background property.
Then if you climb up through the Storyboard for the Indeterminate State you'll find;
<DoubleAnimation Storyboard.TargetName="DeterminateRoot"
Storyboard.TargetProperty="Opacity"
To="0"
Duration="0" />
...and you've got your ProgressBar set to IsIndeterminate="True" so you're setting the one place that accepts the Background property to a zero opacity explicitly.
So you could go pull that animation out of the Storyboard for that state, or put in your own new object to set your thing, or just do the workaround you mentioned by just throwing it in a Border or a Grid or something and doing it that way amongst other possibilities.
You might also try (once you've fixed your opacity setting issue from the storyboard) just flipping your SolidColorBrush with Opacity into just pure hex with the Alpha Channel set as 50% opacity equivalent. Making it just;
<ProgressBar Background="#80000000" IsIndeterminate="True" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
Anyhow, hope this helps, Cheers!
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}"
When writing a custom ControlTemplate (XAML) for a Win 8 Metro control we need to use the VisualStateManager to update the control according to VisualState transitions. I see the below sample all over MSDN, but I can't find where the VisualStateGroup "CommonStates" is documented and what other VisualStates are defined other than "PointerOver" and "Normal"? Do you have to go dig in the SDK to find the default ControlTemplate for a button? If so, where?
<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" />
<!--Change the SolidColorBrush, ButtonBrush, to red when the
Pointer is over the button.-->
<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>
You can go to the design view of your xaml file and with the Button control selected - right click/Edit Template/Edit Current - will get you the default template extracted. Normally controls should be annotated with attributes that indicate which visual states should be used in the template like below, but I can't see them when I just navigate to definition of a control like Button.
[TemplateVisualState(GroupName="CommonStates", Name="Normal")]
[TemplateVisualState(GroupName="CommonStates", Name="PointerOver")]