UWP Change Grid.HorizontalAlignment to stretch/left using VisualStateManager - xaml

I'm having trouble getting the visual state manager to correctly change the HorizontalAlignment/VerticleAlignment of the main grid of my application.
For screen sizes that would be used on phone, I want the HorizontalAlignment/ VerticleAlignment to stretch, with Height/Width set to Auto.
For Desktop it should be Left/Top with Height/Width set to a specific size. For whatever reason when I try to mess with the alignment it acts quirky and does not do what I want
Here is an example of what I have tried:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="PhoneView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Grid.HorizontalAlignment" Value="Stretch"/>
<Setter Target="Grid.VerticleAlignment" Value="Stretch"/>
<Setter Target="Grid.Height" Value="Auto"/>
<Setter Target="Grid.Width" Value="Auto"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="DesktopSmall">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1920"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Grid.HorizontalAlignment" Value="Left"/>
<Setter Target="Grid.VerticleAlignment" Value="Top"/>
<Setter Target="Grid.Height" Value="1280"/>
<Setter Target="Grid.Width" Value="1920"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Another issue is when I try to set the max resolution to 1920x1280, if I manually set the height/width of the Grid, the Windows TaskBar (the OS taskbar, not the applications app bar/command bar) cuts off part of my application. I don't want to set the alignments to stretch, because I'm trying to limit the real time stretching of the view.
Thanks! Let me know if more details are needed.

It should write like this -
<Setter Target="Container.(Grid.HorizontalAlignment)" Value="Left" />
<Setter Target="Container.(Grid.VerticalAlignment)" Value="Top" />
I have some tips here for creating visual state setters without writing a single line of code.

Related

Rider Xamarin xaml: "Field Normal is already declared" from VisualStateManager

I'm using Xamarin Forms 4.5.0.617 and want to use a VisualStateManager (https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/visual-state-manager) to change the style if an element is disabled. To apply this to all my styles, I have to use the x:Name="Normal" or "Disabled" or "Focused" multiple times, but Rider (https://www.jetbrains.com/de-de/rider/) says error
The app runs correctly (style is changing) but the warning of rider is still annoying.
Am I doing something wrong?
<?xml version="1.0" encoding="utf-8"?>
<Application
x:Class="ProjectApp.App"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:components="clr-namespace:Project.Components"
xmlns:converters="clr-namespace:Project.Converters"
xmlns:helpers="clr-namespace:Project.Helpers"
xmlns:iconize="clr-namespace:Plugin.Iconize;assembly=Plugin.Iconize">
<Application.Resources>
<ResourceDictionary>
<!-- Text -->
<Style
x:Key="Label"
TargetType="Label">
<Setter
Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup>
<VisualState
x:Name="Normal">
<VisualState.Setters>
<Setter
Property="TextColor"
Value="Black" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Disabled">
<VisualState.Setters>
<Setter
Property="TextColor"
Value="Gray" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Focused">
<VisualState.Setters>
<Setter
Property="TextColor"
Value="{StaticResource Primary}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
<!-- Picker -->
<Style
x:Key="Picker"
TargetType="Picker">
<Setter
Property="FontSize"
Value="14" />
<Setter
Property="TextColor"
Value="Black" />
<Setter
Property="VerticalOptions"
Value="Center" />
<Setter
Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup>
<VisualState
x:Name="Normal">
<VisualState.Setters>
<Setter
Property="TextColor"
Value="Black" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Disabled">
<VisualState.Setters>
<Setter
Property="TextColor"
Value="Gray" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Focused">
<VisualState.Setters>
<Setter
Property="TextColor"
Value="{StaticResource Primary}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
You are not doing anything wrong. This is a confirmed known issue with Rider/ReSharper. I have already reported it here.
What I can suggest is that you upvote the issue and/or write a comment, so that they can escalate it and fix it quickly.

Xamarin ImageButton states

I am trying to create an ImageButton that uses a different image for the normal (unpressed) state and the state where the user is actively pressing the button. I found an article that uses a VisualStateGroup to change the appearance of the button based on the state:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/imagebutton#imagebutton-visual-states
I am able to successfully use this to change the image. However, if I set a different image for the 'Pressed' state, when I click on the button, it does change to the new image as expected, but when I release the button it's visual state continues to display the pressed image and does not return to the 'Normal' state until I click somewhere else in the window. The XAML I am using to set the states is as follows:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="Scale"
Value="1" />
<Setter Property="Source" Value="Assets/changeuser.png" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="Scale"
Value="0.8" />
<Setter Property="Source" Value="Assets/changeuser_highlight.png" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Does anyone know how to make this work? Is there a different state than 'Pressed' that I should be using. Is there some other way to do this?
Thanks.
You can use Released to return the initial image.
For me it worked.
<VisualState x:Name="Released">
<VisualState.Setters>
<Setter Property="Scale"
Value="1" />
<Setter Property="Source"
Value="Assets/changeuser.png" />
</VisualState.Setters>
</VisualState>

How to set the color for RatingControl stars in UWP?

I have added a RatingControl in my UWP application. How can I set the color for filled and empty stars? Here is the code that I have added:
<RatingControl x:Name="MyRating" Value="3.5" Width="300" Height="200" />
If you check the default style of the RatingControl, you can find the following VisualStateGroup:
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="ForegroundContentPresenter.Foreground"
Value="{ThemeResource RatingControlDisabledSelectedForeground}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Placeholder">
<VisualState.Setters>
<Setter Target="ForegroundContentPresenter.Foreground"
Value="{ThemeResource RatingControlPlaceholderForeground}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOverPlaceholder">
<VisualState.Setters>
<Setter Target="ForegroundContentPresenter.Foreground"
Value="{ThemeResource RatingControlPointerOverPlaceholderForeground}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOverUnselected">
<VisualState.Setters>
<Setter Target="ForegroundContentPresenter.Foreground"
Value="{ThemeResource RatingControlPointerOverUnselectedForeground}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Set">
<VisualState.Setters>
<Setter Target="ForegroundContentPresenter.Foreground"
Value="{ThemeResource RatingControlSelectedForeground}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOverSet">
<VisualState.Setters>
<Setter Target="ForegroundContentPresenter.Foreground"
Value="{ThemeResource RatingControlSelectedForeground}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
As you can see, the colors are based on resources like RatingControlSelectedForeground, RatingControlPointerOverUnselectedForeground etc.
You can either provide your custom overrides for these as separate resources, or you can edit the style of the control.
Note - empty stars color
Although it is not part of the template, you can customize empty stars color by modifying the RatingControlUnselectedForeground resource.
Resource overrides
You can override the resources on the level of a single rating control, any parent or on the application level.
Override on RatingControl level will apply only to this single RatingControl:
<RatingControl x:Name="MyRating" Value="3.5" Width="300" Height="200" >
<RatingControl.Resources>
<SolidColorBrush x:Key="RatingControlSelectedForeground" Color="Red" />
<SolidColorBrush Color="Blue" x:Key="RatingControlUnselectedForeground" />
</RatingControl.Resources>
</RatingControl>
You can do the override on any parent, like on the page:
<Page.Resources>
<SolidColorBrush x:Key="RatingControlSelectedForeground" Color="Red" />
<SolidColorBrush Color="Blue" x:Key="RatingControlUnselectedForeground" />
</Page.Resources>
Or finally you can put it on application level if you add it in <Application.Resources> in App.xaml. Then it will apply to any RatingControl in the app.
Alternative solution - Custom style
If you want more control and even better customization, you can directly edit the default RatingControl style and its template.
Right-click the RatingControl in Designer (or in Document Outline window) and select Edit style, then Edit a copy, set a custom name and location where the style should be placed and confirm with OK. This will create a copy of the default template of the control, where you can edit the VisualState Setter values to match your desired color scheme.
Also note, that you will still have to provide a custom resource for the empty stars (RatingControlUnselectedForeground).

How to set ScrollViewer Width bound to a page element ActualWidth in AdaptiveTrigger UWP

I have a ScrollViewer which Width property binds to another page element. I want to apply this only on certain AdaptiveTrigger MinWindowWidth
<ScrollViewer x:Name="scrollViewerEditor" Width="{Binding ElementName=stackPanelSearch, Path=ActualWidth}">
...
</ScrollViewer>
I want to place the Width binding in AdaptiveTrigger like the following. What's the proper way to do it?
<VisualState x:Name="VisualStateWide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource WideMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="scrollViewerEditor.(FrameworkElement.Width)" Value="Binding ElementName=stackPanelSearch, Path=ActualWidth}" />
If you don't mind to do this work in the code behind, there is an easy way to solve this problem, using the VisualStateGroup.CurrentStateChanged event for example like this:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup CurrentStateChanged="VisualStateGroup_CurrentStateChanged">
<VisualState x:Name="VisualStateNarrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="scrollViewerEditor.Style" Value="{StaticResource ScrollViewerStyle1}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateWide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="scrollViewerEditor.Style" Value="{StaticResource ScrollViewerStyle2}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
In code behind:
private void VisualStateGroup_CurrentStateChanged(object sender, VisualStateChangedEventArgs e)
{
var state = e.NewState;
if (state.Name == "VisualStateNarrow")
{
scrollViewerEditor.Width = 300;
}
else
{
if (tb.ActualWidth != 0)
scrollViewerEditor.Width = tb.ActualWidth;
else
scrollViewerEditor.Width = 600;
}
}
It is not allowed to use data binding in Setter, usually the right way to solve this problem is to create a custom AttachedProperty for your ScrollViewer and bind this attached Property to the WidthProperty, but the support for custom attached property inside the VisualState is not quite ideal, I will keep researching on this and see if it works with custom AttachedProperty.

Is it possible to scale a control in a VisualState

Using MinWindowWidth in an AdaptiveTrigger I am able change the background color but I am unable to apply a scale transform.
<VisualState x:Name="NarrowState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0"
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="hsCards.(Control.Background)">
<Setter.Value>
<SolidColorBrush Color="Green"/>
</Setter.Value>
</Setter>
<Setter Target="hubFlashCards.(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Value="0.8"/>
<Setter Target="hubFlashCards.(UIElement.RenderTransform).(CompositeTransform.ScaleY)" Value="0.8"/>
</VisualState.Setters>
</VisualState>
Not only does the scaling not work but the background Setter does not either. If I remove the scale transform the background Setter works fine.
Am I doing something wrong or is it not possible to use the RenderTransform in this way?
In this case I would assign x:Name straight to the CompositeTrasform element. And then the Visual state:
<VisualState x:Name="NarrowState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0">
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="hsCards.Background">
<Setter.Value>
<SolidColorBrush Color="Green"/>
</Setter.Value>
</Setter>
<Setter Target="yourComposite1.ScaleX" Value="0.8"/>
<Setter Target="yourComposite1.ScaleY" Value="0.8"/>
</VisualState.Setters>
</VisualState>
I may not be exactly like your solution, but it's the way I use since I started with UWP.