I want to use the VisualStateManager to change the appearance of my listbox items. I created a simplified example. When the listbox or listbox items got only space for width = 500 it should set for example the background to Beige otherwise to Green.
I tried the following and some other variations but neither of them worked. Has anyone a idea how to fix this?
<ListBox Grid.Column="0">
<ListBoxItem>asdfasf</ListBoxItem>
<ListBoxItem>fasf</ListBoxItem>
<ListBoxItem>fasf</ListBoxItem>
<ListBoxItem>asdsf</ListBoxItem>
<ListBoxItem>aasf</ListBoxItem>
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="visualStateGroup" >
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="500" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PathTextBlock.Text" Value="a" />
<Setter Target="border.Background" Value="Beige" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PathTextBlock.Text" Value="b" />
<Setter Target="border.Background" Value="Green" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentControl.Content>
<Border x:Name="border" >
<TextBlock x:Name="PathTextBlock" Text="{Binding RelativeSource={RelativeSource Mode=None}}" />
</Border>
</ContentControl.Content>
</ContentControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I tried to adopt:
https://stackoverflow.com/a/32092547/740651
The easiest way I find to do this is to create a UserControl of your DataTemplate code. So something like this
<UserControl x:class="MyListBoxControl">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="visualStateGroup" >
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="500" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PathTextBlock.Text" Value="a" />
<Setter Target="border.Background" Value="Beige" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PathTextBlock.Text" Value="b" />
<Setter Target="border.Background" Value="Green" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="border" >
<TextBlock x:Name="PathTextBlock" Text="{Binding RelativeSource={RelativeSource Mode=None}}" />
</Border>
</Grid>
</UserControl>
and then add to your ListBox ItemTemplate. The Visual States will then work accordingly. Note you will need to create a reference to where your UserControls are stored at the top of your page something like xmlns:myUserControls="[location of your controls]"
<ListBox Grid.Column="0">
<ListBoxItem>asdfasf</ListBoxItem>
<ListBoxItem>fasf</ListBoxItem>
<ListBoxItem>fasf</ListBoxItem>
<ListBoxItem>asdsf</ListBoxItem>
<ListBoxItem>aasf</ListBoxItem>
<ListBox.ItemTemplate>
<DataTemplate>
<myUserControls:MyListBoxControl />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Usually we don’t manipulate the ListBox's item directly, the common way is adding the items to the ObservableCollection and set ItemSource property of ListBox to bind to the ObservableCollection.
If you use the ItemSource, you can use the UserControl like #SWilko said. But it does not need to use the RelativeSource.
For example, I create a Person class, and it has a property Name. I use <TextBlock x:Name="PathTextBlock" Text="{Binding name}" /> replace <TextBlock x:Name="PathTextBlock" Text="{Binding RelativeSource={RelativeSource Mode=None}}" />.
If you want to add the ListBox’s item directly, and use the VisualStateManager to change the appearance of the ListBox items. You can edit the ItemContainerStyle.
To modify the template of ListBoxItem, we can select the ListBox in "Document Outline" and right click, then select "Edit Additional Templates"→ "Edit Generated Item Container (ItemContainerStyle)" → "Edit a Copy...".
You can create a VisualStateGroup into the <VisualStateManager.VisualStateGroups>.
For example:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
...
</VisualStateGroup>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="600" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PathTextBlock.Text" Value="a" />
<Setter Target="border.Background" Value="Beige" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PathTextBlock.Text" Value="b" />
<Setter Target="border.Background" Value="Green" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
And you can edit the ContentPresenterlike:
<ContentPresenter x:Name="ContentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Style="{StaticResource BodyContentPresenterStyle}" TextWrapping="NoWrap" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Border Name="border">
<TextBlock Name="PathTextBlock" Text="{TemplateBinding Content}"></TextBlock>
</Border>
</ContentPresenter>
By the way, you set the MinWindowWidth property to 500 of AdaptiveTrigger, the effect will not obvious. You can set it to 600.
Related
I can use VisualStateManager to change individual properties of controls. Something like this:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<!--small window-->
<AdaptiveTrigger MinWindowHeight="0" MinWindowWidth="0"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Control1.FontSize" Value="13"/>
<Setter Target="Control2.FontSize" Value="13"/>
<Setter Target="Control3.FontSize" Value="13"/>
<Setter Target="Control4.FontSize" Value="13"/>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<!--large window-->
<AdaptiveTrigger MinWindowHeight="665" MinWindowWidth="1000"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Control1.FontSize" Value="24"/>
<Setter Target="Control2.FontSize" Value="24"/>
<Setter Target="Control3.FontSize" Value="24"/>
<Setter Target="Control4.FontSize" Value="24"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
This works but is soooo much typing!
Is it possible to use VisualStateManager to set a value for the font and than refer to this variable in XAML?
Something like this:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<!--small window-->
<AdaptiveTrigger MinWindowHeight="0" MinWindowWidth="0"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="#MyFontSize" Value="13"/>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<!--large window-->
<AdaptiveTrigger MinWindowHeight="665" MinWindowWidth="1000"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="#MyFontSize" Value="24"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
I could then use #MyFontSize variable in XAML when designing controls and I could change it in one place.
<TextBlock x:Name="Control1" FontSize="#MyFontSize"/>
<TextBlock x:Name="Control2" FontSize="#MyFontSize"/>
<TextBlock x:Name="Control3" FontSize="#MyFontSize"/>
Is it possible to do something like this with UWP VisualStateManager?
Is it possible to use VisualStateManager to set a value for the font and than refer to this variable in XAML
I'm afraid you can't set variable within VisualStateManager, But for your scenario, we have a workaround that use Setting class as medium and effect other TextControl with MVVM bind.
For example
public class Setting : INotifyPropertyChanged
{
private double _fontSize = 10;
public double CFontSize
{
get { return _fontSize; }
set { _fontSize = value; OnPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Usage
<Page.Resources>
<local:Setting x:Key="Setting" />
</Page.Resources>
<StackPanel>
<TextBlock
x:Name="BaseControl"
VerticalAlignment="Center"
FontSize="{Binding CFontSize, Source={StaticResource Setting}, Mode=TwoWay}"
Text="Hello" />
<TextBlock
x:Name="Control1"
VerticalAlignment="Center"
FontSize="{Binding CFontSize, Source={StaticResource Setting}, Mode=TwoWay}"
Text="How are you" />
<TextBlock
x:Name="Control2"
VerticalAlignment="Center"
FontSize="{Binding CFontSize, Source={StaticResource Setting}, Mode=TwoWay}"
Text="Fine thank you, and you?" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<!-- small window -->
<AdaptiveTrigger MinWindowHeight="0" MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="BaseControl.FontSize" Value="13" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<!-- large window -->
<AdaptiveTrigger MinWindowHeight="665" MinWindowWidth="1000" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="BaseControl.FontSize" Value="24" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</StackPanel>
Found a similar but simpler way to do this inspired by #Nico Zhu's approach. Sharing here in case someone else finds it useful.
My approach is to use one control as a template and bind all other controls of that type to it.
The VisualStateManager sets the property for the "master" controls:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<!--VisualState to be triggered when window width is <665 effective pixels.-->
<AdaptiveTrigger MinWindowHeight="0" MinWindowWidth="0"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="txtHeader.FontSize" Value="13"/>
<Setter Target="txtRegular.FontSize" Value="10"/>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowHeight="665" MinWindowWidth="1000"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="txtHeader.FontSize" Value="20"/>
<Setter Target="txtRegular.FontSize" Value="16"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
All other controls can bind to "master" controls.
<TextBlock Text="My Header 1" FontSize="{Binding ElementName=txtHeader, Path=FontSize}" />
<TextBlock Text="My Header 2" FontSize="{Binding ElementName=txtHeader, Path=FontSize}" />
<TextBlock Text="My regular text 1" FontSize="{Binding ElementName=txtRegular, Path=FontSize}" />
<TextBlock Text="My regular text 2" FontSize="{Binding ElementName=txtRegular, Path=FontSize}" />
When a user resizes page, VisualStateManager will change the master controls, all others will get it through binding.
If you want to, you can create hidden controls just to server as templates.
I am trying to have a simple header of the page "adaptively" change the padding value based off of the width of the Page. Namely I have a header TextBlock using a style from a Resource Dictionary as shown below:
<Style x:Key="PageHeaderStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="16" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
In my page now I have a simple TextBlock that uses the Style from the Resource Dictionary above. In the page if I use the following code my adaptive triggers as shown below everything works:
<Page
...
Style="{StaticResource PageStyle}">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Narrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PageHeader.Padding" Value="48,0,0,0" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Compact">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PageHeader.Padding" Value="0,0,0,0" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Wide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1024"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PageHeader.Padding" Value="0,0,0,0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="{StaticResource GridHamburgerHeight}"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="14"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{x:Bind Path=helper:CommonStyles.HamburgerPaneBackgroundColour}" Grid.Row="0" Grid.ColumnSpan="2"/>
<TextBlock Style="{StaticResource PageHeaderStyle}" Grid.Column="1" Text="HOME"/>
</Grid>
</Page>
My question is, how can I move that Adaptive VisualStateManager piece into the Style object within the Resource Dictionary itself so that I can re-use this header style and its "adaptive-ness" without having to paste the VisualStateManager on each page.
Thanks!
As I've tried it's not possible to change page's template, seems to always use a default one. Therefore, taking into account that VisualStateManager must be in the root element of a Control - source at MSDN:
Control authors or app developers add VisualStateGroup object elements to the root element of a control template definition in XAML, using the VisualStateManager.VisualStateGroups attached property.
you will probably have to create a custom UserControl or extend Page class - there you can add VisualStateManager and you won't have to repeat it all over, just use that control/page.
This is very simple example and should be extended, but it will give you a point to start (the source code you can check at Github. For your case I would create a TemplatedControl - right click on your project in solution manager, then Add->New Item, then select Templated Control, lets name it AdaptiveTriggerControl, this should create a cs file and a Generic.xaml in Themes folder. Open the AdaptiveTriggerControl.cs file and modify the class it derives from - change from Control to ContentControl:
public sealed class AdaptiveTriggerControl : ContentControl
In Generic.xaml you define the control:
<Style TargetType="local:AdaptiveTriggerControl" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:AdaptiveTriggerControl">
<Border x:Name="MyBorder"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<!--Background="{TemplateBinding Background}"-->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Narrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyBorder.Background" Value="Red"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Compact">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyBorder.Background" Value="Green"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Wide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1024"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyBorder.Background" Value="Blue"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then you can use it simply like this:
<local:AdaptiveTriggerControl>
<TextBlock Text="Content of your page"/>
</local:AdaptiveTriggerControl>
More information about TemplatedControls, a sample of creating UserControl.
I'm working on a UWP app. I'm already using adaptive triggers to adapt my xaml depending on the width of the window, and it works.. only in a Page.
Now I want to do the same for the xaml of a User Control, and it's not working .. Yet I put the VisualStateManager to root grid of the user control.
Is there a difference ?
Here's the code of my user control :
<UserControl
x:Class=.....>
<UserControl.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator"/>
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.DataContext>
<Binding Path="MyUserControlVM" Source="{StaticResource Locator}"/>
</UserControl.DataContext>
<Grid x:Name="LayoutRoot" Background="white">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Narrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="LastName.Foreground" Value="Red" />
<Setter Target="LastName.Fontsize" Value="10" />
<Setter Target="FirstName.Foreground" Value="Red"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Normal">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="600" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="LastName.Foreground" Value="Red" />
<Setter Target="LastName.Fontsize" Value="25" />
<Setter Target="FirstName.Foreground" Value="Red"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Wide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1000"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="LastName.Foreground" Value="Red" />
<Setter Target="FirstName.Foreground" Value="Red"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Listbox>
...
</ListBox>
<TextBlock x:Name="lblNoData" Grid.ColumnSpan="2" Text="No Data" Visibility="{Binding NoDataVisible, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<ProgressRing x:Name="prLoading" Width="60" Height="60" Foreground="Blue" IsActive="{Binding InitializationNotifier.IsNotCompleted}" />
</Grid>
("LastName" and "FirstName" are textblocks in the DataTemplate of my listbox. I'm just trying to put my text in red in order to see when the triggers work)
And I call the user control in a simple page like this :
<Grid x:Name="LayoutRoot" Background="{StaticResource white}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="0,0,0,10">
...
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="10,0">
<UC:MyUserControl/>
</Grid>
</Grid>
I don't understand why this code won't work. Thank you in advance for your help !
("LastName" and "FirstName" are textblocks in the DataTemplate of my listbox. I'm just trying to put my text in red in order to see when the triggers work)
You can refer to my another answer here, as I said in that answer, when the controls are placed in the DataTemplate, they becomes the visual structure of your data objects. I think there is no clean way to do this work only in the xaml code, Data Binding here is your friend.
From your code I can see that you want to change the Foreground (but all to Red?) and the FontSize of the TextBlocks inside of the DataTemplate depending on the window's size. So you can bind these two proprieties to the window's size, or you can use ItemsControl.ItemTemplateSelector to select different template when the window's size is changed.
I have UWP app.
<GridView Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" x:Name="GridColections" IsItemClickEnabled="True" SelectionMode=" None " ItemsSource="{x:Bind DS.AllRem, Mode=OneWay}" ItemClick="GridColections_ItemClick" >
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Small">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="RemXML.Background" Value="Red" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Middle">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="400"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="RemXML.Background" Value="Green"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Big">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="500"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="RemXML.Background" Value="Yellow"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:GetRem">
<RelativePanel x:Name="RemXML" Width="345" Background="Cyan">
<TextBlock TextWrapping="Wrap" Text="{x:Bind ReminderName}" Margin="5,5,0,0" RelativePanel.AlignLeftWithPanel="True" FontSize="20" />
<TextBlock TextWrapping="Wrap" Text="{x:Bind ReminderDescription}" Margin="6,35,0,0" RelativePanel.AlignLeftWithPanel="True" FontSize="13.333"/>
<CheckBox RelativePanel.AlignRightWithPanel="True" Margin="100,0,-200,0" Width="220" RelativePanel.AlignVerticalCenterWithPanel="True">
<CheckBox.RenderTransform>
<CompositeTransform ScaleX="-1"/>
</CheckBox.RenderTransform>
</CheckBox>
</RelativePanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
So adaptive triggers don't work in my app. I need to change RelativePanel background. When Visual state I have in first control I have ERROR "An animation is trying to modify an object named 'RemXML', but no such object can be found in the Page." When Visual State I have in RelativePanel is don't work
Try putting the VisualStateManager inside of the DataTemplate which has a UserControl as top element.
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:GetRem">
<UserControl>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Small">
......
</VisualStateManager.VisualStateGroups>
<RelativePanel x:Name="RemXML" Width="345" Background="Cyan">
I have been struggling with SplitView control while trying to create a sample (and simple!) UW App. First the list of issues and then the code:
I am using VisualStateManager to control the DisplayState and Pane Visibility. So I do not use the corresponding attributes (DisplayMode and IsPaneOpen) in the XAML.
Issues Faced:
a. Sometimes the designer shows Exception from HRESULT: 0x88000FA8
b. The Pane is always in Closed state - in Designer and in Runtime.
c. I was also getting a runtime exception showing Debugger code but after restarting Visual Studio it's stopped.
If I add the two attributes in the XAML markup (commenting out VisualStateManager) then for the following combination the Hamburger button does not work: IsPaneOpen="False" DisplayMode="Overlay". The code for the Hamburger button is plain vanilla - MainSplitView.IsPaneOpen = !MainSplitView.IsPaneOpen;
Markup:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="721" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MainSplitView.DisplayMode" Value="Inline" />
<Setter Target="MainSplitView.IsPaneOpen" Value="True" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="548" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MainSplitView.DisplayMode" Value="CompactOverlay" />
<Setter Target="MainSplitView.IsPaneOpen" Value="True" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MainSplitView.DisplayMode" Value="Overlay" />
<Setter Target="MainSplitView.IsPaneOpen" Value="False" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Name="HamBurgerButton" Background="Transparent" Padding="0,-6" Margin="12" Click="HamBurgerButton_Click">
<FontIcon FontFamily="{ThemeResource ContentControlThemeFontFamily}"
Glyph="≡" FontSize="32" Margin="0,-8,0,0"/>
</Button>
<TextBlock RelativePanel.RightOf="HamBurgerButton"
Style="{ThemeResource TitleTextBlockStyle}" Margin="5,0,0,0"
Text="Title"/>
<SplitView x:Name="MainSplitView" PaneBackground="{ThemeResource ApplicationPageBackgroundThemeBrush}"
RelativePanel.AlignLeftWithPanel="True" RelativePanel.AlignRightWithPanel="True"
RelativePanel.Below="HamBurgerButton" OpenPaneLength="200" CompactPaneLength="50">
<SplitView.Pane>
<StackPanel Orientation="Horizontal" Background="Gray">
<AppBarButton x:Name="AboutButton" Icon="Important" IsCompact="True" Click="AboutButton_Click"/>
<TextBlock Text="About"/>
</StackPanel>
</SplitView.Pane>
<SplitView.Content>
<ScrollViewer VerticalScrollBarVisibility="Auto" VerticalScrollMode="Auto"
HorizontalScrollBarVisibility="Disabled" HorizontalScrollMode="Disabled">
<Frame x:Name="ContentFrame"/>
</ScrollViewer>
</SplitView.Content>
</SplitView>
</RelativePanel>
So can somebody either confirm that these issues can be replicated at their end (i.e. they are bugs) or that I am wrong somewhere or there are workarounds available?
This code will work...
<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Name="HamBurgerButton" Background="Transparent" Padding="0,-6" Margin="12" Click="HamBurgerButton_Click">
<FontIcon FontFamily="{ThemeResource ContentControlThemeFontFamily}"
Glyph="≡" FontSize="32" Margin="0,-8,0,0"/>
</Button>
<TextBlock RelativePanel.RightOf="HamBurgerButton"
Style="{ThemeResource TitleTextBlockStyle}" Margin="5,0,0,0"
Text="Title"/>
<SplitView x:Name="MainSplitView" IsPaneOpen="False" PaneBackground="{ThemeResource ApplicationPageBackgroundThemeBrush}"
RelativePanel.AlignLeftWithPanel="True" RelativePanel.AlignRightWithPanel="True"
RelativePanel.Below="HamBurgerButton" OpenPaneLength="200" CompactPaneLength="50">
<SplitView.Pane>
<StackPanel Orientation="Horizontal" Background="Gray">
<AppBarButton x:Name="AboutButton" Icon="Important" IsCompact="True" Click="AboutButton_Click"/>
<TextBlock Text="About"/>
</StackPanel>
</SplitView.Pane>
<SplitView.Content>
<ScrollViewer VerticalScrollBarVisibility="Auto" VerticalScrollMode="Auto"
HorizontalScrollBarVisibility="Disabled" HorizontalScrollMode="Disabled">
<Frame x:Name="ContentFrame"/>
</ScrollViewer>
</SplitView.Content>
</SplitView>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="721" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MainSplitView.DisplayMode" Value="Inline" />
<Setter Target="MainSplitView.IsPaneOpen" Value="True" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="548" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MainSplitView.DisplayMode" Value="CompactOverlay" />
<Setter Target="MainSplitView.IsPaneOpen" Value="True" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MainSplitView.DisplayMode" Value="Inline" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</RelativePanel>
The hamburger button did not work when width was between 0 and 548 because the mode is set to overlay... actually the pane had been opened and closed outside the frame...that's why it was not visible which made you to think that the button was not working. It isn't a bug in splitview... If it doesnt work comment...will help yo...
I dont think your Adaptive Trigger is working after all. Place it inside the relativePanel and see if it gets triggered.
<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Name="HamBurgerButton" Background="Transparent" Padding="0,-6" Margin="12" Click="HamBurgerButton_Click">
<FontIcon FontFamily="{ThemeResource ContentControlThemeFontFamily}"
Glyph="≡" FontSize="32" Margin="0,-8,0,0"/>
</Button>
<TextBlock RelativePanel.RightOf="HamBurgerButton"
Style="{ThemeResource TitleTextBlockStyle}" Margin="5,0,0,0"
Text="Title"/>
<SplitView x:Name="MainSplitView" PaneBackground="{ThemeResource ApplicationPageBackgroundThemeBrush}"
RelativePanel.AlignLeftWithPanel="True" RelativePanel.AlignRightWithPanel="True"
RelativePanel.Below="HamBurgerButton" OpenPaneLength="200" CompactPaneLength="50">
<SplitView.Pane>
<StackPanel Orientation="Horizontal" Background="Gray">
<AppBarButton x:Name="AboutButton" Icon="Important" IsCompact="True" Click="AboutButton_Click"/>
<TextBlock Text="About"/>
</StackPanel>
</SplitView.Pane>
<SplitView.Content>
<ScrollViewer VerticalScrollBarVisibility="Auto" VerticalScrollMode="Auto"
HorizontalScrollBarVisibility="Disabled" HorizontalScrollMode="Disabled">
<Frame x:Name="ContentFrame"/>
</ScrollViewer>
</SplitView.Content>
</SplitView><VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="721" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MainSplitView.DisplayMode" Value="Inline" />
<Setter Target="MainSplitView.IsPaneOpen" Value="True" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="548" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MainSplitView.DisplayMode" Value="CompactOverlay" />
<Setter Target="MainSplitView.IsPaneOpen" Value="True" />
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MainSplitView.DisplayMode" Value="Overlay" />
<Setter Target="MainSplitView.IsPaneOpen" Value="False" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</RelativePanel>