tag:blogger.com,1999:blog-74074068834095956202024-02-18T21:48:59.334-08:00< Damien Delaire /> .NET BlogDamien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comBlogger53125tag:blogger.com,1999:blog-7407406883409595620.post-66655744399672154612022-02-09T00:56:00.000-08:002022-02-09T00:56:38.352-08:00Propagating a VisualState of your ListViewItemPresenter to your DataTemplate using the Parent element [XAML]<h3 style="text-align: left;">In this Article we are going to see how to Propagate a VisualState of your ListViewItemPresenter to your DataTemplate using the Parent element</h3><div>My need was that I needed to be able to pass down the information that an item was selected so that I could have the round blue border around the icon. One solution would have been to add a isSelected property to my header items however I wished something simple to manage the selected state of my header.</div><div><br /></div><div>Here is a snapshot of what I wanted:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://i.imgur.com/Y8VnSxB.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="641" height="400" src="https://i.imgur.com/Y8VnSxB.png" width="321" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div>In the end you have two options to propagate the VisualState. First you can use this option which I found on <a href=" https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.visualstatemanager?view=winrt-19041">Microsoft Docs </a><h4 style="background-color: white; box-sizing: inherit; color: #171717; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 1.75rem; line-height: 1.3; margin: 30px 0px 18px -1.875rem; outline-color: inherit; padding: 0px 0px 0px 1.875rem; position: relative; text-align: left;">Visual states for elements that aren't controls</h4><p><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717; font-size: 16px;"></span></p><blockquote><span style="font-size: x-small;"><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">Visual states are sometimes useful for scenarios where you want to change the state of some area of UI that's not immediately a</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.control?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">Control</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">subclass. You can't do this directly because the</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><em style="box-sizing: inherit; color: #171717; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit;">control</em><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">parameter of the</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.visualstatemanager.gotostate?view=winrt-19041#Windows_UI_Xaml_VisualStateManager_GoToState_Windows_UI_Xaml_Controls_Control_System_String_System_Boolean_" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">GoToState</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">method requires a</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.control?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">Control</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">subclass, which refers to the object that the VisualStateManager acts upon.</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.page?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">Page</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">is a</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.control?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">Control</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">subclass, and it's fairly rare that you'd be showing UI in a context where you don't have a</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.page?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">Page</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">, or your</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.window.content?view=winrt-19041#Windows_UI_Xaml_Window_Content" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">Window.Content</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">root isn't a</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.control?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">Control</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">subclass. We recommend you define a custom</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.usercontrol?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">UserControl</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">to either be the</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.window.content?view=winrt-19041#Windows_UI_Xaml_Window_Content" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">Window.Content</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">root or be a container for other content you want to apply states to (such as a</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.panel?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">Panel</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">). Then you can call</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.visualstatemanager.gotostate?view=winrt-19041#Windows_UI_Xaml_VisualStateManager_GoToState_Windows_UI_Xaml_Controls_Control_System_String_System_Boolean_" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">GoToState</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">on your</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.usercontrol?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">UserControl</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">and apply states regardless of whether the rest of the content is a</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.control?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">Control</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">. For example you could apply visual states to UI that otherwise consists of just a</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.swapchainpanel?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">SwapChainPanel</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">so long as you placed that within your</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.usercontrol?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">UserControl</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">and declared named states that apply to the properties of the parent</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.usercontrol?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">UserControl</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">or of the named</span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><a data-linktype="relative-path" href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.swapchainpanel?view=winrt-19041" style="box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif; outline-color: inherit; outline-style: initial; outline-width: 0px; overflow-wrap: break-word; text-decoration-line: none;">SwapChainPanel</a><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;"> </span><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717;">part of the template.</span></span></blockquote><span face=""Segoe UI", SegoeUI, "Helvetica Neue", Helvetica, Arial, sans-serif" style="background-color: white; color: #171717; font-size: 16px;"></span><p></p><p>Source: https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.visualstatemanager?view=winrt-19041</p><p>However this was a total fail for me as it never worked and also seemed overkill to set a Usercontrol inside my DataTemplate, I do think that with a bit more work I could have gotten it to work but belived that a simpler solution was possible for my needs.</p><h3 style="text-align: left;">Binding to the ParentElement</h3><p>In the end the solution that I found that worked the best for my needs was to bind the element to its parent so that when the parent knew that its item was being selected I could pass down this information to my the DataTemplate. The idea was to bind the BorderThickness of my elements in my DataTemplate to it ParentElement, in xaml this means:</p><pre style="background-color: white; line-height: 16.25px; margin-bottom: 0px; margin-top: 0px;"><span style="color: #0000cc;">BorderThickness=</span><span style="background-color: #fff0f0;">"{Binding BorderThickness, RelativeSource={RelativeSource TemplatedParent}}"</span></pre><p>Here my <span style="background-color: #fff0f0;">TemplatedParent</span> is the ListViewItemPresenter that is located in my ListView. And with this I was able to pass the different states values Selected/UnSelected to my DataTemplate. I do agree that If i was able to pass all the different states to my DataTemplate that would have been better but this is the next best thing for me.</p><p>Here is my DataTemplate:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="line-height: 125%; margin: 0px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52</pre></td><td><pre style="line-height: 125%; margin: 0px;"><span style="color: #007700;"><DataTemplate</span> <span style="color: #0000cc;">x:Key=</span><span style="background-color: #fff0f0;">"KeyHeaderFollowingItemTemplate"</span> <span style="color: #0000cc;">x:DataType=</span><span style="background-color: #fff0f0;">"m:HeaderItemViewModel"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><Grid</span>
<span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"RootGrid"</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"235"</span>
<span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"65"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"4"</span>
<span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><Grid.RowDefinitions></span>
<span style="color: #007700;"><RowDefinition</span> <span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"65"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></Grid.RowDefinitions></span>
<span style="color: #007700;"><StackPanel</span> <span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Left"</span> <span style="color: #0000cc;">Orientation=</span><span style="background-color: #fff0f0;">"Horizontal"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><Grid></span>
<span style="color: #007700;"><Border</span>
<span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"58"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"0,0,12,0"</span>
<span style="color: #0000cc;">Background=</span><span style="background-color: #fff0f0;">"Transparent"</span>
<span style="color: #0000cc;">BorderBrush=</span><span style="background-color: #fff0f0;">"{StaticResource DmLightBlueBrush}"</span>
<span style="color: #0000cc;">BorderThickness=</span><span style="background-color: #fff0f0;">"{Binding BorderThickness, RelativeSource={RelativeSource TemplatedParent}}"</span>
<span style="color: #0000cc;">CornerRadius=</span><span style="background-color: #fff0f0;">"5"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><Grid></span>
<span style="color: #007700;"><controls:ImageEx</span>
<span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"HeaderImg"</span>
<span style="color: #0000cc;">Grid.Row=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"51"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"0,0,0,0"</span>
<span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Center"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Center"</span>
<span style="color: #0000cc;">BorderThickness=</span><span style="background-color: #fff0f0;">"{Binding BorderThickness, RelativeSource={RelativeSource TemplatedParent}}"</span>
<span style="color: #0000cc;">CornerRadius=</span><span style="background-color: #fff0f0;">"4"</span>
<span style="color: #0000cc;">Source=</span><span style="background-color: #fff0f0;">"{Binding HeaderImg}"</span>
<span style="color: #0000cc;">Stretch=</span><span style="background-color: #fff0f0;">"UniformToFill"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></Grid></span>
<span style="color: #007700;"></Border></span>
<span style="color: #007700;"></Grid></span>
<span style="color: #007700;"><TextBlock</span>
<span style="color: #0000cc;">Name=</span><span style="background-color: #fff0f0;">"TitleTxt"</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"160"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"0,8,0,8"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Center"</span>
<span style="color: #0000cc;">FontFamily=</span><span style="background-color: #fff0f0;">"Retina"</span>
<span style="color: #0000cc;">FontSize=</span><span style="background-color: #fff0f0;">"16"</span>
<span style="color: #0000cc;">FontWeight=</span><span style="background-color: #fff0f0;">"Bold"</span>
<span style="color: #0000cc;">LineHeight=</span><span style="background-color: #fff0f0;">"16"</span>
<span style="color: #0000cc;">Text=</span><span style="background-color: #fff0f0;">"{Binding HeaderTitle, FallbackValue=Loading}"</span>
<span style="color: #0000cc;">TextTrimming=</span><span style="background-color: #fff0f0;">"WordEllipsis"</span>
<span style="color: #0000cc;">TextWrapping=</span><span style="background-color: #fff0f0;">"Wrap"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></StackPanel></span>
<span style="color: #007700;"></Grid></span>
<span style="color: #007700;"></DataTemplate></span>
</pre></td></tr></tbody></table></div>
<br />Happy Coding!<br /><br /><br />
Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-31337605385875201992021-11-29T06:22:00.000-08:002022-03-17T00:24:59.670-07:00UWP using ChangeView() on a ScrollViewer so that the focused item can be placed with a specific offset [C#]<div class="question" data-questionid="22535838" id="question" style="background-color: white; border: 0px; box-sizing: inherit; clear: both; color: #242729; font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; font-size: 13px; font-stretch: inherit; font-variant-east-asian: inherit; font-variant-numeric: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">
<div class="post-layout" style="border: 0px; box-sizing: border-box; display: grid; flex-wrap: wrap; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; grid-template-columns: max-content 1fr; justify-content: flex-end; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;">
<div class="postcell post-layout--right" style="border: 0px; box-sizing: inherit; flex-shrink: 1; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; grid-column: 2 / auto; line-height: inherit; margin: 0px; min-width: 0px; padding: 0px; vertical-align: top; width: auto;">
<div class="post-text" itemprop="text" style="border: 0px; box-sizing: inherit; font-size: 15px; font-stretch: inherit; font-style: inherit; font-variant: inherit; line-height: 1.3; margin: 0px 0px 5px; overflow-wrap: break-word; padding: 0px; vertical-align: baseline; width: 664px;">
<h3 style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; text-align: left; vertical-align: baseline;"><b>The initial need was that I needed to be able to sync two listview together, however one of these listview had horizontal items and was not selectable which meant that it would not inform the first listview that the selected view had changed. </b></h3><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;">The first listview is not only and indicator but can also allow to quickly access a certain row in our main listview, here is quick screenshot to better understand what I wanted to do, in red the two selected items that need to be sync and in the other colors that other ListView.</div><div class="separator" style="clear: both; font-weight: inherit; text-align: center;"><a href="https://i.imgur.com/JOnrqWw.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="625" data-original-width="800" height="501" src="https://i.imgur.com/JOnrqWw.png" width="640" /></a></div><div class="post-text" itemprop="text" style="border: 0px; box-sizing: inherit; font-size: 15px; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: 1.3; margin: 0px 0px 5px; overflow-wrap: break-word; padding: 0px; vertical-align: baseline; width: 664px;"><br /></div><span style="font-weight: inherit;">The main issue was to be able to detect when the user scrolled down on the second ListView Vertical and to also know at what index position he was at in the listview.</span><br /><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;"><br /></div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;">First we need to get the ScrollView of our ListView to detect when the user was scrolling.</div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;"><span style="font-weight: inherit;">We will create class </span><b>ListViewBaseExtension</b><span style="font-weight: inherit;">.cs which will hold the following method</span></div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;"><!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="line-height: 125%; margin: 0px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24</pre></td><td><pre style="line-height: 125%; margin: 0px;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> ScrollViewer <span style="color: #0066bb; font-weight: bold;">GetScrollViewer</span>(<span style="color: #008800; font-weight: bold;">this</span> DependencyObject element)
{
<span style="color: #008800; font-weight: bold;">if</span> (element <span style="color: #008800; font-weight: bold;">is</span> ScrollViewer)
{
<span style="color: #008800; font-weight: bold;">return</span> (ScrollViewer)element;
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i = <span style="color: #6600ee; font-weight: bold;">0</span>; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
<span style="color: #333399; font-weight: bold;">var</span> child = VisualTreeHelper.GetChild(element, i);
<span style="color: #333399; font-weight: bold;">var</span> result = GetScrollViewer(child);
<span style="color: #008800; font-weight: bold;">if</span> (result == <span style="color: #008800; font-weight: bold;">null</span>)
{
<span style="color: #008800; font-weight: bold;">continue</span>;
}
<span style="color: #008800; font-weight: bold;">else</span>
{
<span style="color: #008800; font-weight: bold;">return</span> result;
}
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">null</span>;
}
</pre></td></tr></tbody></table></div>
</div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;">This method uses <span style="color: black; font-family: inherit; font-style: inherit; font-variant-caps: inherit; font-variant-ligatures: inherit;">VisualTreeHelper which can allow us to easily access the UI visual tree.</span></div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;">Next, we will use the <span style="font-family: inherit; font-style: inherit; font-variant-caps: inherit; font-variant-ligatures: inherit;">GetScrollViewer() </span><span style="font-family: inherit; font-style: inherit; font-variant-caps: inherit; font-variant-ligatures: inherit; font-weight: inherit;">method on our ListView to get our ScrollViewer:</span></div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;">
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #888888;">//our second vertical listview</span>
AppListView.Loaded += (sender, e) =>
{
<span style="color: #888888;">//getting scrollview</span>
ScrollViewer scrollViewer = AppListView.GetScrollViewer(); <span style="color: #888888;">//Extension method</span>
<span style="color: #008800; font-weight: bold;">if</span> (scrollViewer != <span style="color: #008800; font-weight: bold;">null</span>)
{
scrollViewer.ViewChanging += ScrollViewerListView_ViewChanging;
}
};
</pre></div>
</div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;">Now let's look at our method called <span style="color: #0066bb; font-family: inherit; font-style: inherit; font-variant-caps: inherit; font-variant-ligatures: inherit; font-weight: bold;">ScrollViewerListView_ViewChanging</span><span style="font-family: inherit; font-style: inherit; font-variant-caps: inherit; font-variant-ligatures: inherit; font-weight: inherit;"> that handles the ViewChanging event from our scrollViewer.</span></div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;">Everytime we will need to get the position of our items in the list using <span style="color: black; font-family: inherit; font-style: inherit; font-variant-caps: inherit; font-variant-ligatures: inherit;">GetAllItemsPositions(), also we need to calculate the height that that user has scrolled down which will give us a </span><span style="color: black; font-family: inherit; font-style: inherit; font-variant-caps: inherit; font-variant-ligatures: inherit;">currentVerticalPosition. We will then use this to find an item that is on this position, which will then allow us to inform which item should be selected on the first listview:</span></div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;"><!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="line-height: 125%; margin: 0px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37</pre></td><td><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ScrollViewerListView_ViewChanging</span>(<span style="color: #333399; font-weight: bold;">object</span> sender, ScrollViewerViewChangingEventArgs e)
{
<span style="color: #888888;">//Offset of first listview</span>
<span style="color: #333399; font-weight: bold;">double</span> AdditionOffSetToAdd = -<span style="color: #6600ee; font-weight: bold;">200</span>;
MyItemPositions = AppListView.GetAllItemsPositions();
<span style="color: #008800; font-weight: bold;">if</span> (MyItemPositions != <span style="color: #008800; font-weight: bold;">null</span>)
{
<span style="color: #333399; font-weight: bold;">var</span> currentVerticalPosition = e.FinalView.VerticalOffset + AdditionOffSetToAdd;
<span style="color: #333399; font-weight: bold;">double</span> itemIndex = MyItemPositions.Values.Where(a => a >= currentVerticalPosition).FirstOrDefault();
CurrentVisibleItemIndex = MyItemPositions.FirstOrDefault(x => x.Value == itemIndex).Key;
<span style="color: #888888;">//Debug.WriteLine($"CurrentVisibleItemIndex :{CurrentVisibleItemIndex}");</span>
<span style="color: #888888;">//Debug.WriteLine($"previousItemIndex :{previousItemIndex}");</span>
<span style="color: #008800; font-weight: bold;">if</span> (previousItemIndex != CurrentVisibleItemIndex)
{
<span style="color: #888888;">//update previous</span>
previousItemIndex = CurrentVisibleItemIndex;
<span style="color: #888888;">//Debug.WriteLine("VerticalOffset :{0}", e.FinalView.VerticalOffset);</span>
<span style="color: #888888;">//Debug.WriteLine("possible visible item {0}", CurrentVisibleItemIndex);</span>
CurrentItemIndexChangedCommand();
}
}
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">event</span> EventHandler CurrentItemIndexChanged;
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">CurrentItemIndexChangedCommand</span>()
{
CurrentItemIndexChanged?.Invoke(<span style="color: #008800; font-weight: bold;">this</span>, <span style="color: #008800; font-weight: bold;">new</span> EventArgs());
}
</pre></td></tr></tbody></table></div>
</div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;">By listening to the event <span style="color: black; font-family: inherit; font-style: inherit; font-variant-caps: inherit; font-variant-ligatures: inherit;">CurrentItemIndexChanged, we can now update our selected item on on first listview.</span></div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;"><br /></div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;">You can find the sample application here: https://github.com/Delaire/Samples/tree/master/SyncTwoListviews</div><div style="border: 0px; box-sizing: inherit; clear: both; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin-bottom: 1em; padding: 0px; vertical-align: baseline;"><br /></div></div></div></div></div><div id="answers" style="background-color: white; border: 0px; box-sizing: inherit; clear: both; color: #242729; float: none; font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; font-size: 13px; font-stretch: inherit; font-variant-east-asian: inherit; font-variant-numeric: inherit; line-height: inherit; margin: 0px; padding: 10px 0px 0px; vertical-align: baseline; width: auto;"><div class="answer accepted-answer" data-answerid="22654499" id="answer-22654499" itemprop="acceptedAnswer" itemscope="" itemtype="http://schema.org/Answer" style="border-bottom-color: rgb(228, 230, 232); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; box-sizing: inherit; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 20px 0px; vertical-align: baseline; width: 725px;"><div class="post-layout" style="border: 0px; box-sizing: border-box; display: grid; flex-wrap: wrap; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; grid-template-columns: max-content 1fr; justify-content: flex-end; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;"><div class="answercell post-layout--right" style="border: 0px; box-sizing: inherit; flex-shrink: 1; font-family: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; grid-column: 2 / auto; line-height: inherit; margin: 0px; min-width: 0px; padding: 0px; vertical-align: baseline; width: auto;"><div class="post-text" itemprop="text" style="border: 0px; box-sizing: inherit; font-size: 15px; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: 1.3; margin: 0px 0px 5px; overflow-wrap: break-word; padding: 0px; vertical-align: baseline; width: 664px;">
</div>
</div>
</div>
</div>
</div>
Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-65164661043293835212021-10-06T00:01:00.000-07:002022-03-17T00:24:15.734-07:00Adding custom Input Validation on TextBox and PasswordBox [UWP][XAML]<h2>
<b>We are going to go over how to create a custom TextBox & PasswordBox with a new visual state.</b></h2>
I needed this kind on input box for my account creation view, where the user inputs his email and his password, the default controls don't allow you to set these controls in a invalide state when you check for example if the email is valid and if the password is strong enough. <br />
What I wanted to do is set the border of the control to red when the user had not meet the necessary steps to go to the next step in the account creation process.<br />
<br />
While we wait for WinUI 3.0 to support<a href="https://github.com/microsoft/microsoft-ui-xaml/issues/179"> input validation </a>here is my very simple version of how I implemented one on a <b>TextBox </b>and <b>PasswordBox</b>.<br />
<br />
The idea was to add a property called <b>HasError </b>to my new control and bind it to my ViewModel, when the <b>HasError </b>property is changed we can use <b>VisualStateManager </b>to change the visual of our control. What I learned was that you can create a custom <b>TextBox </b>but not a <b>PasswordBox </b>as the <b>PasswordBox </b>is a sealed class.<br />
<br />
<h2>
TextBox custom control</h2>
Here is my simple control with <b>HasError </b>property added to a TextBox my controler is called <b>LoginValidatingTextBox.cs</b><br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">LoginValidatingTextBox</span> : TextBox
{
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">LoginValidatingTextBox</span>()
{
<span style="color: #008800; font-weight: bold;">this</span>.DefaultStyleKey = <span style="color: #008800; font-weight: bold;">typeof</span>(LoginValidatingTextBox);
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #333399; font-weight: bold;">bool</span> HasError
{
<span style="color: #008800; font-weight: bold;">get</span> { <span style="color: #008800; font-weight: bold;">return</span> (<span style="color: #333399; font-weight: bold;">bool</span>)GetValue(HasErrorProperty); }
<span style="color: #008800; font-weight: bold;">set</span> { SetValue(HasErrorProperty, <span style="color: #008800; font-weight: bold;">value</span>); }
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #008800; font-weight: bold;">readonly</span> DependencyProperty HasErrorProperty =
DependencyProperty.Register(<span style="background-color: #fff0f0;">"HasError"</span>, <span style="color: #008800; font-weight: bold;">typeof</span>(<span style="color: #333399; font-weight: bold;">bool</span>), <span style="color: #008800; font-weight: bold;">typeof</span>(LoginValidatingTextBox), <span style="color: #008800; font-weight: bold;">new</span> PropertyMetadata(<span style="color: #008800; font-weight: bold;">false</span>, HasErrorUpdated));
<span style="color: #888888;">// This method will update the Validation visual state which will be defined later in the Style</span>
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">HasErrorUpdated</span>(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LoginValidatingTextBox textBox = d <span style="color: #008800; font-weight: bold;">as</span> LoginValidatingTextBox;
<span style="color: #008800; font-weight: bold;">if</span> (textBox != <span style="color: #008800; font-weight: bold;">null</span>)
{
<span style="color: #008800; font-weight: bold;">if</span> (textBox.HasError)
VisualStateManager.GoToState(textBox, <span style="background-color: #fff0f0;">"InvalidState"</span>, <span style="color: #008800; font-weight: bold;">false</span>);
<span style="color: #008800; font-weight: bold;">else</span>
VisualStateManager.GoToState(textBox, <span style="background-color: #fff0f0;">"ValidState"</span>, <span style="color: #008800; font-weight: bold;">false</span>);
}
}
}
</pre>
</div>
<br />
<br />
Next, we need to add this <b>VisualStateGroup </b>to the default style of my <b>TextBox </b>so that when we have the InvalideState activated we can update our <b>TextBox</b> UI as we wish.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #007700;"><VisualStateGroup</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"ValidationState"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><VisualState</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"InvalidState"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><Storyboard></span>
<span style="color: #007700;"><ObjectAnimationUsingKeyFrames</span> <span style="color: #0000cc;">Storyboard.TargetName=</span><span style="background-color: #fff0f0;">"BorderElement"</span> <span style="color: #0000cc;">Storyboard.TargetProperty=</span><span style="background-color: #fff0f0;">"BorderBrush"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><DiscreteObjectKeyFrame</span> <span style="color: #0000cc;">KeyTime=</span><span style="background-color: #fff0f0;">"0"</span> <span style="color: #0000cc;">Value=</span><span style="background-color: #fff0f0;">"{StaticResource DmRedBrush}"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></ObjectAnimationUsingKeyFrames></span>
<span style="color: #007700;"></Storyboard></span>
<span style="color: #007700;"></VisualState></span>
<span style="color: #007700;"><VisualState</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"ValidState"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><Storyboard</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></VisualState></span>
<span style="color: #007700;"></VisualStateGroup></span>
</pre>
</div>
<br />
Here is how we can implement this control in our UWP app<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #007700;"><controls:LoginValidatingTextBox</span>
<span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"AddressTextbox"</span>
<span style="color: #0000cc;">HasError=</span><span style="background-color: #fff0f0;">"{Binding InvalidEmailErrorVisible}"</span>
<span style="color: #0000cc;">PlaceholderText=</span><span style="background-color: #fff0f0;">"Email address"</span>
<span style="color: #0000cc;">Text=</span><span style="background-color: #fff0f0;">"{Binding UserEmailAddress}"</span> <span style="color: #007700;">/></span>
</pre>
</div>
<br />
And, now when <span style="background-color: #fff0f0;"><b>InvalidEmailErrorVisible </b></span>is true we will update our <b>TextBox </b>as needed.<br />
<br />
<h2>
<b>PasswordBox custom control</b></h2>
<div>
Next we will try to and do the same thing for the password box is not as pretty as you cant inherit from the base control you have to do it in <b>CS</b> of your view.</div>
<div>
<br /></div>
<div>
First off you need to add the same <b>VisualStateGroup </b>to the style of your <b>PasswordBox </b>same as the <b>TextBox</b>, int he code behind of your view you will need to listen to when your <span style="background-color: #fff0f0;"><b>PasswordErrorVisible </b></span>property has changed and call a method that will call:<br />
<br />
VisualStateManager.GoToState(UI ELEMENT, STATE YOU WISH, false)</div>
<div>
<br /></div>
Here is the full code:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ViewModel_PropertyChanged</span>(<span style="color: #333399; font-weight: bold;">object</span> sender, PropertyChangedEventArgs e)
{
Debug.WriteLine(e.PropertyName);
<span style="color: #008800; font-weight: bold;">switch</span> (e.PropertyName)
{
<span style="color: #008800; font-weight: bold;">case</span> <span style="background-color: #fff0f0;">"PasswordErrorVisible"</span>:
PasswordErrorChanged();
<span style="color: #008800; font-weight: bold;">break</span>;
}
}
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">PasswordErrorChanged</span>()
{
<span style="color: #008800; font-weight: bold;">if</span> (ViewModel.PasswordErrorVisible)
VisualStateManager.GoToState(password, <span style="background-color: #fff0f0;">"InvalidState"</span>, <span style="color: #008800; font-weight: bold;">false</span>);
<span style="color: #008800; font-weight: bold;">else</span>
VisualStateManager.GoToState(password, <span style="background-color: #fff0f0;">"ValidState"</span>, <span style="color: #008800; font-weight: bold;">false</span>);
}
</pre>
</div>
<br />
and there you have it fr both TextBox and PasswordBox we now have an invalid state.<br />
<br />
Hope this helps!<br />
Happy coding.<br />
<br />
<br />
<br />
<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-22994217069002362021-07-01T05:57:00.000-07:002022-03-17T00:23:34.270-07:00Microsoft Login for UWP on Windows 10 apps and Xbox One using Microsoft Graph [2020] [C#]<h2 style="text-align: left;"><b>We are going to go over how to implement Microsoft login inside your application on Windows 10 apps and Xbox One apps.</b></h2>
<b><br /></b>We used to use the old login endpoint login.microsoft.com to login our users and today we have update our app to use the new graph endpoint from Microsoft you can download the nuget package called Microsoft.Graph and also <span face="SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace" style="background-color: #fafafa; color: #171717; font-size: 14px; white-space: pre;">Microsoft.Identity.Client.</span><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://i.imgur.com/QDsOllQ.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="243" data-original-width="800" height="121" src="https://i.imgur.com/QDsOllQ.png" width="400" /></a></div><br />Microsoft has greatly improved how you can login to its API compared to how I used to <a href="https://blog.damiendelaire.com/2017/11/using-microsoft-account-login-in-your.html">login</a> or it might have been me that was not doing the best way.</div><div><br /></div><div>Next we will try to login a user using the MS documentation. We are using simple scopes for our login "user.read" and our ClientId was registered in our Azure portal.</div><div><br /></div><div>The login code:</div><div><br />
<b><!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="line-height: 125%; margin: 0px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25</pre></td><td><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">async</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">CallMsGraphLogin</span>()
{
<span style="color: #008800; font-weight: bold;">try</span>
{
<span style="color: #888888;">// Sign-in user using MSAL and obtain an access token for MS Graph</span>
GraphServiceClient graphClient = <span style="color: #008800; font-weight: bold;">await</span> SignInAndInitializeGraphServiceClient(scopes);
<span style="color: #888888;">// Call the /me endpoint of Graph</span>
Microsoft.Graph.User graphUser = <span style="color: #008800; font-weight: bold;">await</span> graphClient.Me.Request().GetAsync();
<span style="color: #333399; font-weight: bold;">string</span> token = <span style="color: #008800; font-weight: bold;">await</span> SignInUserAndGetTokenUsingMSAL(scopes);
MsTokenReceived?.Invoke(token);
}
<span style="color: #008800; font-weight: bold;">catch</span> (MsalException msalEx)
{
MsErrorLoginReceived?.Invoke(<span style="background-color: #ffaaaa; color: red;">$</span><span style="background-color: #fff0f0;">"Error Acquiring Token:{System.Environment.NewLine}{msalEx}"</span>);
<span style="color: #888888;">//await DisplayMessageAsync($"Error Acquiring Token:{System.Environment.NewLine}{msalEx}");</span>
}
<span style="color: #008800; font-weight: bold;">catch</span> (Exception ex)
{
MsErrorLoginReceived?.Invoke(<span style="background-color: #ffaaaa; color: red;">$</span><span style="background-color: #fff0f0;">"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}"</span>);
<span style="color: #008800; font-weight: bold;">return</span>;
}
}
</pre></td></tr></tbody></table></div>
</b><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">The app will register to the MS Graph API and will ask the user to login, which will generate the Microsoft login window.</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://i.imgur.com/BuN2vAo.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="755" data-original-width="800" height="302" src="https://i.imgur.com/BuN2vAo.png" width="320" /></a></div><br /><b><br /></b></div><div><br /></div><div>We will not go over the methods call <span style="background-color: white;">SignInUserAndGetTokenUsingMSAL and </span><span style="background-color: white;">SignInAndInitializeGraphServiceClient as I would be saying the same thing as the Microsoft documentation which can be found <a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-windows-uwp">here</a>.</span></div><div><br /></div><div><b><br /><!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="line-height: 125%; margin: 0px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49</pre></td><td><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #008800; font-weight: bold;">async</span> Task<<span style="color: #333399; font-weight: bold;">string</span>> SignInUserAndGetTokenUsingMSAL(<span style="color: #333399; font-weight: bold;">string</span>[] scopes)
{
<span style="color: #888888;">// Initialize the MSAL library by building a public client application</span>
PublicClientApp = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority(Authority)
.WithUseCorporateNetwork(<span style="color: #008800; font-weight: bold;">false</span>)
.WithRedirectUri(<span style="background-color: #fff0f0;">"https://login.microsoftonline.com/common/oauth2/nativeclient"</span>)
.WithLogging((level, message, containsPii) =>
{
Debug.WriteLine(<span style="background-color: #ffaaaa; color: red;">$</span><span style="background-color: #fff0f0;">"MSAL: {level} {message} "</span>);
}, LogLevel.Warning, enablePiiLogging: <span style="color: #008800; font-weight: bold;">false</span>, enableDefaultPlatformLogging: <span style="color: #008800; font-weight: bold;">true</span>)
.Build();
<span style="color: #888888;">// It's good practice to not do work on the UI thread, so use ConfigureAwait(false) whenever possible.</span>
IEnumerable<IAccount> accounts = <span style="color: #008800; font-weight: bold;">await</span> PublicClientApp.GetAccountsAsync().ConfigureAwait(<span style="color: #008800; font-weight: bold;">false</span>);
IAccount firstAccount = accounts.FirstOrDefault();
<span style="color: #008800; font-weight: bold;">try</span>
{
authResult = <span style="color: #008800; font-weight: bold;">await</span> PublicClientApp.AcquireTokenSilent(scopes, firstAccount)
.ExecuteAsync();
}
<span style="color: #008800; font-weight: bold;">catch</span> (MsalUiRequiredException ex)
{
<span style="color: #888888;">// A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token</span>
Debug.WriteLine(<span style="background-color: #ffaaaa; color: red;">$</span><span style="background-color: #fff0f0;">"MsalUiRequiredException: {ex.Message}"</span>);
authResult = <span style="color: #008800; font-weight: bold;">await</span> PublicClientApp.AcquireTokenInteractive(scopes)
.ExecuteAsync()
.ConfigureAwait(<span style="color: #008800; font-weight: bold;">false</span>);
}
<span style="color: #008800; font-weight: bold;">return</span> authResult.AccessToken;
}
<span style="color: #888888;">/// <summary></span>
<span style="color: #888888;">/// Sign in user using MSAL and obtain a token for MS Graph</span>
<span style="color: #888888;">/// </summary></span>
<span style="color: #888888;">/// <returns>GraphServiceClient</returns></span>
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">async</span> <span style="color: #008800; font-weight: bold;">static</span> Task<GraphServiceClient> SignInAndInitializeGraphServiceClient(<span style="color: #333399; font-weight: bold;">string</span>[] scopes)
{
GraphServiceClient graphClient = <span style="color: #008800; font-weight: bold;">new</span> GraphServiceClient(MSGraphURL,
<span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">DelegateAuthenticationProvider</span>(<span style="color: #008800; font-weight: bold;">async</span> (requestMessage) =>
{
requestMessage.Headers.Authorization = <span style="color: #008800; font-weight: bold;">new</span> AuthenticationHeaderValue(<span style="background-color: #fff0f0;">"bearer"</span>, <span style="color: #008800; font-weight: bold;">await</span> SignInUserAndGetTokenUsingMSAL(scopes));
}));
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">await</span> Task.FromResult(graphClient);
}
</pre></td></tr></tbody></table></div>
</b></div><div><b><br /></b></div><div><b><br /></b></div><div><b><br /></b></div><div><b><br /></b></div><div><b><br /></b></div><div><b><br /></b></div><div><b><br /></b></div><div><b><br /></b></div>Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-22787702441340764422020-12-02T02:17:00.001-08:002020-12-30T03:16:16.583-08:00UWP Entity framework update your DB schema with a new column [UWP][C#][Database]<p>The point of this article is to go over the different steps that were needed to add a new column to one of my existing table. This table was already used by my users using my application called <a href="https://www.microsoft.com/en-us/p/my-stocks-alerts-charts/9pblpg6t46ns">My Stocks Alerts & Charts</a>.</p><p>To add a new column or table to your existing DB you are going to need to create 3 new files. The first new class will be called <span style="color: #bb0066; font-weight: bold;">MyAlertQuotesModelSnapshot</span> which inherit from ModelSnapshot and have the annotation of DbContext, this will hold the new table schema model of our updated table.</p><p>Next, we will create a class called <span style="color: #bb0066; font-weight: bold;">MyFirstMigration </span>this will also hold you new table schema model, this class will not inherit from anything but will have the annotations of DbContext and Migration.</p><p>Lastly the most important part we are going to create the class that will add the column to our table this will be called <span style="color: #bb0066; font-weight: bold;">MyFirstMigration </span>will inherit from Migration and will allow us to add our new column to our table by using migrationBuilder.AddColumn as follows:</p><pre style="line-height: 16.25px; margin-bottom: 0px; margin-top: 0px;">migrationBuilder.AddColumn<<span style="color: #333399; font-weight: bold;">string</span>>(
name: <span style="background-color: #fff0f0;">"ExtraColumn"</span>,
table: <span style="background-color: #fff0f0;">"MyAlertQuotes"</span>,
nullable: <span style="color: #008800; font-weight: bold;">true</span>);</pre><p>If you had wanted to add a new table that was called <span style="background-color: #fff0f0;">MyAlertQuotes</span> we would have used migrationBuilder.CreateTable as follows:</p>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="line-height: 125%; margin: 0px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19</pre></td><td><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">override</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Up</span>(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: <span style="background-color: #fff0f0;">"MyAlertQuotes"</span>,
columns: table => <span style="color: #008800; font-weight: bold;">new</span>
{
Id = table.Column<Guid>(nullable: <span style="color: #008800; font-weight: bold;">false</span>),
SymbolId = table.Column<<span style="color: #333399; font-weight: bold;">string</span>>(nullable: <span style="color: #008800; font-weight: bold;">false</span>),
FullName = table.Column<<span style="color: #333399; font-weight: bold;">string</span>>(nullable: <span style="color: #008800; font-weight: bold;">false</span>),
Currency = table.Column<<span style="color: #333399; font-weight: bold;">string</span>>(nullable: <span style="color: #008800; font-weight: bold;">false</span>),
ExtraColumn = table.Column<<span style="color: #333399; font-weight: bold;">string</span>>(nullable: <span style="color: #008800; font-weight: bold;">false</span>),
},
constraints: table =>
{
table.PrimaryKey(<span style="background-color: #fff0f0;">"PK_MyAlertQuotes"</span>, x => x.Id);
});
}
</pre></td></tr></tbody></table></div>
<p>Which would have added a new table to our DbSchema. </p><p>One last step, you will also have a class that inherits from DbContext, make you that you add check on initialization to make sure your users have migrated to the new Db schema</p><p><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="line-height: 125%; margin: 0px;">1
2
3
4
5
6
7</pre></td><td><pre style="line-height: 125%; margin: 0px;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">CheckMigrations</span>()
{
<span style="color: #008800; font-weight: bold;">using</span> (<span style="color: #333399; font-weight: bold;">var</span> db = <span style="color: #008800; font-weight: bold;">new</span> LocalStorageContext())
{
db.Database.Migrate();
}
}
</pre></td></tr></tbody></table></div>
<div><br /></div>Personally in my App.xaml.cs I check to make sure that users have updated to my new Db Schema.<br /><p></p><p>Here are my full classes:</p><p><b>20201101_MyFirstMigration.cs
</b><!--HTML generated using hilite.me--></p><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">Microsoft.EntityFrameworkCore</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">Microsoft.EntityFrameworkCore.Infrastructure</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">Microsoft.EntityFrameworkCore.Migrations</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">MyPersonalStocks.Helpers</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System</span>;
<span style="color: #008800; font-weight: bold;">namespace</span> <span style="color: #0e84b5; font-weight: bold;">MyPersonalStocks.Common.DataBase.Migrations</span>
{
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">partial</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">MyFirstMigration</span> : Migration
{
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">override</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Up</span>(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<<span style="color: #333399; font-weight: bold;">string</span>>(
name: <span style="background-color: #fff0f0;">"ExtraColumn"</span>,
table: <span style="background-color: #fff0f0;">"MyAlertQuotes"</span>,
nullable: <span style="color: #008800; font-weight: bold;">true</span>);
}
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">override</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Down</span>(MigrationBuilder migrationBuilder)
{
//migrationBuilder.DropColumn(
// name: <span style="background-color: #fff0f0;">"ExtraColumn"</span>,
// table: <span style="background-color: #fff0f0;">"MyAlertQuotes"</span>
// );
}
}
}
</pre></div>
<p></p><p>
<br /></p><b> 20201101_MyFirstMigration.design.cs</b><br />
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">Microsoft.EntityFrameworkCore</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">Microsoft.EntityFrameworkCore.Infrastructure</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">Microsoft.EntityFrameworkCore.Migrations</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">MyPersonalStocks.Helpers</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System.Collections.Generic</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System.Linq</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System.Text</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System.Threading.Tasks</span>;
<span style="color: #008800; font-weight: bold;">namespace</span> <span style="color: #0e84b5; font-weight: bold;">MyPersonalStocks.Common.DataBase.Migrations</span>
{
<span style="color: #0000cc;"> [DbContext(typeof(LocalStorageContext))]</span>
<span style="color: #0000cc;"> [Migration("20201101_MyFirstMigration")]</span>
<span style="color: #008800; font-weight: bold;">partial</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">MyFirstMigration</span>
{
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">override</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">BuildTargetModel</span>(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation(<span style="background-color: #fff0f0;">"ProductVersion"</span>, <span style="background-color: #fff0f0;">"1.0.4"</span>);
modelBuilder.Entity(<span style="background-color: #fff0f0;">"MyPersonalStocks.Model.DbModel.AlertQuotesDb"</span>, b =>
{
b.Property<Guid>(<span style="background-color: #fff0f0;">"Id"</span>);
b.Property<<span style="color: #333399; font-weight: bold;">string</span>>(<span style="background-color: #fff0f0;">"SymbolId"</span>);
b.Property<<span style="color: #333399; font-weight: bold;">string</span>>(<span style="background-color: #fff0f0;">"FullName"</span>);
b.Property<<span style="color: #333399; font-weight: bold;">string</span>>(<span style="background-color: #fff0f0;">"Currency"</span>);
b.Property<<span style="color: #333399; font-weight: bold;">string</span>>(<span style="background-color: #fff0f0;">"ExtraColumn"</span>);
b.HasKey(<span style="background-color: #fff0f0;">"Id"</span>);
b.ToTable(<span style="background-color: #fff0f0;">"MyAlertQuotes"</span>);
});
}
}
}
</pre></div>
<br /> <br /><b>MyAlertQuotesModelSnapshot.cs</b><br /> <!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><pre style="line-height: 125%; margin: 0px;"><span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">Microsoft.EntityFrameworkCore</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">Microsoft.EntityFrameworkCore.Infrastructure</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">MyPersonalStocks.Helpers</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">MyPersonalStocks.Model.DbModel</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System.Collections.Generic</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System.Linq</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System.Text</span>;
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">System.Threading.Tasks</span>;
<span style="color: #008800; font-weight: bold;">namespace</span> <span style="color: #0e84b5; font-weight: bold;">MyPersonalStocks.Common.DataBase.Migrations</span>
{
<span style="color: #0000cc;"> [DbContext(typeof(LocalStorageContext))]</span>
<span style="color: #008800; font-weight: bold;">partial</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">MyAlertQuotesModelSnapshot</span> : ModelSnapshot
{
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">override</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">BuildModel</span>(ModelBuilder modelBuilder)
{
modelBuilder
.HasAnnotation(<span style="background-color: #fff0f0;">"ProductVersion"</span>, <span style="background-color: #fff0f0;">"1.0.4"</span>);
modelBuilder.Entity(<span style="background-color: #fff0f0;">"MyPersonalStocks.Model.DbModel.AlertQuotesDb"</span>, b =>
{
b.Property<Guid>(<span style="background-color: #fff0f0;">"Id"</span>);
b.Property<<span style="color: #333399; font-weight: bold;">string</span>>(<span style="background-color: #fff0f0;">"SymbolId"</span>);
b.Property<<span style="color: #333399; font-weight: bold;">string</span>>(<span style="background-color: #fff0f0;">"FullName"</span>);
b.Property<<span style="color: #333399; font-weight: bold;">string</span>>(<span style="background-color: #fff0f0;">"Currency"</span>);
b.Property<<span style="color: #333399; font-weight: bold;">string</span>>(<span style="background-color: #fff0f0;">"ExtraColumn"</span>);
b.HasKey(<span style="background-color: #fff0f0;">"Id"</span>);
b.ToTable(<span style="background-color: #fff0f0;">"MyAlertQuotes"</span>);
});
}
}
}
</pre></div>
<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-10378062163017828192019-10-10T02:29:00.004-07:002019-10-10T02:33:24.072-07:00Building a SMARTER Placeholder Loading UI 2.0 using only C# for your UWP application [C#,Storyboard]Previously to build my Placeholder UI I would be using a UserControl, that contained Grid, Storyboard, adding a gradient styling and a ContentControl.<br />
However this could be quite resource intensive which is not great and also I was not happy with my initial implementation.<br />
<br />
After a quick refactoring it was decided that a blinking rectangle would better fit the need and we would not need to have to animate something going to left to right.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE_yfSrotXXZe2uT1kQBvtYgBiHa9_V-dVuqz-4gNuEEny2KArYtoeuid7sXRAzFrp0mY-hhS5AFNFvcpEe3bTm2lCgrnL0EQQ1iKtZr7gilwXasEfVvNK-E4LNUpg_5O6F4KidhU2SerJ/s1600/Simple+animation+cropped.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="255" data-original-width="418" height="194" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE_yfSrotXXZe2uT1kQBvtYgBiHa9_V-dVuqz-4gNuEEny2KArYtoeuid7sXRAzFrp0mY-hhS5AFNFvcpEe3bTm2lCgrnL0EQQ1iKtZr7gilwXasEfVvNK-E4LNUpg_5O6F4KidhU2SerJ/s320/Simple+animation+cropped.gif" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<br />
To make things simple it was decided to create a new Class that would inherited from Grid:<br />
<pre style="line-height: 16.25px;"><span style="color: #008800; font-weight: bold;">
</span></pre>
<pre style="line-height: 16.25px;"><b><span style="color: #008800;">public</span> <span style="color: #008800;">class</span> <span style="color: #bb0066;">PlaceholderSkeletonView</span> : Grid</b></pre>
<pre style="line-height: 16.25px;"></pre>
Next we just needed to add a Storyboard animation that will make this element "<b>blink</b>"<br />
<br />
<pre style="line-height: 16.25px;"><b><span style="color: #333399;">var</span> blinkAnimation = <span style="color: #008800;">new</span> DoubleAnimation()
{
From = <span style="color: #6600ee;">1</span>,
To = <span style="color: #6600ee;">0.4</span>,
AutoReverse = <span style="color: #008800;">true</span>,
<span style="color: #888888;">//blink every 1sec</span>
Duration = <span style="color: #008800;">new</span> Windows.UI.Xaml.Duration(TimeSpan.FromSeconds(<span style="color: #6600ee;">1</span>)),
RepeatBehavior = RepeatBehavior.Forever
};</b></pre>
<br />
And lastly all we need is to add this blinking animation to our Storyboard:<br />
<br />
<pre style="line-height: 16.25px;"><b> myLoadingStoryboard.Children.Add(blinkAnimation);
Storyboard.SetTarget(myLoadingStoryboard, <span style="color: #008800;">this</span>);
Storyboard.SetTargetProperty(blinkAnimation, <span style="background-color: #fff0f0;">"Opacity"</span>);
Loaded += (a, e) => myLoadingStoryboard.Begin();</b></pre>
<pre style="line-height: 16.25px;"></pre>
All in all it was<br />
<br />
<br />
Full class here:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">PlaceholderSkeletonView</span> : Grid
{
Storyboard myLoadingStoryboard { <span style="color: #008800; font-weight: bold;">get</span>; <span style="color: #008800; font-weight: bold;">set</span>; }
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">PlaceholderSkeletonView</span>()
{
myLoadingStoryboard = <span style="color: #008800; font-weight: bold;">new</span> Storyboard();
<span style="color: #333399; font-weight: bold;">var</span> blinkAnimation = <span style="color: #008800; font-weight: bold;">new</span> DoubleAnimation()
{
From = <span style="color: #6600ee; font-weight: bold;">1</span>,
To = <span style="color: #6600ee; font-weight: bold;">0.4</span>,
AutoReverse = <span style="color: #008800; font-weight: bold;">true</span>,
<span style="color: #888888;">//blink every 1sec</span>
Duration = <span style="color: #008800; font-weight: bold;">new</span> Windows.UI.Xaml.Duration(TimeSpan.FromSeconds(<span style="color: #6600ee; font-weight: bold;">1</span>)),
RepeatBehavior = RepeatBehavior.Forever
};
myLoadingStoryboard.Children.Add(blinkAnimation);
Storyboard.SetTarget(myLoadingStoryboard, <span style="color: #008800; font-weight: bold;">this</span>);
Storyboard.SetTargetProperty(blinkAnimation, <span style="background-color: #fff0f0;">"Opacity"</span>);
Loaded += (a, e) => myLoadingStoryboard.Begin();
}
}
</pre>
</div>
<br />
<br />
In your XAML it would look as follows for example:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #007700;"><StackPanel</span> <span style="color: #0000cc;">Orientation=</span><span style="background-color: #fff0f0;">"Horizontal"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><local:PlaceholderSkeletonView</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"120"</span>
<span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"120"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"20"</span>
<span style="color: #0000cc;">Background=</span><span style="background-color: #fff0f0;">"#ebebeb"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><StackPanel</span> <span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"20"</span> <span style="color: #0000cc;">Orientation=</span><span style="background-color: #fff0f0;">"Vertical"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><local:PlaceholderSkeletonView</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"190"</span>
<span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"20"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"10"</span>
<span style="color: #0000cc;">Background=</span><span style="background-color: #fff0f0;">"#ebebeb"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><local:PlaceholderSkeletonView</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"150"</span>
<span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"20"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"10"</span>
<span style="color: #0000cc;">Background=</span><span style="background-color: #fff0f0;">"#ebebeb"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><local:PlaceholderSkeletonView</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"120"</span>
<span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"20"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"10"</span>
<span style="color: #0000cc;">Background=</span><span style="background-color: #fff0f0;">"#ebebeb"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></StackPanel></span>
<span style="color: #007700;"></StackPanel></span>
</pre>
</div>
<br />
<br />
Happy Coding!<br />
<br />
Github repo: <a href="https://github.com/Delaire/UIPlaceholder">https://github.com/Delaire/UIPlaceholder</a><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-57423650402770940252019-09-01T02:12:00.000-07:002019-09-05T00:52:03.382-07:00XAMARIN Tizen for Tvs and .NET Standard 2.0 [9-2019][XAML, C#]<b>My return of Experience on XAMARIN for TIZEN TVs the 1st of September 2019.</b><br />
<b><br /></b>
<a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/platform/other/tizen">Here </a>is documentation where you can find about Xamarin Forms for Tizen:<br />
<br />
After a long summer of slowly migrating all of my app libraries to .NET Standard 2 I could finally really test Tizen to see how much code I could share between my Xbox One UWP app and a new Tizen TV app.<br />
<br />
<b>Framework versions:</b><br />
<ul>
<li>Tizen.NET (5.0.0.14562)</li>
<li>Tizen.TV.UIControls (1.0.0)</li>
<li>Tizen.NET.Sdk (1.0.1) (this nuget would not update to the latest version 1.0.3)</li>
<li>Xamarin.Forms(4.1.0.709249) (forms 4.2.0.709249 was generating an error when building the app)</li>
</ul>
<div>
<br /></div>
<div>
I discovered a new library called Tizen.TV.UIControls which greatly improve the UI layout for the TV. This library contains awesome features like:</div>
<div>
<br /></div>
<div>
<b>MediaPlayer</b></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://user-images.githubusercontent.com/1029155/42200625-34b8332a-7ecf-11e8-9494-5f97cf4c3e60.gif" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="320" data-original-width="616" height="166" src="https://user-images.githubusercontent.com/1029155/42200625-34b8332a-7ecf-11e8-9494-5f97cf4c3e60.gif" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>RecycleItemsView</b></div>
<div>
<br /></div>
<div>
<img data-canonical-src="https://samsung.github.io/Tizen.TV.UIControls/guides/resources/RecycleItemsView_concept.png" height="179" src="https://camo.githubusercontent.com/3e22ff418d963fa269eacaeb91dcd4e765f265c9/68747470733a2f2f73616d73756e672e6769746875622e696f2f54697a656e2e54562e5549436f6e74726f6c732f6775696465732f7265736f75726365732f52656379636c654974656d73566965775f636f6e636570742e706e67" style="background-color: white; border-style: none; box-sizing: content-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; max-width: 100%;" width="320" /></div>
<div>
<br /></div>
<div>
<b>Horizontal lists</b></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
<img height="165" src="https://user-images.githubusercontent.com/1029155/42200631-3b63edcc-7ecf-11e8-8435-31e12c5ed79e.gif" style="border-style: none; box-sizing: content-box; max-width: 100%;" width="320" /> <img height="165" src="https://user-images.githubusercontent.com/1029155/42200633-3d5b9396-7ecf-11e8-91c2-72f3d1003360.gif" style="border-style: none; box-sizing: content-box; max-width: 100%;" width="320" /></div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
<img height="165" src="https://user-images.githubusercontent.com/1029155/42200637-4685077c-7ecf-11e8-9984-4c68048da265.gif" style="border-style: none; box-sizing: content-box; max-width: 100%;" width="320" /></div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 16px; margin-bottom: 16px;">
You can find the github repo <a href="https://github.com/Samsung/Tizen.TV.UIControls/wiki/Introducing-Tizen.TV.UIControls">here</a>.</div>
</div>
<div>
<br /></div>
<div>
<h2>
<b>Tizen TV Xamarin C#</b></h2>
</div>
<div>
<br /></div>
<div>
To get started I wanted to do a simple HTTP call to get data and set this data into a horizontal list, well I never got passed this step...</div>
<div>
<br /></div>
<div>
As for all applications you need to tell the app that it will have special privileges. First you will need to start by adding <b>http://tizen.org/privilege/internet</b> which is located in the file <b>tizen-manifest.xm</b>l and then the tab Privileges. </div>
<div>
<br />
Next here is the code I am using to get weather information:</div>
<div>
<br /></div>
<div>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;">HttpClient client;
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">async</span> System.Threading.Tasks.Task GetWeatherServiceAsync()
{
<span style="color: #333399; font-weight: bold;">var</span> uri = <span style="color: #008800; font-weight: bold;">new</span> Uri(<span style="background-color: #fff0f0;">"https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22"</span>);
<span style="color: #008800; font-weight: bold;">try</span>
{
client = <span style="color: #008800; font-weight: bold;">new</span> HttpClient();
<span style="color: #333399; font-weight: bold;">var</span> response = <span style="color: #008800; font-weight: bold;">await</span> client.GetAsync(uri);
<span style="color: #008800; font-weight: bold;">if</span> (response.IsSuccessStatusCode)
{
<span style="color: #333399; font-weight: bold;">var</span> responseContent = <span style="color: #008800; font-weight: bold;">await</span> response.Content.ReadAsStringAsync();
}
}
<span style="color: #008800; font-weight: bold;">catch</span> (Exception ex)
{
<span style="color: #333399; font-weight: bold;">var</span> error = ex;
}
}
</pre>
</div>
<br /></div>
<div>
<br /></div>
<div>
And the issue is that no matter what I tried client would never be initialized:</div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/pY58gm1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="373" data-original-width="596" height="250" src="https://i.imgur.com/pY58gm1.png" width="400" /></a></div>
<br /></div>
<div>
<br /></div>
<div>
So as of today I cant do an HTTP call on my Tizen .NET Xamarin application, ill keep you posted as soon as I find a solution.<br />
<br />
After looking more closely at all of the GitHub Sample for Tizen TV app they all generate their sample data by hand which probably means that their is an issue somewhere for TV apps, I do hope Samsung fix this ASAP as a TV app without being able to do HTTP calls is not very practical...<br />
<br />
<br />
Happy coding<br /><br /><b>- UPDATE 5 Septembre 2019 - </b><br />After discussion with Samsung it was found that I was using an old build of the Tizen emulator.<br />
<span style="background-color: white; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px;">BuildInfo: "tizen_20181210.1228946"</span><br style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px;" /><span style="background-color: white; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px;">BuildDate : "20181210_063435"</span><br />
<br />
When I should have been using a 2019 Build, once I updated to the latest build everything was working. IMO inside Visual Studio I wish I have had a warning telling me that I was using an old build.<br /></div>
<div>
<br /></div>
Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-38358719128512282312019-08-20T00:54:00.001-07:002019-08-20T00:54:13.350-07:00UWP ARM build to release : error APPX0002: Task 'GenerateAppxManifest' failed. An item with the same key has already been added.Today I was about to release a new version of an application when I go this error. This new build was mainly a classic sprint incrimination where I migrated my UWP libraries to .netstandard 2.0 and reworked and renamed small parts of the app to improve architecture of the app. No new features no major refactoring...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://d2e70e9yced57e.cloudfront.net/wallethub/images/posts/19455/how-long-does-it-take-to-build-credit.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="544" data-original-width="700" height="248" src="https://d2e70e9yced57e.cloudfront.net/wallethub/images/posts/19455/how-long-does-it-take-to-build-credit.jpg" width="320" /></a></div>
<br />
<h2>
<b>My day started with Azure DevOPs (VSTS) telling me:</b></h2>
- AppTest.ABC is not compatible with uap10.0.17134 (UAP,Version=v10.0.17134). Project AppTest.ABC supports: netstandard2.0 (.NETStandard,Version=v2.0)<br />
<br />
I had a heart attack! netstandard2.0 doesn't support uap10.0.17134 since when ?!?<br />
<br />
Looking at <a href="https://docs.microsoft.com/en-us/dotnet/standard/net-standard">https://docs.microsoft.com/en-us/dotnet/standard/net-standard</a> we can clearly see that the support starts at 10.0.16299 so this cant be the issue.<br />
<br />
<h3>
Next:</h3>
Having a deeper look at the logs in Visual Studio in Output window I saw that the nuget restore was telling me that I had<br />
<br />
<div style="background-color: black; color: white; font-family: Consolas, "Courier New", monospace; font-size: 12px; line-height: 16px; white-space: pre;">
Incompatible projects: 3</div>
<br />
Which is where I started my morning hunt to find the 3 rogue projects.<br />
<br />
<ul>
<li> To find these projects I looked at the logs and checked to see which libraries has issue</li>
</ul>
I was quickly able to find this one:<br />
<pre style="background-color: #eff0f1; border-radius: 3px; border: 0px; box-sizing: inherit; color: #242729; font-family: consolas, menlo, monaco, "lucida console", "liberation mono", "dejavu sans mono", "bitstream vera sans mono", "courier new", monospace, sans-serif; font-size: 13px; font-stretch: inherit; line-height: inherit; margin-bottom: 1em; max-height: 600px; overflow-wrap: normal; overflow: auto; padding: 12px 8px; vertical-align: baseline; width: auto;">Checking compatibility for NotificationsExtensions.Win10 14332.0.2 with UAP,Version=v10.0.17134 (win10-arm) </pre>
<div>
This was an old nuget package that I was not using anymore (don't ask me why it was not removed before), and having a second look I also saw that I had a NotificationsExtensions nuget package by removing these 2 packages I only had one incompatible projects left to find.</div>
<br />
<h3>
Nuget</h3>
Not being to find the last incompatible project I decided to look into my nuget packages to see what I could do. Here is the documentation <a href="https://docs.microsoft.com/en-us/nuget/consume-packages/managing-the-global-packages-and-cache-folders">https://docs.microsoft.com/en-us/nuget/consume-packages/managing-the-global-packages-and-cache-folders</a><br />
<br />
Next I decided to clear all of my nuget packages:<br />
<br />
You can clear all caches with this command:
<br />
<pre style="background-color: #eff0f1; border-radius: 3px; border: 0px; box-sizing: inherit; color: #242729; font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, sans-serif; font-size: 13px; font-stretch: inherit; font-variant-east-asian: inherit; font-variant-numeric: inherit; line-height: inherit; margin-bottom: 1em; max-height: 600px; overflow-wrap: normal; overflow: auto; padding: 12px 8px; vertical-align: baseline; width: auto;"><code style="border: 0px; box-sizing: inherit; font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, sans-serif; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline; white-space: inherit;">nuget locals all -clear
</code></pre>
<br />
This did not fix my issue, however when building the app in Debug ARM I was getting a new error: <b>error APPX1101: Payload contains two or more files with the same destination path 'System.Memory.dll'.</b><br />
<br />
Full error:<br />
<br />
<pre style="background-color: #eff0f1; border-radius: 3px; border: 0px; box-sizing: inherit; color: #242729; font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, sans-serif; font-size: 13px; font-stretch: inherit; font-variant-east-asian: inherit; font-variant-numeric: inherit; line-height: inherit; margin-bottom: 1em; max-height: 600px; overflow-wrap: normal; overflow: auto; padding: 12px 8px; vertical-align: baseline; width: auto;"><code style="border: 0px; box-sizing: inherit; font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, sans-serif; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline; white-space: inherit;">
6>"C:\AppTest\uap\src\AppTest.csproj" (_GenerateAppxPackage target) (1) ->
6>(_ComputeAppxPackagePayload target) ->
6> C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VisualStudio\v16.0\AppxPackage\Microsoft.AppXPackage.Targets(1793,5): error APPX1101: Payload contains two or more files with the same destination path 'System.Memory.dll'. Source files:
6>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VisualStudio\v16.0\AppxPackage\Microsoft.AppXPackage.Targets(1793,5): error APPX1101: C:\Users\damie\.nuget\packages\runtime.win10-arm-aot.microsoft.netcore.universalwindowsplatform\6.2.8\runtimes\win10-arm-aot\lib\uap10.0.15138\System.Memory.dll
6>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VisualStudio\v16.0\AppxPackage\Microsoft.AppXPackage.Targets(1793,5): error APPX1101: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\PublicAssemblies\System.Memory.dll
6>
</code></pre>
<br />
Something is going terribly wrong, I am building my app in 10.0.17134 and it is pulling a 10.0.15138 package version WHY??<br />
<br />
<span style="background-color: #eff0f1; color: #242729; font-family: "consolas" , "menlo" , "monaco" , "lucida console" , "liberation mono" , "dejavu sans mono" , "bitstream vera sans mono" , "courier new" , monospace , sans-serif; font-size: 13px; font-style: inherit; font-weight: inherit; white-space: inherit;">runtime.win10-arm-aot.microsoft.netcore.universalwindowsplatform\6.2.8\runtimes\win10-arm-aot\lib\uap10.0.15138\System.Memory.dll</span><br />
<br />
<h3>
Looking a Visual Studio</h3>
I decide to check the Compile with .NET Native tool chain for the ARM builds to see if this would fix my error. The Compile with .NET chain was already active for my builds in x86 but not for ARM<br />
<br />
Under My Project => Properties=>Build I checked :<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/6YKr803.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="275" data-original-width="759" height="228" src="https://i.imgur.com/6YKr803.png" width="640" /></a></div>
<br />
Using the .NET Native tool chain allowed me to fix my issue as the application was now using these bits to build the app.<br />
<br />
Now that I have my ARM builds working in Debug but still not in Release, to make things simpler I just opened my .<b>csproj </b>file and edited it as follows:<br />
<br />
<br />
<pre style="background-color: #eff0f1; border-radius: 3px; border: 0px; box-sizing: inherit; color: #242729; font-family: consolas, menlo, monaco, "lucida console", "liberation mono", "dejavu sans mono", "bitstream vera sans mono", "courier new", monospace, sans-serif; font-size: 13px; font-stretch: inherit; line-height: inherit; margin-bottom: 1em; max-height: 600px; overflow-wrap: normal; overflow: auto; padding: 12px 8px; vertical-align: baseline; width: auto;"><code style="border: 0px; box-sizing: inherit; font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, sans-serif; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline; white-space: inherit;"><PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>$(DefineConstants);TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
<CodeAnalysisRuleSet />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>$(DefineConstants);DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<CodeAnalysisRuleSet />
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>$(DefineConstants);TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
<CodeAnalysisRuleSet />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>$(DefineConstants);DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<CodeAnalysisRuleSet />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>$(DefineConstants);TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
<CodeAnalysisRuleSet />
<EnableGatekeeperAnalysis>true</EnableGatekeeperAnalysis>
</PropertyGroup> </code></pre>
<br />
In the end all I really needed to do was to enable<br />
<span style="background-color: #eff0f1; color: #242729; font-family: "consolas" , "menlo" , "monaco" , "lucida console" , "liberation mono" , "dejavu sans mono" , "bitstream vera sans mono" , "courier new" , monospace , sans-serif; font-size: 13px; font-style: inherit; font-weight: inherit; white-space: inherit;"><UseDotNetNativeToolchain>true</UseDotNetNativeToolchain></span><br />
on my ARM builds which means to not have been the case before.<br />
<br />
In the end I was able to once again build and release my application, I hope that this has helped you.<br />
<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-28238463635079171882019-03-01T03:07:00.000-08:002019-08-28T01:44:56.223-07:00XAMARIN Tizen for Tvs and .NET Standard 2.0 [2019][XAML, C#]<b>My return of Experience on XAMARIN for TIZEN TVs the 1st of March 2019</b><br />
<br />
<a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/platform/other/tizen">Here </a>is documentation where you can find about Xamarin Forms for Tizen:<br />
<br />
Having reseted my laptop since last time I had used Xamarin Tizen I needed to go through the all the different steps to re install Tizen, you can find the full steps <a href="https://developer.tizen.org/development/visual-studio-tools-tizen/installing-visual-studio-tools-tizen#install">here</a>:<br />
<br />
TIP: took me 10 minutes to figure out why I could not create an emulator image , make sure that in your package manager you install the Tizen 4 TV emulator and the Tizen SDK tools. Under Extensions SDK make sure you also select TV extensions, the download of all of the SDK and emulators can take up quite a long time so in the mean time I had recommended that you head over to <a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/platform/other/tizen">Microsoft Docs for Tizen </a>for some light reading =).<br />
<br />
<h2>
My Findings:</h2>
Last year when I used the Preview of Xamarin for Tizen here where my initial findings, you had the sensation that the SDK was not fully finish (being a preview that seemed normal), the emulator was very buggy and often crashed, the debugger did not work (unable to set a break point).<br />
<br />
<b>Framework versions:</b><br />
<br />
<ul>
<li>Tizen.NET (5.0.0.14562)</li>
<li>Tizen.NET.Sdk (1.0.1)</li>
<li>Xamarin.Forms(3.6.0.26487)</li>
</ul>
<br />
<br />
The application that I built is on one page for now, it receives and formats my data into a a list that contains a list. It will populate a ListView, this first ListView data template will hold another ListView so that we can show data horizontally (imagine the Netflix application).<br />
<br />
<h3>
Universal Windows Platform (UWP) </h3>
When creating this application I first started by the UWP as I thought it would be quicker, the first issue that I was that the debugger did not want to stop on my break points I had the follow error:<br />
<br />
<b>"The breakpoint will not currently be hit. No symbols have been loaded for this document"</b><br />
<br />
which is not practical (at all!).<br />
<br />
To fix this issue I removed all of the bin and obj folders in my UWP app and removed this options<br />
<span style="background-color: white; font-family: "segoe ui" , "open sans" , "helvetica neue" , "helvetica" , "arial" , sans-serif; font-size: 14px;">Debug=>Options=>General => </span><strong style="background-color: white; box-sizing: border-box; font-family: "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px;">Remove </strong><span style="background-color: white; font-family: "segoe ui" , "open sans" , "helvetica neue" , "helvetica" , "arial" , sans-serif; font-size: 14px;">the check mark for "</span><strong style="background-color: white; box-sizing: border-box; font-family: "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px;">Enable Just My Cod</strong><span style="background-color: white; font-family: "segoe ui" , "open sans" , "helvetica neue" , "helvetica" , "arial" , sans-serif; font-size: 14px;">e"</span><br />
and it did the trick for me.<br />
<br />
Here is what it looks like on the UWP app:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/w960w3O.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="625" data-original-width="800" height="499" src="https://i.imgur.com/w960w3O.jpg" width="640" /></a></div>
<br />
Not pretty but it gets the job done.<br />
<br />
<h3>
Next on Tizen for TV</h3>
For the Tizen, application the debugger is still "weak", it will break on you often unfortunately, another issue I found was that I was not not able to move the debug back when it hit a break point.<br />
<br />
After a sometime even Visual Studio was telling me that something was wrong:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/WjukVzP.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="23" data-original-width="800" height="18" src="https://i.imgur.com/WjukVzP.png" width="640" /></a></div>
<br />
To be fair it was not all doom and gloom because the debugger did work sometimes:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/cw6pBdh.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="431" data-original-width="800" height="344" src="https://i.imgur.com/cw6pBdh.png" width="640" /></a></div>
<br />
And you could go inside the properties and investigate, this is a great improvement over the last time I tested this platform. On other issue that I found was that the debugger did not resurface errors, even when explicitly crating an error it never surfaced it.<br />
<br />
When launching the app in the Tizen Emulator it can take a few seconds for everything to lunch.<br />
<br />
Here is what the same app looks like in the Tizen emulator:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/XVPUuTe.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="432" data-original-width="800" height="344" src="https://i.imgur.com/XVPUuTe.png" width="640" /></a></div>
It would seem that some of the binding elements are not 100% finished, none of the images will load. Also navigating inside the app is very very slow, from what I am seeing you might better off buying a Samsung TV to debug then using the emulator!<br />
<br />
<h3>
<b>All in all here are a summary of my findings:</b></h3>
<ol>
<li>Tizen 5 Tv SDK is working much better then the Tizen 4 Tv Sdk</li>
<li>The emulator really works this time (last year I needed hacks to get it working), however only the version 5 worked for me and not the version 4, also you must arm yourself with patience for the app to load. Everything is very lagy in the emulator.</li>
<li>the debugger from Visual Studio is now working"ish", it can crash your Visual Studio but at least this time around you cant setup break points in your code.</li>
<li>Binding still seems to be an issue, maybe this is a Xamarin issue ill have to investigate</li>
</ol>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-72068228159969657352019-01-14T02:10:00.004-08:002019-01-14T02:27:31.350-08:00[how to] Using Multilingual App Toolkit to translate your UWP applicationIn this post we are going to see who easy it is to make your application multilingual using Microsoft Multilingual App Toolkit to translate your UWP application.<br />
<br />
First you need a class that will allow us to get the translated string by using the ResourceLoader property.<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">MyLocalizedClass</span>
{
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">static</span> ResourceLoader _localizedResources;
<span style="color: #008800; font-weight: bold;">public</span> ResourceLoader LocalizedResources
{
<span style="color: #008800; font-weight: bold;">get</span>
{
<span style="color: #008800; font-weight: bold;">if</span> (_localizedResources == <span style="color: #008800; font-weight: bold;">null</span>)
{
_localizedResources = <span style="color: #008800; font-weight: bold;">new</span> ResourceLoader();
}
<span style="color: #008800; font-weight: bold;">return</span> _localizedResources;
}
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #333399; font-weight: bold;">string</span> <span style="color: #008800; font-weight: bold;">this</span>[<span style="color: #333399; font-weight: bold;">string</span> key]
{
<span style="color: #008800; font-weight: bold;">get</span>
{
<span style="color: #008800; font-weight: bold;">if</span> (_localizedResources == <span style="color: #008800; font-weight: bold;">null</span>)
{
_localizedResources = <span style="color: #008800; font-weight: bold;">new</span> ResourceLoader();
}
<span style="color: #008800; font-weight: bold;">return</span> _localizedResources.GetString(key);
}
}
</pre>
<pre style="line-height: 125%; margin: 0;">}</pre>
</div>
<br />
You will need to bind all of the text in your application to your resource file, you can do this as follow:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><TextBlock</span>
<span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"Header"</span>
<span style="color: #0000cc;">Style=</span><span style="background-color: #fff0f0;">"{StaticResource TitleTextBlockStyle}"</span>
<span style="color: #0000cc;">Text=</span><span style="background-color: #fff0f0;">"{Binding Path=[MyApplicationHeader], Source={StaticResource LocalizedStrings}, FallbackValue='MyApplicationHeader'}"</span> <span style="color: #0000cc;">TextWrapping=</span><span style="background-color: #fff0f0;">"NoWrap"</span> <span style="color: #007700;">/></span>
</pre>
</div>
<br />
My MyApplicationHeader key will need to be added in resources.resw with a value as follows:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/MW4BWtd.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="90" data-original-width="800" height="72" src="https://i.imgur.com/MW4BWtd.png" width="640" /></a></div>
<br />
<br />
Next we will need to structure our application to with a folder string at the root of the app, this folder will also need to add a folder en and then add a resource file that we will call: <b>Resources.resw</b><br />
<b><br /></b>
It should look as follows:<br />
<b><br /></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/yg0RiLN.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="673" height="320" src="https://i.imgur.com/yg0RiLN.png" width="269" /></a></div>
<b><br /></b>
<b><br /></b>
Next you will need to install Multilingual App Toolkit v4.0 (VS 2017), which you can find <a href="https://marketplace.visualstudio.com/items?itemName=MultilingualAppToolkit.MultilingualAppToolkit-18308">here</a>. Once installed in Visual Studio under Tools your should see Multilingual App Toolkit:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/Di0U6IF.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="223" data-original-width="800" height="178" src="https://i.imgur.com/Di0U6IF.png" width="640" /></a></div>
<br />
you will need to Enable selection in the Multilingual App Toolkit.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/d1FkhJJ.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="101" data-original-width="551" height="116" src="https://i.imgur.com/d1FkhJJ.png" width="640" /></a></div>
<br />
<br />
Next you are going to need to install the <a class="" data-linktype="external" href="https://developer.microsoft.com/en-us/windows/develop/multilingual-app-toolkit" style="background-color: white; box-sizing: inherit; cursor: pointer; font-family: "Segoe UI", SegoeUI, "Segoe WP", "Helvetica Neue", Helvetica, Tahoma, Arial, sans-serif; font-size: 16px; overflow-wrap: break-word; text-decoration-line: none;">Multilingual App Toolkit 4.0 Editor</a>.<br />
<br />
Now we are going to add translation languages to the application, again make sure you have enable Multilingual App Toolkit in your UWP application next click on the project, select Multilingual App Toolkit and click on <b>Add translation</b> as follows:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/Ozq2gxo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="639" data-original-width="800" height="508" src="https://i.imgur.com/Ozq2gxo.png" width="640" /></a></div>
<br />
<br />
I will add french:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/EcHaq2O.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="673" height="640" src="https://i.imgur.com/EcHaq2O.png" width="538" /></a></div>
<br />
<br />
A new folder should be created inside you Strings folder:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/xH5MqcI.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="564" height="640" src="https://i.imgur.com/xH5MqcI.png" width="450" /></a></div>
<br />
<b><br /></b>
We are going to right click on the project and use automatic translate from English to French using machine translations:<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/5GpHfxv.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="338" data-original-width="657" height="328" src="https://i.imgur.com/5GpHfxv.png" width="640" /></a></div>
<b><br /></b>
<br />
If you select Generate machine translations and you have errors most likely the issue is that you don't have the correct credentials to use Cognitive Services, you can fix this by reading <a href="https://multilingualapptoolkit.uservoice.com/knowledgebase/articles/1167898">this</a>.<br />
<br />
Once you have fixed your credential issues or if you don't have any issues you should see that the resources file under fr has been updated with french translated strings:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/V7OYvvU.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="234" data-original-width="800" height="186" src="https://i.imgur.com/V7OYvvU.png" width="640" /></a></div>
<br />
<br />
Now to test this new language you can force your application in French by overriding the application language as follows:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = <span style="background-color: #fff0f0;">"fr"</span>
</pre>
</div>
<br />
Happy coding!<br />
<br />
<br />
<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-66421828547534303152018-12-09T08:02:00.000-08:002019-03-21T16:00:07.808-07:00Using WinAppDriver to do UI Test Automation on your Windows Application, using the My Radio UWP - Part I<div class="graf graf--p" name="a6ee">
Because test is caring you should always try to test as much as possible your application to make sure that is it running smoothly.</div>
<div class="graf graf--p" name="a6ee">
<br /></div>
<div class="graf graf--p" name="a6ee">
We are going to setup multiples UI tests paths that need to be passed before a new version of the application can be pushed to the store. This will allows us to make sure that our application passes all of the basic quality checks and that all classic user paths are still functional.</div>
<div class="graf graf--p" name="a6ee">
<br /></div>
<div class="graf graf--p" name="1f51">
We are going to have a deep look into one of these test path so that you too can improve your app by using UI test automation. </div>
<h3 class="graf graf--h3" name="c6ad">
Setup</h3>
<div class="graf graf--p" name="03d3">
First I highly recommend to have a look at the github repository on how WinAppDriver can be used:</div>
<div class="graf graf--mixtapeEmbed" name="7252">
<a class="markup--anchor markup--mixtapeEmbed-anchor" data-href="https://github.com/Microsoft/WinAppDriver" href="https://github.com/Microsoft/WinAppDriver" title="https://github.com/Microsoft/WinAppDriver"><strong class="markup--strong markup--mixtapeEmbed-strong">Microsoft/WinAppDriver</strong><br /><em class="markup--em markup--mixtapeEmbed-em">WinAppDriver - Windows Application Driver</em>github.com</a><a class="js-mixtapeImage mixtapeImage u-ignoreBlock" data-media-id="cf977148e462ba1b49849fc8f587a48c" data-thumbnail-img-id="0*V6-SE7qCmDz88slI" href="https://github.com/Microsoft/WinAppDriver" style="background-image: url(https://cdn-images-1.medium.com/fit/c/400/400/0*V6-SE7qCmDz88slI);"></a></div>
<h3 class="graf graf--h3" name="0db5">
Installing and Running Windows Application Driver</h3>
<ol class="postList">
<li class="graf graf--li" name="1214">Download Windows Application Driver installer from <a class="markup--anchor markup--li-anchor" data-href="https://github.com/Microsoft/WinAppDriver/releases" href="https://github.com/Microsoft/WinAppDriver/releases" rel="noopener" target="_blank">https://github.com/Microsoft/WinAppDriver/releases</a></li>
<li class="graf graf--li" name="04fb">Run the installer on a Windows 10 machine where your application under test is installed and will be tested</li>
<li class="graf graf--li" name="ae2a">Run <code class="markup--code markup--li-code">WinAppDriver.exe</code> from the installation directory (E.g. <code class="markup--code markup--li-code">C:\Program Files (x86)\Windows Application Driver</code>)</li>
</ol>
<div class="graf graf--p" name="924a">
Windows Application Driver will then be running on the test machine listening to requests on the default IP address and port (<code class="markup--code markup--p-code">127.0.0.1:4723</code>). You should have something as follows:</div>
<br />
<br />
<br />
<figure class="graf graf--figure" name="0f9b"><img class="graf-image" data-height="517" data-image-id="1*2HyGAn78nC5voq8CgKvq9w.png" data-width="986" src="https://cdn-images-1.medium.com/max/2000/1*2HyGAn78nC5voq8CgKvq9w.png" /></figure><br />
<h3 class="graf graf--h3" name="7092">
Locating Elements</h3>
<div class="graf graf--p" name="5fcd">
The latest Visual Studio version by default includes the Windows SDK with a great tool to inspect the application you are testing. <strong class="markup--strong markup--p-strong">This tool allows you to see every UI element/node that you can query using Windows Application Driver</strong>. </div>
<div class="graf graf--p" name="e4d4">
This<strong class="markup--strong markup--p-strong"> inspect.exe</strong> tool can be found under the Windows SDK folder which is typically <strong class="markup--strong markup--p-strong">C:\Program Files (x86)\Windows Kits\10\bin\</strong></div>
<div class="graf graf--p" name="e4d4">
<strong class="markup--strong markup--p-strong"><br /></strong></div>
<div class="graf graf--p" name="ebb9">
Once you have launched the tool you should have a window as follows:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/hZvjvaI.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="616" data-original-width="800" height="492" src="https://i.imgur.com/hZvjvaI.png" width="640" /></a></div>
<br />
<br />
<br />
<br />
<br />
<br />
<figure class="graf graf--figure" name="88ae"></figure>Here we can see that I have already launch the My Radio application.<br />
<h3 class="graf graf--h3" name="da19">
We are going to be looking at 3 users Paths:</h3>
<ul>
<li>Arrive on Home, check we are on Home, click on favorite check we are on favorite and then go back to home</li>
<li>Can we will click on a radio thumbnail and make sure that it is playing</li>
<li><b>Advanced test</b> : In another post we will go over how to create a more complex test in which we will: We click on discovery, click on a category, click on a radio add it to our favorites, go to favorites and check that it is there.</li>
</ul>
<br />
<h3 class="graf graf--h3" name="da19">
Can I click on a button</h3>
<div>
First to be able to have the inspect tool select and highlight your selected item you must have activated these two buttons which are called watch cursor and show highlighted rectangle.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/d7ss8Zy.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="206" data-original-width="800" height="164" src="https://i.imgur.com/d7ss8Zy.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
<br /></div>
<div>
Now we are going to select the item that we wish to click on. In my application the XAML code for this home button is:</div>
<div>
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><NavigationViewItem</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"MainView"</span> <span style="color: #0000cc;">Tag=</span><span style="background-color: #fff0f0;">"MainView"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><StackPanel</span> <span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Left"</span> <span style="color: #0000cc;">Orientation=</span><span style="background-color: #fff0f0;">"Horizontal"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><SymbolIcon</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"30"</span>
<span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"30"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"-5,0,0,0"</span>
<span style="color: #0000cc;">Symbol=</span><span style="background-color: #fff0f0;">"Home"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><TextBlock</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"12,0,0,0"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Center"</span>
<span style="color: #0000cc;">Text=</span><span style="background-color: #fff0f0;">"Home"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></StackPanel></span>
<span style="color: #007700;"></NavigationViewItem></span>
</pre>
</div>
<br />
Here is what it looks like in the inspect tool:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/TMteu34.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="572" data-original-width="800" height="456" src="https://i.imgur.com/TMteu34.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
<br /></div>
<span style="font-weight: normal;">We can see that the automation id is "MainView" and when we look on the favorite button we can see that its id is "FavoriteView" for our first test we are going to be using </span>FindElementByName to check and see if we have a specific text in the visible view and FindElementByAccessibilityId to look for a UIElement that has this specific Id.<br />
<br />
Here is the TestMethod:<br />
<span style="font-weight: normal;"><br /></span>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #0000cc;"> [TestMethod]</span>
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">IsSideNavigationWorking</span>()
{
<span style="color: #888888;">//We arrive on home </span>
<span style="color: #333399; font-weight: bold;">var</span> homeText = session.FindElementByName(<span style="background-color: #fff0f0;">"Explore Radios"</span>);
<span style="color: #888888;">//check to see if we see the explore radios text</span>
Assert.IsNotNull(homeText);
<span style="color: #888888;">//click on categorie</span>
session.FindElementByAccessibilityId(<span style="background-color: #fff0f0;">"FavoriteView"</span>).Click();
<span style="color: #888888;">//check to see if we see the fav radios text</span>
<span style="color: #333399; font-weight: bold;">var</span> favText = session.FindElementByName(<span style="background-color: #fff0f0;">"My Favorite Radios"</span>);
Assert.IsNotNull(favText);
<span style="color: #888888;">//go back on home view</span>
session.FindElementByAccessibilityId(<span style="background-color: #fff0f0;">"MainView"</span>).Click();
<span style="color: #333399; font-weight: bold;">var</span> homeTextV2 = session.FindElementByName(<span style="background-color: #fff0f0;">"Explore Radios"</span>);
<span style="color: #888888;">//check to see if we are on correct view</span>
Assert.IsNotNull(homeTextV2);
}
</pre>
</div>
<span style="font-weight: normal;"><br /></span>
<br />
<h3 class="graf graf--h3" name="da19">
Is Radio playing user path</h3>
<span style="font-weight: normal;">Here is the user path we are going to check:</span><br />
<span style="font-weight: normal;"></span><br />
<ul class="postList">
<li class="graf graf--li" name="e75e">launch the application</li>
<li class="graf graf--li" name="e75e">click on home and check that home is selected</li>
<li class="graf graf--li" name="e75e">click on first radio thumbnail and check that the radio is playing.</li>
<ul>
<li class="graf graf--li" name="e75e">to check that radio is playing we are going to look for the media element that plays the radio item</li>
</ul>
</ul>
<span style="font-weight: normal;">Here is the inspect tool on the first radio in our list.</span>
<span style="font-weight: normal;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/Y2mo4zP.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="533" data-original-width="800" height="426" src="https://i.imgur.com/Y2mo4zP.jpg" width="640" /></a></div>
<br />
<ul class="postList">
</ul>
<div class="graf graf--p" name="c2b9">
And here is the full test:<br />
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/fmQvEYF.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="673" height="570" src="https://i.imgur.com/fmQvEYF.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here you have it, we have gone over two easy example on how to use WinAppDriver to do our UI Test Automation on a UWP Application. In the next Article we will do a deepdive on how to use WinAppDriver.</div>
<div class="graf graf--p" name="218a">
<br />
<br />
<br />
<br /></div>
Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-18535641279050902542018-08-27T05:17:00.003-07:002018-08-30T08:27:14.808-07:00[UWP/XAML] How to customize your NavigationView and add NavigationViewItem next to the Settings buttonIn this tutorial we are going to see how to add NavigationViewItems next to your Settings button in your NavigationView view.<br />
<br />
First we need to get the Template of the NavigationView, Document Outline => Your NavigationView => Edit Template => edit a Copy.<br />
<br />
Here is mine:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/cLLQ7sH.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="553" data-original-width="800" height="442" src="https://i.imgur.com/cLLQ7sH.png" width="640" /></a></div>
<br />
<!-- HTML generated using hilite.me -->Look for the style that has a target type = Navigation View, here is mine:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><Style</span> <span style="color: #0000cc;">x:Key=</span><span style="background-color: #fff0f0;">"NavigationViewStyle1"</span> <span style="color: #0000cc;">TargetType=</span><span style="background-color: #fff0f0;">"NavigationView"</span><span style="color: #007700;">></span>
</pre>
</div>
<br />
Next we will need to find the NavigationViewItem that holds our settings button:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #007700;"><NavigationViewItem</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"SettingsNavPaneItem"</span> <span style="color: #0000cc;">Grid.Row=</span><span style="background-color: #fff0f0;">"7"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><NavigationViewItem.Icon></span>
<span style="color: #007700;"><SymbolIcon</span> <span style="color: #0000cc;">Symbol=</span><span style="background-color: #fff0f0;">"Setting"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></NavigationViewItem.Icon></span>
<span style="color: #007700;"></NavigationViewItem></span>
</pre>
</div>
<br />
<br />
Now we are going to add our 2 new buttons, first we are going to add s stackpanel and move the property Grid.Row=7 to it as follows:<br />
<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #007700;"><StackPanel</span> <span style="color: #0000cc;">Grid.Row=</span><span style="background-color: #fff0f0;">"7"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><NavigationViewItem</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"AddedNavItemOne<span style="background-color: #fff0f0;">"</span><span style="background-color: white;"> </span></span> <span style="color: #0000cc;">Tag=</span><span style="background-color: #fff0f0;">"MyViewOne"</span><span style="color: #007700;">></span>
<NavigationViewItem.Icon><pre style="line-height: 16.25px;"> <span style="color: #007700;"><SymbolIcon</span> <span style="color: #0000cc;">Symbol=</span><span style="background-color: #fff0f0;">"World"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></NavigationViewItem.Icon></span></pre>
<span style="color: #007700;"></NavigationViewItem></span>
<span style="color: #007700;"><NavigationViewItem</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"AddedNavItemTwo<span style="background-color: #fff0f0;">"</span><span style="background-color: white;"> </span><span style="background-color: white; color: #0000cc;">Tag=</span><span style="background-color: #fff0f0;">"MyViewTwo"</span><span style="background-color: white; color: #007700;">></span></span> </pre>
<pre style="line-height: 125%; margin: 0;"> <NavigationViewItem.Icon><pre style="line-height: 16.25px;"> <span style="color: #007700;"><SymbolIcon</span> <span style="color: #0000cc;">Symbol=</span><span style="background-color: #fff0f0;">"Search"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></NavigationViewItem.Icon></span></pre>
<span style="color: #007700;"></NavigationViewItem></span>
<span style="color: #007700;"><NavigationViewItem</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"SettingsNavPaneItem"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><NavigationViewItem.Icon></span>
<span style="color: #007700;"><SymbolIcon</span> <span style="color: #0000cc;">Symbol=</span><span style="background-color: #fff0f0;">"Setting"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></NavigationViewItem.Icon></span>
<span style="color: #007700;"></NavigationViewItem></span>
<span style="color: #007700;"></StackPanel></span>
</pre>
</div>
<br />
Now we need to be able to handle the Click actions of these 2 new <span style="color: #007700;">NavigationViewItem.</span><br />
<br />
We are going to create a class that inherits from NavigationView that will be called ExtendedNavigationView and we arer going to look for our 2 buttons and set handlers on the Tapped events as follows:<br />
<br />
<pre style="line-height: 16.25px;">_navItemOne= GetTemplateChild(<span style="background-color: #fff0f0;">"AddedNavItemOne"</span>) <span style="color: #008800; font-weight: bold;">as</span> NavigationViewItem;
<span style="color: #888888;">//addign events</span>
_navItemOne.Tapped += NavItem_Tapped;</pre>
<br />
The full class will look as follows:<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">ExtendedNavigationView</span> : NavigationView
{
<span style="color: #008800; font-weight: bold;">private</span> NavigationViewItem _navItemOne;
<span style="color: #008800; font-weight: bold;">private</span> NavigationViewItem _navItemTwo;
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">override</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">OnApplyTemplate</span>()
{
<span style="color: #008800; font-weight: bold;">base</span>.OnApplyTemplate();
SetupExtraNavItems();
}
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">SetupExtraNavItems</span>()
{
<span style="color: #888888;">//check to see if not already set</span>
<span style="color: #008800; font-weight: bold;">if</span> (_navItemOne!= <span style="color: #008800; font-weight: bold;">null</span>)
{
<span style="color: #888888;">//unload events</span>
_navItemOne.Tapped -= NavItem_Tapped;
}
<span style="color: #008800; font-weight: bold;">if</span> (_navItemTwo!= <span style="color: #008800; font-weight: bold;">null</span>)
{
_navItemTwo.Tapped -= NavItem_Tapped;
}
_navItemOne= GetTemplateChild(<span style="background-color: #fff0f0;">"AddedNavItemOne"</span>) <span style="color: #008800; font-weight: bold;">as</span> NavigationViewItem;
_navItemTwo = GetTemplateChild(<span style="background-color: #fff0f0;">"AddedNavItemTwo<span style="background-color: #fff0f0;">"</span><span style="background-color: white;">) </span><span style="background-color: white; color: #008800; font-weight: bold;">as</span><span style="background-color: white;"> NavigationViewItem;</span></span>
<span style="color: #008800; font-weight: bold;">if</span> (_navItemOne== <span style="color: #008800; font-weight: bold;">null</span> || _navItemTwo== <span style="color: #008800; font-weight: bold;">null</span>)
{
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #888888;">//addign events</span>
_navItemOne.Tapped += NavItem_Tapped;
_navItemTwo.Tapped += NavItem_Tapped;
}
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">NavItem_Tapped</span>(<span style="color: #333399; font-weight: bold;">object</span> sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
<span style="color: #333399; font-weight: bold;">var</span> NavView = (sender <span style="color: #008800; font-weight: bold;">as</span> NavigationViewItem).Tag;
//navigate to item
}
</pre>
</div>
<br />
<br />
And there you have it you have customized your NavigationView with 2 new NavigationViewItems above the Settings button.<br />
<br />
Happy Coding.<br />
<br />
<br />
<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-46079830023350700532018-08-01T03:48:00.000-07:002018-08-27T03:49:04.626-07:00[UWP/XAML] using Microsoft.Toolkit for Implicit animations using ScalarAnimation, OpacityAnimation, TranslationAnimationDo you hate having to use Compositor?<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;">_compositor = <span style="color: #008800; font-weight: bold;">new</span> Compositor();
_root = ElementCompositionPreview.GetElementVisual(RootGrid);
</pre>
</div>
<br />
Well Microsoft.Toolkit.Uwp.UI.Animations is here to save you (and me). The toolkit has added <a href="https://docs.microsoft.com/en-us/windows/communitytoolkit/animations/implicitanimations">implicit animation</a> which will allow you to easily add animations to your elements. You wont need to use Storyboard animation!<br />
<br />
In this example we are going to see how to:<br />
<br />
<ul>
<li> Add a translation to an element</li>
<li>Show and hide an element using Opacity</li>
<li>Scale an element</li>
</ul>
<div>
The advantage of using an <span style="color: #007700;">Implicit </span>animation is that it can for example be execute when you change the visibility of a component using:</div>
<div>
<pre style="line-height: 16.25px;"> <span style="color: #007700;"><animations:Implicit.ShowAnimations></span></pre>
</div>
<div>
<br /></div>
<div>
Or</div>
<div>
<pre style="line-height: 16.25px;"> <span style="color: #007700;"><animations:Implicit.HideAnimations></span></pre>
<pre style="line-height: 16.25px;"></pre>
</div>
<h2>
Animations</h2>
<div>
To move an element in your app using implicit animation you have 2 options either you use <span style="color: #007700;">ScalarAnimation </span>or <span style="color: #007700;">TranslationAnimation.</span></div>
<h4>
</h4>
<h4>
TranslationAnimation</h4>
<div>
Has 3 main properties that you are going to want to set:</div>
<div>
<ul>
<li>From</li>
<li>To</li>
<li>Duration</li>
</ul>
</div>
From and To are based on the <b>x-y-z axis</b><br />
Duration uses a <b>h:m:s</b> format<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><animations:TranslationAnimation</span>
<span style="color: #0000cc;">From=</span><span style="background-color: #fff0f0;">"500,300,0"</span>
<span style="color: #0000cc;">To=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">Duration=</span><span style="background-color: #fff0f0;">"0:0:1"</span> <span style="color: #007700;">/></span>
</pre>
</div>
<br />
<!-- HTML generated using hilite.me -->This means we are going to add 500 to the x position, 300 to the y postion and 0 to the z. The To=0 will take the element from its current position and the translation will take 1 second.<br />
<br />
<br />
<h3>
OpacityAnimation </h3>
Same as the translation this also takes 3 properties, however the From and To only takes one value as the opacity property is only based on one value.<br />
<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #007700;"><animations:OpacityAnimation</span>
<span style="color: #0000cc;">From=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">To=</span><span style="background-color: #fff0f0;">"1"</span>
<span style="color: #0000cc;">Duration=</span><span style="background-color: #fff0f0;">"0:0:2"</span> <span style="color: #007700;">/></span>
</pre>
</div>
<br />
<br />
<h3>
ScalarAnimation</h3>
If you wish to have more control on your animation you can also use ScalarAnimation which will allow you to more precisely (I find) to set the values to the property you wish to change.<br />
<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><animations:ScalarAnimation</span>
<span style="color: #0000cc;">Target=</span><span style="background-color: #fff0f0;">"Translation.Y"</span>
<span style="color: #0000cc;">From=</span><span style="background-color: #fff0f0;">"100"</span>
<span style="color: #0000cc;">To=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">Duration=</span><span style="background-color: #fff0f0;">"0:0:1"</span><span style="color: #007700;">/></span>
</pre>
</div>
<br />
<br />
First you need to set your Target, which is the property you are going to want to change. Then depending on your target like the other animations you will set the From, To, Duration<br />
<br />
<br />
<h3>
Combining Animations</h3>
Now we are going to combine 2 animations using the ShowAnimations and HideAnimations. We will use <span style="color: #007700;">ScalarAnimation</span> and <span style="color: #007700;">OpacityAnimation </span>to move and change the opacity of our object.<br />
<br />
Here is the full XAML:<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><Button</span> <span style="color: #0000cc;">Click=</span><span style="background-color: #fff0f0;">"Button_Click"</span> <span style="color: #0000cc;">Content=</span><span style="background-color: #fff0f0;">"Hit me"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><Rectangle</span>
<span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"MyRec"</span>
<span style="color: #0000cc;">Grid.Row=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"45"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"0,0,0,0"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Bottom"</span>
<span style="color: #0000cc;">Fill=</span><span style="background-color: #fff0f0;">"Red"</span>
<span style="color: #0000cc;">Visibility=</span><span style="background-color: #fff0f0;">"Collapsed"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><animations:Implicit.ShowAnimations></span>
<span style="color: #888888;"><!--<animations:TranslationAnimation</span>
<span style="color: #888888;"> From="100,0,0"</span>
<span style="color: #888888;"> To="0,0,0"</span>
<span style="color: #888888;"> Duration="0:0:1" />--></span>
<span style="color: #007700;"><animations:ScalarAnimation</span>
<span style="color: #0000cc;">Target=</span><span style="background-color: #fff0f0;">"Translation.Y"</span>
<span style="color: #0000cc;">From=</span><span style="background-color: #fff0f0;">"100"</span>
<span style="color: #0000cc;">To=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">Duration=</span><span style="background-color: #fff0f0;">"0:0:1"</span><span style="color: #007700;">></span>
<span style="color: #007700;"></animations:ScalarAnimation></span>
<span style="color: #007700;"><animations:OpacityAnimation</span>
<span style="color: #0000cc;">From=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">To=</span><span style="background-color: #fff0f0;">"1"</span>
<span style="color: #0000cc;">Duration=</span><span style="background-color: #fff0f0;">"0:0:2"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></animations:Implicit.ShowAnimations></span>
<span style="color: #007700;"><animations:Implicit.HideAnimations></span>
<span style="color: #007700;"><animations:OpacityAnimation</span>
<span style="color: #0000cc;">From=</span><span style="background-color: #fff0f0;">"1"</span>
<span style="color: #0000cc;">To=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">Duration=</span><span style="background-color: #fff0f0;">"0:0:2"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><animations:ScalarAnimation</span>
<span style="color: #0000cc;">Target=</span><span style="background-color: #fff0f0;">"Translation.Y"</span>
<span style="color: #0000cc;">From=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">To=</span><span style="background-color: #fff0f0;">"100"</span>
<span style="color: #0000cc;">Duration=</span><span style="background-color: #fff0f0;">"0:0:1"</span><span style="color: #007700;">></span>
<span style="color: #007700;"></animations:ScalarAnimation></span>
<span style="color: #888888;"><!--<animations:TranslationAnimation</span>
<span style="color: #888888;"> From="0,0,0"</span>
<span style="color: #888888;"> To="100,0,0"</span>
<span style="color: #888888;"> Duration="0:0:1" />--></span>
<span style="color: #007700;"></animations:Implicit.HideAnimations></span>
<span style="color: #007700;"></Rectangle></span>
</pre>
</div>
<br />
C# Code:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Button_Click</span>(<span style="color: #333399; font-weight: bold;">object</span> sender, RoutedEventArgs e)
{
<span style="color: #008800; font-weight: bold;">if</span> (MyRec != <span style="color: #008800; font-weight: bold;">null</span>)
{
MyRec.Visibility = MyRec.Visibility == Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed;
}
}
</pre>
</div>
<br />
Happy Coding.<br />
<br />
<br />
<br />
<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-53975184864985904832018-06-25T01:35:00.004-07:002018-08-24T02:50:11.475-07:00UWP/XAML using PopupThemeTransition / PopOutThemeAnimation / PopInThemeAnimation to animate elements coming in and out of your app [Part 1]In UWP we have this great control called Popup this control can allow you to quickly and cleanly have element pop in and pop out of your view. Also we will look at how to do more of less the same thing with only a Grid.<br />
<br />
In this post I wont go into details about the popup control itselft however if you are interested in getting more information <a href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.primitives.popup">msdn is the best place to look</a>.<br />
<br />
First we are going to create our simple popup element, make sure that you set the <span style="color: #0000cc;">IsOpen </span>property to false (this will hide your popup), <span style="color: #0000cc;">IsLightDismissEnabled </span>to true will mean that if the user clicks outside of the popup it will disappear.<br />
<br />
Here is what the XAML can look like:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><Popup</span>
<span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"PopupFromBottom"</span>
<span style="color: #0000cc;">Grid.Row=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"459"</span>
<span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"90"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"20,0,20,20"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Bottom"</span>
<span style="color: #0000cc;">IsLightDismissEnabled=</span><span style="background-color: #fff0f0;">"True"</span>
<span style="color: #0000cc;">IsOpen=</span><span style="background-color: #fff0f0;">"False"</span><span style="color: #007700;">/></span>
</pre>
</div>
<br />
To add transition to when the popup will be shown we will add <span style="color: #007700;">ChildTransitions</span>:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><Popup.ChildTransitions></span>
<span style="color: #007700;"><TransitionCollection></span>
<span style="color: #007700;"><PopupThemeTransition</span> <span style="color: #0000cc;">FromVerticalOffset=</span><span style="background-color: #fff0f0;">"100"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></TransitionCollection></span>
<span style="color: #007700;"></Popup.ChildTransitions></span>
</pre>
</div>
<br />
This will add an animation, the popup will come from the bottom with a translation of 100px. If you have wanted a Horizontal translation then you could have used FromHorizontalOffset.<br />
<br />
For this popup to be displayed all you need is to set the IsOpen to true :<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> PopupFromBottom.IsOpen = <span style="color: #008800; font-weight: bold;">true</span>;
</pre>
</div>
<br />
Now if we wanted the popup to hide it self after 3 seconds all we would need to add is a wait of 3 seconds and again change the IsOpen to false as follows:<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #888888;">//show</span>
PopupFromBottom.IsOpen = <span style="color: #008800; font-weight: bold;">true</span>;
<span style="color: #888888;">//wait 3 sec</span>
<span style="color: #008800; font-weight: bold;">await</span> Task.Delay(TimeSpan.FromSeconds(<span style="color: #6600ee; font-weight: bold;">3</span>));
<span style="color: #888888;">//close </span>
PopupFromBottom.IsOpen = <span style="color: #008800; font-weight: bold;">false</span>;
</pre>
</div>
<br />
In the previous example we used the default popup control which allowed us to use the lightdismiss and directly attach the <span style="color: #007700;">PopupThemeTransition </span>animations to the popup. However we always have custome cases where we need custome code and sometimes the default controls just wont cut it. NOw we are going to see how to use a Grid as a popup.<br />
<br />
first we are going to create our Grid as follows:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #007700;"><Grid</span>
<span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"GridPopup"</span>
<span style="color: #0000cc;">Grid.Row=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"459"</span>
<span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"90"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"20,0,20,20"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Bottom"</span>
<span style="color: #0000cc;">Background=</span><span style="background-color: #fff0f0;">"LightGray"</span>
<span style="color: #0000cc;">Opacity=</span><span style="background-color: #fff0f0;">"0"</span> <span style="color: #007700;">/></span>
</pre>
</div>
<br />
Next we are going to add storyboards and use <span style="color: #007700;">PopInThemeAnimation </span>and <span style="color: #007700;">PopOutThemeAnimation</span><br />
to pop in and pop out our grid. Here is the Storyboard XAML code:<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><Storyboard</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"PopOutStoryboard"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><PopOutThemeAnimation</span> <span style="color: #0000cc;">SpeedRatio=</span><span style="background-color: #fff0f0;">"2"</span> <span style="color: #0000cc;">TargetName=</span><span style="background-color: #fff0f0;">"GridPopup"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></Storyboard></span>
<span style="color: #007700;"><Storyboard</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"PopInStoryboard"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><PopInThemeAnimation</span>
<span style="color: #0000cc;">FromVerticalOffset=</span><span style="background-color: #fff0f0;">"150"</span>
<span style="color: #0000cc;">SpeedRatio=</span><span style="background-color: #fff0f0;">"0.3"</span>
<span style="color: #0000cc;">TargetName=</span><span style="background-color: #fff0f0;">"GridPopup"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><DoubleAnimation</span>
<span style="color: #0000cc;">d:IsOptimized=</span><span style="background-color: #fff0f0;">"True"</span>
<span style="color: #0000cc;">Storyboard.TargetName=</span><span style="background-color: #fff0f0;">"GridPopup"</span>
<span style="color: #0000cc;">Storyboard.TargetProperty=</span><span style="background-color: #fff0f0;">"Opacity"</span>
<span style="color: #0000cc;">To=</span><span style="background-color: #fff0f0;">"1"</span>
<span style="color: #0000cc;">Duration=</span><span style="background-color: #fff0f0;">"0"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></Storyboard></span>
</pre>
</div>
<br />
and now to easily call this code all we need to do:<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">OpenStoryboard_Click</span>(<span style="color: #333399; font-weight: bold;">object</span> sender, RoutedEventArgs e)
{
PopInStoryboard.Begin();
}
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">CloseStoryboard_Click</span>(<span style="color: #333399; font-weight: bold;">object</span> sender, RoutedEventArgs e)
{
PopOutStoryboard.Begin();
}
</pre>
</div>
<br />
And there you are! You can find the full <a href="https://github.com/Delaire/Samples/tree/master/PopupAnimationsSample">code here.</a><br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-53735194458355462632018-03-22T03:21:00.003-07:002018-08-24T02:48:27.102-07:00UWP, C# - Retrieve the redirect url using HttpClient from the Headers of the Response - [HttpClient,C#]I wanted to share this little piece of code because I did not quickly find any great documentation on this.<br />
<br />
My needs where as follows: I had a URL lets say http://bit.ly/2pwccfo and I did not have the direct access to the image of the URL. So I ended up creating a small static class that holds a method GetRedirectedUrl that will get my redirect url.<br />
<!-- HTML generated using hilite.me --><br />
Here is my code:<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">CoreTools</span>
{
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> <span style="color: #008800; font-weight: bold;">async</span> Task<<span style="color: #333399; font-weight: bold;">string</span>> GetRedirectedUrl(<span style="color: #333399; font-weight: bold;">string</span> url)
{
<span style="color: #888888;">//this allows you to set the settings so that we can get the redirect url</span>
<span style="color: #333399; font-weight: bold;">var</span> handler = <span style="color: #008800; font-weight: bold;">new</span> HttpClientHandler()
{
AllowAutoRedirect = <span style="color: #008800; font-weight: bold;">false</span>
};
<span style="color: #333399; font-weight: bold;">string</span> redirectedUrl = <span style="color: #008800; font-weight: bold;">null</span>;
<span style="color: #008800; font-weight: bold;">using</span> (HttpClient client = <span style="color: #008800; font-weight: bold;">new</span> HttpClient(handler))
<span style="color: #008800; font-weight: bold;">using</span> (HttpResponseMessage response = <span style="color: #008800; font-weight: bold;">await</span> client.GetAsync(url))
<span style="color: #008800; font-weight: bold;">using</span> (HttpContent content = response.Content)
{
<span style="color: #888888;">// ... Read the StatusCode in the response </span></pre>
<pre style="line-height: 125%; margin: 0;"><span style="color: #888888;"> // to see if we have the redirected url</span>
<span style="color: #008800; font-weight: bold;">if</span> (response.StatusCode == System.Net.HttpStatusCode.Found)
{
HttpResponseHeaders headers = response.Headers;</pre>
<pre style="line-height: 125%; margin: 0;"><pre style="line-height: 16.25px;"><span style="color: #888888;"> // do we have headers </span></pre>
<pre style="line-height: 16.25px;"><span style="color: #888888;"> //do we have something in location</span></pre>
<span style="color: #008800; font-weight: bold;">if</span> (headers != <span style="color: #008800; font-weight: bold;">null</span> && headers.Location != <span style="color: #008800; font-weight: bold;">null</span>)
{
redirectedUrl = headers.Location.AbsoluteUri;
}
}
}
<span style="color: #008800; font-weight: bold;">return</span> redirectedUrl;
}
}
</pre>
</div>
<br />
You can find my gist <a href="https://gist.github.com/Delaire/3f1283dc6365d705dfd6ba24498d4993">here</a>.<br />
Happy CodingDamien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-54765030400969023732018-03-01T02:23:00.000-08:002018-03-01T02:23:17.448-08:00UWP Imbricking a ItemTemplateSelector in a ItemTemplateSelector to create a dynamic listview with horizontal and vertical itemsIn this tutorial we are going to see how to create a dynamic listview that can hold horizontal and vertical items, this tutorial will be broken into 3 parts :<br />
<br />
<ul>
<li>First we will create ou Model and and Data</li>
<li>Next we we create the UserControl and DataTemplates to hold our listview and gridviews</li>
<li>Lastly we will look at how to use a ItemTemplateSelectoron our first listview.</li>
</ul>
<br />
Now here are 2 screen shots of what we would like to do, the first one is from the Window Store App and the second one from the dailymotion UWP app.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/JaMADGM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="753" height="400" src="https://i.imgur.com/JaMADGM.png" width="376" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
this one looks like one listview that is holding another listview with an ItemTemplateSelector, however these seem to have a fix number of items they are showing so in the end it could be the it is only one listview with an ItemTemplateSelector that select the correct template for when you have 4 items, 6 items or 3 items and so on.</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I want to create something more generic like in the dailymotion app :</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/hHdT20y.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="578" data-original-width="800" height="288" src="https://i.imgur.com/hHdT20y.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<!-- HTML generated using hilite.me -->Let start coding!<br />
<br />
Here is a quick diagram of how the idea of imbricking 2 <b>DataTemplateSelector </b>selector will work:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/QRemG7k.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="404" data-original-width="800" height="322" src="https://i.imgur.com/QRemG7k.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<br />
We are going to need 2 enums that will allow us to say when the segment is vertical or horizontal and the second one will allow us to know which template we will need to set in the second gridview.<br />
<br />
This allows us to know what to sent in our first listview in its ItemTemplate: Horizontal/Vertical<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">enum</span> SegmentType
{
HorizontalSegment,
VerticalSegment,
}
</pre>
</div>
<br />
<br />
This is for when we are in the Horizontal/Vertical Control so that we can set the ItemTemplate for the GridView:<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">enum</span> ItemTemplateType
{
CircleUserItem,
SquareUserItem,
}
</pre>
</div>
<br />
Next we are going to need to create two <b>DataTemplateSelector </b>so that depending on what kind of enum the EntityViewModel is passing we can assign the correct DataTemplate.<br />
<br />
This is our <b>DataTemplateSelector </b>for our main listview, it will server either a horizontal gridview or a vertical Gridview:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">SegementTemplateSelector</span> : DataTemplateSelector
{
<span style="color: #008800; font-weight: bold;">public</span> DataTemplate KeyHorizontalControl = Application.Current.Resources[<span style="background-color: #fff0f0;">"KeyHorizontalControl"</span>] <span style="color: #008800; font-weight: bold;">as</span> DataTemplate;
<span style="color: #008800; font-weight: bold;">public</span> DataTemplate KeyVerticalControl = Application.Current.Resources[<span style="background-color: #fff0f0;">"KeyVerticalControl"</span>] <span style="color: #008800; font-weight: bold;">as</span> DataTemplate;
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">override</span> DataTemplate <span style="color: #0066bb; font-weight: bold;">SelectTemplateCore</span>(<span style="color: #333399; font-weight: bold;">object</span> item, DependencyObject container)
{
<span style="color: #333399; font-weight: bold;">var</span> element = item <span style="color: #008800; font-weight: bold;">as</span> BaseSegementEntityViewModel;
<span style="color: #008800; font-weight: bold;">if</span> (element != <span style="color: #008800; font-weight: bold;">null</span>)
{
<span style="color: #008800; font-weight: bold;">if</span> (element.ItemType == SegmentType.HorizontalSegment)
<span style="color: #008800; font-weight: bold;">return</span> KeyHorizontalControl;
<span style="color: #008800; font-weight: bold;">else</span>
<span style="color: #008800; font-weight: bold;">return</span> KeyVerticalControl;
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">base</span>.SelectTemplateCore(item, container);
}
}
</pre>
</div>
<br />
<br />
This is our <b>DataTemplateSelector </b>for the Gridviews that are inside our Horizontal/Vertical Control it allows to know if we are serving a square or a circle DataTemplate:<br />
<br />
<br />
<div style="background: rgb(255, 255, 255); border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 16.25px;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">ItemTemplateSelector</span> : DataTemplateSelector
{
<span style="color: #008800; font-weight: bold;">public</span> DataTemplate KeyCircleUserControl = Application.Current.Resources[<span style="background-color: #fff0f0;">"KeyCircleUserControl"</span>] <span style="color: #008800; font-weight: bold;">as</span> DataTemplate;
<span style="color: #008800; font-weight: bold;">public</span> DataTemplate KeySquareUserControl = Application.Current.Resources[<span style="background-color: #fff0f0;">"KeySquareUserControl"</span>] <span style="color: #008800; font-weight: bold;">as</span> DataTemplate;
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">override</span> DataTemplate <span style="color: #0066bb; font-weight: bold;">SelectTemplateCore</span>(<span style="color: #333399; font-weight: bold;">object</span> item, DependencyObject container)
{
<span style="color: #333399; font-weight: bold;">var</span> element = item <span style="color: #008800; font-weight: bold;">as</span> BaseItemEntityViewModel;
<span style="color: #008800; font-weight: bold;">if</span> (element != <span style="color: #008800; font-weight: bold;">null</span>)
{
<span style="color: #008800; font-weight: bold;">switch</span> (element.ItemTemplate)
{
<span style="color: #008800; font-weight: bold;">case</span> ItemTemplateType.CircleUserItem:
<span style="color: #008800; font-weight: bold;">return</span> KeyCircleUserControl;
<span style="color: #008800; font-weight: bold;">default</span>:
<span style="color: #008800; font-weight: bold;">return</span> KeySquareUserControl;
}
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">base</span>.SelectTemplateCore(item, container);
}
}
</pre>
</div>
<br />
Bonus: this could also be used to serve BOTH a Circle DataTemplate and a square DataTemplate in the Gridview depending on the type of the item.<br />
<br />
Next we will be looking at the XAML in our Horizontal/Vertical Controls.<br />
<br />
HorizontalControl.xaml :<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><GridView</span>
<span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"HorizontalGridView"</span>
<span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"250"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"26,0,0,0"</span>
<span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">ItemTemplateSelector=</span><span style="background-color: #fff0f0;">"{StaticResource KeyItemTemplateSelector}"</span>
<span style="color: #0000cc;">ItemsSource=</span><span style="background-color: #fff0f0;">"{Binding MyItemSource}"</span>
<span style="color: #0000cc;">ScrollViewer.HorizontalScrollBarVisibility=</span><span style="background-color: #fff0f0;">"Hidden"</span>
<span style="color: #0000cc;">ScrollViewer.HorizontalScrollMode=</span><span style="background-color: #fff0f0;">"Enabled"</span>
<span style="color: #0000cc;">ScrollViewer.VerticalScrollBarVisibility=</span><span style="background-color: #fff0f0;">"Disabled"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><GridView.ItemsPanel></span>
<span style="color: #007700;"><ItemsPanelTemplate></span>
<span style="color: #007700;"><ItemsStackPanel</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"5"</span>
<span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Left"</span>
<span style="color: #0000cc;">Orientation=</span><span style="background-color: #fff0f0;">"Horizontal"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></ItemsPanelTemplate></span>
<span style="color: #007700;"></GridView.ItemsPanel></span>
<span style="color: #007700;"></GridView></span>
</pre>
</div>
<br />
In the HorizontalControl we need to change the orientation of the <span style="color: #007700;">ItemsStackPanel </span>of the <span style="color: #007700;">ItemsPanelTemplate. </span>In this <span style="color: #007700;">GridView</span>I edit the <span style="color: #0000cc;">ScrollViewer </span>settings so that they match my neededs.<br />
<br />
VerticalControl.xaml :<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><GridView</span>
<span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"VerticalGridView"</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"300"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"26,0,0,0"</span>
<span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">ItemTemplateSelector=</span><span style="background-color: #fff0f0;">"{StaticResource KeyItemTemplateSelector}"</span>
<span style="color: #0000cc;">ItemsSource=</span><span style="background-color: #fff0f0;">"{Binding MyItemSource}"</span>
<span style="color: #0000cc;">ScrollViewer.HorizontalScrollBarVisibility=</span><span style="background-color: #fff0f0;">"Disabled"</span>
<span style="color: #0000cc;">ScrollViewer.HorizontalScrollMode=</span><span style="background-color: #fff0f0;">"Disabled"</span>
<span style="color: #0000cc;">ScrollViewer.IsHorizontalScrollChainingEnabled=</span><span style="background-color: #fff0f0;">"False"</span>
<span style="color: #0000cc;">ScrollViewer.IsVerticalScrollChainingEnabled=</span><span style="background-color: #fff0f0;">"False"</span>
<span style="color: #0000cc;">ScrollViewer.VerticalScrollBarVisibility=</span><span style="background-color: #fff0f0;">"Disabled"</span>
<span style="color: #0000cc;">ScrollViewer.VerticalScrollMode=</span><span style="background-color: #fff0f0;">"Disabled"</span><span style="color: #007700;">></span>
<span style="color: #007700;"></GridView></span>
</pre>
</div>
<br />
This is really just your normal <span style="color: #007700;">GridView</span> with an item template selector.<br />
<br />
Now we will look at our main page which will be holding our Listview with an ItemTemplateSelector which will select if your items will be displayed Horizontally or Verticaly.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><ListView</span>
<span style="color: #0000cc;">Grid.Row=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"0,0,0,0"</span>
<span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">IsTabStop=</span><span style="background-color: #fff0f0;">"False"</span>
<span style="color: #0000cc;">ItemTemplateSelector=</span><span style="background-color: #fff0f0;">"{StaticResource KeySegementTemplateSelector}"</span>
<span style="color: #0000cc;">ItemsSource=</span><span style="background-color: #fff0f0;">"{Binding MyData}"</span>
<span style="color: #0000cc;">ScrollViewer.VerticalScrollBarVisibility=</span><span style="background-color: #fff0f0;">"Auto"</span>
<span style="color: #0000cc;">ScrollViewer.VerticalScrollMode=</span><span style="background-color: #fff0f0;">"Enabled"</span>
<span style="color: #0000cc;">SelectionMode=</span><span style="background-color: #fff0f0;">"None"</span>
<span style="color: #0000cc;">ShowsScrollingPlaceholders=</span><span style="background-color: #fff0f0;">"False"</span>
<span style="color: #0000cc;">VirtualizingStackPanel.VirtualizationMode=</span><span style="background-color: #fff0f0;">"Recycling"</span>
<span style="color: #0000cc;">Visibility=</span><span style="background-color: #fff0f0;">"Visible"</span> <span style="color: #007700;">/></span>
</pre>
</div>
<br />
<br />
Now we need to create some data, first we will start by creating 2 lists. One that will hold our list of Circles and the second one that will hold our list of Squares:<br />
<br />
<span style="color: #888888;">//circle list</span><br />
<pre style="line-height: 16.25px;"> <span style="color: #333399; font-weight: bold;">var</span> CircleList = <span style="color: #008800; font-weight: bold;">new</span> List<SmallItemViewModel>();</pre>
<pre style="line-height: 16.25px;"></pre>
<pre style="line-height: 16.25px;"><span style="color: #888888;">//square list</span>
<span style="color: #333399; font-weight: bold;">var</span> SquareList = <span style="color: #008800; font-weight: bold;">new</span> List<SmallItemViewModel>();</pre>
<br />
Next we will need to populate these 2 lists:<br />
<br />
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i = <span style="color: #6600ee; font-weight: bold;">0</span>; i < <span style="color: #6600ee; font-weight: bold;">10</span>; i++)<br />
<pre style="line-height: 16.25px;">{
CircleList.Add(<span style="color: #008800; font-weight: bold;">new</span> SmallItemViewModel(<span style="color: #333399; font-weight: bold;">string</span>.Format(<span style="background-color: #fff0f0;">"title circle {0}"</span>, i ), ItemTemplateType.CircleUserItem));
SquareList.Add(<span style="color: #008800; font-weight: bold;">new</span> SmallItemViewModel(<span style="color: #333399; font-weight: bold;">string</span>.Format(<span style="background-color: #fff0f0;">"title square {0}"</span>, i), ItemTemplateType.SquareUserItem));
}</pre>
<br />
Now we create another list that will hold the Segements and their data.<br />
<br />
<pre style="line-height: 16.25px;"><span style="color: #888888;">//horizontal // vertical </span>
MyData = <span style="color: #008800; font-weight: bold;">new</span> ObservableCollection<BaseSegementEntityViewModel>();</pre>
<pre style="line-height: 16.25px;"></pre>
now we populate this list:<br />
<pre style="line-height: 16.25px;">MyData.Add(NeonExploreTemplateEngine(SquareList, SegmentType.HorizontalSegment));
MyData.Add(NeonExploreTemplateEngine(CircleList.Take(<span style="color: #6600ee; font-weight: bold;">3</span>).ToList(), SegmentType.VerticalSegment));
MyData.Add(NeonExploreTemplateEngine(CircleList, SegmentType.HorizontalSegment));
</pre>
<pre style="line-height: 16.25px;">Here is the full code:</pre>
<pre style="line-height: 16.25px;"></pre>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">async</span> Task <span style="color: #0066bb; font-weight: bold;">Init</span>()
{
<span style="color: #888888;">//horizontal // vertical </span>
MyData = <span style="color: #008800; font-weight: bold;">new</span> ObservableCollection<BaseSegementEntityViewModel>();
<span style="color: #888888;">//circle list</span>
<span style="color: #333399; font-weight: bold;">var</span> CircleList = <span style="color: #008800; font-weight: bold;">new</span> List<SmallItemViewModel>();
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i = <span style="color: #6600ee; font-weight: bold;">0</span>; i < <span style="color: #6600ee; font-weight: bold;">10</span>; i++)
{
CircleList.Add(<span style="color: #008800; font-weight: bold;">new</span> SmallItemViewModel(<span style="color: #333399; font-weight: bold;">string</span>.Format(<span style="background-color: #fff0f0;">"title circle {0}"</span>, i ), ItemTemplateType.CircleUserItem));
}
<span style="color: #888888;">//square list</span>
<span style="color: #333399; font-weight: bold;">var</span> SquareList = <span style="color: #008800; font-weight: bold;">new</span> List<SmallItemViewModel>();
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i = <span style="color: #6600ee; font-weight: bold;">0</span>; i < <span style="color: #6600ee; font-weight: bold;">10</span>; i++)
{
SquareList.Add(<span style="color: #008800; font-weight: bold;">new</span> SmallItemViewModel(<span style="color: #333399; font-weight: bold;">string</span>.Format(<span style="background-color: #fff0f0;">"title square {0}"</span>, i), ItemTemplateType.SquareUserItem));
}
<span style="color: #888888;">//data</span>
MyData.Add(NeonExploreTemplateEngine(SquareList, SegmentType.HorizontalSegment));
MyData.Add(NeonExploreTemplateEngine(CircleList.Take(<span style="color: #6600ee; font-weight: bold;">3</span>).ToList(), SegmentType.VerticalSegment));
MyData.Add(NeonExploreTemplateEngine(CircleList, SegmentType.HorizontalSegment));
MyData.Add(NeonExploreTemplateEngine(SquareList.Take(<span style="color: #6600ee; font-weight: bold;">3</span>).ToList(), SegmentType.VerticalSegment));
MyData.Add(NeonExploreTemplateEngine(SquareList, SegmentType.HorizontalSegment));
MyData.Add(NeonExploreTemplateEngine(CircleList, SegmentType.HorizontalSegment));
MyData.Add(NeonExploreTemplateEngine(CircleList.Take(<span style="color: #6600ee; font-weight: bold;">3</span>).ToList(), SegmentType.VerticalSegment));
}
<span style="color: #008800; font-weight: bold;">public</span> BaseSegementEntityViewModel <span style="color: #0066bb; font-weight: bold;">NeonExploreTemplateEngine</span>(List<SmallItemViewModel> item, SegmentType type)
{
<span style="color: #008800; font-weight: bold;">if</span> (type == SegmentType.HorizontalSegment)
{
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">new</span> <span style="color: #0066bb; font-weight: bold;">HorizontalSegmentViewModel</span>(item);
}
<span style="color: #008800; font-weight: bold;">else</span>
{
<span style="color: #008800; font-weight: bold;">return</span> (<span style="color: #008800; font-weight: bold;">new</span> VerticalSegmentViewModel(item));
}
}
</pre>
</div>
<br />
<br />
And here is what we would get:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/smyRjG5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="485" data-original-width="800" height="241" src="https://i.imgur.com/smyRjG5.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/pq6O8Ty.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="467" data-original-width="800" height="232" src="https://i.imgur.com/pq6O8Ty.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
In the same Listview you will have elements position Vertically and Horizontally at the same time, also you will be able to change your design on the fly depending on the data that you send to your application. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
We can quickly see how powerful it can be to design an application that relies on <span style="color: #0000cc;">ItemTemplateSelector</span> , for example this could mean that if you didn't want to use a certain template anymore you would not need to update the application but just the API that the application is using. This could be a great time saver! </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You could also do some form of A/B testing, if for example you had multiple Circles Template you could try different templates to see which templates your user will more likely click on!</div>
<br />
I hope that this will help you build better apps!<br />
<br />
Happy Coding!<br />
You can find the <a href="https://github.com/Delaire/Samples/tree/master/DoubleListViewItemTemplatesv">full sample here</a>.<br />
<br />
<br />
<br />
<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-76651597245120424262018-02-21T01:03:00.000-08:002018-02-21T01:03:42.445-08:00WebView using InvokeScriptAsync and calling a method and passing the parameters using JSON.parse [WebView,C#]Calling a method on your WebView is simple just call the WebView.InvokeScriptAsync( method , param) (more information on <a href="https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.webview">MSDN</a>) and you are good to go. However imagine if you need to send json in the param, how do you send it?<br />
<br />
<br />
This is the issue that we are going to have a quick look in the post, here is an example in of a javascript call that needs to be called with JSON data. Looking at the MSDN <a href="https://docs.microsoft.com/en-us/scripting/javascript/reference/json-parse-function-javascript">documentation </a>, we can see that we need to surrond ou json string with JSON.parse({0}), in the params value in the InvokeScriptAsync.<br />
<br />
Here is an example of the method name <b>'eval'</b> and the javascript parameter that I would like to send to the UWP WebView:<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="background-color: #ffaaaa; color: red;">loadUrl</span> <span style="background-color: #ffaaaa; color: red;">javascript:object.load('x</span><span style="background-color: #ffaaaa; color: red;">sazphf',</span>
<span style="background-color: #ffaaaa; color: red;">JSON.parse('</span>{
<span style="color: #007700;">"props"</span>:{
<span style="color: #007700;">"param"</span>:{
<span style="color: #007700;">"action"</span>:{
<span style="color: #007700;">"gesture"</span>:<span style="background-color: #fff0f0;">"click"</span>,
<span style="color: #007700;">"id"</span>:<span style="background-color: #fff0f0;">"63825b13-dff5-4f45-81e9-a9dbe2aca39b"</span>
},
<span style="color: #007700;">"screen"</span>:{
<span style="color: #007700;">"id"</span>:<span style="background-color: #fff0f0;">"662dfa95-6ad2-43c1-b403-4e9a4118be4c"</span>
},
<span style="color: #007700;">"section"</span>:{
<span style="color: #007700;">"id"</span>:<span style="background-color: #fff0f0;">"2bcd2be7-9c10-49e9-b71e-b77dee17c7fb"</span>,
<span style="color: #007700;">"index"</span>:<span style="color: #0000dd; font-weight: bold;">1</span>
}
}
}
}<span style="background-color: #ffaaaa; color: red;">'))</span>
</pre>
</div>
<br />
All in all,the json string that we want to pass to our javascript object needs to be wrapped in <span style="background-color: #fff0f0; color: #333333;">JSON.parse('{0}')).</span> This will allow the javascript to understand that the data that we are passing is JSON.<br />
<br />
When we are building our string to call with the eval function in javasciprt we will need to have some like this : <b>myJsObject.MyMethode(Paramater1, ,JSON.parse("MyJSONStringFormat")) , </b>when using StringBuilder we just need follow the pattern above.<br />
<br />
Here is the code that will help you pass the correct string to your webview:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">async</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">CallPlayerMethod</span>(<span style="color: #333399; font-weight: bold;">string</span> method, <span style="color: #333399; font-weight: bold;">string</span> param, <span style="color: #333399; font-weight: bold;">string</span> json)
{
StringBuilder builder = <span style="color: #008800; font-weight: bold;">new</span> StringBuilder();
builder.Append(<span style="background-color: #fff0f0;">"myJSObject."</span>);
builder.Append(method);</pre>
<pre style="line-height: 125%; margin: 0;"><pre style="color: #333333; line-height: 16.25px;"> builder.Append(<span style="color: #333399; font-weight: bold;">string</span>.Format(<span style="background-color: #fff0f0;">"('{0}'"</span>, param)) ;
builder.Append(<span style="color: #333399; font-weight: bold;">string</span>.Format(<span style="background-color: #fff0f0;">",JSON.parse('{0}'))"</span>, json)); </pre>
<span style="color: #888888;">// old</span></pre>
<pre style="line-height: 125%; margin: 0;"><span style="color: #888888;"> //builder.Append('(');</span><pre style="color: #333333; line-height: 16.25px;"> <span style="color: #888888;">//builder.Append("'" + param + "'");</span>
<span style="color: #888888;">//builder.Append(",JSON.parse('" + json + "')");</span>
<span style="color: #888888;">//builder.Append(')');</span></pre>
<span style="color: #888888;">//call webview</span>
CallEvalWebviewMethod(builder.ToString());
}
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">async</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">CallEvalWebviewMethod</span>(<span style="color: #333399; font-weight: bold;">string</span> callMethod)
{</pre>
<pre style="line-height: 125%; margin: 0;"> List<<span style="color: #333399; font-weight: bold;">string</span>> callingJsMethod = <span style="color: #008800; font-weight: bold;">new</span> List<<span style="color: #333399; font-weight: bold;">string</span>>();
callingJsMethod.Add(callMethod);
<span style="color: #008800; font-weight: bold;">try</span>
{
<span style="color: #008800; font-weight: bold;">await</span> MyWebView?.InvokeScriptAsync(<span style="background-color: #fff0f0;">"eval"</span>, callingJsMethod);
}
<span style="color: #008800; font-weight: bold;">catch</span> (Exception e)
{
<span style="color: #888888;">//silent fail</span>
}
}
</pre>
</div>
<br />
You can find my sample <a href="https://github.com/Delaire/Samples/tree/master/WebViewInvokeScriptApp">here</a><br />
Happy coding<br />
<br />
<br />
<br />
<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-24109574280857010942018-02-19T05:07:00.001-08:002018-02-19T05:07:36.882-08:00Building a Placeholder Loading UI like Facebook using only XAML for your UWP application [XAML,C#,Composition]Building beautiful native UI is very important, and keeping your users informed of what is going in the app is even more important.<br />
<br />
We are going to look at creating a placeholder loading control that looks like what facebook is using in its application.<br />
<br />
Here is a static version of the loading control:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/zUwHcgx.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="368" data-original-width="800" height="147" src="https://i.imgur.com/zUwHcgx.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here is what we could do if we add some animation using composition.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/i6KILyC.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="248" data-original-width="509" height="155" src="https://i.imgur.com/i6KILyC.gif" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
It is super important to remember that the loading animation should not hide or distract the user from using y our application, the loading animation should just be there to help your user understand that they must wait a bit for the loading to end.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
For this example we will be build 2 different UI loaders to show that data is being loaded, here is what the placeholders will have to show that they are loading:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/Q4tC2wY.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="514" data-original-width="800" height="205" src="https://i.imgur.com/Q4tC2wY.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here is an example of what we want to do:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/kqHI7tt.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="672" data-original-width="800" height="268" src="https://i.imgur.com/kqHI7tt.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You have two options either we have a control with a shimmer over to simulate that something is loading or we just have a static rectangle (or grid) with a background color. If you only want to use the backgroudn color you can look at the <b>RectangleNoShimmerControl.xaml</b> file, if you do want the shimmer keep on reading =).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
First we are going to create a RectangleControl UserControl that will hold a <span style="color: #007700;">ContentControl </span>and a <span style="color: #007700;">StackPanel </span>with a <span style="color: #007700;">FontIcon.</span></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The ContentControl with its <span style="color: #007700;">LinearGradientBrush </span>is what will allow you have the gradient effect when we move the element, in the samlpe you can change: </div>
<pre style="line-height: 16.25px;"><span style="color: #007700;"><GradientStop</span> <span style="color: #0000cc;">Offset=</span><span style="background-color: #fff0f0;">"0.5"</span> <span style="color: #0000cc;">Color=</span><span style="background-color: #fff0f0;">"#dcdcdc"</span> <span style="color: #007700;">/></span></pre>
<div class="separator" style="clear: both; text-align: left;">
by</div>
<pre style="color: #333333; line-height: 16.25px;"><span style="color: #007700;"><GradientStop</span> <span style="color: #0000cc;">Offset=</span><span style="background-color: #fff0f0;">"0.5"</span> <span style="color: #0000cc;">Color=</span><span style="background-color: #fff0f0;">"Red"</span> <span style="color: #007700;">/></span></pre>
<pre style="color: #333333; line-height: 16.25px;"><span style="color: #007700;">
</span></pre>
<div class="separator" style="clear: both; text-align: left;">
which will give you this for example:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/qfS7kOr.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="479" data-original-width="769" height="199" src="https://i.imgur.com/qfS7kOr.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Next we will need to add the animation on the content control, we need something to move on the X axis, so using a <span style="color: #007700;">DoubleAnimationUsingKeyFrames </span> and targeting <span style="background-color: #fff0f0; color: #333333;">CompositeTransform.TranslateX</span> we will be able to do this.</div>
<pre style="color: #333333; line-height: 16.25px;"></pre>
<pre style="color: #333333; line-height: 16.25px;"><span style="color: #007700;"><Storyboard</span><span style="color: #007700;">></span>
<span style="color: #007700;"><DoubleAnimationUsingKeyFrames</span>
<span style="color: #0000cc;">EnableDependentAnimation=</span><span style="background-color: #fff0f0;">"True"</span></pre>
<pre style="color: #333333; line-height: 16.25px;"><pre style="background-color: white; line-height: 16.25px;"><span style="color: #0000cc;"> RepeatBehavior=</span><span style="background-color: #fff0f0;">"Forever"</span></pre>
<span style="color: #0000cc;">Storyboard.TargetName=</span><span style="background-color: #fff0f0;">"contentControl"</span>
<span style="color: #0000cc;">Storyboard.TargetProperty=</span><span style="background-color: #fff0f0;">"(Control.Foreground).(Brush.RelativeTransform).(CompositeTransform.TranslateX)"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><EasingDoubleKeyFrame</span> <span style="color: #0000cc;">KeyTime=</span><span style="background-color: #fff0f0;">"0"</span> <span style="color: #0000cc;">Value=</span><span style="background-color: #fff0f0;">"-1"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><EasingDoubleKeyFrame</span> <span style="color: #0000cc;">KeyTime=</span><span style="background-color: #fff0f0;">"0:0:1.5"</span> <span style="color: #0000cc;">Value=</span><span style="background-color: #fff0f0;">"1"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></DoubleAnimationUsingKeyFrames></span>
<span style="color: #007700;"></Storyboard></span></pre>
<pre style="color: #333333; line-height: 16.25px;"></pre>
<div class="separator" style="clear: both; text-align: left;">
We are going to nest our <span style="color: #007700;">Storyboard i</span>nside a <span style="background-color: white; color: #007700;"><Grid.Triggers> => </span><span style="background-color: white; color: #333333;"> </span><span style="color: #007700;"><EventTrigger</span><span style="background-color: white; color: #333333;"> </span><span style="color: #0000cc;">RoutedEvent=</span><span style="background-color: #fff0f0; color: #333333;">"Grid.Loaded"</span><span style="color: #007700;">> => </span><span style="color: #007700;"><EventTrigger.Actions> </span>which will allow us to start the animation when the Grid is loaded.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here is the full XAML code for the page:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<!-- HTML generated using hilite.me --></div>
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><UserControl.Resources></span> <span style="color: #007700;"> </span>
<span style="color: #007700;"><Color</span> <span style="color: #0000cc;">x:Key=</span><span style="background-color: #fff0f0;">"EmptyStateLightgray"</span><span style="color: #007700;">></span>#ebebeb<span style="color: #007700;"></Color></span>
<span style="color: #007700;"><Color</span> <span style="color: #0000cc;">x:Key=</span><span style="background-color: #fff0f0;">"EmptyStatebackground"</span><span style="color: #007700;">></span>#f7f7f7<span style="color: #007700;"></Color></span>
<span style="color: #007700;"><SolidColorBrush</span> <span style="color: #0000cc;">x:Key=</span><span style="background-color: #fff0f0;">"EmptyStateColorBrush"</span> <span style="color: #0000cc;">Color=</span><span style="background-color: #fff0f0;">"{StaticResource EmptyStateLightgray}"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></UserControl.Resources></span>
<span style="color: #007700;"><Grid></span><pre style="color: #333333; line-height: 16.25px;"> <span style="color: #007700;"><Grid.Triggers></span>
<span style="color: #007700;"><EventTrigger</span> <span style="color: #0000cc;">RoutedEvent=</span><span style="background-color: #fff0f0;">"Grid.Loaded"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><EventTrigger.Actions></span>
<span style="color: #007700;"><BeginStoryboard></span>
<span style="color: #007700;"><Storyboard></span>
<span style="color: #007700;"><DoubleAnimationUsingKeyFrames</span>
<span style="color: #0000cc;">EnableDependentAnimation=</span><span style="background-color: #fff0f0;">"True"</span>
<span style="color: #0000cc;">RepeatBehavior=</span><span style="background-color: #fff0f0;">"Forever"</span>
<span style="color: #0000cc;">Storyboard.TargetName=</span><span style="background-color: #fff0f0;">"contentControl"</span>
<span style="color: #0000cc;">Storyboard.TargetProperty=</span><span style="background-color: #fff0f0;">"(Control.Foreground).(Brush.RelativeTransform).(CompositeTransform.TranslateX)"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><EasingDoubleKeyFrame</span> <span style="color: #0000cc;">KeyTime=</span><span style="background-color: #fff0f0;">"0"</span> <span style="color: #0000cc;">Value=</span><span style="background-color: #fff0f0;">"-1"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><EasingDoubleKeyFrame</span> <span style="color: #0000cc;">KeyTime=</span><span style="background-color: #fff0f0;">"0:0:1.5"</span> <span style="color: #0000cc;">Value=</span><span style="background-color: #fff0f0;">"1"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></DoubleAnimationUsingKeyFrames></span>
<span style="color: #007700;"></Storyboard></span>
<span style="color: #007700;"></BeginStoryboard></span>
<span style="color: #007700;"></EventTrigger.Actions></span>
<span style="color: #007700;"></EventTrigger></span>
<span style="color: #007700;"></Grid.Triggers></span></pre>
<span style="color: #007700;"><ContentControl</span>
<span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"contentControl"</span>
<span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">HorizontalContentAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><ContentControl.Foreground></span>
<span style="color: #007700;"><LinearGradientBrush</span> <span style="color: #0000cc;">StartPoint=</span><span style="background-color: #fff0f0;">"0.5,0"</span> <span style="color: #0000cc;">EndPoint=</span><span style="background-color: #fff0f0;">"0.5,1"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><LinearGradientBrush.RelativeTransform></span>
<span style="color: #007700;"><CompositeTransform</span>
<span style="color: #0000cc;">CenterX=</span><span style="background-color: #fff0f0;">"0.5"</span>
<span style="color: #0000cc;">CenterY=</span><span style="background-color: #fff0f0;">"0.5"</span>
<span style="color: #0000cc;">Rotation=</span><span style="background-color: #fff0f0;">"95"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></LinearGradientBrush.RelativeTransform></span>
<span style="color: #007700;"><GradientStop</span> <span style="color: #0000cc;">Offset=</span><span style="background-color: #fff0f0;">"0"</span> <span style="color: #0000cc;">Color=</span><span style="background-color: #fff0f0;">"{StaticResource EmptyStateLightgray}"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><GradientStop</span> <span style="color: #0000cc;">Offset=</span><span style="background-color: #fff0f0;">"0.5"</span> <span style="color: #0000cc;">Color=</span><span style="background-color: #fff0f0;">"#dcdcdc"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><GradientStop</span> <span style="color: #0000cc;">Offset=</span><span style="background-color: #fff0f0;">"1"</span> <span style="color: #0000cc;">Color=</span><span style="background-color: #fff0f0;">"{StaticResource EmptyStateLightgray}"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></LinearGradientBrush></span>
<span style="color: #007700;"></ContentControl.Foreground></span>
<span style="color: #007700;"><StackPanel</span>
<span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">Background=</span><span style="background-color: #fff0f0;">"{StaticResource EmptyStateColorBrush}"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><FontIcon</span> <span style="color: #0000cc;">FontSize=</span><span style="background-color: #fff0f0;">"800"</span> <span style="color: #0000cc;">Glyph=</span><span style="background-color: #fff0f0;">"&#xE009;"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></StackPanel></span>
<span style="color: #007700;"></ContentControl></span>
<span style="color: #007700;"></Grid></span>
</pre>
</div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now that we have our Facebook like shimmer animation we will create our loading states using that UserControl. Now we are going to create another UserControl to resemble something like this:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/oVYoZms.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="476" data-original-width="751" height="202" src="https://i.imgur.com/oVYoZms.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
To create this in XAML I will use a Grid which will use multiple <span style="color: #007700;">RowDefinitions , </span>which gives us this:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #007700;"><Grid></span>
<span style="color: #007700;"><Grid.RowDefinitions></span>
<span style="color: #007700;"><RowDefinition</span> <span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"120"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><RowDefinition</span> <span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"15"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><RowDefinition</span> <span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"20"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><RowDefinition</span> <span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"15"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></Grid.RowDefinitions></span>
<span style="color: #007700;"><local:RectangleControl</span>
<span style="color: #0000cc;">Grid.Row=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"290"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #007700;">/></span>
<span style="color: #007700;"><local:RectangleControl</span>
<span style="color: #0000cc;">Grid.Row=</span><span style="background-color: #fff0f0;">"1"</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"60"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"0,5,0,0"</span>
<span style="color: #007700;">/></span>
<span style="color: #007700;"><local:RectangleControl</span>
<span style="color: #0000cc;">Grid.Row=</span><span style="background-color: #fff0f0;">"2"</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"210"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"0,9,0,0"</span>
<span style="color: #007700;">/></span>
<span style="color: #007700;"><local:RectangleControl</span>
<span style="color: #0000cc;">Grid.Row=</span><span style="background-color: #fff0f0;">"3"</span>
<span style="color: #0000cc;">Width=</span><span style="background-color: #fff0f0;">"170"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"0,5,0,0"</span>
<span style="color: #007700;">/></span>
<span style="color: #007700;"></Grid></span>
</pre>
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You can find <a href="https://github.com/Delaire/Samples/tree/master/loadingStateSample">my code sample here.</a></div>
<div class="separator" style="clear: both; text-align: left;">
Happy coding </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-41390794470258332292018-02-16T04:47:00.002-08:002018-02-21T00:54:50.314-08:00Return of development expirence on using XAMARIN for Tizen TV [XAML,C#,TIZEN]<b>My return of Experience on the 16th of February 2018</b><br />
Long story short: I have been playing around for a while now with Xamarin for Tizen TV, and this will be great for us XAML/.NET developer when:<br />
<br />
<ol>
<li>It is fully finished and compatible with Tizen TV, Tizen 4 Tv are released to the public</li>
<li>that the emulator really works "correctly"</li>
<li>the debugger from Visual Studio actually works</li>
<li>that you can create custom controls to make beautiful UI</li>
</ol>
<br />
I am not in the habit of writing negative posts and this is not one, so let me explain why we should hold off just a bit before we really start using this:<br />
<ul>
<li>After having played with the framework and after feed back from Samsung and having spoken with a developer from the Xamarin porting team from Samsung, as of today Xamarin for Tizen is more in beta IMO then in release even thought the road map says that it is finished:</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/fakp3SI.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="656" height="320" src="https://i.imgur.com/fakp3SI.png" width="262" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
The framework is working however there as still a lot of missing pieces. From what I am told 2018 will allow Samsung to finish developing/debug and see who is interested in using Xamarin for Tizen TV.<br />
<ul>
<li>The Visual Studio Debugger is not working as it should, for example if you set a break point and launch the application on the emulator for Tizen TV I would be hit by one of the following issues either the app will crash, visual studio will crash or when you do hit the break point you will not be able to see the value in you objects using quick watch. (When using the same code FORMS code for UWP, Android or IOS the debugger worked perfectly)</li>
</ul>
As you can see here:<br />
<div>
<a href="https://i.imgur.com/dOzEgen.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="309" data-original-width="800" height="153" src="https://i.imgur.com/dOzEgen.png" width="400" /></a></div>
<br />
<ul>
<li>Another issue that Samsung has informed me is that the Emulator for Tizen 4 Tv, is not the best way to develop for their TVs they very strongly recommend that you buy a Tizen 4 TV, the Tv will be updated with the latest firmware and OS. The emulator doesn't have the same performance as a TV, it has more limitation because it is being vitalized.</li>
</ul>
<div>
<ul>
<li>Currently Rendering custom controls on Tizen with Xamrin is not working which can also be issue as you can imagine. In my case I was trying to create a listview that we holding another listview horizontally, this worked fine on the UWP app but nothing happened of the Tizen TV App. </li>
</ul>
<div>
<br /></div>
</div>
<div>
All in all Samsung has a little way to go to finish the Tizen APIs for Xamarin and to finish polishing their code before we (developers) can start building awesome Tizen TV application =). From what I am told the Xamarin porting team at Samsung are working at 100% to fix everything and I am sure that within a few months everything will be finished.</div>
<br />
<br />
<br />
<br />
<br />
<br />
.Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-23258096212872201862018-02-05T07:02:00.000-08:002018-02-05T07:02:46.691-08:00Reactive UI with your UWP applications Example II (using your ViewModel) [XAML,C#,RxUI]In the previous example we saw how to us Reactive UI on a auto complet, in this example we will see another example of how to Reactive UI on a ViewModel in your UWP application.<br />
<br />
Here we will connect an property to a Service and a SelectedItem using ReactiveCommand.<br />
<br />
First we will create a small class:<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">
</span></pre>
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;"> public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">MyItem</span>
{
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #333399; font-weight: bold;">int</span> id { <span style="color: #008800; font-weight: bold;">get</span>; <span style="color: #008800; font-weight: bold;">set</span>; }
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #333399; font-weight: bold;">string</span> name { <span style="color: #008800; font-weight: bold;">get</span>; <span style="color: #008800; font-weight: bold;">set</span>; }
}
</pre>
<pre style="line-height: 125%; margin: 0;"></pre>
</div>
<br />
Next we will create a small service:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;"> </span></pre>
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;"> public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">MyItemService</span>
{
<span style="color: #008800; font-weight: bold;">public</span> IObservable<IEnumerable<MyItem>> GetUpcomingItems(<span style="color: #333399; font-weight: bold;">int</span> index)
{
<span style="color: #888888;">//get your items here</span>
<span style="color: #888888;">//do your http call here</span>
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #008800; font-weight: bold;">null</span>;
}
}
</pre>
<pre style="line-height: 125%; margin: 0;"></pre>
</div>
<br />
Here is my ViewModel:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">MainViewModel</span> : ViewModelBase
{
<span style="color: #888888;">//My item loader</span>
<span style="color: #008800; font-weight: bold;">public</span> ReactiveCommand<<span style="color: #333399; font-weight: bold;">int</span>, IEnumerable<MyItem>> LoadMyItems
{
<span style="color: #008800; font-weight: bold;">get</span>;
}
<span style="color: #888888;">//my selected item</span>
MyItem m_selectedItem;
<span style="color: #008800; font-weight: bold;">public</span> MyItem MySelectedItem
{
<span style="color: #008800; font-weight: bold;">get</span> { <span style="color: #008800; font-weight: bold;">return</span> m_selectedItem; }
<span style="color: #008800; font-weight: bold;">set</span> { RaisePropertyChanged(<span style="background-color: #fff0f0;">"MySelectedItem"</span>); }
}
<span style="color: #888888;">//my service</span>
<span style="color: #008800; font-weight: bold;">private</span> MyItemService myItemService;
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">MainViewModel</span>()
{
<span style="color: #888888;">//init the serivce</span>
myItemService = <span style="color: #008800; font-weight: bold;">new</span> MyItemService();
<span style="color: #888888;">//getting items using the CreateFromObservable</span>
LoadMyItems = ReactiveCommand
.CreateFromObservable((<span style="color: #333399; font-weight: bold;">int</span> index) =>
myItemService.GetUpcomingItems(index));
<span style="color: #888888;">//when the vm is activated bind the properties</span>
<span style="color: #008800; font-weight: bold;">this</span>.WhenActivated((CompositeDisposable disposables) =>
{
<span style="color: #888888;">//init</span>
SelectedItem = <span style="color: #008800; font-weight: bold;">null</span>;
<span style="color: #888888;">//when SelectedItem has a value go to page</span>
<span style="color: #008800; font-weight: bold;">this</span>
.WhenAnyValue(x => x.SelectedItem)
.Where(x => x != <span style="color: #008800; font-weight: bold;">null</span>)
.Subscribe(x => LoadSelectedPage(x))
.DisposeWith(disposables);
});
}
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">LoadSelectedPage</span>(MyItem item)
{
<span style="color: #888888;">//load this page</span>
}
}
</pre>
</div>
<br />
The interesting part are the loading of the items using <b>ReactiveCommand.CreateFromObservable</b> this will start the loading once this property is binded to a ListView or GridView.<br />
<br />
Next the <b>SelectedItem </b>and the <b><span style="color: #008800;">this</span>.WhenAnyValue(x => x.SelectedItem) </b>will allow me to navigate or perform an action when this property has a value.<br />
<br />
As you can see, Reactive UI allows us to bind events in the ViewModel, of course you could have used <b>ICommand</b> or <b>RelayCommand </b>but I find Reactive UI to be a much more elegant solution!<br />
<br />
Happy coding!<br />
<br />
<br />
<br />
<br />
<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-90410405347077424742018-01-10T09:57:00.000-08:002018-03-04T09:57:41.318-08:00[Return of experience] UWP WebView and playing with it http headers to change the user-agent [C#,WebView,HTTP]Over the years I have had the opportunity to work a lot with the UWP Webview on Windows Mobile (sic), Desktop, Xbox and HoloLens.<br />
<br />
This has given me the opportunity to really see what happens when you play with the user-agent of the WebView. One would imagine that even if the WebView was used on Desktop / Mobile and Xbox that even if you had used the same user agent for all three platform that everything would work. This will probably be the case for 90% of your HTTP calls but every now and then this will not be the case.<br />
<br />
First a little bit of back story about why did I override the WebViews user-agent, by default it works great, however I encountered a case that when the WebView calls other urls (redirections mainly) on Desktop and Xbox the HTTP headers are lost/ not passed along. Which is why I had to set the user-agent in the first place.<br />
<br />
The next issue that I encounter was that I was using the same user-agent on all 3 platforms Desktop/Mobile/Xbox which meant that the url that I was calling thought that for all 3 platforms I was a desktop. The url that I calling was serving a video media element and depending on which platforms it was being called it would either be using the media stack from the device or the media stack for the webview.<br />
<br />
Here are 2 user agents for Xbox One and Windows 10 Desktop devices:<br />
<table class="table table-striped" style="border-collapse: collapse; border-spacing: 0px; color: #616464; font-family: Lato, sans-serif; font-size: 0.9em; letter-spacing: 0.2px; margin: 0px auto 1em; max-width: 100%; width: 545px;"><thead>
<tr><th style="border-top: 0px; line-height: 28px; padding: 14px; text-align: left; vertical-align: bottom;">Xbox One</th></tr>
</thead><tbody>
<tr style="background-color: rgb(249, 249, 249) !important;"><td style="border-top: 1px solid rgb(226, 226, 226); line-height: 28px; padding: 14px; vertical-align: top;">Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Xbox; Xbox One) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586</td></tr>
</tbody></table>
The issue that I was having with this user-agent is that on our servers the app was serving the video on the wrong media stack again. This was because on the Xbox the application would think that it was being run on a Windows Mobile wish is not great. In the end i ended up edit the string as follows <b>"(Windows NT 10.0; Win64; x64; Xbox; Xbox One)" </b>instead of<b> "(Windows Phone 10.0; Android 4.2.1; Xbox; Xbox One)"</b>.<br />
<br />
<table class="table table-striped" style="border-collapse: collapse; border-spacing: 0px; color: #616464; font-family: Lato, sans-serif; font-size: 0.9em; letter-spacing: 0.2px; margin: 0px auto 1em; max-width: 100%; width: 545px;"><thead>
<tr><th style="border-top: 0px; line-height: 28px; padding: 14px; text-align: left; vertical-align: bottom;">Windows 10-based PC using Edge browser</th></tr>
</thead><tbody>
<tr style="background-color: rgb(249, 249, 249) !important;"><td style="background-color: #f1f1f1; border-top: 1px solid rgb(226, 226, 226); line-height: 28px; padding: 14px; vertical-align: top;">Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246</td></tr>
</tbody></table>
<br />
In the end everything ended up working as expected and the Media stack of the device was used and not the WebViewmedia stack. This however was only achieved by being able to send the correct user-agent to the WebView so that the url called would then give back the correct information.<br />
<br />
Happy coding,<br />
<br />
Website with all lots of user agents: <a href="https://deviceatlas.com/blog/list-of-user-agent-strings">https://deviceatlas.com/blog/list-of-user-agent-strings </a>Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-84033516310257324552017-12-06T08:56:00.005-08:002017-12-06T08:56:53.264-08:00Reactive UI with your UWP applications [XAML,C#,RxUI]In the tutorial we will create a sample application that uses ReactiveUI in a UWP application. what we will do is have a text field, and whenever the user types something into it, you want to make a network request which searches for that query. In bonus we will add a back off to wait for the user to stop typing before doing the request.<br />
<br />
The idea is not mine but taken from the <a href="https://github.com/reactiveui/reactiveui/#a-compelling-example">ReactiveUI</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://camo.githubusercontent.com/36ef198099ec39e5b569ba77ca38608c7fa4e755/687474703a2f2f692e67697068792e636f6d2f78546b6130327752324869464f4641436f452e676966" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="240" data-original-width="500" height="191" src="https://camo.githubusercontent.com/36ef198099ec39e5b569ba77ca38608c7fa4e755/687474703a2f2f692e67697068792e636f6d2f78546b6130327752324869464f4641436f452e676966" width="400" /></a></div>
<br />
First create your UWP application and add the ReactiveUI nuget package:<br />
<br />
Either by using the command line:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/Ne4BALz.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="76" data-original-width="800" height="60" src="https://i.imgur.com/Ne4BALz.png" width="640" /></a></div>
<br />
Or in the Nuget package Manager:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/fFEbrQQ.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="244" data-original-width="800" height="194" src="https://i.imgur.com/fFEbrQQ.png" width="640" /></a></div>
<br />
Once installed let the fun begin!<br />
<br />
Because we want to do a search we will have to bind a property to the textblock, first in the ViewModel of the page we will add:<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">private</span> <span style="color: #333399; font-weight: bold;">string</span> _searchValue;
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #333399; font-weight: bold;">string</span> SearchValue
{
<span style="color: #008800; font-weight: bold;">get</span> { <span style="color: #008800; font-weight: bold;">return</span> _searchValue; }
<span style="color: #008800; font-weight: bold;">set</span> { Set(<span style="color: #008800; font-weight: bold;">ref</span> _searchValue, <span style="color: #008800; font-weight: bold;">value</span>); }
}
</pre>
</div>
<br />
Next in the XAML page we will add the SearchValue property to the AutoSuggestBox control as follow:<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #007700;"><AutoSuggestBox</span>
<span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"SearchBoxSuggestions"</span>
<span style="color: #0000cc;">Grid.Row=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">PlaceholderText=</span><span style="background-color: #fff0f0;">"{Binding Path=[txt_SearchPlaceHolder], Source={StaticResource LocalizedStrings}, FallbackValue='txt_SearchPlaceHolder'}"</span>
<span style="color: #0000cc;">QueryIcon=</span><span style="background-color: #fff0f0;">"Find"</span>
<span style="color: #0000cc;">Text=</span><span style="background-color: #fff0f0;">"{Binding SearchValue, Mode=TwoWay}"</span> <span style="color: #007700;">/></span>
</pre>
</div>
<br />
<br />
In our ViewModel we will need to setup the ReactiveUI events:<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">SetupRxUI</span>()
{
<span style="color: #008800; font-weight: bold;">this</span>.WhenAnyValue(x => x.SearchValue)
.Where(x => x != <span style="color: #008800; font-weight: bold;">null</span> && x.Length >= <span style="color: #6600ee; font-weight: bold;">3</span>)
.Subscribe(o => OnSearchCommand());
}
</pre>
</div>
<br />
This means that when the SearchValue property changes and that it is not null and have more then 2 chars we will launch the OnSearchCommand() method.<br />
<div style="background: rgb(255, 255, 255); border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 16.25px;"><span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">OnSearchCommand</span>()
{
<span style="color: #888888;">//do a search</span>
}
</pre>
</div>
<br />
We can even imagine that the search command should not be fired every time but only once the user has stopped typing for 700 milliseconds and we would have something like this:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">SetupRxUI</span>()
{
<span style="color: #333399; font-weight: bold;">var</span> Interval = TimeSpan.FromMilliseconds(<span style="color: #6600ee; font-weight: bold;">700</span>);
<span style="color: #008800; font-weight: bold;">this</span>.WhenAnyValue(x => x.SearchValue)
.Where(x => x != <span style="color: #008800; font-weight: bold;">null</span> && x.Length >= <span style="color: #6600ee; font-weight: bold;">3</span>)
.Throttle(Interval, RxApp.MainThreadScheduler)
.Subscribe(o => OnSearchCommand());
}
</pre>
</div>
<br />
and there you have it!<br />
<br />
//Happy Coding<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-16767329914232013022017-11-30T04:34:00.000-08:002017-12-05T04:34:50.859-08:00Building your Shell for your UWP app, quick tutorial on how to get started [XAML,C#]In this tutorial we will see how to setup your shell in your UWP application using the <a href="https://github.com/Microsoft/UWPCommunityToolkit/">UWP Community Toolkit</a> HamburgerMenu control. I really liked the shell that was done for the sample app of the UWP Community Toolkit and thus we will try to do the same thing!<br />
<br />
The HamburgerMenu control in the UWP Community Toolkit sample has an ineteresting way or using narrow and wide states. It allow us to have a hamburger menu when the app is in narrow mode or have the navigation at the top when we are in the wide mode, this is what we are going to reproduce.<br />
<br />
This is when you are in wide mode:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/PhH2aPX.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="666" data-original-width="800" height="532" src="https://i.imgur.com/PhH2aPX.png" width="640" /></a></div>
<br />
<br />
This is when you are in Narrow mode:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/2VXn8r2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="503" height="640" src="https://i.imgur.com/2VXn8r2.png" width="401" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
And that is what we are going to setup in this tutorial!</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Lets start, first we need create a page called Shell.xaml/.cs this will be our shell of our application. </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Next we will create a HamburgerMenu control that we will named x:Name="HamburgerMenu" inside the HamburgerMenu tag we will add a VisualStateManager which will allow us to change between the Narrow and Wide States of the app. Depending on which state we are in we will need to change the style and the ItemTample of the HamburgerMenu.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><VisualStateManager.VisualStateGroups></span>
<span style="color: #007700;"><VisualStateGroup</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"WindowStates"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><VisualState</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"NarrowState"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><VisualState.StateTriggers></span>
<span style="color: #007700;"><AdaptiveTrigger</span> <span style="color: #0000cc;">MinWindowWidth=</span><span style="background-color: #fff0f0;">"0"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></VisualState.StateTriggers></span>
<span style="color: #007700;"><VisualState.Setters></span>
<span style="color: #007700;"><Setter</span> <span style="color: #0000cc;">Target=</span><span style="background-color: #fff0f0;">"HamburgerMenu.Style"</span> <span style="color: #0000cc;">Value=</span><span style="background-color: #fff0f0;">"{StaticResource VerticalHamburgerMenu}"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><Setter</span> <span style="color: #0000cc;">Target=</span><span style="background-color: #fff0f0;">"HamburgerMenu.ItemTemplate"</span> <span style="color: #0000cc;">Value=</span><span style="background-color: #fff0f0;">"{StaticResource VerticalItemTemplate}"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><Setter</span> <span style="color: #0000cc;">Target=</span><span style="background-color: #fff0f0;">"HamburgerMenu.IsPaneOpen"</span> <span style="color: #0000cc;">Value=</span><span style="background-color: #fff0f0;">"False"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></VisualState.Setters></span>
<span style="color: #007700;"></VisualState></span>
<span style="color: #007700;"><VisualState</span> <span style="color: #0000cc;">x:Name=</span><span style="background-color: #fff0f0;">"WideState"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><VisualState.StateTriggers></span>
<span style="color: #007700;"><AdaptiveTrigger</span> <span style="color: #0000cc;">MinWindowWidth=</span><span style="background-color: #fff0f0;">"700"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></VisualState.StateTriggers></span>
<span style="color: #007700;"><VisualState.Setters></span>
<span style="color: #007700;"><Setter</span> <span style="color: #0000cc;">Target=</span><span style="background-color: #fff0f0;">"HamburgerMenu.Style"</span> <span style="color: #0000cc;">Value=</span><span style="background-color: #fff0f0;">"{StaticResource HorizontalHamburgerMenu}"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><Setter</span> <span style="color: #0000cc;">Target=</span><span style="background-color: #fff0f0;">"HamburgerMenu.ItemTemplate"</span> <span style="color: #0000cc;">Value=</span><span style="background-color: #fff0f0;">"{StaticResource HorizontalItemTemplate}"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><Setter</span> <span style="color: #0000cc;">Target=</span><span style="background-color: #fff0f0;">"HamburgerMenu.PaneBackground"</span> <span style="color: #0000cc;">Value=</span><span style="background-color: #fff0f0;">"White"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"><Setter</span> <span style="color: #0000cc;">Target=</span><span style="background-color: #fff0f0;">"HamburgerMenu.PaneForeground"</span> <span style="color: #0000cc;">Value=</span><span style="background-color: #fff0f0;">"Black"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></VisualState.Setters></span>
<span style="color: #007700;"></VisualState></span>
<span style="color: #007700;"></VisualStateGroup></span>
<span style="color: #007700;"></VisualStateManager.VisualStateGroups></span>
</pre>
</div>
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
For this page we will add 2 DataTemplates :</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<!-- HTML generated using hilite.me --></div>
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><Page.Resources></span>
<span style="color: #007700;"><DataTemplate</span> <span style="color: #0000cc;">x:Key=</span><span style="background-color: #fff0f0;">"HorizontalItemTemplate"</span> <span style="color: #0000cc;">x:DataType=</span><span style="background-color: #fff0f0;">"local:SampleCategory"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><Grid></span>
<span style="color: #007700;"><TextBlock</span>
<span style="color: #0000cc;">Grid.Column=</span><span style="background-color: #fff0f0;">"1"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Center"</span>
<span style="color: #0000cc;">FontFamily=</span><span style="background-color: #fff0f0;">"Segoe UI"</span>
<span style="color: #0000cc;">FontSize=</span><span style="background-color: #fff0f0;">"15px"</span>
<span style="color: #0000cc;">FontWeight=</span><span style="background-color: #fff0f0;">"Normal"</span>
<span style="color: #0000cc;">Foreground=</span><span style="background-color: #fff0f0;">"Black"</span>
<span style="color: #0000cc;">Text=</span><span style="background-color: #fff0f0;">"{x:Bind Name}"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></Grid></span>
<span style="color: #007700;"></DataTemplate></span>
<span style="color: #007700;"><DataTemplate</span> <span style="color: #0000cc;">x:Key=</span><span style="background-color: #fff0f0;">"VerticalItemTemplate"</span> <span style="color: #0000cc;">x:DataType=</span><span style="background-color: #fff0f0;">"local:SampleCategory"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><Grid></span>
<span style="color: #007700;"><TextBlock</span>
<span style="color: #0000cc;">Padding=</span><span style="background-color: #fff0f0;">"30,14"</span>
<span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Top"</span>
<span style="color: #0000cc;">FontFamily=</span><span style="background-color: #fff0f0;">"Segoe UI"</span>
<span style="color: #0000cc;">FontSize=</span><span style="background-color: #fff0f0;">"20px"</span>
<span style="color: #0000cc;">FontWeight=</span><span style="background-color: #fff0f0;">"SemiBold"</span>
<span style="color: #0000cc;">Foreground=</span><span style="background-color: #fff0f0;">"White"</span>
<span style="color: #0000cc;">Opacity=</span><span style="background-color: #fff0f0;">"0.8"</span>
<span style="color: #0000cc;">Text=</span><span style="background-color: #fff0f0;">"{x:Bind Name}"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></Grid></span>
<span style="color: #007700;"></DataTemplate></span>
<span style="color: #007700;"></Page.Resources></span>
</pre>
</div>
<br />
Next we will need to set the different styles for the HamburgerMenu which you can find <a href="https://github.com/Delaire/Samples/blob/master/DemoShell/App.xaml">here</a>, most of these style were taken from the sample UWP app of the toolkit and reworked to fit our needs you can check it out <a href="https://github.com/Delaire/Samples/blob/master/DemoShell/App.xaml">here</a>.<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
In our Shell.xaml.cs file we will add 3 properties:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> Shell Current { <span style="color: #008800; font-weight: bold;">get</span>; <span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">set</span>; }
</pre>
</div>
<div>
So that we can acces the shell from anywhere in the application.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">private</span> NavViewModel _currentSample;
</pre>
</div>
So that we know under which tab we arer navigating<br />
<br />
<div style="background: rgb(255, 255, 255); border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 16.25px;"><pre style="line-height: 16.25px;"><span style="color: #008800; font-weight: bold;">private</span> List<NavViewModel> NavigationViews { <span style="color: #008800; font-weight: bold;">get</span>; <span style="color: #008800; font-weight: bold;">set</span>; }</pre>
</pre>
</div>
To load the different view that should be accessible in the nav bar.<br />
<br />
<br />
Next we need to work on the <span style="color: #0066bb; font-weight: bold;">OnNavigatedTo </span>method, here we are going to want to populate our NavigationViews property and bind it to our HamburgerMenu as follows:<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;"> protected</span> <span style="color: #008800; font-weight: bold;">override</span> <span style="color: #008800; font-weight: bold;">async</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">OnNavigatedTo</span>(NavigationEventArgs e)
{
<span style="color: #008800; font-weight: bold;">base</span>.OnNavigatedTo(e);
NavigationFrame.Navigating += NavigationFrame_Navigating;
NavigationViews = <span style="color: #008800; font-weight: bold;">new</span> List<NavViewModel>();
NavigationViews.Add(<span style="color: #008800; font-weight: bold;">new</span> NavViewModel() { Name = <span style="background-color: #fff0f0;">"Red view"</span>, PageView = <span style="background-color: #fff0f0;">"RedView"</span> });
NavigationViews.Add(<span style="color: #008800; font-weight: bold;">new</span> NavViewModel() { Name = <span style="background-color: #fff0f0;">"Blue view"</span>, PageView = <span style="background-color: #fff0f0;">"BlueView"</span> });
NavigationViews.Add(<span style="color: #008800; font-weight: bold;">new</span> NavViewModel() { Name = <span style="background-color: #fff0f0;">"Orange view"</span>, PageView = <span style="background-color: #fff0f0;">"OrangeView"</span> });
HamburgerMenu.ItemsSource = NavigationViews;
NavigationFrame.Navigate(<span style="color: #008800; font-weight: bold;">typeof</span>(BlueView));
}
</pre>
</div>
<br />
<br />
You should have something like this in the end:<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">public</span> <span style="color: #008800; font-weight: bold;">static</span> Shell Current { <span style="color: #008800; font-weight: bold;">get</span>; <span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">set</span>; }
<span style="color: #008800; font-weight: bold;">private</span> NavViewModel _currentSample;
<span style="color: #008800; font-weight: bold;">private</span> List<NavViewModel> NavigationViews { <span style="color: #008800; font-weight: bold;">get</span>; <span style="color: #008800; font-weight: bold;">set</span>; }
<span style="color: #008800; font-weight: bold;">public</span> <span style="color: #0066bb; font-weight: bold;">Shell</span>()
{
<span style="color: #008800; font-weight: bold;">this</span>.InitializeComponent();
Current = <span style="color: #008800; font-weight: bold;">this</span>;
}
<span style="color: #008800; font-weight: bold;">protected</span> <span style="color: #008800; font-weight: bold;">override</span> <span style="color: #008800; font-weight: bold;">async</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">OnNavigatedTo</span>(NavigationEventArgs e)
{
<span style="color: #008800; font-weight: bold;">base</span>.OnNavigatedTo(e);
NavigationFrame.Navigating += NavigationFrame_Navigating;
NavigationViews = <span style="color: #008800; font-weight: bold;">new</span> List<NavViewModel>();
NavigationViews.Add(<span style="color: #008800; font-weight: bold;">new</span> NavViewModel() { Name = <span style="background-color: #fff0f0;">"Red view"</span>, PageView = <span style="background-color: #fff0f0;">"RedView"</span> });
NavigationViews.Add(<span style="color: #008800; font-weight: bold;">new</span> NavViewModel() { Name = <span style="background-color: #fff0f0;">"Blue view"</span>, PageView = <span style="background-color: #fff0f0;">"BlueView"</span> });
NavigationViews.Add(<span style="color: #008800; font-weight: bold;">new</span> NavViewModel() { Name = <span style="background-color: #fff0f0;">"Orange view"</span>, PageView = <span style="background-color: #fff0f0;">"OrangeView"</span> });
HamburgerMenu.ItemsSource = NavigationViews;
NavigationFrame.Navigate(<span style="color: #008800; font-weight: bold;">typeof</span>(BlueView));
}
</pre>
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Next we will what to handle the <span style="color: #0066bb; font-weight: bold;">NavigationFrame_Navigating </span>this will allow us to make sure that the correct tab is selected deepending on which tab we click, tap, etc</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<!-- HTML generated using hilite.me --></div>
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">async</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">NavigationFrame_Navigating</span>(<span style="color: #333399; font-weight: bold;">object</span> sender, NavigatingCancelEventArgs navigationEventArgs)
{
<span style="color: #008800; font-weight: bold;">if</span> (navigationEventArgs.Parameter != <span style="color: #008800; font-weight: bold;">null</span> && NavigationViews != <span style="color: #008800; font-weight: bold;">null</span>)
{
_currentSample = NavigationViews.Where(a => a.Name == navigationEventArgs.Parameter).FirstOrDefault();
}
<span style="color: #008800; font-weight: bold;">else</span>
{
_currentSample = <span style="color: #008800; font-weight: bold;">null</span>;
}
<span style="color: #008800; font-weight: bold;">await</span> <span style="color: #0066bb; font-weight: bold;">SetHamburgerMenuSelection</span>();
}
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">async</span> Task <span style="color: #0066bb; font-weight: bold;">SetHamburgerMenuSelection</span>()
{
<span style="color: #008800; font-weight: bold;">if</span> (_currentSample != <span style="color: #008800; font-weight: bold;">null</span>)
{
<span style="color: #008800; font-weight: bold;">if</span> (HamburgerMenu.Items.Contains(_currentSample))
{
HamburgerMenu.SelectedItem = _currentSample;
HamburgerMenu.SelectedOptionsItem = <span style="color: #008800; font-weight: bold;">null</span>;
}
}
<span style="color: #008800; font-weight: bold;">else</span>
{
<span style="color: #008800; font-weight: bold;">try</span>
{
HamburgerMenu.SelectedItem = <span style="color: #008800; font-weight: bold;">null</span>;
HamburgerMenu.SelectedOptionsIndex = <span style="color: #6600ee; font-weight: bold;">0</span>;
}
<span style="color: #008800; font-weight: bold;">catch</span> (Exception e)
{
<span style="color: #888888;">//fail in silence</span>
}
}
}
</pre>
</div>
<br />
<div class="separator" style="clear: both; text-align: left;">
and there you have it =), have fun paying around with the demo app.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Happy coding!</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Full Source code of the app <a href="https://github.com/Delaire/Samples/tree/master/DemoShell">here</a>.</div>
<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-43439698162962591022017-10-11T00:35:00.000-07:002017-12-04T00:38:47.630-08:00Allowing a Horizontal list to have a Slidable items [XAML,UWP]For a hackathon I needed to have items that where slideable when they where in a Horizontal list.<br />
To do this I decided to use the <a href="https://github.com/Microsoft/UWPCommunityToolkit">UWP Community Toolkit</a> and rework the <a href="https://github.com/Microsoft/UWPCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls/SlidableListItem">SlidableListItem</a> control.<br />
<br />
To speed things up we will need to use the Animations from the UWP Community toolkit, install it by using package manager:<br />
<br />
<a href="https://i.imgur.com/kv9sqFu.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="92" data-original-width="900" height="75" src="https://i.imgur.com/kv9sqFu.png" width="740" /></a><br />
<br />
Now you should be able to use this namespace :<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #008800; font-weight: bold;">using</span> <span style="color: #0e84b5; font-weight: bold;">Microsoft.Toolkit.Uwp.UI.Animations</span>;
</pre>
</div>
<br />
Next lets have a look at the <b><a href="https://github.com/Microsoft/UWPCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls/SlidableListItem">SlidableItem </a></b>from the UWP toolkit. You can see that it has a slidable mechanism from left to right and right to left, and that it uses animation to transition from on state to another.<br />
<br />
I converted this control so that it would work for my needs, basically all I did was replace these with a mechanism from top to bottom and left to top. Also all of the animations where changed from the X axis to the Y axis and I had to rework how the animations worked.<br />
<br />
You can see the changes here on the <a href="https://github.com/Delaire/Samples/blob/master/SlidableItemSample/SlidableItemSample/SlidableItemSample/SlidableItem/SlidableGridItem.cs">Github page</a>, I wont go over them as there isnt any added value for me to do this.<br />
<br />
In the demo app, you will see a horizontal list with items in it:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/u6tfT9F.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="282" data-original-width="800" height="140" src="https://i.imgur.com/u6tfT9F.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
When you swipe down in this sample you will see a red background with the wording delete (you can customise this as you wish) :</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/67jW3TS.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="354" data-original-width="800" height="176" src="https://i.imgur.com/67jW3TS.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
When you swipe up you will see another possible action:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://i.imgur.com/eQChex0.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="340" data-original-width="800" height="168" src="https://i.imgur.com/eQChex0.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
To customize your DataTemplate have a look at the one in the sample app:</div>
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #007700;"><DataTemplate</span> <span style="color: #0000cc;">x:Key=</span><span style="background-color: #fff0f0;">"KeyQueueSwipeTemplate"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><local:SlidableGridItem</span>
<span style="color: #0000cc;">MinWidth=</span><span style="background-color: #fff0f0;">"300"</span>
<span style="color: #0000cc;">MaxWidth=</span><span style="background-color: #fff0f0;">"300"</span>
<span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">ActivationWidth=</span><span style="background-color: #fff0f0;">"71"</span>
<span style="color: #0000cc;">AllowDrop=</span><span style="background-color: #fff0f0;">"True"</span>
<span style="color: #0000cc;">BottomBackground=</span><span style="background-color: #fff0f0;">"SkyBlue"</span>
<span style="color: #0000cc;">BottomCommand=</span><span style="background-color: #fff0f0;">"{Binding DataContext.CallBottomItemCommand, RelativeSource={RelativeSource TemplatedParent}}"</span>
<span style="color: #0000cc;">BottomForeground=</span><span style="background-color: #fff0f0;">"White"</span>
<span style="color: #0000cc;">BottomIcon=</span><span style="background-color: #fff0f0;">"Play"</span>
<span style="color: #0000cc;">BottomLabel=</span><span style="background-color: #fff0f0;">"Next"</span>
<span style="color: #0000cc;">CanDrag=</span><span style="background-color: #fff0f0;">"True"</span>
<span style="color: #0000cc;">DataContext=</span><span style="background-color: #fff0f0;">"{Binding DataContext, ElementName=Page, Mode=OneWay}"</span>
<span style="color: #0000cc;">IsBottomCommandEnabled=</span><span style="background-color: #fff0f0;">"True"</span>
<span style="color: #0000cc;">IsOffsetLimited=</span><span style="background-color: #fff0f0;">"False"</span>
<span style="color: #0000cc;">IsPointerReleasedOnSwipingHandled=</span><span style="background-color: #fff0f0;">"True"</span>
<span style="color: #0000cc;">IsTopCommandEnabled=</span><span style="background-color: #fff0f0;">"True"</span>
<span style="color: #0000cc;">MouseSlidingEnabled=</span><span style="background-color: #fff0f0;">"True"</span>
<span style="color: #0000cc;">TopBackground=</span><span style="background-color: #fff0f0;">"OrangeRed"</span>
<span style="color: #0000cc;">TopCommand=</span><span style="background-color: #fff0f0;">"{Binding DataContext.CallTopActionItemCommand, RelativeSource={RelativeSource TemplatedParent}}"</span>
<span style="color: #0000cc;">TopForeground=</span><span style="background-color: #fff0f0;">"White"</span>
<span style="color: #0000cc;">TopIcon=</span><span style="background-color: #fff0f0;">"Delete"</span>
<span style="color: #0000cc;">TopLabel=</span><span style="background-color: #fff0f0;">"Delete"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><Grid</span> <span style="color: #0000cc;">Height=</span><span style="background-color: #fff0f0;">"190"</span> <span style="color: #0000cc;">Background=</span><span style="background-color: #fff0f0;">"LightGray"</span><span style="color: #007700;">></span>
<span style="color: #007700;"><Grid.ColumnDefinitions></span>
<span style="color: #007700;"><ColumnDefinition</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></Grid.ColumnDefinitions></span>
<span style="color: #007700;"><slidableitemsample:MyUserControl</span>
<span style="color: #0000cc;">Grid.Column=</span><span style="background-color: #fff0f0;">"0"</span>
<span style="color: #0000cc;">Margin=</span><span style="background-color: #fff0f0;">"0,0,0,0"</span>
<span style="color: #0000cc;">HorizontalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">VerticalAlignment=</span><span style="background-color: #fff0f0;">"Stretch"</span>
<span style="color: #0000cc;">AllowDrop=</span><span style="background-color: #fff0f0;">"True"</span>
<span style="color: #0000cc;">CanDrag=</span><span style="background-color: #fff0f0;">"True"</span>
<span style="color: #0000cc;">DataContext=</span><span style="background-color: #fff0f0;">"{Binding DataContext, RelativeSource={RelativeSource TemplatedParent}}"</span> <span style="color: #007700;">/></span>
<span style="color: #007700;"></Grid></span>
<span style="color: #007700;"></local:SlidableGridItem></span>
<span style="color: #007700;"></DataTemplate></span>
</pre>
</div>
<br />
<br />
As you can see the most important parts are:<br />
<pre style="line-height: 16.25px;"><ul>
<li> <span style="color: #0000cc;">BottomBackground=</span><span style="background-color: #fff0f0;">"SkyBlue"</span></li>
<li> <span style="color: #0000cc;">BottomCommand=</span><span style="background-color: #fff0f0;">"{Binding DataContext.CallBottomItemCommand, RelativeSource={RelativeSource TemplatedParent}}"</span></li>
<li> <span style="color: #0000cc;">BottomForeground=</span><span style="background-color: #fff0f0;">"White"</span></li>
<li> <span style="color: #0000cc;">BottomIcon=</span><span style="background-color: #fff0f0;">"Play"</span></li>
<li> <span style="color: #0000cc;">BottomLabel=</span><span style="background-color: #fff0f0;">"Next"</span></li>
</ul>
</pre>
Bottom part of the control and<br />
<pre style="line-height: 16.25px;"><ul>
<li><span style="color: #0000cc;">TopBackground=</span><span style="background-color: #fff0f0;">"OrangeRed"</span></li>
<li><span style="color: #0000cc;">TopCommand=</span><span style="background-color: #fff0f0;">"{Binding DataContext.CallTopActionItemCommand, RelativeSource={RelativeSource TemplatedParent}}"</span></li>
<li><span style="color: #0000cc;">TopForeground=</span><span style="background-color: #fff0f0;">"White"</span></li>
<li><span style="color: #0000cc;">TopIcon=</span><span style="background-color: #fff0f0;">"Delete"</span></li>
<li><span style="color: #0000cc;">TopLabel=</span><span style="background-color: #fff0f0;">"Delete"</span></li>
</ul>
</pre>
for the top part of the control, changing these are what will allow you to change how the control behaves.<br />
<br />
You can find my<a href="https://github.com/Delaire/Samples/tree/master/SlidableItemSample/SlidableItemSample"> code and the sample here</a>.<br />
<br />
Happy coding!<br />
<br />Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.comtag:blogger.com,1999:blog-7407406883409595620.post-76989779964834004222017-10-04T08:07:00.000-07:002018-01-05T08:15:38.227-08:00Editing the HTTP header done by your WebView using NavigationStarting in a UWP application [HTML,C#]I recently encounter a very weird issue with how my <b>WebView</b> was doing some of my HTTP calls on redirects. Sometimes when calling a URL that will do a redirect the HTTP headers would get lost or replaced by some default values.<br />
<br />
To fix this the only solution that I found was to override the HTTP query done every time the <b>WebView</b> started navigating to another page. In this I was lucky as we have a <b>NavigationStarting</b> event that is fired when this happens, thus I have <b>NavigationStarting += Wb_NavigationStarting; </b>when I am creating my <b>WebView</b>.<br />
<br />
Now that ce have caught this event we need to edit it in <b>Wb_NavigationStarting</b> method, I will unbind the event (so that it dosent fire multiple times), tell the <b>WebView</b> that I am handling the event with <b>args.Cancel = <span style="color: #008800;">true</span>;</b> and now edit the HTTP query with a method that I will call <b>NavigateWithHeader</b> .<br />
<br />
In the method <b>NavigateWithHeader </b>I will just add again my header and my authorization token so that the HTTP query has all of the values it is supposed to have, you will have something like this:<br />
<br />
<pre style="line-height: 16.25px;"><span style="color: #333399; font-weight: bold;">var</span> requestMsg = <span style="color: #008800; font-weight: bold;">new</span> Windows.Web.Http.HttpRequestMessage(HttpMethod.Get, uri);
requestMsg.Headers.Add(<span style="background-color: #fff0f0;">"User-Agent"</span>, <span style="background-color: #fff0f0;">"some user agent"</span>);
<pre style="line-height: 16.25px;">requestMsg.Headers.Add(<span style="background-color: #fff0f0;">"Authorization"</span>, <span style="background-color: #fff0f0;">"token abc"</span>); </pre>
</pre>
<pre style="line-height: 16.25px;">MyWebView.NavigateWithHttpRequestMessage(requestMsg);
MyWebView.NavigationStarting += Wb_NavigationStarting;</pre>
<br />
<br />
Here is the full code:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"> <span style="color: #008800; font-weight: bold;">private</span> WebView <span style="color: #0066bb; font-weight: bold;">NewWebView</span>()
{
<span style="color: #333399; font-weight: bold;">var</span> webView = <span style="color: #008800; font-weight: bold;">new</span> WebView(WebViewExecutionMode.SameThread);
webView.NavigationStarting += Wb_NavigationStarting;
<span style="color: #008800; font-weight: bold;">return</span> webView;
}
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">NavigateWithHeader</span>(Uri uri)
{
<span style="color: #333399; font-weight: bold;">var</span> requestMsg = <span style="color: #008800; font-weight: bold;">new</span> Windows.Web.Http.HttpRequestMessage(HttpMethod.Get, uri);
requestMsg.Headers.Add(<span style="background-color: #fff0f0;">"User-Agent"</span>, <span style="background-color: #fff0f0;">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063"</span>);
MyWebView.NavigateWithHttpRequestMessage(requestMsg);
MyWebView.NavigationStarting += Wb_NavigationStarting;
}
<span style="color: #008800; font-weight: bold;">private</span> <span style="color: #008800; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Wb_NavigationStarting</span>(WebView sender, WebViewNavigationStartingEventArgs args)
{
MyWebView.NavigationStarting -= Wb_NavigationStarting;
args.Cancel = <span style="color: #008800; font-weight: bold;">true</span>;
NavigateWithHeader(args.Uri);
}
</pre>
</div>
<br />
Happy Coding!Damien Delairehttp://www.blogger.com/profile/11772312717747093684noreply@blogger.com