Sergiy Baydachnyy

Blog about technologies

Archive for June 30th, 2015

UWP: New features of Visual State Manager (part 2)

with one comment

In the previous post I told about two new features of Visual State Manager like setters and adaptive triggers and you can see that adaptive triggers are limited to screen size only. But in real applications you can change your interface based on lots of different parameters like Xbox controller availability, screen orientation, data availability etc. So, in this article I want to show how to extend existing infrastructure of adaptive triggers creating new one.

It’s hard to find an application which is not connected to Internet. But getting data from the Internet takes some time. Usually I use ProgressRing to show that getting the data is in progress and I use VisualStateManager to show or hide elements based on data availability. Usually there are three states like Loading, Loaded and Error. Of course, I needed to implement some code which change state of application based on state of “view model”. Let’s see if it’s possible to implement our own trigger which helps to avoid coding in code-behind class of my page completely.

First of all we need to check if our “view model” class is ready for triggers. It’s better to implement a property which shows current state of our model as well as an event which fires every time when model change own state. Of course, it’s better to implement base class for all view models in our application.

public enum StateEnum { Loading, Loaded, Error } public class StateChangeEventArgs:EventArgs { public StateEnum State { get; set; } } public delegate void StateChangedDelegate(object model, StateChangeEventArgs args); public class PageViewModel { public event StateChangedDelegate StateChanged; public void InitModel() { if (StateChanged != null) StateChanged.Invoke(this, new StateChangeEventArgs() { State = StateEnum.Loading }); //load data if (StateChanged != null) StateChanged.Invoke(this, new StateChangeEventArgs() { State = StateEnum.Loaded }); } }

I have implemented InitModel method as well as an example of code where we need to invoke StateChanged event. Usually you will implement this method in your own way and into inherited classes.

Once you have updated “view model” you can create object of it inside page XAML file:

<Page.Resources> <st:PageViewModel x:Name="model"></st:PageViewModel> </Page.Resources>

It’s time to create your own trigger. In order to do it you need to create a new class which inherits StateTriggerBase class. Inside the class you can declare any method and properties but you need find a place where you will call SetActive method. Thanks to this method you can activate or deactivate your trigger. For example, I implemented the following class:

public class DataTrigger: StateTriggerBase { private PageViewModel model; public PageViewModel Model { get { return model; } set { model = value; model.StateChanged += Model_StateChanged; } } public string StateOfModel { get; set; } private void Model_StateChanged(object model, StateChangeEventArgs args) { SetActive(args.State.ToString().Equals(StateOfModel)); } }

You can see that I have two properties in the class which allow to set reference to the current view model and define a state which we are going to use to activate the trigger. Once view model is initialized we will activate or deactivate the trigger using the event handler for StateChanged event.

Finally, I declared the following states:

<VisualState x:Name="Loading"> <VisualState.Setters> <Setter Target="gridView.Visibility" Value="Collapsed"></Setter> <Setter Target="progress.Visibility" Value="Visible"></Setter> </VisualState.Setters> <VisualState.StateTriggers> <st:DataTrigger Model="{StaticResource model}" StateOfModel="Loading"></st:DataTrigger> </VisualState.StateTriggers> </VisualState> <VisualState x:Name="Loaded"> <VisualState.Setters> <Setter Target="gridView.Visibility" Value="Visible"></Setter> <Setter Target="progress.Visibility" Value="Collapsed"></Setter> </VisualState.Setters> <VisualState.StateTriggers> <st:DataTrigger Model="{StaticResource model}" StateOfModel="Loaded"></st:DataTrigger> </VisualState.StateTriggers> </VisualState>

It’s really cool and allows to make better implementation of MVVM pattern.

Written by Sergiy Baydachnyy

06/30/2015 at 10:46 PM

UWP: New features of Visual State Manager (part 1)

with one comment

If you are going to develop Universal Windows applications for Windows 10 you should think about adaptive interface which will successfully work on all Windows devices with different screen sizes, orientations and resolutions. As I mentioned in my previous post, Visual State Manager is a very good approach to implement adaptive interface. Visual State Managers allow to declare different states of UI with ability to change the current state in runtime. That’s why Microsoft continues to invest resources to this component and today developers can use two more features there.

Setters

If you are going to use animation to change the state you can continue to use old approach with Storyboard but in many cases animation is not needed. For example if you want to change your layout because user changed screen orientation, you need to change properties of controls very quickly. So, developers usually used ObjectAnimationUsingKeyFrame in order to make all needed changes in 0 seconds:

<Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/> </ObjectAnimationUsingKeyFrames> </Storyboard>

You can see that this approach is not optimal because it requires using several complex objects with many parameters to make the simple thing. That’s why a new XAML element called Setter can be very useful. For example, you can rewrite the same thing using the Setter element:

<VisualState.Setters> <Setter Target="comboBox.Visibility" Value="Collapsed"></Setter> </VisualState.Setters>

It’s much clearer. Developers need to declare a property’s name and a new value in the selected state.

If you want you can mix Setters and Storyboard inside the same state.

Adaptive triggers

Of course it’s not enough to declare all possible states – developers need to implement code which allows to change the state dynamically. For example, if you are going to change the state based on screen size, you need to implement event handler for SizeChanged event and use GoToState method of VisualStateManager class. Sometimes it’s not clear when a state should be applied. Additionally, if you have several state groups and need to combine several states, you can easily make a mistake. That’s why Microsoft implemented an infrastructure for state triggers. It allows to declare one trigger or a set of triggers inside XAML to understand which state should be applied. So, you can declare all needed rules without coding at all.

In the current version Microsoft presented just one trigger – AdaptiveTrigger, but I hope that in release we might see some more triggers. Additionally you can develop your own triggers as well.

In the following code you can see usage of AdaptiveTrigger:

<VisualState x:Name="Normal"> <VisualState.Setters> <Setter Target="comboBox.Visibility" Value="Visible"></Setter> </VisualState.Setters> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="700"></AdaptiveTrigger> </VisualState.StateTriggers> </VisualState> <VisualState x:Name="Mobile"> <VisualState.Setters> <Setter Target="comboBox.Visibility" Value="Collapsed"></Setter> </VisualState.Setters> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="0"></AdaptiveTrigger> </VisualState.StateTriggers> </VisualState>

You can see that AdaptiveTrigger has only two parameters: MinWindowWidth and MinWindowHeight. These parameters allow to switch state of window based on size. In our example, if we have the width of the windows smaller than 700 pixels, we will collapse an element called comboBox.

In the next post I am going to show how to create your own trigger.

Written by Sergiy Baydachnyy

06/30/2015 at 10:40 PM