Darken element background on hover - xaml

I do not want to define a color and style for every button on hover or PointerOver. I want to darken any element by say 20% or I’d be fine with an overlay that is say black with an opacity on it. I’ve looked into VisualStates on a ControlTemplate and also using reveal highlight, reveal focus, and acrylics but have not been able to get this to work. Do UWP not allow for this? I’d be fine having this in XAML or C# code. Can someone point me in the right direction or show an example from their project that does similar to what I’m looking to do? In my code below I have removed the default pointer over visual state because it looks terrible. Thanks.
<ControlTemplate x:Key="DefaultButtonControlTemplate" TargetType="Button">
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="PointerOver"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter
x:Name="ContentPresenter"
AutomationProperties.AccessibilityView="Raw"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}"
Content="{TemplateBinding Content}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
Padding="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
TextWrapping="WrapWholeWords"/>
</Grid>
</ControlTemplate>

I want to darken any element by say 20% or I’d be fine with an overlay that is say black with an opacity on it.
I'm afraid you can't specify style for each element, In general, we need edit PointerOver VisualState change the matched part to darken the element, but it can't apply to all the elements, Currently, modify the style to change PointerOver state is only way that we can approach.

UWP allows this. However you are not using UWP but rather Xamarin.Forms. UWP is only your compilation target, the user interface capabilities of your Xamarin project are limited by Xamarin.Forms capabilities.
The only way to achieve that in Xamarin.Forms would be to write a custom renderer for UWP.

Related

Did ScrollViewer change between 8.1 and 10?

I have a Windows 8.1 Store app I am moving to 10 as a Universal app. On 8.1 it works fine. On 10 (both Windows and Phone) it will not scroll. You can see a viewport worth of entries, but it stubbornly refuses to show a scrollbar on mouseover, move if you drag with your finger on a touch screen, scroll when I use the down arrow key to move from item to item, or respond to mouse wheel if there's a mouse - all of which the 8.1 version does.
Has something happened between 8.1 and 10 that might cause this?
There are a number of ScrollViewers in the system and they all do this. Here is one, implicitly on a gridview:
<GridView
x:Name="itemListViewSnapped"
AutomationProperties.AutomationId="ItemListView"
AutomationProperties.Name="Grouped Items"
Grid.Row="5"
Margin="20,5,10,0"
Padding="10,0,0,60"
Background="{StaticResource TimeBucketsSections}"
ItemsSource="{Binding Source={StaticResource ItemsViewSource}}"
ItemTemplate="{StaticResource Bucket80ItemTemplate}"
SelectionMode="Single"
SelectedItem="{Binding SelectedBucketViewModel}"
SelectionChanged="ItemGridViewSelectionChanged"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
Visibility="{Binding BucketsVisable}"
ScrollViewer.HorizontalScrollMode="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Enabled"
ScrollViewer.BringIntoViewOnFocusChange="False">
I'm leaving all the binding and background and whatnot in there on the offchance they're relevant. The ScrollViewer. parts are what matter, imo.
Not sure this will help but I have had issues with ScrollViewer when in a GridView. I usually wrap the element in a ScrollViewer and turn the one in the GridView off for more stable behaviour.
<ScrollViewer ScrollViewer.HorizontalScrollMode="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Enabled">
<GridView ScrollViewer.HorizontalScrollMode="Disabled"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollMode="Disabled">
</GridView>
</ScrollViewer>

Strange behaviour of combobox in WinRT

Comboboxes in WinRT have a default ItemsPanel of type CarouselPanel. This gives Windows 8.1 apps an "infinite loop" when scrolling combobox items.
If you don't want this behaviour, there are a lot of blog posts explaining how to "fix it".
For example this: Cancel WinRT ComboBox infinte scroll effect
or: http://netitude.bc3tech.net/2013/04/12/windows-8s-combobox-and-the-carouselpanel/
The problem with this solution is that you get a weird behaviour on the first item in the combobox.
How to reproduce:
Create a new blank Windows 8.1 app
In mainpage.xaml put:
<TimePicker Time="0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
Create a style.xaml resource dictionary like this:
<Style TargetType="ComboBox">
<Style.Setters>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Now start the app, select an item down the list (for example '05' minutes), then select the first item in the same dropdown (for example '00' minutes). The text in the dropdown control will now disappear.
Anyone know how to fix this? If I change the style of combobox itemspanel back to CarouselPanel it works (but with the infinite loop of course).
Just corrected this issue using a VirtualizingStackPanel in place of a StackPanel.
We had to set a size cause otherthise it take all the width of the screen.
<VirtualizingStackPanel HorizontalAlignment="Center" Width="150"/>
We didn't try to get a more flexible solution because we don't need it yet
Hope it will help you
StackPanel just not working with ComoboBox the possible solution is changing it to VirtualizingStackPanel, but you must bind with to the parent, otherthise it will stretch to screen width.
<ComboBox Name="ReasonComboBox"">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Width="{Binding ActualWidth, ElementName=ReasonComboBox}"/>
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>

How to rearrange WrapGrid contents when zoom level changes?

I am developing a Windows 8 Metro application whose layout is pretty simple. It consists of a single page with a WrapGrid enclosed in an ItemsControl, which is in turn enclosed in a ScrollViewer. This is the XAML code of the application main page:
<Page ...>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="MainGrid" Margin="120,140,32,0">
<ScrollViewer x:Name="ScrollView"
VerticalScrollBarVisibility="Auto"
HorizontalAlignment="Stretch">
<ItemsControl x:Name="itemsControl" HorizontalAlignment="Stretch">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal"
HorizontalChildrenAlignment="Stretch"
Margin="0"
HorizontalAlignment="Center">
<WrapGrid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition />
<RepositionThemeTransition />
</TransitionCollection>
</WrapGrid.ChildrenTransitions>
</WrapGrid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</Grid>
<Page.BottomAppBar>
...
</Page.BottomAppBar>
</Page>
There is also an user control of which new instances are created and added to the ItemsControl programmatically when the user clicks on a certain button in the application bar. As expected by the fact of using a WrapGrid, the control instances are stacked sequentially in a single row until there is no more room in the screen, at which point they appear in a new row and it is necessary to scroll down in order to see them. So far so good.
Now I want to implement a feature and I don't know how to achieve it. What I want is the following: when the user zooms out in the application, causing the controls to appear smaller, I want the new available space to be used so that more controls can be displayed per row; instead, the current behavior is that the ItemsControl itself is reduced and the extra surrounding space is unused.
For example, imagine that the user adds 10 controls. There is room for 4 controls in one row, so that 3 rows of controls are displayed, with 4, 4 and 2 controls. If the user zooms out and now there is room for 7 controls in a row, I want the ItemsControl to rearrange itself so that now there are only two rows with 7 and 3 controls. How could I achieve this?
I hope I have explained myself properly. Please don't hesitate to ask if my question is not clear enough. Thank you very much!

Performance with XAML binding one value to many elements in GridView (Windows 8)

I have a Windows 8 XAML page with a grid in it that shows sample text in 100+ different fonts. The sample text is the same in each grid view item and can be changed using a textbox at the top of the page.
Every time you type a character all the grid view items are updated. The problem is that this is noticeably slow. Particularly if you type quickly.
I'm not sure what is making it so slow. Is it updating all the grid view items including the ones not on screen? Is something else causing the problem and this particular binding is just a red herring?
Here is my binding code (I've removed some xaml from my data template to make it clearer):
<ScrollViewer>
<GridView x:Name="FontGridView" ItemsSource="{Binding Fonts}" SelectionMode="Multiple" Margin="116,0,40,46">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="600" MinHeight="100" MaxHeight="120">
<TextBox Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText, Mode=OneWay}"
FontFamily="{Binding FamilyName}" FontSize="32" Background="Transparent" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</ScrollViewer>
Is there a better way to do this, or are there any other performance tuning things I can turn on?
UPDATE: You're less likely to make this mistake since Visual Studio 2012 RC came out. The templates for WinRT apps no longer use a ScrollViewer in this way. I'm keeping the question here for those that have ported apps they created using Visual Studio 2011.
Try removing the ScrollViewer.
Because the GridView is inside a scrollviewer, it is effectively given an infinite width. That might kill the virtualization of the WrapGrid in the GridView.
Furthermore, the GridView internally contains a ScrollViewer already. Obviously, you don't need two of them. But the inner ScrollViewer will also eat mouse wheel events, leaving no events for the outer ScrollViewer to react to. As a result scrolling with the mouse will not work.
Visual Studio 11 (bèta 1) templates contain code like this, to set a margin on the GridView. However, it's better to set a margin on the GridView's ItemsPanel, like this:
<GridView x:Name="FontGridView" ItemsSource="{Binding Fonts}" SelectionMode="Multiple">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="600" MinHeight="100" MaxHeight="120">
<TextBox Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText, Mode=OneWay}"
FontFamily="{Binding FamilyName}" FontSize="32" Background="Transparent" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid x:Name="itemGridViewPanel" Margin="116,53,116,46"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
Your original code did not include the Margin that you set on the GridView. But whatever it was, set the same Margin on the WrapGrid.
Notice also that I gave the WrapGrid a name. You can use that name to change the Margin when the screen orientation changes, typically as follows:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="FullScreenLandscape"/>
<VisualState x:Name="Filled"/>
<VisualState x:Name="FullScreenPortrait">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridViewPanel"
Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0"
Value="96,53,96,46"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Snapped"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
UPDATE:
I had done this before, but with a VariableSizedWrapGrid. That produces the correct layout, but unfortunately, I'm afraid that VariableSizedWrapGrid is not a virtualizing panel.
WrapGrid is virtualizing, but the behavior at the left margin seems wrong when scrolling. It is correct at the right margin though.
Oh well, in two weeks time we should have the release candidate available. Hopefully things will have improved...
UPDATE:
It seems that Microsoft is aware of this. See http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/17385f7d-aadc-4edc-bbff-8738a2f0c917.
UPDATE:
It seems that the WrapGrid has not been fixed in the Release Candidate.
Simplify your data template.
<DataTemplate>
<TextBlock Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText}"
Width="600" MinHeight="100" MaxHeight="120"
FontFamily="{Binding FamilyName}" FontSize="32" />
</DataTemplate>
You don't need the Grid. And it looks like you don't need a (complex) TextBox either, just a (simple) TextBlock.
Also, fixing the height of those text blocks (Height="120") might help (optimize) the layout process.
UPDATE:
I understand you're code is simplified from "the real thing". But that might hide the real problem for us. Remember, the data template is intantiated for every item that is on screen. The more complex it is, the more objects need to be instantiated (CPU and memory usage), possibly need to databind (CPU), need to be measured and laid out (CPU), and need to be rendered (CPU and GPU).
Just do a test with a very simple data template. If your program is faster now, or not, you know whether the data template is the performance problem or not.
Note that the complexity of the data template is not measured by the number of xaml elements you need to describe it, as those elements may have very different internal complexities. For example, do prefer a TextBlock over a TextBox if all you need to do is display text, not allow editing.
Also, if some of these elements have a lot of properties set, do use styles to set them. Using a style on many objects is more efficient than setting many properties on many objects, especially when it come to memory usage. And the less memory you use, the faster your program will be (due to modern CPU multilevel caching architectures).
For example:
<GridView x:Name="FontGridView" ItemsSource="{Binding Fonts}" SelectionMode="Multiple">
<GridView.Resources>
<Style TargetType="TextBlock">
<Setter Property="Width" Value="600" />
<Setter Property="MinHeight" Value="100" />
<Setter Property="MaxHeight" Value="120" />
<Setter Property="FontSize" Value="32" />
</Style>
</GridView.Resources>
<GridView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ElementName=pageRoot, Path=DataContext.SampleText}"
FontFamily="{Binding FamilyName}" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Try using a VirtualizingStackPanel
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>

Using Blend to set a Timer on an ActionState/Transition with Silverlight 4

I'm a developer who has recently downloaded the trial of Blend and I am trying to get to grips with not using CodeBehind to do stuff - it's very cool but it has quite a learning curve!
I started off with these tuts here and implemented some simple animation on the menu as per the example on my poker blind timer. What I want to do now is to make the menu transition only start after 20 seconds - ie. so that the menu on the left that disappears on MouseLeave (see link above) - only does so 20 seconds after the mouse has left (and cancels if they MouseOver again). This will make the menu stay longer in case they mouse off by accident.
I am sure it is really simple in Blend but I am battling to find any decent documentation - I'll happily RTFM - I just need to know where to start looking (I googled "Blend timer stateaction" with no joy).
Thanks for any tips!
If I understand your problem correctly:
When you get a Mouse Enter event over your side menu, it animates out (e.g. a "ShowMenuStoryboard") .
You then want a "HideMenuStoryboard" to slide the menu back off, but only commence it's changes 20 seconds after it is triggered (by the MouseLeave event) but it needs to be cancelled if a subsequent Mouse Enter event fires.
you want to do all this with no code-behind logic.
There are 2 things to do.
Make sure your storyboards only specify the end state values (no starting states) and
You just need to set BeginTime="0:0:20" in the XAML for the HideStoryboard e.g.
<Storyboard x:Name="HideMenuStoryboard" BeginTime="0:0:20">
I have not found a property anywhere for BeginTime in the Expression blend editor, so this has to be done in the XAML view. The properties shows only AutoReverse and RepeatBehavior.
There is an inherent problem with this kind of animation, but should be OK for your example. The time duration is fixed, so if you trigger the opposite animation while one is commencing it will actually animate more slowly to it's final position as it takes a fixed time to go "from where it currently is" to the final position.
Hope this helps. The complete sample MainPage.XAML with memu menu is below. It only requires the 2 storyboards and Storyboard control behaviors:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
x:Class="SilverlightApplication1.MainPage"
mc:Ignorable="d">
<UserControl.Resources>
<Storyboard x:Name="ShowMenuStoryboard">
<DoubleAnimation Duration="0:0:0.5" To="0" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="stackPanel" d:IsOptimized="True"/>
</Storyboard>
<Storyboard x:Name="HideMenuStoryboard" BeginTime="0:0:20">
<DoubleAnimation Duration="0:0:0.5" To="-100" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="stackPanel" d:IsOptimized="True"/>
</Storyboard>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel x:Name="stackPanel" HorizontalAlignment="Left" Orientation="Vertical" Width="150" d:LayoutOverrides="Height" RenderTransformOrigin="0.5,0.5" Background="#FF646CE7">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeave">
<ei:ControlStoryboardAction Storyboard="{StaticResource HideMenuStoryboard}"/>
</i:EventTrigger>
<i:EventTrigger EventName="MouseEnter">
<ei:ControlStoryboardAction Storyboard="{StaticResource ShowMenuStoryboard}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<StackPanel.RenderTransform>
<CompositeTransform TranslateX="-100"/>
</StackPanel.RenderTransform>
<StackPanel.Projection>
<PlaneProjection/>
</StackPanel.Projection>
<TextBlock TextWrapping="Wrap" Text="TextBlock"/>
<TextBlock TextWrapping="Wrap" Text="TextBlock"/>
<TextBlock TextWrapping="Wrap" Text="TextBlock"/>
<TextBlock TextWrapping="Wrap" Text="TextBlock"/>
<TextBlock TextWrapping="Wrap" Text="TextBlock"/>
</StackPanel>
</Grid>
</UserControl>
You can add a 'fake' story board, that serves as a trigger for the second animation.
You will need two story boards. Fake and HideMenu.
You need to ControlStoryboardActions to start each of them.
The first one will have an event trigger (the Mouse out).
The first one will have a StoryboardCompleterTrigger linked to the 'fake' animation.