Adaptive User Interface Windows 10

With the launch of Windows 10, Microsoft changed the whole paradigm of programming. Microsoft took us to era of Universal Applications, which means that our same code will run on all the devices. This is being highly appreciated among developers but at the same time, it’s raising question that how will the same interface work on all devices and different sizes. This article answers the same issue. We’ll be looking on how we can design interface for universal applications, which runs on all devices. The prerequisite for this tutorial are  Windows 10, either Technical preview or updated, and Visual Studio 2015.

 

Discussing some theories of Adaptive Interface, there are different approaches to this. We can either tailor completely different interfaces for different devices and screen sizes, or we can change our existing designs according to device and size. We won’t be going in tailoring different interfaces in the blog, as it’s a topic in its own, but I’ll be covering all the methods through which we can change our existing interface and make it adapt to our Screen sizes.

 

Let’s start by making our Universal Application:

Now, let’s just create a Basic interface, with three rectangles box of different colors. XAML of the interface can be found below:

XAML:
<Grid Background="Black"       
        <Rectangle x:Name="rectangle" Fill="#FF6E6ED8"
HorizontalAlignment="Left" Height="295" Margin="7,165,0,0"
Stroke="Black" VerticalAlignment="Top" Width="306"
d:LayoutOverrides="VerticalAlignment"/> 
        <Rectangle x:Name="rectangle1" Fill="#FF20F09B"
HorizontalAlignment="Left" Height="295" Margin="397,165,0,0"
Stroke="Black" VerticalAlignment="Top" Width="306"
d:LayoutOverrides="HorizontalAlignment"/> 
        <Rectangle x:Name="rectangle2" Fill="#FFD89E6E"
HorizontalAlignment="Left" Height="295" Margin="819,165,0,0"
Stroke="Black" VerticalAlignment="Top" Width="306"
d:LayoutOverrides="HorizontalAlignment"/> 
 
    </Grid>

We will change the position of these boxes on the basis of device screen and size of the application.

This can be done by two techniques, either using visual states or using state triggers. We’ll be going through both. The initial steps is same for both of techniques, only the final and the last step is different.

So let’s open our project in blend:

Now, let’s create different Visual states for different screen sizes. If you are wondering  what exactly is visual state, well, Visual states are a technique whereby changes to the state of a control will change the UI, by loading XAML control templates for the current state. (MSDN)

To create a new visual state Group:

Now, let’s create different states by changing the position and size of our rectangle. Every state will represent an interface for different device and screen size. For this tutorial sake’s, I’ll be just making three states. New States can be added in group by:

What we have to do In every Visual state is, just re-manage or you can say scale our interface according to the given size and our needs. In this way, we’ll be re-creating or scaling our single interface for our every Visual State.

I’m scaling my interface as:

 

Large:

Medium:

Small:

Now save our project (ctrl+s), and let’s move back to visual studio. Visual studio might prompt you and notify that changes outside project has been made and whether you wish to load new changes or not. Click on “yes to all” and that’s it! Your new XAML should look like this:

Code:

XAML
<Grid Background="Black"        <VisualStateManager.VisualStateGroups            <VisualStateGroup x:Name="VisualStateGroup"                <VisualState x:Name="small"                    <VisualState.Setters                        <Setter Target="rectangle.(FrameworkElement.Margin)"                            <Setter.Value                                <Thickness>10,10,0,0</Thickness> 
                            </Setter.Value> 
                        </Setter> 
                        <Setter Target="rectangle.(FrameworkElement.Width)"
 Value="194"/> 
                        <Setter Target="rectangle.(FrameworkElement.Height)"
Value="174"/> 
                        <Setter Target="rectangle1.(FrameworkElement.Margin)"                            <Setter.Value                                <Thickness>10,236,0,0</Thickness> 
                            </Setter.Value> 
                        </Setter> 
                        <Setter Target="rectangle1.(FrameworkElement.Width)"
Value="194"/> 
                        <Setter Target="rectangle1.(FrameworkElement.Height)"
Value="176"/> 
                        <Setter Target="rectangle2.(FrameworkElement.Margin)"                            <Setter.Value                                <Thickness>10,475,0,0</Thickness> 
                            </Setter.Value> 
                        </Setter> 
                        <Setter Target="rectangle2.(FrameworkElement.Width)"
Value="204"/> 
                        <Setter Target="rectangle2.(FrameworkElement.Height)"
Value="195"/> 
                    </VisualState.Setters> 
                </VisualState> 
                <VisualState x:Name="Large"/> 
                <VisualState x:Name="Medium"                    <VisualState.Setters                        <Setter Target="rectangle.(FrameworkElement.Margin)"                            <Setter.Value                                <Thickness>10,10,0,0</Thickness> 
                            </Setter.Value> 
                        </Setter> 
                        <Setter Target="rectangle1.(FrameworkElement.Margin)"                            <Setter.Value                                <Thickness>391,10,0,0</Thickness> 
                            </Setter.Value> 
                        </Setter> 
                        <Setter Target="rectangle2.(FrameworkElement.Margin)"                            <Setter.Value                                <Thickness>10,365,0,0</Thickness> 
                            </Setter.Value> 
                        </Setter> 
                    </VisualState.Setters> 
                </VisualState> 
            </VisualStateGroup> 
        </VisualStateManager.VisualStateGroups> 
        <Rectangle x:Name="rectangle" Fill="#FF6E6ED8" HorizontalAlignment="Left"
 Height="295" Margin="7,165,0,0" Stroke="Black" VerticalAlignment="Top"
Width="306" d:LayoutOverrides="VerticalAlignment"/> 
        <Rectangle x:Name="rectangle1" Fill="#FF20F09B"
HorizontalAlignment="Left" Height="295" Margin="397,165,0,0" Stroke="Black"
VerticalAlignment="Top" Width="306" d:LayoutOverrides="HorizontalAlignment"/> 
        <Rectangle x:Name="rectangle2" Fill="#FFD89E6E" H
orizontalAlignment="Left" Height="295" Margin="819,165,0,0" Stroke="Black"
VerticalAlignment="Top" Width="306" d:LayoutOverrides="HorizontalAlignment"/> 
 
    </Grid>

 

Now, comes the decision of whether you want to move with Visual State Manager for adaptive code or State triggers. It’s to be noted here that Visual State manager is c# based and State triggers are XAML based. More-over, we also have to decide the property and the values for which new state is triggered.

 

Let’s see visual state manager first. The property we’ll be using to change state will be the width of screen size. The widths at which we’ll be changing our states will be 600,900 and 1200. Add the following code in your file:

Code:

C#
public MainPage() 
        { 
            this.InitializeComponent(); 
             
            this.SizeChanged += MainPage_SizeChanged; 
        } 
 
        private void MainPage_SizeChanged 
( object sender, SizeChangedEventArgs e ) 
        { 
            string state = "Large"; 
            if ( e.NewSize.Width < 600 ) 
                state = "small"; 
            else if ( e.NewSize.Width < 900 ) 
                state = "Medium"; 
            else if ( e.NewSize.Width < 1200 ) 
                state = "Large"; 
            VisualStateManager.GoToState ( this, state, true ); 
 
 
 
        } 

 

 

 

 

What’s happening over here is that whenever user changes the screen size of his application, the new size is checked. And the relevant visual state is activated.  And that’s it. That’s how we make adaptive screen for different application size. To use visual state manager for different devices, use the following code:

Code:

C#
public MainPage() 
        { 
            this.InitializeComponent(); 
            this.Loaded += MainPage_Loaded; 
            this.SizeChanged += MainPage_SizeChanged; 
        } 
 
        private void MainPage_Loaded ( object sender, RoutedEventArgs e ) 
        { 
            var width = Window.Current.Bounds.Width; 
            string state = "Large"; 
            if ( width < 600 ) 
                state = "small"; 
            else if ( width < 900 ) 
                state = "Medium"; 
            else if ( width < 1200 ) 
                state = "Large"; 
            VisualStateManager.GoToState ( this, state, true ); 
        } 
 
        private void MainPage_SizeChanged ( object sender, SizeChangedEventArgs e ) 
        { 
            string state = "Large"; 
            if ( e.NewSize.Width < 600 ) 
                state = "small"; 
            else if ( e.NewSize.Width < 900 ) 
                state = "Medium"; 
            else if ( e.NewSize.Width < 1200 ) 
                state = "Large"; 
            VisualStateManager.GoToState ( this, state, true ); 
 
 
 
        } 

 

 

In addition to screen size being changed, we are also catering different devices by checking the width of our screen at the time page is loaded.

 

Now coming to state triggers, as I mentioned earlier, it’s all XAML based. All we have to do is notify our visual states, that when should they be triggered. This can be done by adding VisualState.StateTriggers in every VisualState. Our new XAML code for states will look like:

XAML
<Grid Background="Black"        <VisualStateManager.VisualStateGroups            <VisualStateGroup x:Name="VisualStateGroup"                <VisualState x:Name="small"                    <VisualState.StateTriggers                        <AdaptiveTrigger MinWindowWidth="599"/> 
 
                    </VisualState.StateTriggers> 
                    <VisualState.Setters                        <Setter Target="rectangle.(FrameworkElement.Margin)"                            <Setter.Value                                <Thickness>10,10,0,0</Thickness> 
                            </Setter.Value> 
                        </Setter> 
                        <Setter Target="rectangle.(FrameworkElement.Width)"
Value="194"/> 
                        <Setter Target="rectangle.(FrameworkElement.Height)"
Value="174"/> 
                        <Setter Target="rectangle1.(FrameworkElement.Margin)"                            <Setter.Value                                <Thickness>10,236,0,0</Thickness> 
                            </Setter.Value> 
                        </Setter> 
                        <Setter Target="rectangle1.(FrameworkElement.Width)"
Value="194"/> 
                        <Setter Target="rectangle1.(FrameworkElement.Height)"
Value="176"/> 
                        <Setter Target="rectangle2.(FrameworkElement.Margin)"                            <Setter.Value                                <Thickness>10,475,0,0</Thickness> 
                            </Setter.Value> 
                        </Setter> 
                        <Setter Target="rectangle2.(FrameworkElement.Width)"
Value="204"/> 
                        <Setter Target="rectangle2.(FrameworkElement.Height)"
Value="195"/> 
                    </VisualState.Setters> 
                </VisualState> 
                <VisualState x:Name="Large"                    <VisualState.StateTriggers                        <AdaptiveTrigger MinWindowWidth="1199"/> 
 
                    </VisualState.StateTriggers> 
                </VisualState> 
                <VisualState x:Name="Medium"                    <VisualState.StateTriggers                        <AdaptiveTrigger MinWindowWidth="899"/> 
 
                    </VisualState.StateTriggers> 
                    <VisualState.Setters                        <Setter Target="rectangle.(FrameworkElement.Margin)"                            <Setter.Value                                <Thickness>10,10,0,0</Thickness> 
                            </Setter.Value> 
                        </Setter> 
                        <Setter Target="rectangle1.(FrameworkElement.Margin)"                            <Setter.Value                                <Thickness>391,10,0,0</Thickness> 
                            </Setter.Value> 
                        </Setter> 
                        <Setter Target="rectangle2.(FrameworkElement.Margin)"                            <Setter.Value                                <Thickness>10,365,0,0</Thickness> 
                            </Setter.Value> 
                        </Setter> 
                    </VisualState.Setters> 
                </VisualState> 
            </VisualStateGroup> 
        </VisualStateManager.VisualStateGroups> 
        <Rectangle x:Name="rectangle" Fill="#FF6E6ED8" HorizontalAlignment="Left"
 Height="295" Margin="7,165,0,0" Stroke="Black" VerticalAlignment="Top"
Width="306" d:LayoutOverrides="VerticalAlignment"/> 
        <Rectangle x:Name="rectangle1" Fill="#FF20F09B" HorizontalAlignment="Left"
Height="295" Margin="397,165,0,0" Stroke="Black" VerticalAlignment="Top"
Width="306" d:LayoutOverrides="HorizontalAlignment"/> 
        <Rectangle x:Name="rectangle2" Fill="#FFD89E6E"
HorizontalAlignment="Left" Height="295" Margin="819,165,0,0" Stroke="Black"
VerticalAlignment="Top" Width="306" d:LayoutOverrides="HorizontalAlignment"/> 
 
    </Grid>

 

 

 

Over here, every state has his own trigger, which gets activated on its trigger. The property we are using to activate is MinWindowWidth. The superiority which State Triggers have above visual state managers is that they can be previewed by changing device settings in visual studio at the time of designing. And more over, as it’s XAML based, so we don’t have to code differently for device change and application size change.

 

Demo:

 

You can download the complete code from here

Advertisements

Using Speech Recognition without Internet in Silver light applications

This article will focus on how to use  SpeechRecognizer in applications in order to enable Voice Recognition in offline mode. We’ll be building an application which will have a pre-defined user-customized grammar list and will be able to recognize the text from that grammar.

 

  • To start with exercise, create a Silverlight project of your choice, for this blog, we’ll be working with Blank App application.

 

 

  • Now, First thing we should do is open “WMAppManifest.xaml” and enable “ID_CAP_MICROPHONE” and “ID_CAP_SPEECH_RECOGNITION” under the “Capabilities” tag.

  • Next we’ll create a simple interface with one Application bar Button which will start the listening process and one TextBox. We’ll name the Textbox as “textbox”. Then create a click event_handler for the Button. Overall interface will look something like this
Designer View:

 

Xaml:
<Grid     <TextBlock Text="Speech Recognition without internet" Margin="9,-7,0,0" 
TextWrapping="Wrap" FontSize="50"/> 
    <TextBox x:Name="textbox" HorizontalAlignment="Left" 
Height="154" Margin="33,187,0,0" TextWrapping="Wrap" 
Text="Output box" VerticalAlignment="Top" Width="395"/> 
  
</Grid> 
  
  
<phone:PhoneApplicationPage.ApplicationBar    <shell:ApplicationBar Mode="Default" Opacity="1.0" 
IsMenuEnabled="True" IsVisible="True"        <shell:ApplicationBarIconButton Click="ApplicationBarIconButton_Click"
 IconUri="/Assets/AppBar/Microphone.png" Text="Listen"/> 
     
    </shell:ApplicationBar> 
</phone:PhoneApplicationPage.ApplicationBar>

Code:

  • C#
    SpeechRecognizer speechrecognizer; 
          
         public MainPage() 
         { 
             InitializeComponent(); 
             speechrecognizer = new SpeechRecognizer(); 
             string[] commands = { "Hello""This""is""easy"}; 
      
             speechrecognizer.Grammars.
    AddGrammarFromList("Commandset1", commands); 
         
         }
  • Now we come to the last step of the program that is writing the recognition code. We’ll be implementing all this in the event handler of button. Wait time will be specified, for the duration of which application will listen to speech before processing it. This time is specified by setting the value ofspeechrecognizer.Settings.InitialSilenceTimeout. In order to get the processed result, we need to create an object of class SpeechRecognitionResult  which we’ll be naming result. It will be initialized by speechrecognizer’s result. This is an Async process, so we’ll not only add await command before this but also make this whole function async. Refer to the snippet given below for implementation. Now all that’s left is seeing whether the Audio captured is from the defined grammar or not. For that, we’ll use SpeechRecognitionResult.TextConfidence property. This property can return High, Medium and Low, depending on the similarity with the text from grammar. We can implement any one of them, depending on how precise we want it to detect.

Code:

  •  C#
    private async void ApplicationBarIconButton_Click(object sender, EventArgs e) 
          { 
              speechrecognizer.Settings.InitialSilenceTimeout = 
    TimeSpan.FromMinutes(1.00); 
              SpeechRecognitionResult result = 
    await speechrecognizer.RecognizeAsync(); 
      
              if (result.TextConfidence == SpeechRecognitionConfidence.High
     || result.TextConfidence == SpeechRecognitionConfidence.Medium
     || result.TextConfidence == SpeechRecognitionConfidence.Low) 
              { 
                  try 
                  { 
                      textbox.Text = result.Text; 
      
                  } 
                  catch (Exception ex) 
                  { 
      
                  } 
              } 
          }
  • And that’s it, our basic application is good to go.
You can download the latest code from here.

Windows 10 Relative Panels

Microsoft introduced few new controls in windows 10 universal applications, to further facilitate developers. And one of these new controls is Relative panels . As the name suggests, Relative panels are layout controls, used when we want to bind controls position relative to each other. In simple words, we can say that they are used when we want to define the position of one element, in respect to another element. Following this, theoretically, we can make whole interface relative to each other, and by just defining the position of our main element.

If you are coming from WPF background, you might remember and have even worked with anchors and docks. Relative panels work in same manner.

 

Let’s start with some Hands-on experience with relative panels.

 

Open Visual Studio and create a Universal application:

Now, let’s just make our grid’s background black. Our xaml and interface till now should be something like this:

 

Interface:

Xaml:

  <Grid Background="Black"</Grid>
Now, let’s add our relative panel in grid. It’s to be noted here that the elements in a relative panel will behave/react according to the elements/control of that relative panels. But is it possible to define multiple relative panels under one relative panel and then bind them? Yes, it’s completely possible.

We’ll just add our relative panel, and create few rectangles in them. our interface should look something like this:

 

Interface:

Xaml:

 

    <Grid Background="Black" 
        <RelativePanel 
            <Rectangle Fill="Aquamarine" HorizontalAlignment="Left" 
MinHeight="150"  VerticalAlignment="Top" 
MinWidth="430"/> 
 
            <Rectangle Fill="Azure" HorizontalAlignment="Left" 
MinHeight="150" Margin="587,10,-1007,-150" 
VerticalAlignment="Top" MinWidth="430"/> 
 
            <Ellipse Fill="Blue" HorizontalAlignment="Left" 
MinHeight="300" Margin="357,220,-710,-577" 
VerticalAlignment="Top" MinWidth="430"/> 
 
  
       </RelativePanel> 
 
    </Grid> 

 

 

So, our basic interface is done. It’s time to implement the actual use of relative panels. Few pointers to note over here:

  • Relative panels work on the basis of name of the control. So, we have to name every control through which we have to bind our current control. For this purpose, let’s name our rectangles and Ellipse.
  • There are different properties of Relative Panel, through which we can bind them. These properties defines where we have to place our current control in respect to our other control. This includes properties such as
    • RelativePanel.Above
    • RelativePanel.AlignLeftWith
    • RelativePanel.Below

You can find the complete list and details of every property from MSDN.

Now, getting back to coding and implementing our relative panels, after renaming, our xaml should be like this:

Xaml:

<Grid Background="Black" 
        <RelativePanel 
            <Rectangle x:Name="rectangle1" Fill="Aquamarine" 
HorizontalAlignment="Left" MinHeight="150"  VerticalAlignment="Top"
 MinWidth="430"/> 
 
            <Rectangle x:Name="rectangle2" 
Fill="Azure" HorizontalAlignment="Left" 
MinHeight="150" Margin="587,10,-1007,-150" 
VerticalAlignment="Top" MinWidth="430"/> 
 
            <Ellipse x:Name="ellipse1" Fill="Blue"
 HorizontalAlignment="Left" MinHeight="300" 
Margin="357,220,-710,-577" VerticalAlignment="Top"
 MinWidth="430" /> 
 
 
 
 
 
        </RelativePanel> 
 
    </Grid>

So, finally our code is ready to implement relative paneling.

All we’ll do is remove margins from every control/element, and replace it with relative panel property and define where we want our control/element to be, in regards to other panels.

 

Interface

Xaml:

    <Grid Background="Black" 
        <RelativePanel 
            <Rectangle x:Name="rectangle1" 
Fill="Aquamarine" HorizontalAlignment="Left" 
MinHeight="150"  VerticalAlignment="Top" 
MinWidth="430"/> 
 
            <Rectangle x:Name="rectangle2" Fill="Azure" 
HorizontalAlignment="Left" MinHeight="150" 
VerticalAlignment="Top" MinWidth="430" 
RelativePanel.RightOf="rectangle1"/> 
 
            <Ellipse x:Name="ellipse1" Fill="Blue" 
HorizontalAlignment="Left" MinHeight="300"  V
erticalAlignment="Top" MinWidth="430" 
RelativePanel.AlignRightWithPanel="True" RelativePanel.Below="rectangle2" /> 
 
 
 
 
 
        </RelativePanel> 
 
    </Grid>

 

What I’ve done over here is I’ve binded my element rectangle2 with rectangle1. I’ve binded it in such a manner that it will always remain on the right of rectangle1. But in-case of ellipse1, I’ve not only binded it to remain below of rectangle2, but I’ve also binded it that it will always remain to the right side of my current panel. In this manner, whenever I resize my application, It’ll always remain at the right side of my panel.

 

You can download the complete code from here.