I have two UWP app configurations: Vertical and Horizontal and I dont want to duplicate functional in XAML.
HoriazntalView.xaml:
<Grid>
<!-- some common logic for two pages -->
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<Grid.ColumnDefinitions/>
<CaptureElement x:Name="First" Grid.Column="0" />
<CaptureElement x:Name="Second" Grid.Column="1" />
<!-- some common logic for two pages -->
<Grid/>
VerticalView.xaml:
<Grid>
<!-- some common logic for two pages -->
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<Grid.RowDefinitions/>
<CaptureElement x:Name="First" Grid.Row="0" />
<CaptureElement x:Name="Second" Grid.Row="1" />
<!-- some common logic for two pages -->
<Grid/>
Can I get something like:
View.xaml
<Grid>
<!-- some common logic for two pages -->
<!-- adaptive part -->
<!-- some common logic for two pages -->
<Grid/>
I tried following ways for adaptive part:
Use VisualStateManager with StackPanel
<StackPanel x:Name="PreviewsStack"
Orientation="Vertical">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="HorizontalView">
<VisualState.Setters>
<Setter Target="PreviewsStack.Orientation" Value="Horizontal"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VerticalView">
<VisualState.Setters>
<Setter Target="PreviewsStack.Orientation" Value="Vertical"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<CaptureElement x:Name="First" />
<CaptureElement x:Name="Second"/>
</StackPanel>
Use VisualStateManager with Grid
<Grid x:Name="PreviewsGrid"
Grid.Column="1">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="VerticalView">
<VisualState.Setters>
<Setter Target="FirstPreviewGrid.Grid.Row" Value="0"/>
<Setter Target="FirstPreviewGrid.Grid.ColumnSpan" Value="2"/>
<Setter Target="SecondPreviewGrid.Grid.Row" Value="1"/>
<Setter Target="SecondPreviewGrid.Grid.ColumnSpan" Value="2"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="HorizontalView">
<VisualState.Setters>
<Setter Target="FirstPreviewGrid.Grid.Column" Value="0"/>
<Setter Target="FirstPreviewGrid.Grid.RowSpan" Value="2"/>
<Setter Target="SecondPreviewGrid.Grid.Column" Value="1"/>
<Setter Target="SecondPreviewGrid.Grid.RowSpan" Value="2"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid x:Name="FirstPreviewGrid">
<CaptureElement x:Name="FirstPreview"/>
</Grid>
<Grid x:Name="SecondPreviewGrid">
<CaptureElement x:Name="SecondPreview"/>
</Grid>
</Grid>
Both attempts will be used in code-behind like:
var state = /* condition */
? nameof(VerticalView)
: nameof(HorizontalView);
VisualStateManager.GoToState(this, state, false);
But none of the attempts work.
Can I manage that?
Related
I am running into some issues with styling a radio button in .Net MAUI. Initially, I noticed the the radio button look-and-feel is not consistent across Windows and Android, as can be seen in the image below:
Not only are they different, but the available options for styling the button are limited. The only options for defining colors are "BorderColor", "BackgroundColor", and "TextColor". Both "BorderColor" and "BackgroundColor" have absolutely no effect on the color of the radio button itself. I'd like to change the color of the actual radio button.
So I decided to create a control template to help me out. Here is my control template:
<ControlTemplate x:Key="RadioButtonTemplate">
<Border Stroke="Transparent" BackgroundColor="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup x:Name="CheckedStates">
<VisualState x:Name="Checked">
<VisualState.Setters>
<Setter TargetName="check" Property="Opacity" Value="1" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Unchecked">
<VisualState.Setters>
<Setter TargetName="check" Property="Opacity" Value="0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid WidthRequest="20" HeightRequest="20" Grid.Column="0" VerticalOptions="Center" HorizontalOptions="Center">
<Ellipse x:Name="border_circle" StrokeThickness="2" Stroke="DarkBlue" Fill="White" WidthRequest="18" HeightRequest="18" HorizontalOptions="Center" VerticalOptions="Center" />
<Ellipse x:Name="check" Fill="DarkBlue" WidthRequest="10" HeightRequest="10" HorizontalOptions="Center" VerticalOptions="Center" />
</Grid>
<ContentPresenter Margin="10,0,0,0" Grid.Column="1" HorizontalOptions="Start" VerticalOptions="Center" />
</Grid>
</Border>
</ControlTemplate>
<Style TargetType="RadioButton" x:Key="RadioButtonStyle">
<Setter Property="ControlTemplate" Value="{StaticResource RadioButtonTemplate}" />
</Style>
This worked reasonably well, so now I get the following look-and-feel on both Android and Windows:
Now I have one last problem. When I was using the default radio buttons (without my control template), they would reliably turn a "light gray" color whenever I set IsEnabled to false. I'd like to make it so that I can disable my radio button and have it turn a light gray color (to indicate that it is disabled) while still using my control template so I have a unified look-and-feel.
So I attempted to add a Disabled visual state to my control template, but it doesn't seem to be working. Here is my new control template with a Disabled state:
<ControlTemplate x:Key="RadioButtonTemplate">
<Border Stroke="Transparent" BackgroundColor="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup x:Name="CheckedStates">
<VisualState x:Name="Checked">
<VisualState.Setters>
<Setter TargetName="check" Property="Opacity" Value="1" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Unchecked">
<VisualState.Setters>
<Setter TargetName="check" Property="Opacity" Value="0" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter TargetName="border_circle" Property="Stroke" Value="LightGray" />
<Setter TargetName="check" Property="Fill" Value="LightGray" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid WidthRequest="20" HeightRequest="20" Grid.Column="0" VerticalOptions="Center" HorizontalOptions="Center">
<Ellipse x:Name="border_circle" StrokeThickness="2" Stroke="DarkBlue" Fill="White" WidthRequest="18" HeightRequest="18" HorizontalOptions="Center" VerticalOptions="Center" />
<Ellipse x:Name="check" Fill="DarkBlue" WidthRequest="10" HeightRequest="10" HorizontalOptions="Center" VerticalOptions="Center" />
</Grid>
<ContentPresenter Margin="10,0,0,0" Grid.Column="1" HorizontalOptions="Start" VerticalOptions="Center" />
</Grid>
</Border>
</ControlTemplate>
<Style TargetType="RadioButton" x:Key="RadioButtonStyle">
<Setter Property="ControlTemplate" Value="{StaticResource RadioButtonTemplate}" />
</Style>
Unfortunately, it's not working. Not only does the color not change when the radio button is disabled, but also my 2nd setter (setting the "Fill" property of the "check" object) causes a compile-time error as well ("Cannot resolve property Fill on type Border").
Any suggestions?
I was able to figure out a way to do what I needed to do. Rather than use the "Disabled" visual state in the visual state group, I was able to use style triggers. So now my control template and its corresponding style look like this:
<ControlTemplate x:Key="RadioButtonTemplate">
<Border Stroke="Transparent" BackgroundColor="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup x:Name="CheckedStates">
<VisualState x:Name="Checked">
<VisualState.Setters>
<Setter TargetName="check" Property="Opacity" Value="1" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Unchecked">
<VisualState.Setters>
<Setter TargetName="check" Property="Opacity" Value="0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid WidthRequest="20" HeightRequest="20" Grid.Column="0" VerticalOptions="Center" HorizontalOptions="Center">
<Ellipse x:Name="border_circle" StrokeThickness="2" Stroke="{TemplateBinding BorderColor}" Fill="White" WidthRequest="18" HeightRequest="18" HorizontalOptions="Center" VerticalOptions="Center" />
<Ellipse x:Name="check" Fill="{TemplateBinding BorderColor}" WidthRequest="10" HeightRequest="10" HorizontalOptions="Center" VerticalOptions="Center" />
</Grid>
<ContentPresenter Margin="10,0,0,0" Grid.Column="1" HorizontalOptions="Start" VerticalOptions="Center" />
</Grid>
</Border>
</ControlTemplate>
<Style TargetType="RadioButton" x:Key="RadioButtonStyle">
<Setter Property="ControlTemplate" Value="{StaticResource RadioButtonTemplate}" />
<Style.Triggers>
<Trigger TargetType="RadioButton" Property="IsEnabled" Value="False">
<Setter Property="BorderColor" Value="LightGray" />
</Trigger>
<Trigger TargetType="RadioButton" Property="IsEnabled" Value="True">
<Setter Property="BorderColor" Value="DarkBlue" />
</Trigger>
</Style.Triggers>
</Style>
I am using MasterDetailsView control for my app. It offers a way to customize the details panel when no items are selected, but it doesn't offer a way to customize the master panel when no items are available.
Basically, what I want to accomplish is to display a message (TextBlock) instead of the default ListView when the latter has no items.
I just can't get it to work. My guess is that the ListView is nested inside a ControlTemplate that defines the MasterDetailsView control.
The only way I managed to do this statically (without any update at runtime) was to overwrite MasterDetailsView.Resources, where I add a Controltemplate for ListView, like in the markup below:
<Page
...
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls
...>
<controls:MasterDetailsView.Resources>
<Style TargetType="ListView" >
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="ListView">
<Grid>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
TextAlignment="Center"
Text="No content"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</controls:MasterDetailsView.Resources>
However, as I mentioned, that gives me the static behavior. I need this TextBlock to be displayed only when the data source my ListView is bound to runs out of items.
I tried to solve this by binding the Visibility property of my TextBlock to a Converter, but the converter isn't even reached (I debugged after adding a breakpoint to the Convert() method). I'm not sure if I used it properly though (I ommited the declaration of VisibleWhenZeroConverter and its source code for brevity):
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
TextAlignment="Center"
Text="No content"
Visibility="{Binding ElementName=MyMasterDetailsView, Path=ViewModel.SampleItems.Count, Converter={StaticResource VisibleWhenZeroConverter}}"/>
Obs: ViewModel is a property of MyMasterDetailsView, and it has a ObservableCollection, named SampleItems, which is never null.
I also tried to work this out by using DataTriggerBehavior with a ChangePropertyAction (from Microsoft.Xaml.Interactions.Core), but without any luck either. I'm also not sure if I did it the right way.
In case someone can answer me if this is even possible with MasterDetailsView control, I'd appreciate. Or maybe give an example of how I'd do this using one of the approaches from above, or even another one.
Best regards!
It should be noted that binding the Count of the collection cannot dynamically change the state. Although the Count property is indeed modified, the converter will not take effect because the UI is not notified.
If you are using ObservableCollection as the ItemsSource, you can listen to the ObservableCollection.CollectionChanged event and change the display of MasterDetailsView in the event callback.
On this basis, you can create a custom dependency property by deriving MasterDetailsView to change the display.
CustomMasterDetailsView.cs
public class CustomMasterDetailsView : MasterDetailsView
{
public CustomMasterDetailsView() : base()
{
this.DefaultStyleKey = typeof(CustomMasterDetailsView);
}
public Visibility EmptyTipVisibility
{
get { return (Visibility)GetValue(EmptyTipVisibilityProperty); }
set { SetValue(EmptyTipVisibilityProperty, value); }
}
public static readonly DependencyProperty EmptyTipVisibilityProperty =
DependencyProperty.Register("EmptyTipVisibility", typeof(Visibility), typeof(CustomMasterDetailsView), new PropertyMetadata(Visibility.Collapsed));
}
CustomMasterDetailsView.xaml (ResourceDictionary)
<Style TargetType="local:CustomMasterDetailsView">
<Setter Property="Background" Value="{ThemeResource ApplicationPageBackgroundThemeBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource ApplicationForegroundThemeBrush}" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:CustomMasterDetailsView">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid x:Name="RootPanel">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="MasterColumn"
Width="Auto" />
<ColumnDefinition x:Name="DetailsColumn"
Width="*" />
</Grid.ColumnDefinitions>
<Grid x:Name="MasterPanel"
Width="{TemplateBinding MasterPaneWidth}"
Background="{TemplateBinding MasterPaneBackground}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0,0,1,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentPresenter x:Name="HeaderContentPresenter"
Margin="12,0"
x:DeferLoadStrategy="Lazy"
Content="{TemplateBinding MasterHeader}"
ContentTemplate="{TemplateBinding MasterHeaderTemplate}"
Visibility="Collapsed" />
<ListView x:Name="MasterList"
Grid.Row="1"
IsTabStop="False"
ItemContainerStyle="{TemplateBinding ItemContainerStyle}"
ItemContainerStyleSelector="{TemplateBinding ItemContainerStyleSelector}"
ItemTemplate="{TemplateBinding ItemTemplate}"
ItemTemplateSelector="{TemplateBinding ItemTemplateSelector}"
ItemsSource="{TemplateBinding ItemsSource}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" />
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
TextAlignment="Center"
Grid.Row="1" Visibility="{TemplateBinding EmptyTipVisibility}"
Text="No content"/>
<Grid x:Name="MasterCommandBarPanel" Grid.Row="2"></Grid>
</Grid>
<Grid x:Name="DetailsPanel"
Grid.Column="1">
<ContentPresenter x:Name="NoSelectionPresenter"
Content="{TemplateBinding NoSelectionContent}"
ContentTemplate="{TemplateBinding NoSelectionContentTemplate}" />
<Grid x:Name="SelectionDetailsPanel">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="MasterDetailsBackButton"
Background="Transparent"
Height="44"
Width="48"
Visibility="Collapsed">
<SymbolIcon Symbol="Back"/>
</Button>
<ContentPresenter x:Name="DetailsHeaderPresenter"
Content="{TemplateBinding DetailsHeader}"
ContentTemplate="{TemplateBinding DetailsHeaderTemplate}"
Grid.Column="1"/>
</Grid>
<ContentPresenter x:Name="DetailsPresenter"
Background="{TemplateBinding Background}"
ContentTemplate="{TemplateBinding DetailsTemplate}"
Grid.Row="1">
</ContentPresenter>
<Grid x:Name="DetailsCommandBarPanel" Grid.Row="2"></Grid>
<Grid.RenderTransform>
<TranslateTransform x:Name="DetailsPresenterTransform" />
</Grid.RenderTransform>
</Grid>
</Grid>
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SelectionStates">
<VisualStateGroup.Transitions>
<VisualTransition From="NoSelectionWide"
To="HasSelection">
<Storyboard>
<DrillInThemeAnimation EntranceTargetName="SelectionDetailsPanel"
ExitTargetName="NoSelectionPresenter" />
</Storyboard>
</VisualTransition>
<VisualTransition From="NoSelectionNarrow"
To="HasSelection">
<Storyboard>
<DoubleAnimation BeginTime="0:0:0"
Storyboard.TargetName="DetailsPresenterTransform"
Storyboard.TargetProperty="X"
From="200"
To="0"
Duration="0:0:0.25">
<DoubleAnimation.EasingFunction>
<QuarticEase EasingMode="EaseOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation BeginTime="0:0:0"
Storyboard.TargetName="SelectionDetailsPanel"
Storyboard.TargetProperty="Opacity"
From="0"
To="1"
Duration="0:0:0.25">
<DoubleAnimation.EasingFunction>
<QuarticEase EasingMode="EaseOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</VisualTransition>
<VisualTransition From="HasSelection"
To="NoSelectionWide">
<Storyboard>
<DrillOutThemeAnimation EntranceTargetName="NoSelectionPresenter"
ExitTargetName="SelectionDetailsPanel" />
</Storyboard>
</VisualTransition>
<VisualTransition From="HasSelection"
To="NoSelectionNarrow">
<Storyboard>
<DoubleAnimation BeginTime="0:0:0"
Storyboard.TargetName="DetailsPresenterTransform"
Storyboard.TargetProperty="X"
From="0"
To="200"
Duration="0:0:0.25" />
<DoubleAnimation BeginTime="0:0:0.08"
Storyboard.TargetName="SelectionDetailsPanel"
Storyboard.TargetProperty="Opacity"
From="1"
To="0"
Duration="0:0:0.17">
<DoubleAnimation.EasingFunction>
<QuarticEase EasingMode="EaseOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation BeginTime="0:0:0.0"
Storyboard.TargetName="MasterPanel"
Storyboard.TargetProperty="Opacity"
From="0"
To="1"
Duration="0:0:0.25">
<DoubleAnimation.EasingFunction>
<QuarticEase EasingMode="EaseIn" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="NoSelectionWide">
<VisualState.Setters>
<Setter Target="SelectionDetailsPanel.Visibility" Value="Collapsed" />
<Setter Target="MasterPanel.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="HasSelectionWide">
<VisualState.Setters>
<Setter Target="NoSelectionPresenter.Visibility" Value="Collapsed" />
<Setter Target="MasterPanel.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="HasSelectionNarrow">
<VisualState.Setters>
<Setter Target="MasterPanel.Visibility" Value="Collapsed" />
<Setter Target="NoSelectionPresenter.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="NoSelectionNarrow">
<VisualState.Setters>
<Setter Target="NoSelectionPresenter.Visibility" Value="Collapsed" />
<Setter Target="SelectionDetailsPanel.Visibility" Value="Collapsed" />
<Setter Target="MasterPanel.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="WidthStates">
<VisualState x:Name="NarrowState">
<VisualState.Setters>
<Setter Target="MasterColumn.Width" Value="*" />
<Setter Target="DetailsColumn.Width" Value="0" />
<Setter Target="DetailsPanel.(Grid.Column)" Value="0" />
<Setter Target="NoSelectionPresenter.Visibility" Value="Collapsed" />
<Setter Target="MasterPanel.BorderThickness" Value="0" />
<Setter Target="MasterPanel.Width" Value="NaN" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="WideState">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
App.xaml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
...
<ResourceDictionary Source="ms-appx:///Controls/CustomMasterDetailsView.xaml" />
...
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Usage
if(SampleItems.Count == 0)
{
MyMasterDetailsView.EmptyTipVisibility = Visibility.Visible;
}
else
{
MyMasterDetailsView.EmptyTipVisibility = Visibility.Collapsed;
}
I use an Adaptive trigger to fit the content of my UWP Application to the window size. If the window witdh is smaller than 1000px, all of the three rectangles will be stacked. If not, the first two rectangles will be side by side and the third one will fill the whole window width beneath the two first rectangles.
<Page
x:Class="App4.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App4"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" HorizontalScrollMode="Disabled">
<Grid Margin="10,0,10,0" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1000" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Rect2.(Grid.Row)" Value="0" />
<Setter Target="Rect2.(Grid.Column)" Value="1" />
<Setter Target="Rect2.(Grid.ColumnSpan)" Value="1"/>
<Setter Target="Rect1.(Grid.ColumnSpan)" Value="1"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Rectangle Name="Rect1" Grid.Row="0" Grid.ColumnSpan="2" Grid.Column="0" Margin="10" Height="170" Fill="Red"/>
<Rectangle Name="Rect2" Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="0" Margin="10" Height="170" Fill="Green"/>
<Rectangle Grid.Row="2" Grid.ColumnSpan="2" Grid.Column="0" Height="400" Margin="10" Fill="Yellow"/>
</Grid>
</ScrollViewer>
But the Adaptive trigger only works if I remove the ScrollViewer around the Grid. The HorizontalScrollMode of the ScrollViewer is already disabled but it still doesn't work: All rectangles are stacked and changing the window width has no effect.
Is there a way to get this working with the ScrollViewer?
You have to set the setters in the first control of the XAML, if you change the first the Grid to the ScrollViewer, you have to set the setters before the Grid:
<ScrollViewer...>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1000" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Rect2.(Grid.Row)" Value="0" />
<Setter Target="Rect2.(Grid.Column)" Value="1" />
<Setter Target="Rect2.(Grid.ColumnSpan)" Value="1"/>
<Setter Target="Rect1.(Grid.ColumnSpan)" Value="1"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>...</Grid>
</ScrollViewer>
hello I want that when the vision is less than 720 such as a phone, I would like the grid 2 went below the grid 1. I tried through its panel and adaptive trigger like this:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<RelativePanel >
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualState x:Name="NarrowView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Grid2.(RelativePanel.Below)" Value="Grid1"/>
<Setter Target="Grid1.(RelativePanel.Above)" Value="Grid2"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="WideView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Grid2.(RelativePanel.RightOf)" Value="Grid1"/>
<Setter Target="Grid1.(RelativePanel.LeftOf)" Value="Grid2"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" x:Name="Grid1" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" FontSize="20" PlaceholderText="NOME" Style="{StaticResource ResourceKey=TextBoxStyle}"/>
</Grid>
<Grid Grid.Column="1" x:Name="Grid2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" FontSize="17" Text="Note" Foreground="#222222" Margin="20,15" ></TextBlock>
<TextBox Grid.Row="2" MaxLength="0" FontSize="17" Height="500" PlaceholderText="AGGIUNGI NOTA" Style="{StaticResource ResourceKey=TextBoxStyle}"></TextBox>
</Grid>
</Grid>
</RelativePanel>
</Grid>
But it does not work.
Thank you
There are two things you need to fix:
1) To make VisualState works, place the VisualStateManager under the first child of root Grid:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
......
</VisualStateManager.VisualStateGroups>
......
</Grid>
2) You don't need to add Columns, just place your two Grids under RelativePanel:
<RelativePanel>
<Grid x:Name="Grid1">
......
</Grid>
<Grid x:Name="Grid2">
......
</Grid>
</RelativePanel>
The completed xaml code:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualState x:Name="NarrowView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Grid2.(RelativePanel.Below)" Value="Grid1"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="WideView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Grid2.(RelativePanel.RightOf)" Value="Grid1"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<RelativePanel>
<Grid x:Name="Grid1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" FontSize="20" PlaceholderText="NOME" />
</Grid>
<Grid x:Name="Grid2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" FontSize="17" Text="Note" Foreground="#222222" Margin="20,15" ></TextBlock>
<TextBox Grid.Row="2" MaxLength="0" FontSize="17" Height="500" PlaceholderText="AGGIUNGI NOTA" ></TextBox>
</Grid>
</RelativePanel>
</Grid>
i found a solution without relativePanel, if anyone care:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualState x:Name="NarrowView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="text.(Grid.ColumnSpan)" Value="2" />
<Setter Target="text1.(Grid.ColumnSpan)" Value="2" />
<Setter Target="text2.(Grid.ColumnSpan)" Value="2" />
<Setter Target="text1.(Grid.Row)" Value="1" />
<Setter Target="text1.(Grid.Column)" Value="0" />
<Setter Target="text2.(Grid.Row)" Value="2" />
<Setter Target="text2.(Grid.Column)" Value="0" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="WideView">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="860" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="text.(Grid.ColumnSpan)" Value="1" />
<Setter Target="text1.(Grid.Row)" Value="0" />
<Setter Target="text1.(Grid.Column)" Value="1" />
<Setter Target="text2.(Grid.Row)" Value="1" />
<Setter Target="text2.(Grid.Column)" Value="1" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox x:Name="text" PlaceholderText="NOME" />
<TextBlock x:Name="text1" Grid.Row="0" Grid.Column="1" Text="Note"></TextBlock>
<TextBox x:Name="text2" Grid.Row="1" Grid.Column="1" PlaceholderText="AGGIUNGI NOTA" ></TextBox>
</Grid>
I'm trying to change some attached properties using the VisualStateManager in a Windows 10 Universal App project but the setters aren't working. It's not setting the attached properties of my TopBarGrid element.
If you look below I'm using the parentheses notation in order to change the Grid.Row and Grid.ColumnSpan properties. But when I run the app, the properties are not being set when I enlargen the width. I'm expecting the Grid to move to that position.
Here is my code:
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="wideState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="641" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="splitView.DisplayMode" Value="Inline"/>
<Setter Target="splitView.IsPaneOpen" Value="True"/>
<Setter Target="togglePaneButton.Visibility" Value="Collapsed"/>
<Setter Target="appHeader.Margin" Value="0,0,0,0"/>
<Setter Target="PaneHeader.Margin" Value="6,12,0,0"/>
<Setter Target="TopBarGrid.(Grid.Column)" Value="0"/>
<Setter Target="TopBarGrid.(Grid.RowSpan)" Value="2"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="narrowState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="splitView.DisplayMode" Value="Overlay"/>
<Setter Target="togglePaneButton.Visibility" Value="Visible"/>
<Setter Target="PaneHeader.Margin" Value="60,12,0,0"/>
<Setter Target="searchForInfoBox.Width" Value="270"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition x:Name="TopRowHeight" Height="80"/>
<RowDefinition Height="*"/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid x:Name="TopBarGrid" Grid.Row="0" Grid.ColumnSpan="2">
<toolbars:TopHorizontalToolBar/>
</Grid>
<Grid x:Name="LeftBarGrid" Grid.Column="0" Grid.RowSpan="2" Visibility="Collapsed">
<toolbars:VerticalToolBar />
</Grid>
Your code looks fine, however, in both states, you are setting the Row and ColumnSpan of the TopBarGrid to the same values. That's why you won't see any changes.
Try removing one set from one state.
The reason you still don't see any changes is most likely because there's something wrong with your Setters in your narrowState.
Try the following code, note that the TopBarGrid behaves correctly.
<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="wideState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="641" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="TopBarGrid.(Grid.Column)" Value="0" />
<Setter Target="TopBarGrid.(Grid.RowSpan)" Value="2" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="narrowState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="TopBarGrid.Background" Value="Green" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Grid.RowDefinitions>
<RowDefinition x:Name="TopRowHeight" Height="80" />
<RowDefinition Height="*" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid x:Name="TopBarGrid" Grid.Row="0" Grid.ColumnSpan="2" Background="Red" />
<Grid x:Name="LeftBarGrid" Grid.Column="0" Grid.RowSpan="2" Visibility="Collapsed" />
</Grid>
</Grid>
But as soon as I throw in more Setters (e.g. <Setter Target="PaneHeader.Margin" Value="60,12,0,0" />) to the narrowState, it stops working. I know, PaneHeader wasn't even defined in my test page! But it also tells me that the VSM simply swallows the error for some reason.
So, try removing your Setters and adding them back one to one to locate the bugged one. Then it would be a simple fix.
#Ray As for TopBarGrid.(Grid.Column) you have to provide PaneHeader.(FrameworkElement.Margin)