state manager for xaml SplitView pane inside frame - c#

That's kind of a long title.
So i have a Shell.xaml with a for the content .xaml's
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ShellSplitView.DisplayMode" Value="CompactInline"/>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ShellSplitView.DisplayMode" Value="Overlay"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<SplitView x:Name="ShellSplitView">
<SplitView.Pane>
<Grid>
<ListView x:Name="NavMenuList">
...
</ListView>
</Grid>
</SplitView.Pane>
<Frame x:Name="ContentFrame">
</Frame>
</SplitView>
</Grid>
Inside this Frame other .xaml's are loadad for the actual content. Those also use a (to add further depth, like the mail app: folder->email list->email view) but if i add a to that nested xaml it doesn't do anything.
My goal would be to have it behave like two separate frames when in small view (like phone), so the user can navigate between them (again, like the win10 mail app).
Right now the VisualStateManager of the Frame xaml looks like this, but this was just a test to see it working. As I mentioned I'd prefer a similar behaviour to the mail app.
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PeopleSplitView.DisplayMode" Value="Inline"/>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="PeopleSplitView.DisplayMode" Value="CompactInline"/>
<Setter Target="PeopleSplitView.IsPanelOpen" Value="False"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Also when resizing the Window, the content of the frame splitview content doesn't resize itself and stays full width (thus not wrapping the text).
<SplitView x:Name="PeopleSplitView"
DisplayMode="Inline"
IsPaneOpen="True"
OpenPaneLength="400"
CompactPaneLength="48">
<SplitView.Pane></SplitView.Pane>
<SplitView.Content>
<Grid Padding="0">
<ListView.../>
</Grid>
</SplitView.Content>
</SplitView>

you need to delete this element of your c# code that is found in the event of the listview that selects the frames
i think this should help you
private void ListViewSplit_Tapped(object sender,TappedRoutedEventArgs e)
{
//delete those lines
if (MySplitView.IsPaneOpen)
MySplitView.IsPaneOpen = !MySplitView.IsPaneOpen;
}

Related

C# UWP XAML Check If Exists in XAML

Im working on building different layouts for my app. If the app runs in landscape I want to be able to show a map on one side on the screen, but not show a map if in portrait. I'm using VisualStateManager to help me do this.
I need to run some code in c# on the map control I have named "MyMap" but how can I make that bit of the code run only when the map is present - in other words is there a way I can check if it exists in the XAML?
Without the map any code referring to MyMap of course throws an error - is this the best way of going about this or am I missing a better way?
EDIT
I'm using an approach similar to the below to work out what template should be used depending on the MinWindowWidth. So MyMap will only exist in the LargeTemplate etc
<Page.Resources>
<DataTemplate x:Key="SmallTemplate">
<Grid>
<Border Background="LightGray" Height="100" Width="100">
<TextBlock Text="{Binding Text}"
FontSize="48" Foreground="Green" />
</Border>
</Grid>
</DataTemplate>
<DataTemplate x:Key="LargeTemplate">
<Grid>
<Border Background="LightGray" Height="200" Width="200">
<TextBlock Text="{Binding Text}"
FontSize="48" Foreground="Green" />
</Border>
</Grid>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Small">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyGridView.ItemTemplate" Value="{StaticResource SmallTemplate}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Large">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="MyGridView.ItemTemplate" Value="{StaticResource LargeTemplate}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<GridView Name="MyGridView"/>
</Grid>
Add an x:Name to your VisualStateGroup eg. AdaptiveVisualStateGroup, after that you can check for the CurrentState in your code like this:
AdaptiveVisualStateGroup.CurrentState
If the CurrentState equals Large or whatever the name is your VisualState where you have your map, you can run the code that references MyMap, otherwise you just skip it

How to use splitview's pane in visualstate to achieve adaptive effect in UWP?

I have a few navigation buttons inside StackPanel, I want to put them inside the splitview's pane. When the splitview's pane is open, the stackpanel's orientation is horizontal, and when the pane is closed the stackpanel's orientation is vertical so that user would always be able to see the navigation buttons.
The XAML code is as follows
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="PaneViewStates">
<VisualState x:Name="PaneClosedState">
<VisualState.StateTriggers>
<StateTrigger IsActive="{Binding Path=IsPaneOpen, ElementName=SplitView, Converter={StaticResource BooleanNegationConverter}}"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="NavigationControl.RootGrid.StackPanel.Orientation" Value="Vertical"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PaneOpenState">
<VisualState.StateTriggers>
<StateTrigger IsActive="{Binding Path=IsPaneOpen, ElementName=SplitView}"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="NavigationControl.RootGrid.StackPanel.Orientation" Value="Horizontal"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
But I got the error like The attachable property 'IsPaneOpen' was not found in type 'SplitView'.
I got plane B, that is to use events like OnPaneClosing and OnPaneOpen, however there is only PaneClosing event, no openning event. I'm wondering if anyone can give any suggestion.
Adaptive triggers use MinWidth and MinHeight to check for trigger conditions. It doesn't check for any Boolean conditions. You need to use StateTrigger and bind IsPaneOpen to IsActive to trigger the "PaneOpenState". But if you want to trigger the "PaneClosedState", you cannot directly bind it to IsActive of the StateTrigger. You need to have some other State Triggers that are derived from StateTriggerBase Class, like these awesome WindowsStateTriggers. I am using IsFalseStateTrigger from the above said collection.
The code should be like:
<Page ...
xmlns:triggers="using:WindowsStateTriggers">
...
<VisualState x:Name="PaneOpenState">
<VisualState.StateTriggers>
<StateTrigger IsActive="{Binding IsPaneOpen, ElementName=MySplit}"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="NavigationControl.RootGrid.StackPanel.Orientation" Value="Horizontal"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PaneClosedState">
<VisualState.StateTriggers>
<triggers:IsFalseStateTrigger Value="{Binding ElementName=MySplit, Path=IsPaneOpen}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="NavigationControl.RootGrid.StackPanel.Orientation" Value="Vertical"/>
</VisualState.Setters>
</VisualState>
Edit
After one of our friends pointed out, I came to know that I forgot the most obvious way to do this instead of using IsFalseStateTrigger. You can use a converter like NotTrueConverter that negates the Boolean and use it in the "PaneClosedState" using the StateTrigger

How do you maintain changes made by VisualState triggers after setting another VisualState?

Not sure if am framing the question right. So please bear with me if I'm expecting something absurd. I am building a C#/XAML win10 UWP application following the MVVM pattern.
I've some visual states defined for handling wider screens and also some for running some animations. The problem am facing is that, when the visual state to run the animation is called using the VisualStateManager's GoToState method, the setters effected by the VisualState containing the adaptive triggers are lost.
Here's the sample code:
//Defining my grid here
<Grid x:Name="gridNewDrawing" Margin="4">
<Button x:Name="Confirm" Click="Button_Confirm_Click" Width="180" MaxWidth="220" Height="36" HorizontalAlignment="Left" Style="StaticResource StyleButtonGeneral}"/>
<Button x:Name="Cancel" Click="Button_Cancel_Click" Width="180" MaxWidth="220" Height="36" HorizontalAlignment="Left" Style="StaticResource StyleButtonGeneral}"/>
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="WideLayoutTrigger">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="640" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="gridNewDrawing.Margin" Value="16" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="AnimationState">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Cancel" Storyboard.TargetProperty="Visibility" Duration="0">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
When the width is above 640px; the margin on the gridNewDrawing switches to 16; but when I explicitly call the animation using
GoToState("AnimationState")
The margin on the grid defaults to 4 once again. Is there any way I can have the changes made by the adaptivetrigger persist when setting other visual styles?
The margin of the grid changes to default again because your VisualState are in same VisualStateGroup. You can set the AnimationState in another VisualStateGroup to maintain changes made by the AdaptiveTrigger.
See the Remarks of VisualStateGroup class.
The set of visual states within each VisualStateGroup should be mutually exclusive in the group. In other words, the control should be using exactly one of the visual states from each of its defined VisualStateGroup groups at all times. Whenever there's a case where a control is intended to be simultaneously in two states, make sure that the two states are in different groups.
So apply the following code should get what you want:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="WindowStates">
<VisualState x:Name="WideLayoutTrigger">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="640" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="gridNewDrawing.Margin" Value="16" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="OtherStates">
<VisualState x:Name="AnimationState">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Cancel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>

XAML Defined StoryBoard throws nullpointer when called in C

I'm trying to animate a button so the image enlarges when the user touches it and goes back to normal when he releases It but somehow the XAML Defined StoryBoard throws a nullpointer when called in C#. My code snippets are down here, I've got no clue at all what creates this problem.
XAML:
<UserControl x:Class="Mavie_Base.GUIElements.MenuButton"
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"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="200" d:DesignWidth="140">
<UserControl.Resources>
<Storyboard x:Name="Enlarge">
<DoubleAnimation Duration="0:0:1" From="60" To="66" Storyboard.TargetProperty="Height" Storyboard.TargetName="Rectangle"/>
</Storyboard>
<Storyboard x:Name="Normalize">
<DoubleAnimation Duration="0:0:1" From="66" To="60" Storyboard.TargetProperty="Height" Storyboard.TargetName="Rectangle"/>
</Storyboard>
</UserControl.Resources>
....
</UserControl>
C#:
private void IconContainer_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
Enlarge.Begin();
}
private void IconContainer_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
Normalize.Begin();
}
+1 #thumbmunkeys
Though if it were me, it sounds like something you might want to add other stuff to later for interaction so I'd just let functionality already built in to handle that and then have room to add to it later if you want to add other stuff to its functionality. I'd also think (not positive, would have to check) if you go tinkering with the height property it may offset other artifacts layed out on the screen as it adjusts causing for a jumpy UI that wouldn't be very pleasing to the user.
Again, if it were me, I would probably just do something like this instead. First, instead of fiddling with the Height/Width properties that might push other parts of the screen around, hit the ScaleTransform.ScaleY (and ScaleX respectively, you'll want to play with the Values I'm sure to get the sizes you want.) for your size changes.
I'd also probably go ahead and make it into a "lookless" and stripped down Button for other options later and to handle my events like Pressed. Something like;
<Style x:Key="GrowOnPressedThingy" TargetType="Button">
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="Container"
RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform />
<SkewTransform />
<RotateTransform />
<TranslateTransform />
</TransformGroup>
</Grid.RenderTransform>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<!-- Just left for reference -->
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Container"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<EasingDoubleKeyFrame KeyTime="0:0:0.01" Value="1.05" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Container"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<EasingDoubleKeyFrame KeyTime="0:0:0.01" Value="1.05" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused"/>
<VisualState x:Name="Unfocused" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentControl x:Name="contentPresenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
IsTabStop="False"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This way you could just do a quick... ;
<Button Content="whatever/image/path/blah.png"
Style="{StaticResource GrowOnPressedThingy}"/>
...wherever you need it, and you've got it setup to go easily add other neat UI tricks you might think of in the future. Just a shot in the dark, but maybe worth considering.
Anyway, hope this helps. Cheers
Try casting the targetproperty:
Storyboard.TargetProperty="(FrameworkElement.Height)"

How to Reverse WPF Storyboard animation?

I've created a WPF Storyboard animation on an image in Expression Blend 4. On hover, the image gradually blurs. Is there any way I can have the Storyboard be undone or reversed when the mouse leaves the image? I could make it trigger Storyboard.Remove() but that wouldn't actually play through the Storyboard backwards.
Is there any way I can accomplish that within Expression Blend 4?
Since you are using Blend, you should take advantage of Blend's support for the VisualStateManager. All you have to do is describe what the object looks like in its various states, like MouseOver and Normal and how long the transitions between various states are, and the visual state manager works out how to transition between states.
An image doesn't have any visual states but you can edit a Button template and make its content an image and then edit the states for the button. I've done this and cleaned up the XAML to demonstrate the technique:
<Grid>
<Grid.Resources>
<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Image x:Name="image" Height="100" Width="Auto" Source="http://thecybershadow.net/misc/stackoverflow.png" Margin="0,0,-25,0">
<Image.Effect>
<DropShadowEffect ShadowDepth="0"/>
</Image.Effect>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.5"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.ShadowDepth)" Storyboard.TargetName="image">
<EasingDoubleKeyFrame KeyTime="0" Value="15"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Image>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Button Style="{StaticResource ButtonStyle1}"/>
</Grid>
Note that Blend does all this for you but understanding the XAML will help. Here's a Blend-oriented tutorial:
MORE ARTICLES ON VISUAL STATE MANAGER
Maybe the solution is on this Answer:
How to animate ListBox Items on MouseEnter and MouseLeave events using C#/WPF?

Categories

Resources