I have implemented semantic zoom in my page,
1) when i move screen from left to right with HAND(MY Computer is touch enabled) for reading contents off the screen,i see thin and good scrollviewer horizontally appears when i move left to right and disappears after some time, if application is kept idle.
2)When i bring my Mouse and Hover on Semantic Zoom, I see default/ larger thicker scrollbar horizantal. But i want to have one goood looking scrollviewer which eatly looks like scrollviewer mentioned in Step1 . Let me know if there are any good looking scrollviewer which thinner
It sounds like you want to make the ScrollViewer always show the thin "panning indicators" when mousing over it instead of showing the traditional ScrollBars with draggable thumbs. It's easy to do this and I'll show you an example, but please keep in mind you could be creating an accessibility problem. If a user does not have a touch-enabled device, the traditional ScrollBars with draggable thumbs allow the user to scroll. Without these, the user has to resort to keyboard or mouse wheel to scroll (assuming the user has a mouse wheel input device, or that the ScrollViewer has focusable content the user can tab into). This creates a potential accessibility problem for non-touch users.
To make sure we're referring to the same thing:
traditional mouse scrollbar
panning indicator
By default, the ScrollViewer shows the panning indicator when the user performs a touch gesture on the ScrollViewer, and shows the traditional mouse scrollbar is shown when the user moves the mouse above the ScrollViewer or clicks on the ScrollBars/Thumbs.
To make the ScrollViewer show the panning indicators for mouse input, you need to perform these steps:
Open your project in Expression Blend. Right-click your ScrollViewer and select "Edit Template > Edit a Copy...".
Dig into the ScrollViewer's template and find the vertical ScrollBar. Right-click the ScrollBar and select "Edit Template > Edit a Copy...".
Open the XAML page where the new templates were created, either in Blend or in VS. Find the ScrollBar template that you created. Inside of it, find this line: <VisualStateGroup x:Name="ScrollingIndicatorStates">.
Inside the "ScrollingIndicatorStates" VisualStateGroup, copy the code inside the "TouchIndicator" VisualState:
<Storyboard>
<FadeInThemeAnimation TargetName="HorizontalPanningRoot"/>
<FadeInThemeAnimation TargetName="VerticalPanningRoot"/>
<FadeOutThemeAnimation TargetName="HorizontalRoot"/>
<FadeOutThemeAnimation TargetName="VerticalRoot"/>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="HorizontalRoot">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="VerticalRoot">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
Paste this code into the body of the "MouseIndicator" visual state, overwriting what's already there.
Also, if you show a horizontal ScrollBar as well, make sure to update the horizontal ScrollBar in your modified ScrollViewer template to use the ScrollBar template you created.
So, overall pretty simple. We just had to copy the animations from the "TouchIndicator" state and paste them into the "MouseIndicator" state. Full code example is here:
https://github.com/finnigantime/Samples/tree/master/examples/Win8Xaml/ScrollViewer_PanningIndicatorsOnly
Related
I want to change the position of image and Text when the user resize the app window and width is very small. Please refer the attached gif which shows it happening for a Windows Settings app. I want to do achieve something similar to this.
I want to change the position of image and Text when the user resize the app window
What you are looking for is Adaptive layouts with visual states and state triggers.
When your app window grows or shrinks beyond a certain amount, you could alter layout properties to reposition, resize, reflow, reveal or replace sections of your UI. What you need is to define different visual states for your UI first. Then apply them when the window width or window height crosses a specified threshold. The document above shows different ways to change the visual states for different windows size.
There are two common ways:
handling the Window.SizeChanged Event in the code behind. Then call the VisualStateManager.GoToState method to apply the appropriate visual state.
using the AdaptiveTrigger Class in XAML. It will be triggered to apply the visual state when the size of the window grows or shrinks beyond the value you defined.
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<!-- VisualState to be triggered when the
window width is >=640 effective pixels. -->
<AdaptiveTrigger MinWindowWidth="640" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="mySplitView.DisplayMode" Value="Inline"/>
<Setter Target="mySplitView.IsPaneOpen" Value="True"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Please check this document for more information and code sample: Adaptive layouts with visual states and state triggers.
I have a SplitView:
<SplitView Name="splitView"
DisplayMode="{Binding SplitViewDisplayMode}"
IsPaneOpen="{Binding SplitViewIsPaneOpen}"
OpenPaneLength="200" CompactPaneLength="51"/>
I am also using VisualStateManager to adjust the SplitView based on application window size: (example)
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="500"></AdaptiveTrigger>
</VisualState.StateTriggers>
Thus far everything works correctly, but I ran into an unexpected result when the trigger above and state below are activated.
<VisualState.Setters>
<Setter Value="True" Target="splitView.IsPaneOpen"></Setter>
<Setter Value="Overlay" Target="splitView.DisplayMode"></Setter>
</VisualState.Setters>
I cant seem to find a way to detect the event so that my ViewModel knows when the SplitView pane focus is lost. Right now as designed Overlay displays until the user clicks the view (as designed), but I'd like to know, when the SplitView Overlay is collapsed so that I can add additional binding events into my HamburgerMenu.
From what I am experiencing it appears that VisualStateManager doesn't update/change my bindings
DisplayMode="{Binding SplitViewDisplayMode}"
Any ideas as to how I can discover if/when the Overlay disappears/Closes?
The only thing I can think of is to create methods that discover the Window size, and then determine if the SplitView should be Inline/Compact/Overlay.. This is doable but would result in a lot of potential combinations.
Any thoughts or ideas on how to detect or get SplitView to tell me if Overlay is Collapsed when a user clicks a control outside of the SplitView?
To make the bindings work, you have to specify them as two way bindings. Without this, they will only update the UI with your changes in code, not the other way around:
<SplitView Name="splitView"
DisplayMode="{Binding SplitViewDisplayMode, Mode=TwoWay}"
IsPaneOpen="{Binding SplitViewIsPaneOpen, Mode=TwoWay}"
OpenPaneLength="200" CompactPaneLength="51"/>
Now your properties should be properly updated whenever the state changes.
I have a user interface that adapts to different device form factors using AdaptiveTrigger. In particular, I have a SplitView-based shell menu with two state triggers for when the minimum window width is 1000 epx and 600 epx respectively. The 600 epx state trigger can fire on certain mobile devices in landscape mode depending on their form factor and scale factor, and this is intended behavior.
However, I've noticed that on the desktop, the 600 epx state trigger fires in the background (changing ShellSplitView.DisplayMode from Overlay to CompactOverlay) as soon as I change a theme setting such as toggling between dark and light mode, changing the accent color, or toggling high contrast mode; and on both the mobile emulator and a device, it fires when I go to the Settings app, change a theme setting, and return to my app. Most peculiarly, this only happens in the default state and only after I've caused any of the state triggers to fire, by resizing the window on the desktop or by rotating the mobile emulator or device. Resizing/rotating again after returning to the app makes the problem go away. I have not previously seen this in any other apps, including Microsoft's apps or any third-party UWP apps.
I've confirmed that this is not caused by some other code interfering with the state triggers, by successfully reproducing the problem in a blank UWP project with a single page containing nothing but a SplitView with any number of visual states (and some text content):
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1000"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ShellSplitView.DisplayMode" Value="Inline"/>
<Setter Target="ShellSplitView.IsPaneOpen" Value="True"/>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="600"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ShellSplitView.DisplayMode" Value="CompactOverlay"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<SplitView
x:Name="ShellSplitView"
CompactPaneLength="48"
DisplayMode="Overlay"
IsPaneOpen="False"
OpenPaneLength="256">
<SplitView.Content>
<TextBlock Text="Content"/>
</SplitView.Content>
<SplitView.Pane>
<TextBlock Text="Pane"/>
</SplitView.Pane>
</SplitView>
</Grid>
</Page>
You can attempt to reproduce the problem yourself by creating a blank UWP project, replacing the contents of MainPage.xaml with the above XAML, and running the project.
Considering all I did was change the theme settings, I don't understand why any of the state triggers would fire. In fact, according to this guide on MSDN, the default values reflected in the SplitView element's attributes should be reapplied automatically:
When you use state triggers, you don't need to define an empty DefaultState. The default settings are reapplied automatically when the conditions of the state trigger are no longer met.
And according to the Windows.UI.Xaml.AdaptiveTrigger page itself:
By default, the StackPanel orientation is Vertical. When the window width is >= 720 effective pixels, the VisualState change is triggered, and the StackPanel orientation is changed to Horizontal.
... which, together, reinforce my point — the window width does not change when I change the theme settings, so I don't see why the state trigger would kick in when it shouldn't, and why only after I've triggered a state change by resizing the window or rotating the device.
So why is this happening, and how do I fix it?
This issue appears to have been fixed in the Windows 10 Anniversary Update for all device families. The state triggers will no longer activate when they're not supposed to, and the default values as specified outside of the state triggers are now correctly reapplied.
You do not need this workaround if your app will only be running on the 1607 branch (build 14393) or newer. Note that this refers to the minimum version as specified in your project properties, and not the target version.
You need this workaround if your app will be running on the 1511 branch (build 10586) or 1507 branch (build 10240), even though it will behave correctly on devices with the newer builds.
Unfortunately, I haven't been able to work around this problem without just adding a default state to the VisualStateGroup anyway, using a state trigger with a minimum dimension of 0 epx (you do not need any setters — you just need a state trigger):
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1000"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ShellSplitView.DisplayMode" Value="Inline"/>
<Setter Target="ShellSplitView.IsPaneOpen" Value="True"/>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="600"/>
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="ShellSplitView.DisplayMode" Value="CompactOverlay"/>
</VisualState.Setters>
</VisualState>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0"/>
</VisualState.StateTriggers>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
As to why this happens, my guess is that the VisualStateManager is trying to go to a state when the system theme is updated, but as there is none defined for the initial (or "Default" or "Normal") state, it has to choose the next best alternative. What I still don't understand, is why the VisualStateManager has to change visual states when the system theme is updated in the first place... don't ThemeResources refresh by themselves? Why would they depend on the VisualStateManager?
It's interesting to note that most third-party tutorials on adaptive triggers in UWP already do this. It's not clear if the authors were aware of this problem, or if they added the default state simply because they were used to doing so in the Silverlight/WPF days. Based on the documentation above and the otherwise correct UWP behavior, though, this is probably an edge case.
I am adding localization to my UWP app by adding x:uid tags to all of my elements and using the multilingual toolkit. However I've run into an issue where in one case I change the text itself in the narrow view using the visualstatemanager. How can I do this in a localized app? My first thought would be to change the uid of the element to the new match the new text, I'm not sure it's possible.
Here is an example of what I'd like to do, but doesn't work:
<textblock x:Name="DescriptionTextBox" x:uid="DescriptionTextBox"/> // Normal long description
....
<VisualState x:Name="NarrowState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="DescriptionTextBox.Uid" Value="DescriptionTextBoxShort" /> // Uid of short description
x:Uid is no dependency property on your TextBlock and can't be set at runtime. You can double check this by going to the generated code behind (.g.i.cs file) of your XAML page. To do this, hit F12 on InitializeComponent() in the constructor. Now locate your control in the generated code and start drilling down the object tree: you won't encounter a Uid property. It's a XAML directive backed up by an attribute.
How I typically solve this is having 2 TextBlocks (one collapsed) with the the long and short text and toggle Visibility between both TextBlocks in your VisualStates. Depending on what the parent container of these TextBlocks is, you might need to add a StackPanel or Grid as some parent controls can only have 1 child element.
Quick question for the pros. I have a userControl sitting in the centre of my page. When the page is tapped I want to use a doubleAnimation to dock the control to the left of the page.
This line To="{Binding Canvas.Left}" is not working. I have to specify a value. eg. -200 which will animate (TranslateX) to the left but for some screens it never reaches the left of the page. How should I handle this? Also is the tapped event of the page the correct place to check for the first interaction on the page since it should only happen the first time the user interacts?
In my code behind I want to use something like if(usercontrol.left > 0){storyboard.begin;}. What is the best way to achieve this?
I will probably have to put a From={Binding UserControl.CurrentPosition} as well
Thanks
<Page.Resources>
<Storyboard x:Name="EntryAnimation">
<DoubleAnimation Duration="0:0:1"
To="{Binding Canvas.Left}"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)"
Storyboard.TargetName="idcMain"
d:IsOptimized="True" />
</Storyboard>
</Page.Resources>
Instead of using storyboards, You can use system transitions (RepositionTransition in your case). This way, You Just modify the Canvas.Left property and it's automagically animated using transitions timing consistent with the global OS UX.