<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>Edi Wang</title><subtitle>Microsoft MVP for Azure</subtitle><rights>© 2009 - 2026 edi.wang</rights><updated>2026-11-07T16:05:23Z</updated><generator uri="https://edi.wang">Moonglade v16.9.0</generator><entry><id>3cc911b8-f4e2-494d-bcfd-ae2dd664bfc8</id><title>Automating Price Calculation from File Names Using PowerShell</title><updated>2025-01-02T08:08:35Z</updated><published>2025-01-02T08:08:35Z</published><link href="https://edi.wang/post/2025/1/2/automating-price-calculation-from-file-names-using-powershell" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;h2&gt;Problem&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;In many industries, files are named using conventions that embed useful metadata directly in the file name. For example, in e-commerce, logistics, or billing systems, file names might include prices, order numbers, or other key details.&lt;/p&gt;
&lt;p&gt;In my case, I have a folder full of PDF files, each named with a format like&amp;nbsp;&lt;code&gt;Hotel-996.35.pdf&lt;/code&gt;, where the last part (&lt;code&gt;996.35&lt;/code&gt;) represents the price of this invoice. Now, I want to calculate the total price of all transactions by summing up the prices embedded in these file names. Doing this manually for a large number of files is time-consuming and is easy to make errors.&lt;/p&gt;
&lt;p&gt;By using &lt;a href="https://learn.microsoft.com/en-us/powershell/?WT.mc_id=AZ-MVP-5002809" target="_blank" rel="noopener"&gt;PowerShell&lt;/a&gt;, you can quickly extract prices from file names and calculate the total. This blog post show you a PowerShell script that solves this problem efficiently.&lt;/p&gt;
&lt;h2&gt;Solution&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;The following PowerShell script below automates the process of extracting prices from file names and calculating their total.&amp;nbsp;&lt;/p&gt;
&lt;pre class="language-powershell"&gt;&lt;code&gt;$directory = Get-Location
$totalPrice = 0
$pdfFiles = Get-ChildItem -Path $directory

foreach ($file in $pdfFiles) {
    if ($file.BaseName -match "-([0-9]+(\.[0-9]{1,2})?)") {
		Write-Host "Found: " $file.Name		
		$unitPrice = [decimal]::Parse($matches[1], [Globalization.NumberStyles]::Float)
        $totalPrice += $unitPrice
    }
}

Write-Host "Total: $totalPrice"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src="/image/img-776a26b9-f067-45a9-bcff-c54ee76a4858.png" border="0" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s break down how it works step by step.&lt;/p&gt;
&lt;h3&gt;1. Working Directory&lt;/h3&gt;
&lt;p&gt;Get the current working directory using the&amp;nbsp;&lt;a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-location?view=powershell-7.4&amp;amp;WT.mc_id=AZ-MVP-5002809" target="_blank" rel="noopener"&gt;&lt;code&gt;Get-Location&lt;/code&gt;&lt;/a&gt; cmdlet. This is the folder where the script will look for files.&amp;nbsp;&lt;/p&gt;
&lt;pre class="language-powershell"&gt;&lt;code&gt;$directory = Get-Location&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Retrieve Files in the Directory&lt;/h3&gt;
&lt;p&gt;The&amp;nbsp;&lt;a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem?view=powershell-7.4&amp;amp;WT.mc_id=AZ-MVP-5002809" target="_blank" rel="noopener"&gt;&lt;code&gt;Get-ChildItem&lt;/code&gt;&lt;/a&gt;&amp;nbsp;cmdlet retrieves all files in the specified directory. By default, it fetches all file types, but you can filter it to only include PDF files by adding a&amp;nbsp;&lt;code&gt;-Filter&lt;/code&gt;&amp;nbsp;parameter (e.g.,&amp;nbsp;&lt;code&gt;-Filter *.pdf&lt;/code&gt;).&lt;/p&gt;
&lt;pre class="language-powershell"&gt;&lt;code&gt;$pdfFiles = Get-ChildItem -Path $directory&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. Extract the Price Using Regex&lt;/h3&gt;
&lt;p dir="auto"&gt;The&amp;nbsp;&lt;code&gt;-match&lt;/code&gt; operator is used to apply a regular expression (regex) to the file's base name (the file name without extension). The regex pattern&amp;nbsp;&lt;code&gt;-([0-9]+(\.[0-9]{1,2})?)&lt;/code&gt;&amp;nbsp;is designed to match a hyphen (&lt;code&gt;-&lt;/code&gt;) followed by a number.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[0-9]+&lt;/code&gt;: Matches one or more digits (e.g.,&amp;nbsp;&lt;code&gt;996&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(\.[0-9]{1,2})?&lt;/code&gt;: Optionally matches a decimal point followed by 1 or 2 digits (e.g.,&amp;nbsp;&lt;code&gt;.35&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The entire pattern is enclosed in parentheses to capture the matched number for later use.&lt;/li&gt;
&lt;/ul&gt;
&lt;p dir="auto"&gt;If a match is found, the matched value is stored in the&amp;nbsp;&lt;code&gt;$matches&lt;/code&gt; automatic variable.&lt;/p&gt;
&lt;pre class="language-powershell"&gt;&lt;code&gt;$file.BaseName -match "-([0-9]+(\.[0-9]{1,2})?)"&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. Convert the Price to Decimal&lt;/h3&gt;
&lt;p&gt;The matched price (stored in&amp;nbsp;&lt;code&gt;$matches[1]&lt;/code&gt;) is converted to a decimal number using the&amp;nbsp;&lt;code&gt;[decimal]::Parse()&lt;/code&gt; method.&amp;nbsp;&lt;/p&gt;
&lt;pre class="language-powershell"&gt;&lt;code&gt;$unitPrice = [decimal]::Parse($matches[1], [Globalization.NumberStyles]::Float)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. Add Total Price&lt;/h3&gt;
&lt;pre class="language-powershell"&gt;&lt;code&gt;$totalPrice += $unitPrice&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;This PowerShell script provides a simple yet powerful solution to a common problem: extracting numeric data from file names and performing calculations. You can modify it to make it works for your scenarios!&lt;/p&gt;</content></entry><entry><id>181c72c9-b99d-4af6-94e5-8e697527542b</id><title>How to Check If .NET Core Program is Running under Remote Desktop</title><updated>2020-02-04T13:19:14Z</updated><published>2020-02-04T13:19:14Z</published><link href="https://edi.wang/post/2020/2/4/how-to-check-if-net-core-program-is-running-under-remote-desktop" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><category term=".NET" /><content>&lt;p&gt;There are a few reasons that we need to know if our program is running under the Windows Remote Desktop (RDP) session. For example, if it is running under RDP, we may disable animation and other fancy graphics effects. But how can we detect if our program is currently under RDP? Let's see.&lt;/p&gt;
&lt;h2&gt;Windows Forms&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;If you are developing Windows Forms Apps using .NET Core 3.x, there's a built-in API that can return if the current program is under RDP: &lt;strong&gt;SystemInformation.TerminalServerSession&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        if (IsRDP)
        {
            MessageBox.Show("Under RDP");
        }
    }

    public static Boolean IsRDP =&amp;gt; SystemInformation.TerminalServerSession;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src="/image/img-f7c41eff-1aff-457a-b7f6-940b6e134bac.png" border="0" alt="" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;Very straight forward.&lt;/p&gt;
&lt;h2&gt;Other .NET Core Programs&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;For other .NET Core program types that we can't use Windows Forms classes. We need to use the old school way: &lt;strong&gt;P/Invoke&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;According to a &lt;a href="https://docs.microsoft.com/en-us/windows/win32/termserv/detecting-the-terminal-services-environment" target="_blank" rel="noopener"&gt;Microsoft document&lt;/a&gt;, &lt;strong&gt;User32.dll&lt;/strong&gt; got a method to return if the current invoker program is running under RDP: &lt;strong&gt;GetSystemMetrics( SM_REMOTESESSION )&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Here, the &lt;strong&gt;SM_REMOTESESSION&amp;nbsp;&lt;/strong&gt;is actually an integer value, which can be presented as &lt;code&gt;0x1000&lt;/code&gt; in C#. So the example code would be:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;static void Main(string[] args)
{
    bool isRDP = GetSystemMetrics(SM_REMOTESESSION);
    Console.WriteLine($"Running under RDP: {isRDP}");

    Console.ReadKey();
}

const int SM_REMOTESESSION = 0x1000;

[DllImport("user32")]
static extern bool GetSystemMetrics(int index);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src="/image/img-d23e3ace-cb1a-4297-955f-e743977cfd37.png" border="0" alt="" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;Tip: The ".dll" behind "user32" can actually be left out because .NET Core is smart enough to look for .dll on Windows systems and .so on Linux. But in this example, the code won't work on Linux since it neither has RDP nor user32 API :)&lt;/p&gt;
&lt;p&gt;However, you should be very careful when using P/Invoke to call unmanaged code from managed code, in fact, you should avoid this trick as much as possible in .NET programming because it will make your code couple with a specific platform unless you write a whole bunch of platforms checking code. Anyway, it can get things complicated in seconds.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;For more information on P/Invoke, please see Microsoft document: &lt;a href="https://docs.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke" target="_blank" rel="noopener"&gt;https://docs.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke&lt;/a&gt;&amp;nbsp;&lt;/p&gt;</content></entry><entry><id>8fff396d-307d-4946-a0f5-c4c885e37979</id><title>Upgrade WinForms Apps from .NET Core 3.0 to 3.1</title><updated>2019-12-06T05:37:51Z</updated><published>2019-12-06T05:37:51Z</published><link href="https://edi.wang/post/2019/12/6/upgrade-winforms-apps-from-net-core-30-to-31" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><category term=".NET" /><content>&lt;p&gt;I upgraded a WinForms App to .NET Core 3.1 these days. It's an open-source on-screen ruler created by Jeff Key in 2004, the original code was for .NET Framework 2.0, I've already upgraded it to .NET Core 3.0 in September this year, it was very smooth without any code change. But this time, .NET Core 3.1 does require some code changes.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-e39c4e81-0fb2-4e58-828a-9c616f692df1.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The project is on my GitHub: &lt;a href="https://github.com/EdiWang/Ruler" target="_blank" rel="noopener"&gt;https://github.com/EdiWang/Ruler&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;According to &lt;a href="https://devblogs.microsoft.com/dotnet/announcing-net-core-3-1/" target="_blank" rel="noopener"&gt;Microsoft .NET Blog&lt;/a&gt;, .NET Core 3.1 for Windows Forms has some breaking changes by removing some controls.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The following Windows Forms controls have been removed from .NET Core 3.1:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;DataGrid&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;ToolBar&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;ContextMenu&lt;/em&gt;&lt;/li&gt;
&lt;li class=""&gt;&lt;em&gt;Menu&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;MainMenu&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;MenuItem&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;These controls were replaced with more powerful controls in .NET Framework 2.0, back in 2005. They have not been available by default in the Visual Studio Designer Toolbox for many years. As a result, we decided to remove these controls and focus only on the new ones.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And they have recommended replacements for these controls:&lt;/p&gt;
&lt;table class="table table-bordered"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong class=""&gt;Old Control (API)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Recommended Replacement&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Other associated APIs removed&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DataGrid&lt;/td&gt;
&lt;td&gt;DataGridView&lt;/td&gt;
&lt;td&gt;DataGridCell, DataGridRow, DataGridTableCollection, DataGridColumnCollection, DataGridTableStyle, DataGridColumnStyle, DataGridLineStyle, DataGridParentRowsLabel, DataGridParentRowsLabelStyle, DataGridBoolColumn, DataGridTextBox, GridColumnStylesCollection, GridTableStylesCollection, HitTestType&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ToolBar&lt;/td&gt;
&lt;td&gt;ToolStrip&lt;/td&gt;
&lt;td class=""&gt;ToolBarAppearance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ToolBarButton&lt;/td&gt;
&lt;td&gt;ToolStripButton&lt;/td&gt;
&lt;td&gt;ToolBarButtonClickEventArgs, ToolBarButtonClickEventHandler, ToolBarButtonStyle, ToolBarTextAlign&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ContextMenu&lt;/td&gt;
&lt;td&gt;ContextMenuStrip&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Menu&lt;/td&gt;
&lt;td&gt;ToolStripDropDown, ToolstripDropDownMenu&lt;/td&gt;
&lt;td&gt;MenuItemCollection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MainMenu&lt;/td&gt;
&lt;td&gt;MenuStrip&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MenuItem&lt;/td&gt;
&lt;td&gt;ToolstripMenuItem&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In the &lt;strong&gt;Ruler&lt;/strong&gt; project, I need to migrate just the menu controls besides retargeting the runtime version.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;TargetFramework&amp;gt;netcoreapp3.1&amp;lt;/TargetFramework&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h6&gt;Type Replacement&lt;/h6&gt;
&lt;p&gt;Replace &lt;strong&gt;ContextMenu&amp;nbsp;&lt;/strong&gt;with &lt;strong&gt;ContextMenuStrip&lt;/strong&gt;, and replace &lt;strong&gt;MenuItem&lt;/strong&gt; with &lt;strong&gt;ToolStripMenuItem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For example, the old code:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private readonly ContextMenu _menu = new ContextMenu();
private MenuItem _verticalMenuItem;
private MenuItem _toolTipMenuItem;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Is replaced with&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private readonly ContextMenuStrip _menu = new ContextMenuStrip();
private ToolStripMenuItem _verticalMenuItem;
private ToolStripMenuItem _toolTipMenuItem;&lt;/code&gt;&lt;/pre&gt;
&lt;h6&gt;API Differences&lt;/h6&gt;
&lt;p&gt;Shortcut Enum that used by &lt;code&gt;MenuItem&lt;/code&gt; isn't there anymore. Replace old code:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private MenuItem AddMenuItem(string text, Shortcut shortcut = Shortcut.None)
{
    MenuItem mi = new MenuItem(text);
    mi.Click += MenuHandler;
    mi.Shortcut = shortcut;
    _menu.MenuItems.Add(mi);

    return mi;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with new code&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private ToolStripMenuItem AddMenuItem(string text, Keys shortcut = Keys.None)
{
    ToolStripMenuItem mi = new ToolStripMenuItem(text);
    mi.Click += MenuHandler;
    mi.ShortcutKeys = shortcut;
    _menu.Items.Add(mi);

    return mi;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the old Menu control, the "-" string represented a separator, which is now replaced by &lt;code&gt;ToolStripSeparator&lt;/code&gt;. So, old code:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;AddMenuItem("-");&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Is now&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;_menu.Items.Add(new ToolStripSeparator());&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, the new menu looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-fe7aa87a-8eb7-4928-aebd-28ad4b4804c9.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The project is very simple, so everything works after a few code changes in .NET Core 3.1. As you can see, to replace the old controls isn't too much difficult. Hope you can also get your old project running on the latest platform soon!&lt;/p&gt;</content></entry><entry><id>1d421931-694d-42b3-9f9f-1603719ca1a2</id><title>About Per Monitor-DPI aware for WinForms Applications</title><updated>2019-07-23T05:47:55Z</updated><published>2019-07-23T05:47:55Z</published><link href="https://edi.wang/post/2019/7/23/about-per-monitordpi-aware-for-winforms-applications" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><category term=".NET" /><content>&lt;p&gt;WinForms is the traditional .NET desktop application workload running on Windows. For historical reasons, there are some problems with its support for high DPI and for different DPI screens, and this article explores the possible solutions.&lt;/p&gt;
&lt;h2&gt;Windows "96" PPI history&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;The default DPI for Windows systems (more precisely called PPI) is 96. PPI means pixel per inch, which means how many pixels are displayed per inch screen.&lt;/p&gt;
&lt;p&gt;The higher this value, the more delicate the display capability of the screen. But it also means that to display the same picture as a low PPI screen, a high PPI screen needs more pixels to fill. For a non-vector graph, this problem is not easy to solve, because of the high pixel stretch, the picture will be "pulled blurred." Similar problems occur in Windows, especially in older programs, which are designed with only 96 PPI in mind. This historical reason can be found in Microsoft's blog:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blogs.msdn.microsoft.com/fontblog/2005/11/08/where-does-96-dpi-come-from-in-windows/" target="_blank" rel="noopener"&gt;https://blogs.msdn.microsoft.com/fontblog/2005/11/08/where-does-96-dpi-come-from-in-windows/&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Example: On a 150% DPI screen, the Windows Management Console (MMC) is blurred.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-36f8e7fe-d1ca-454b-8ec6-65e5c6a71fce.png" alt="" /&gt;&lt;/p&gt;
&lt;h2&gt;Windows 10 improvements&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;With more and more HDPI computers on the market today, Windows 10's semi-annual Feature Updates has been working to resolve DPI issues. We can fix many old programs with the settings shown in the following image. But it's hard to adapt across screens with different DPI.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-bfb2afbf-c787-4e19-bbda-3ae173b1dfd9.png" alt="" width="736" height="501" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-5397a68b-cfb8-4709-9425-1abd4f49db3a.png" alt="" width="816" height="687" /&gt;&lt;/p&gt;
&lt;p&gt;The so-called &lt;strong&gt;Per Monitor-DPI aware&lt;/strong&gt; means that when your computer has an external screen, Windows chooses a DPI that fits the screen to display an image of the external screen. This DPI is probably different from your computer's main screen. For example, with a 22-inch display with 1920x1080 attached to a Surface Pro, the Surface's home screen is typically more than 150% DPI, while the external display is 100%.&lt;/p&gt;
&lt;p&gt;If the program doesn't support Per Monitor-DPI aware itself, you can try the compatibility mode that comes with Windows. You will find that although both screens have clear images, the app interface is magnified on a low DPI screen. It's not perfect. So the most authentic solution is to develop programs that support Per Monitor-DPI aware.&lt;/p&gt;
&lt;p&gt;Microsoft's own applications have also improved regarding &lt;strong&gt;Per Monitor-DPI aware&lt;/strong&gt;. For example, Visual Studio 2019 supports Per Monitor-DPI aware. (Windows 10 v1803 and .NET Framework 4.8)&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-d2dfe659-c2b2-47a2-aa54-108a57faa6dc.png" alt="" width="670" height="241" /&gt;&lt;/p&gt;
&lt;h2&gt;What can we do about WinForms applications?&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;The three most native technologies for Windows desktop development are WinForms, WPF, and UWP. Because UWP was born in modern times, there is no DPI adaptation problem. WPF's XAML interface can also be easily adapted to DPI. But WinForms is way too old. Let's try to save it.&lt;/p&gt;
&lt;p&gt;First of all, I use the 150% DPI main screen with VS2019, the designer view is not blurry, the control position is as follows:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-7ca09107-a073-4d8b-92de-77bbac14671d.png" alt="" width="860" height="588" /&gt;&lt;/p&gt;
&lt;p&gt;Pay attention to the position of the red arrow. Everything's fine in VS. However, when it runs, the main screen at 150% DPI is blurry and the controls are misplaced.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-384ab155-7868-4307-9f38-210925750b98.png" alt="" width="845" height="523" /&gt;&lt;/p&gt;
&lt;p&gt;Drag the window to the 100% DPI external screen, the UI is not blurry, but the controls are still misplaced.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-b095ed58-ae35-44f2-8fe5-97c21567c629.png" alt="" width="549" height="340" /&gt;&lt;/p&gt;
&lt;p&gt;According to Microsoft's documentation &lt;a href="https://docs.microsoft.com/en-us/dotnet/framework/winforms/high-dpi-support-in-windows-forms" target="_blank" rel="noopener"&gt;https://docs.microsoft.com/en-us/dotnet/framework/winforms/high-dpi-support-in-windows-forms&lt;/a&gt;, .NET Framework improves WinForms' DPI support starting at 4.7. So I changed the runtime of the program to 4.7.2 (Windows 10 1803 or more comes with it) Add an app.manifest file to the app root.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-c569152f-fa32-4c96-88f6-d9c3a3a1fbe5.png" alt="" width="1180" height="720" /&gt;&lt;/p&gt;
&lt;p&gt;Uncomment Windows 10 GUID under &lt;code&gt;assembly/compatibility/application&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;!-- Windows 10 --&amp;gt;
&amp;lt;supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add these into App.config&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;System.Windows.Forms.ApplicationConfigurationSection&amp;gt;
  &amp;lt;add key="DpiAwareness" value="PerMonitorV2" /&amp;gt;
&amp;lt;/System.Windows.Forms.ApplicationConfigurationSection&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you find that the control position is displayed correctly on the home screen of 150% DPI, and the entire UI is not blurred.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-5bfafba9-ab13-43bb-b14c-12ba8d9e66da.png" alt="" width="849" height="526" /&gt;&lt;/p&gt;
&lt;p&gt;But on a 100% DPI screen, although the UI is not blurry, the control position is still incorrect, and the TextBox control is huge.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-a65fb3f2-6a4b-4571-bc37-4451f15c7e54.png" alt="" width="565" height="352" /&gt;&lt;/p&gt;
&lt;p&gt;There's no other way out of the Microsoft documentation. But I found that changing the runtime to .NET Framework 4.8 could fix the TextBox, with the control location still incorrect.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-2ffa60dc-7e6f-4eff-ad8d-64a32ddb49a6.png" alt="" width="547" height="341" /&gt;&lt;/p&gt;
&lt;p&gt;On closer inspection, it's not TextBox, Label, Checkbox that's causing the problem, but the MonthCalendar control is much wider on a 100% DPI screen than on a 150% DPI screen. And the combination of Panel, TableLayoutPanel and Dock won't solve the problem.&lt;/p&gt;
&lt;h2&gt;What about .NET Core 3.0&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;Net Core 3.0 is still in preview 6. From the results of my experiment, its DPI settings do not require App.config, but add this into program.cs:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But unfortunately, the result is the same as above .NET Framework applications.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;On Windows 10 v1903 (I haven't tried other versions), with .NET Framework 4.8, WinForms can get a certain level of &lt;strong&gt;Per Monitor-DPI aware&lt;/strong&gt;, but some controls will be rendered in incorrect sizes, so you need to carefully test before publishing the application.&lt;/p&gt;</content></entry><entry><id>4f7addcc-d16c-49ae-be12-1c81aa75e28a</id><title>Read and Write Windows Registry in .NET Core</title><updated>2019-03-04T07:42:19Z</updated><published>2019-03-04T07:42:19Z</published><link href="https://edi.wang/post/2019/3/4/read-and-write-windows-registry-in-net-core" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><category term=".NET" /><content>&lt;p&gt;Yes, you read it right! It's totally possible! Even .NET Core is designed to be cross platform, but it does not mean you can not use platform specific APIs. Take Windows Registry for example, although .NET Standard can not contain Windows API like this. But there's still a way to use Windows Regisitry in .NET Core Applications.&lt;/p&gt;
&lt;p&gt;But first, you should be absolutely clear, that using platform specific APIs like Windows Regisitry will make your App or that part of code Windows only. Let's see how can we use read and write Windows Registry in .NET Core.&lt;/p&gt;
&lt;div&gt;
&lt;h2&gt;Microsoft.Win32.Registry&lt;/h2&gt;
&lt;hr /&gt;&lt;/div&gt;
&lt;p&gt;The API for Windows Registry is contained in package: &lt;strong&gt;&lt;span style="font-size: 0.9rem;"&gt;Microsoft.Win32.Registry&lt;/span&gt;&lt;/strong&gt;&lt;span style="font-size: 0.9rem;"&gt;. &lt;/span&gt;&lt;span style="font-size: 0.9rem;"&gt;It is a part of the Windows Compatibility Pack, which is designed to help developers to port their old .NET Framework applications to .NET Core piece by piece.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="font-size: 0.9rem;"&gt;Add this package to your .NET Core Application:&lt;/span&gt;&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;dotnet add package Microsoft.Win32.Registry&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This contains types as:&lt;/p&gt;
&lt;p&gt;Microsoft.Win32.RegistryKey&lt;br /&gt;Microsoft.Win32.Registry&lt;br /&gt;Microsoft.Win32.RegistryValueKind&lt;br /&gt;Microsoft.Win32.RegistryHive&lt;br /&gt;Microsoft.Win32.RegistryView&lt;/p&gt;
&lt;p&gt;and add the namespace into your code:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;using Microsoft.Win32;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Write Registry&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;I choose &lt;strong&gt;HKEY_CURRENT_USER&lt;/strong&gt; to do this demo, because it does not require administrator privilege to access.&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;using (RegistryKey key = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\edi_wang"))
{
    key.SetValue("Title", $".NET Core Rocks! {DateTime.UtcNow:MM/dd/yyyy-HHmmss}");
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create a key "&lt;strong&gt;edi_wang&lt;/strong&gt;" under &lt;strong&gt;HKEY_CURRENT_USER\Software&lt;/strong&gt;, and create a string named "&lt;strong&gt;Title&lt;/strong&gt;" with value like "&lt;strong&gt;.NET Core Rocks! 03/04/2019-073320&lt;/strong&gt;"&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-90abbf12-ddac-404c-9b03-8ffba35de37f.png" width="534" height="309" /&gt;&lt;/p&gt;
&lt;h2&gt;Read Registry&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;To read this value from registry:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;using (RegistryKey key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\edi_wang"))
{
    if (key != null)
    {
        Object o = key.GetValue("Title");
        Console.WriteLine(o.ToString());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we can get:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-5d3fd6e7-b67f-48c0-8a69-c00dbe26e342.png" /&gt;&lt;/p&gt;
&lt;h2&gt;Check Platform&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;We know these code only works on Windows. So in practice, when we have to access Registry in .NET Core Application. We need to check the current platform before executing the code.&amp;nbsp;&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
    // Registry Code
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, the example code is on my GitHub: &lt;a href="https://github.com/EdiWang/DotNet-Samples/tree/master/NetCoreRegistry"&gt;https://github.com/EdiWang/DotNet-Samples/tree/master/NetCoreRegistry&lt;/a&gt;&amp;nbsp;&lt;/p&gt;</content></entry><entry><id>a09e5f7f-3dd6-4233-ad60-84a945936709</id><title>How to Remove Default FDS Effects in UWP Apps</title><updated>2018-12-31T13:02:55Z</updated><published>2018-12-31T13:02:55Z</published><link href="https://edi.wang/post/2018/12/31/how-to-remove-default-fds-effects-in-uwp-apps" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;The Fluent Design System introduced by Windows 10 from v1709 is very beautiful, the latest v1809 further refined FDS, many UWP built in controls got FDS effect by default while developers do not need to do anything. This is usually a good thing, but it can also cause performance problems for some apps. My &lt;em&gt;Character Map UWP&lt;/em&gt; is one of the victimized apps, and let's take a look at how to remove the default FDS effect in a UWP app to avoid performance issues.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Problem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The specific problem is that &lt;em&gt;Character Map UWP&amp;nbsp;&lt;/em&gt;has is that the same version, the same code, can run smoothly on Windows 1809 v1803, but and after upgrading to 1908, even scrolling a little bit on he page, select a few characters can immediately stuck the App.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-d37ad13a-1d11-4e63-abb1-0d7b9c82e916.png" alt="" width="1614" height="959" /&gt;&lt;/p&gt;
&lt;p&gt;A few days ago, I received an email from a user saying that just turning off the transparency in Windows 10 personalization settings, that is, turning off all FDS, would allow the app to resume responding.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-a29726fb-990c-4f45-aed0-a2401113b7aa.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The main performance impact is the &lt;strong&gt;GridViewItem&lt;/strong&gt; and &lt;strong&gt;ListViewItem&lt;/strong&gt; got the reveal effect, which is one of the effects of FDS. That is, when the mouse moves onto the element, the surrounding border is highlighted. In my &lt;em&gt;Character Map UWP&lt;/em&gt;, this affects performance, mainly because &lt;strong&gt;GridView&lt;/strong&gt; shows hundreds of or even tens of thousands of characters, this is way too much for the FDS to render.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-fc7b7df6-c11d-46f1-b968-0107e599f11c.png" alt="" width="153" height="156" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fixing the Problem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On Windows 10 v1809, the reveal effects of &lt;strong&gt;GridViewItem&lt;/strong&gt; and &lt;strong&gt;ListViewItem&lt;/strong&gt; are turned on by default, it do not require any designation from the developer, and do not require updating the code of the old app, it will appear automatically. However, it is not so straightforward to turn off.&lt;/p&gt;
&lt;p&gt;The way to turn off the default reveal effect is to rewrite several brush key in the system, and for my application, I need to rewrite these keys:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;SolidColorBrush x:Key="SystemControlTransparentRevealBackgroundBrush" Color="Transparent" /&amp;gt;
&amp;lt;SolidColorBrush x:Key="SystemControlTransparentRevealBorderBrush" Color="Transparent" /&amp;gt;
&amp;lt;SolidColorBrush x:Key="GridViewItemRevealBorderBrush" Color="Transparent" /&amp;gt;
&amp;lt;Thickness x:Key="ListViewItemRevealBorderThemeThickness"&amp;gt;0&amp;lt;/Thickness&amp;gt;
&amp;lt;Thickness x:Key="GridViewItemRevealBorderThemeThickness"&amp;gt;0&amp;lt;/Thickness&amp;gt;
&amp;lt;SolidColorBrush x:Key="ListViewItemRevealBackgroundSelectedPressed" Color="Transparent" /&amp;gt;
&amp;lt;SolidColorBrush x:Key="ListViewItemRevealPlaceholderBackground" Color="Transparent" /&amp;gt;
&amp;lt;SolidColorBrush x:Key="GridViewItemRevealBackground" Color="Transparent" /&amp;gt;
&amp;lt;SolidColorBrush x:Key="GridViewItemRevealBackgroundPointerOver" Color="Transparent" /&amp;gt;
&amp;lt;SolidColorBrush x:Key="GridViewItemRevealBackgroundPressed" Color="Transparent" /&amp;gt;
&amp;lt;SolidColorBrush x:Key="GridViewItemRevealBackgroundSelected" Color="Transparent" /&amp;gt;
&amp;lt;SolidColorBrush x:Key="GridViewItemRevealBackgroundSelectedPointerOver" Color="Transparent" /&amp;gt;
&amp;lt;SolidColorBrush x:Key="GridViewItemRevealBackgroundSelectedPressed" Color="Transparent" /&amp;gt;
&amp;lt;SolidColorBrush x:Key="GridViewItemRevealPlaceholderBackground" Color="Transparent" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now run the app and you'll find that the reveal effect is gone and the overall experience is very good.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-0e169450-89ac-4e70-9493-c98540aaae11.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How did I Find These Keys&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As for how these keys were found, it's actually very simple, after you install the UWP SDK, all the system's brush and other style definitions of the controls are in this file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C:\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\10.0.17763.0\Generic\generic.xaml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Open ths file and search for "&lt;strong&gt;Reveal&lt;/strong&gt;", you can find everything:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-b36eca1d-09e7-460c-be83-11621206ae16.png" alt="" /&gt;&lt;/p&gt;</content></entry><entry><id>7117da78-f826-4fd0-913b-8644dbc42250</id><title>Automate Windows 10 Developer Machine Setup</title><updated>2018-12-21T13:12:23Z</updated><published>2018-12-21T13:12:23Z</published><link href="https://edi.wang/post/2018/12/21/automate-windows-10-developer-machine-setup" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;One of the things programmers hate most is probably setup a computer. Because the programmer's computer environment configuration is very different from normal people. In general, it takes several hours to manually install a new development machine. Let this process automating, after all, the essence of programming is to let complex things simplify, find a way to be lazy!&lt;/p&gt;
&lt;p&gt;In fact, automatic installation and configuration of Windows is nothing new, as early as more than 10 years ago that the folk in computer stores used packaging image to achieve a one-click installation system and software. There are many ways to do this, such as editing Windows installation image through Microsoft or a third-party tool, adding automatic answer files, and finally installing common software with silent parameters, as well as a lazier Ghost images, and so on. More than 10 years ago, I was passionate about packaging windows, scripting and installing software also.&lt;/p&gt;
&lt;p&gt;The method I introduced today is different from what it was more than 10 years ago, comparing to 10 years ago, now we must face some new problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Software updates are becoming more frequent, and every time you install a computer, you want to use the latest version. Traditional way of packaging applications will be out of date in a few days.&lt;/li&gt;
&lt;li&gt;Applications does not want to be distributed with operating system, Windows 10 is in semi-annual update, maintain the traditional way of OS image packaged with Applications is very laborious.&lt;/li&gt;
&lt;li&gt;Normal people's computers are easy to install without the need to specifically design automatic tools. But programmers' environments are becoming more complex with more tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In response to these realities, I chose to use &lt;strong&gt;PowerShell&lt;/strong&gt; and &lt;strong&gt;Choco&lt;/strong&gt; to design a new automatic setup script. PowerShell is Responsible for configuring Windows while Choco can automatically download the latest software installation package from the Internet and install it silently. This way, you don't have to integrate the software installation package into the Windows image.&lt;/p&gt;
&lt;p&gt;In my own case, I am an ASP.NET Programmers, but also do some UWP development. So, for me, the environmental requirements are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows 10 Pro&lt;/li&gt;
&lt;li&gt;Enable IIS + ASP.NET&lt;/li&gt;
&lt;li&gt;Enable Developer Mode&lt;/li&gt;
&lt;li&gt;Install Chrome, 7z, NotePad++, VSCode, LINQPad etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's see how &lt;strong&gt;PowerShell&lt;/strong&gt; + &lt;strong&gt;Choco&lt;/strong&gt; automate these tasks. The code for my entire setup script is open source, and there is a GitHub link in the end of this article, so this article only describes the key steps and code. For full script, you can see GitHub while free to modify and use. I welcome everyone to participate in the contribution, together we can complete a script for the benefit of a variety of programmers.&lt;/p&gt;
&lt;p&gt;&lt;iframe src="//www.youtube.com/embed/phfGRI9GwD4" width="720" height="405" frameborder="0" allowfullscreen="allowfullscreen"&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rename Computer&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first step I like to rename the computer for easier management. In PowerShell, you can use the &lt;strong&gt;Rename-Computer&lt;/strong&gt; command to do this.&lt;/p&gt;
&lt;p&gt;To get the user input value, use command &lt;strong&gt;Read-Host&lt;/strong&gt;. For output text, use &lt;strong&gt;Write-Host&lt;/strong&gt;. To assign a value to a variable, use &lt;strong&gt;=&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The PowerShell code that requires the user to enter the computer name and rename it is as follows:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;$computerName = Read-Host 'Enter New Computer Name'
Write-Host "Renaming this computer to: " $computerName  -ForegroundColor Yellow
Rename-Computer -NewName $computerName&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, this step requires restarting the computer to take effect, we will do it later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disable Auto Sleep&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We don't want the computer to go to sleep in the middle of the automatic setup process. So we need to disable auto sleep when the AC power is plugin.&lt;/p&gt;
&lt;p&gt;Use &lt;strong&gt;PowerCfg&lt;/strong&gt; command to set the screen timeout to 20 minutes, and disable auto sleep in AC power.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;Powercfg /Change monitor-timeout-ac 20
Powercfg /Change standby-timeout-ac 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Desktop Icons&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A newly installed Windows 10 machine does not have "This PC" icon by default on the desktop. However there is a short cut icon for Microsoft Edge, the browser which its only purpose is to download Chrome, and it is becoming Chromium anyway. So we don't need it. Lets take out Edge icon and add "This PC" to our desktop.&lt;/p&gt;
&lt;p&gt;To add "This PC" icon, we just need to modify the Registry.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;$thisPCIconRegPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel"
$thisPCRegValname = "{20D04FE0-3AEA-1069-A2D8-08002B30309D}"
$item = Get-ItemProperty -Path $thisPCIconRegPath -Name $thisPCRegValname -ErrorAction SilentlyContinue

if ($item) {
Set-ItemProperty  -Path $thisPCIconRegPath -name $thisPCRegValname -Value 0  
}

else {
New-ItemProperty -Path $thisPCIconRegPath -Name $thisPCRegValname -Value 0 -PropertyType DWORD  | Out-Null  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Removing Edge short cut is very simple, just delete the file directly. The way to use environment variables in PowerShell is to use &lt;strong&gt;$env&lt;/strong&gt; keywords.&lt;/p&gt;
&lt;p&gt;The current user's environment variable is &lt;strong&gt;userprofile&lt;/strong&gt;, Edge is on the desktop.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;$edgeLink = $env:USERPROFILE + "\Desktop\Microsoft Edge.lnk"
Remove-Item $edgeLink&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Install IIS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;IIS is used to maintain some old ASP.NET projects.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The command for enabling Windows features in PowerShell is &lt;strong&gt;Enable-WindowsOptionalFeature&lt;/strong&gt;, with "&lt;strong&gt;-All&lt;/strong&gt;" parameter, it can install dependencies automatically.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;Enable-WindowsOptionalFeature -Online -FeatureName IIS-DefaultDocument -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-HttpCompressionDynamic -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-HttpCompressionStatic -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-WebSockets -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-ApplicationInit -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-ASPNET45 -All
Enable-WindowsOptionalFeature -Online -FeatureName IIS-ServerSideIncludes
Enable-WindowsOptionalFeature -Online -FeatureName IIS-BasicAuthentication
Enable-WindowsOptionalFeature -Online -FeatureName IIS-WindowsAuthentication&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By the way, &lt;strong&gt;DISM&lt;/strong&gt; command can also do this task.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enable Windows 10 Developer Mode&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The developer mode on Windows 10 is for UWP development. To enable it, just edit Registry.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Enable Remote Desktop&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Modify Registry and enable firewall.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\" -Name "fDenyTSConnections" -Value 0
Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\" -Name "UserAuthentication" -Value 1
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Install Choco for Windows&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chocolatey&amp;nbsp;&lt;/strong&gt;is the tool we are about to use for automatically installing applications. It is just like apt/yum on Linux. We will use the official script to install:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Restart Windows&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We changed the computer name in the first step, it requires reboot of the system. We can let the user to trigger the reboot by asking the user to press enter key. In PowerShell, we use &lt;strong&gt;Restart-Computer&amp;nbsp;&lt;/strong&gt;to reboot the system. You can also do it with &lt;strong&gt;shutdown -r -t 0&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;Read-Host -Prompt "Configuration is done, restart is needed, press [ENTER] to restart computer."
Restart-Computer&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Self Elevate&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As you may have discovered, the steps above are almost all requiring administrator privileges to be performed. We can run PowerShell as administrator manually, but it is more convenient to run under normal permissions and elevate itself to administrator permissions. Put this in the header of the script file:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this way, the script detects whether it currently has administrative permissions, and if not, a UAC will pop up to request an administrator right to PowerShell and continue running the current script.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use Choco to Automatically Install Applications&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After restart Windows, we can use &lt;strong&gt;choco&lt;/strong&gt; command to install applications under PowerShell or CMD with Administrator previlege. I choose CMD this time.&lt;/p&gt;
&lt;p&gt;There are plenty of applications in &lt;strong&gt;chocolatey&amp;nbsp;&lt;/strong&gt;gallery. Many of them are developer tools. You can check online: &lt;a href="https://chocolatey.org/packages" target="_blank" rel="noopener"&gt;https://chocolatey.org/packages&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-f4bd7214-d92f-4b93-a785-e2124035a0c6.png" alt="" width="1027" height="901" /&gt;&lt;/p&gt;
&lt;p&gt;Install command is: &lt;strong&gt;choco install [packagename] -y&lt;/strong&gt;, which the "&lt;strong&gt;-y&lt;/strong&gt;" means automatically respond "yes" to any confirm message. This is how we can install applications unattended.&lt;/p&gt;
&lt;p&gt;So, the batch script to install applications is like this:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;@echo ------------------------------------
@echo Installing 7-Zip...
@echo ------------------------------------
choco install 7zip.install -y

@echo.
@echo ------------------------------------
@echo Installing Google Chrome...
@echo ------------------------------------
choco install googlechrome -y&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have included the following applications in my script:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;7-Zip&lt;/li&gt;
&lt;li&gt;Google Chrome&lt;/li&gt;
&lt;li&gt;Pot Player&lt;/li&gt;
&lt;li&gt;Microsoft Teams&lt;/li&gt;
&lt;li&gt;SysInternals&lt;/li&gt;
&lt;li&gt;Lightshot&lt;/li&gt;
&lt;li&gt;FileZilla&lt;/li&gt;
&lt;li&gt;TeamViewer&lt;/li&gt;
&lt;li&gt;Notepad++&lt;/li&gt;
&lt;li&gt;Visual Studio Code
&lt;ul&gt;
&lt;li&gt;C-Sharp&lt;/li&gt;
&lt;li&gt;Icons&lt;/li&gt;
&lt;li&gt;MSSQL&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DotPeek&lt;/li&gt;
&lt;li&gt;LINQPad&lt;/li&gt;
&lt;li&gt;Fiddler&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;GitHub for Windows&lt;/li&gt;
&lt;li&gt;FFMpeg&lt;/li&gt;
&lt;li&gt;CURL&lt;/li&gt;
&lt;li&gt;WGet&lt;/li&gt;
&lt;li&gt;OpenSSL&lt;/li&gt;
&lt;li&gt;Beyond Compare&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Delete Pre-Installed UWP Apps&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The newly installed Windows 10 will include a few UWP applications we don't want. We can also delete them in PowerShell.&lt;/p&gt;
&lt;p&gt;First, we need to find the UWP applications' package name, run &lt;strong&gt;Get-AppxPackage&amp;nbsp;&lt;/strong&gt;command, it will return a long list like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-302826e5-1c3e-44c0-899d-84b3ca2e4379.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;To delete an UWP application, the official way is to use &lt;strong&gt;PackageFullName&lt;/strong&gt;&lt;strong&gt;&amp;nbsp;&lt;/strong&gt;to delete it. For example, Bing News:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;Remove-AppxPackage -Package Microsoft.BingNews_4.28.3242.0_x64__8wekyb3d8bbwe&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, this can make problem. If Windows 10 updates this application in background, the version number will change, which will make your script useless. So I use another trick to delete the UWP appliction by name instead of full name.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;Get-AppxPackage -Name Microsoft.BingNews | Remove-AppxPackage&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We have a lot of UWP to delete, and the programmer's thinking is, of course, writing a loop, not copy of the command everywhere. The way you do loops in PowerShell is very similar to C #, using &lt;strong&gt;foreach&lt;/strong&gt; syntax. In this example, I put the UWP name I want to delete in an array of strings, and then use loop to remove them.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;$uwpRubbishApps = @(
    "Microsoft.Messaging",
    "king.com.CandyCrushSaga",
    "Microsoft.BingNews",
    "Microsoft.MicrosoftSolitaireCollection",
    "Microsoft.People",
    "Microsoft.WindowsFeedbackHub",
    "Microsoft.YourPhone",
    "Microsoft.MicrosoftOfficeHub",
    "Fitbit.FitbitCoach",
    "4DF9E0F8.Netflix")

foreach ($uwp in $uwpRubbishApps) {
    Get-AppxPackage -Name $uwp | Remove-AppxPackage
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we are finished with our automated setup on a Windows 10 machine!&lt;/p&gt;
&lt;p&gt;The GitHub repository for my scripts is here: &lt;a href="https://github.com/EdiWang/EnvSetup/"&gt;https://github.com/EdiWang/EnvSetup/&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>6ba0ccea-b3a2-47ee-8302-ce991b2bb665</id><title>Build a Pixel Ruler with UWP</title><updated>2018-11-05T02:59:30Z</updated><published>2018-11-05T02:59:30Z</published><link href="https://edi.wang/post/2018/11/5/build-pixel-ruler-uwp" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;In certain applications, we may need an on-screen ruler that indicates pixels on the screen. However, the only built-in ruler in UWP is within the InkToolbar control, we are not able to use it elsewhere. So, I will teach you how to build a pixel ruler which can be used anywhere in your UWP applications.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-e8a6483b-4b81-45a7-ad08-a34604b64ecf.png" border="0" alt="" loading="lazy"&gt;&lt;/p&gt;
&lt;h2&gt;The Demo App&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;Create a new blank UWP application called &lt;strong&gt;PixelRulerUwp&lt;/strong&gt; with minimal runtime version as &lt;strong&gt;Windows 10, &amp;nbsp;version 1803 (10.0; Build 17134)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-33ed4659-9900-460c-b92d-caf4ec102e56.png" border="0" alt="" width="505" height="119" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Win2D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Official document describes Win2D as: Win2D is an easy-to-use Windows Runtime API for immediate mode 2D graphics rendering with GPU acceleration. It is available to C#, C++ and VB developers writing apps for the Windows Universal Platform (UWP). It utilizes the power of Direct2D, and integrates seamlessly with XAML and CoreWindow.&lt;/p&gt;
&lt;p&gt;We will use Win2D to draw the ruler. To add Win2D to our application, install it from NuGet:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;Install-Package Win2D.uwp&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Create PixelRuler User Control&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Add a new user control called &amp;ldquo;&lt;strong&gt;PixelRuler.xaml&lt;/strong&gt;&amp;rdquo; into your application.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-5f268001-4763-4d4c-a05d-5bd76f574cac.png" border="0" alt="" width="851" height="540" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;The Win2D can draw things on a CanvasControl, so we need to add a CanvasControl named &amp;ldquo;RulerCanvas&amp;rdquo; which we are going to draw the ruler UI onto it.&lt;/p&gt;
&lt;p&gt;This will need a new namespace to be added into &lt;strong&gt;UserControl&lt;/strong&gt; attributes.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;xmlns:xaml="using:Microsoft.Graphics.Canvas.UI.Xaml"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then add the &lt;strong&gt;CanvasControl&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;xaml:CanvasControl x:Name="RulerCanvas" 
                    VerticalAlignment="Top" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is not the final XAML code, we will also complete it later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Create Binding Properties&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The ruler needs at least a width and a background color. So, we need to add them into the code behind &lt;strong&gt;PixelRuler.xaml.cs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;By implementing the &lt;strong&gt;INotifyPropertyChanged&lt;/strong&gt; interface, we can enable bindings.&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;using System.ComponentModel;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public sealed partial class PixelRuler : UserControl, INotifyPropertyChanged&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and implement it:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public event PropertyChangedEventHandler PropertyChanged;

[NotifyPropertyChangedInvocator]
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, create the &lt;strong&gt;RulerWidth&lt;/strong&gt; property:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public static readonly DependencyProperty RulerWidthProperty = DependencyProperty.Register(
    nameof(RulerWidth),
    typeof(int),
    typeof(PixelRuler),
    new PropertyMetadata(null)
);

public int RulerWidth
{
    get =&amp;gt; (int)GetValue(RulerWidthProperty);
    set =&amp;gt; SetValue(RulerWidthProperty, value);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src="/image/img-466d26bd-6c42-4f68-bf4c-7a80ccf45d75.png" border="0" alt="" width="316" height="185" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;DependencyProperty&lt;/strong&gt; type is usually used in &lt;strong&gt;UserControl&lt;/strong&gt; so that the user can set values to it when using your &lt;strong&gt;UserControl&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Similarly, add the &lt;strong&gt;BackgroundColor&lt;/strong&gt; property:&lt;/p&gt;
&lt;p&gt;Include namespace&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;using Windows.UI;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And add:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public static readonly DependencyProperty BackgroundColorProperty = DependencyProperty.Register(
    nameof(BackgroundColor),
    typeof(Color),
    typeof(PixelRuler),
    new PropertyMetadata(null)
);

public Color BackgroundColor
{
    get =&amp;gt; (Color)GetValue(BackgroundColorProperty);
    set { SetValue(BackgroundColorProperty, value); OnPropertyChanged(); }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Give them default values in the constructor:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public PixelRuler()
{
    this.InitializeComponent();
    RulerWidth = 50;
    BackgroundColor = Color.FromArgb(128, 238, 238, 238);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now modify the &lt;strong&gt;PixelRuler.xaml&lt;/strong&gt; and bind these properties.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;xaml:CanvasControl x:Name="RulerCanvas" 
                    Height="{x:Bind RulerWidth, Mode=OneWay}"
                    ClearColor="{x:Bind BackgroundColor, Mode=OneWay}"
                    VerticalAlignment="Top" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the &lt;strong&gt;PixelRuler&lt;/strong&gt; UserControl into your MainPage.xaml:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;local:PixelRuler HorizontalAlignment="Stretch"
                  VerticalAlignment="Top" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Draw Ruler&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To draw graphics onto the &lt;strong&gt;CanvasControl&lt;/strong&gt;, use the &amp;ldquo;Draw&amp;rdquo; event, name the event handler as &amp;ldquo;&lt;strong&gt;RulerCanvas_OnDraw&lt;/strong&gt;&amp;rdquo;.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;xaml:CanvasControl x:Name="RulerCanvas" 
                    VerticalAlignment="Top" 
                    Height="{x:Bind RulerWidth, Mode=OneWay}"
                    ClearColor="{x:Bind BackgroundColor, Mode=OneWay}"
                    Draw="RulerCanvas_OnDraw" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For tutorial purpose, I will use hard coded values for now:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private void RulerCanvas_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
    var session = args.DrawingSession;
    session.DrawLine(0, 0, 1920, 0, Colors.Black, 1);
    session.DrawLine(0, RulerWidth, 1920, RulerWidth, Colors.Black, 1);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As the API signature:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public void DrawLine(float x0, float y0, float x1, float y1, Color color, float strokeWidth);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, 1920 means your screen width, (x0, y0) is the start point for the line, (x1, y1) is the end point, 0 is the top left corner of the App screen.&lt;/p&gt;
&lt;p&gt;Run the project, you will get an empty ruler with a top line and a bottom line.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-a440ddae-fa96-4fe8-99cc-899b302805a5.png" border="0" alt="" width="722" height="279" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;Now you understand the basic concept of how to use Win2D to draw things on a CanvasControl and use it in an application page. Let&amp;rsquo;s dig in to more details to complete the ruler.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Draw Steps&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A ruler has large steps and small steps, we can allow user to customize them.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-0f2ef486-7426-45f1-a415-efea94f6abb5.png" border="0" alt="" width="465" height="309" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;To represent those two things, add two properties:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public static readonly DependencyProperty LargeStepsProperty = DependencyProperty.Register(
    nameof(LargeSteps),
    typeof(int),
    typeof(PixelRuler),
    new PropertyMetadata(null)
);

public int LargeSteps
{
    get =&amp;gt; (int)GetValue(LargeStepsProperty);
    set =&amp;gt; SetValue(LargeStepsProperty, value);
}

public static readonly DependencyProperty SmallStepsProperty = DependencyProperty.Register(
    nameof(SmallSteps),
    typeof(int),
    typeof(PixelRuler),
    new PropertyMetadata(null)
);

public int SmallSteps
{
    get =&amp;gt; (int)GetValue(SmallStepsProperty);
    set =&amp;gt; SetValue(SmallStepsProperty, value);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also add default values for them in the constructor:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public PixelRuler()
{
    // &amp;hellip;
    LargeSteps = 50;
    SmallSteps = 10;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For tutorial purpose, I also use hard code here, now the &lt;strong&gt;RulerCanvas_OnDraw&lt;/strong&gt; event handler is:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private void RulerCanvas_OnDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
    var session = args.DrawingSession;
    session.DrawLine(0, 0, 1920, 0, Colors.Black, 1);
    session.DrawLine(0, RulerWidth, 1920, RulerWidth, Colors.Black, 1);

    for (int x = 0; x &amp;lt; 1920; x += LargeSteps)
    {
        for (int x1 = x + SmallSteps; x1 &amp;lt; x + LargeSteps; x1 += SmallSteps)
        {
            session.DrawLine(x1, 0, x1, 10, Colors.Black, 1);
        }
        session.DrawLine(x, 0, x, 20, Colors.Black, 1);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, 10 means small step mark length, 20 means large step mark length.&lt;/p&gt;
&lt;p&gt;Run the project, you will get a ruler with large and small steps.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-671bed6b-bf4d-4e6b-9fb4-a1aace1fa9da.png" border="0" alt="" width="706" height="340" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Draw Text&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A ruler needs text on large step. Add this code to &lt;strong&gt;RulerCanvas_OnDraw&lt;/strong&gt; event handler.&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;for (int x = 0; x &amp;lt; 1920; x += LargeSteps)
{
    session.DrawText(x.ToString(), x, 30, Colors.Black, new CanvasTextFormat()
    {
        FontSize = (float)FontSize,
        FontFamily = FontFamily.Source,
        HorizontalAlignment = CanvasHorizontalAlignment.Center,
        VerticalAlignment = CanvasVerticalAlignment.Center
    });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, 30 means the margin from ruler top to the text, it equals the large step mark length added by 10px.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;FontSize&lt;/strong&gt; and &lt;strong&gt;FontFamily&lt;/strong&gt; don&amp;rsquo;t need to add another two properties, they are inherited from UserControl type itself, which makes them already can be controlled by the user, e.g. from MainPage.xaml:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;local:PixelRuler HorizontalAlignment="Stretch" 
                   VerticalAlignment="Top" FontSize="12" FontFamily="Consolas" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the project, you will get a ruler with steps and text:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-28a1fff1-64c7-4d08-b379-13e097794e1c.png" border="0" alt="" width="650" height="274" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;Now you have a ruler with a basic functionality. Let&amp;rsquo;s make it more awesome.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;More Complete Functions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Our UserControl need to be used in different scenarios and allow user to customize based on their needs. So, we can&amp;rsquo;t use hard coded values. Let&amp;rsquo;s make it more flexible to use.&lt;/p&gt;
&lt;p&gt;For example, about the screen width, I hard coded it to 1920. Let&amp;rsquo;s set it to the large side of the user&amp;rsquo;s device screen resolution. To get the screen resolution, you can install my UWP helper library:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;Install-Package Edi.UWP.Helpers&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can change every &amp;ldquo;1920&amp;rdquo; to &lt;strong&gt;largePixel&lt;/strong&gt; like this:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;var pixelW = Edi.UWP.Helpers.UI.GetScreenWidth();
var pixelH = Edi.UWP.Helpers.UI.GetScreenHeight();
var largePixel = pixelW &amp;gt; pixelH ? pixelW : pixelH;

session.DrawLine(0, 0, (int)largePixel, 0, Colors.Black, 1);
session.DrawLine(0, RulerWidth, (int)largePixel, RulerWidth, Colors.Black, 1);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;rsquo;ve also added these properties for customization:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DrawBorder&lt;/li&gt;
&lt;li&gt;ScaleMarkPosition&lt;/li&gt;
&lt;li&gt;ScaleMarkLength&lt;/li&gt;
&lt;li&gt;ScaleMarkColor&lt;/li&gt;
&lt;li&gt;TextColor&lt;/li&gt;
&lt;li&gt;TextMargin&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can have deep control of the ruler:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;local:PixelRuler HorizontalAlignment="Stretch"
                  VerticalAlignment="Top"
                  RulerWidth="80"
                  LargeSteps="50"
                  SmallSteps="10"
                  ScaleMarkLength="20"
                  FontSize="12"
                  ScaleMarkPosition="Both"
                  ScaleMarkColor="#CCC"
                  TextColor="#CCC"
                  FontFamily="Segoe UI"
                  TextMargin="10"
                  BackgroundColor="#333" 
                  DrawBorder="True"
                  Height="80" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A complete code sample is on my GitHub: &lt;a href="https://github.com/EdiWang/PixelRulerUwp"&gt;https://github.com/EdiWang/PixelRulerUwp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can also check the demo App on Microsoft Store: &lt;a href="https://www.microsoft.com/en-us/p/pixelruleruwp-demo/9nblggh5fjhn"&gt;https://www.microsoft.com/en-us/p/pixelruleruwp-demo/9nblggh5fjhn&lt;/a&gt; &amp;nbsp;&lt;/p&gt;</content></entry><entry><id>7cb71439-9e3a-4e09-99f3-0c68f59c73d6</id><title>Fix AcrylicBrush Missing on NavigationView in Windows 10 SDK 17763</title><updated>2018-10-09T13:53:14Z</updated><published>2018-10-09T13:53:14Z</published><link href="https://edi.wang/post/2018/10/9/fix-acrylicbrush-missing-navigationview-windows-10-17763" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;Microsoft released a new version of Windows 10 UWP SDK Build 17763, you can check the &lt;a href="https://docs.microsoft.com/en-us/windows/uwp/whats-new/windows-10-build-17763" target="_blank" rel="noopener"&gt;What's New document&lt;/a&gt; for more details. But when I retarget my App to version 17763, something unexpected happens, the&amp;nbsp;&lt;strong&gt;AcrylicBrush&lt;/strong&gt; gone missing if I change my App runtime to version 17763.&lt;/p&gt;
&lt;p&gt;I am not sure if this is by design on 17763 or it is a bug, I am trying to contact Microsoft product group on this problem. For now, I can address a workaround for this problem.&lt;/p&gt;
&lt;p&gt;If you don't understand the problem I am talking about, here's a simple test.&lt;/p&gt;
&lt;p&gt;Create a new blank App, use &lt;strong&gt;17134&lt;/strong&gt; for both Min and Target runtime.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-b7b814ea-9c64-42d4-a305-f32ffdaa3f7f.png" /&gt;&lt;/p&gt;
&lt;p&gt;Add a basic &lt;strong&gt;NavigationView&lt;/strong&gt; control into MainPage.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;NavigationView IsSettingsVisible="True"&amp;gt;
    &amp;lt;NavigationView.MenuItems&amp;gt;
        &amp;lt;NavigationViewItem Content="Main" Icon="Document" /&amp;gt;
    &amp;lt;/NavigationView.MenuItems&amp;gt;
&amp;lt;/NavigationView&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the App, you should get a fine&amp;nbsp;&lt;strong&gt;NavigationView&lt;/strong&gt;&amp;nbsp;control with correct &lt;strong&gt;AcrylicBrush&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-c9b1ea80-32d0-4c44-a2c2-7738fa90fe18.png" /&gt;&lt;/p&gt;
&lt;p&gt;Now, change the target version to &lt;strong&gt;17763&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-ed7f4a6a-37ff-4137-8378-b759d3a89d01.png" /&gt;&lt;/p&gt;
&lt;p&gt;Run the App again, the &lt;strong&gt;AcrylicBrush&amp;nbsp;&lt;/strong&gt;is gone:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-a80171d2-9a1b-4afe-a287-c9ccca85631a.png" /&gt;&lt;/p&gt;
&lt;p&gt;To fix this, I have to use a workaround by overriding the pane's background. Add this code in App.xaml&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;ResourceDictionary&amp;gt;
    &amp;lt;AcrylicBrush x:Key="NavigationViewDefaultPaneBackground"
                  BackgroundSource="Backdrop" TintColor="{ThemeResource SystemChromeMediumColor}" TintOpacity=".5"/&amp;gt;
    &amp;lt;AcrylicBrush x:Key="NavigationViewTopPaneBackground"
                  BackgroundSource="Backdrop" TintColor="{ThemeResource SystemChromeMediumColor}" TintOpacity=".5"/&amp;gt;
    &amp;lt;AcrylicBrush x:Key="NavigationViewExpandedPaneBackground"
                  BackgroundSource="HostBackdrop" TintColor="{ThemeResource SystemChromeMediumColor}" TintOpacity=".7"/&amp;gt;
&amp;lt;/ResourceDictionary&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you should get an&amp;nbsp;&lt;strong&gt;AcrylicBrush&amp;nbsp;&lt;/strong&gt;similar to the origin one on runtime version 17763.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-d341214c-e9c4-4be2-8eb1-87c6db55903e.png" /&gt;&lt;/p&gt;
&lt;p&gt;Note: the same problem happens to the &lt;strong&gt;NavigationView&lt;/strong&gt; control in &lt;strong&gt;WinUI&lt;/strong&gt; (&lt;a href="https://docs.microsoft.com/en-us/uwp/toolkits/winui/"&gt;https://docs.microsoft.com/en-us/uwp/toolkits/winui/&lt;/a&gt;) also, even targeting version is 17134.&lt;/p&gt;</content></entry><entry><id>44afeb2a-ca42-44ad-a453-8da04fa381f3</id><title>How to Fix Extended TitleBar Overlapping NavigationView PaneToggleButton</title><updated>2018-07-31T05:33:00Z</updated><published>2018-07-31T05:33:00Z</published><link href="https://edi.wang/post/2018/7/31/fix-titlebar-overlapping-navigationview-pane-toggle-button" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;In UWP Apps, we some times extend our main view into title bar to get rid of Windows 10 default title bar. However if you are using &lt;code&gt;NavigationView&lt;/code&gt; under extended title bar, you will find your &lt;code&gt;PaneToggleButton&lt;/code&gt; overlapped by the title bar. And the user won't be able to click on the upper part of the button because it is where the title bar need to respond to window drag actions.&lt;/p&gt;
&lt;p&gt;This image shows the common problem in this scenario. The problem also exists even in Microsoft's official "&lt;strong&gt;&lt;a href="https://www.microsoft.com/store/productId/9MSVH128X2ZT" target="_blank" rel="noopener"&gt;XAML Control Gallery&lt;/a&gt;&lt;/strong&gt;" App for it's back button. Let's see how can we fix it by a workaround.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-ce6044b0-ad58-49f6-ae77-131f5dd7d05d.png" /&gt;&lt;/p&gt;
&lt;p&gt;First, the code I used to hide the Windows default title bar is very common as Microsoft official sample:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;//draw into the title bar
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;

//remove the solid-colored backgrounds behind the caption controls and system back button
var viewTitleBar = ApplicationView.GetForCurrentView().TitleBar;
viewTitleBar.ButtonBackgroundColor = Colors.Transparent;
viewTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
viewTitleBar.ButtonForegroundColor = (Color)Resources["SystemBaseHighColor"];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And my App does not need a back button, so I hided it in &lt;code&gt;NavigationView&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;NavigationView IsBackEnabled="False" IsBackButtonVisible="Collapsed"&amp;gt;
    &amp;lt;NavigationView.MenuItems&amp;gt;
        &amp;lt;NavigationViewItem Content="Item1"&amp;gt;
            &amp;lt;NavigationViewItem.Icon&amp;gt;
                &amp;lt;FontIcon Glyph="&amp;amp;#xE81E;"/&amp;gt;
            &amp;lt;/NavigationViewItem.Icon&amp;gt;
        &amp;lt;/NavigationViewItem&amp;gt;
    &amp;lt;/NavigationView.MenuItems&amp;gt;
&amp;lt;/NavigationView&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we need to customize the style of the &lt;code&gt;PaneToggleButton&lt;/code&gt;. You can get a copy of the style and template of any built-in UWP controls by right click on the &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;Blend for Visual Studio&lt;/strong&gt;&lt;/span&gt; designer and choose &lt;span style="color: #3366ff;"&gt;&lt;strong&gt;Edit Template&lt;/strong&gt;&lt;/span&gt;, &lt;strong&gt;&lt;span style="color: #3366ff;"&gt;Edit a Copy&lt;/span&gt;&amp;nbsp;&lt;/strong&gt;and name it &lt;span style="color: #3366ff;"&gt;&lt;strong&gt;ExtTitleBarNavigationViewStyle&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-2883eaf9-52c0-406d-a5d4-042c5432de80.png" /&gt;&lt;/p&gt;
&lt;p&gt;Find &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;PaneToggleButtonGrid&lt;/strong&gt; &lt;/span&gt;and change the Margin value to &lt;span style="color: #3366ff;"&gt;&lt;strong&gt;0,32,0,8&lt;/strong&gt;,&lt;/span&gt;&amp;nbsp;which &lt;span style="color: #3366ff;"&gt;&lt;strong&gt;32&lt;/strong&gt; &lt;/span&gt;is the height of Windows 10 title bar.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;Grid x:Name="PaneToggleButtonGrid" HorizontalAlignment="Left" Margin="0,32,0,8" VerticalAlignment="Top" Canvas.ZIndex="100"&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the hamburger button is moved to lower space, however it will overlap the &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;SplitView&amp;nbsp;&lt;/strong&gt;&lt;/span&gt;pane.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-8e0f7d47-0fbb-4740-94dd-93b1c8b0edf8.png" /&gt;&lt;/p&gt;
&lt;p&gt;So we have to do another change. Find &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;PaneContentGrid&amp;nbsp;&lt;/strong&gt;&lt;/span&gt;and add a margin of &lt;span style="color: #3366ff;"&gt;&lt;strong&gt;0,32,0,0&lt;/strong&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;Grid x:Name="PaneContentGrid" Margin="0,32,0,0"&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src="/image/img-d223eaea-d1d1-4dbf-ae69-a4637b444dec.png" /&gt;&lt;/p&gt;
&lt;p&gt;You will get a space with the height of the title bar above the &lt;code&gt;PaneToggleButton&lt;/code&gt; now, which makes the button fully clickable!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;img src="/image/img-bd1e5edb-56a0-46eb-8eed-ec23609cd4e0.png" /&gt;&lt;/p&gt;</content></entry><entry><id>2594eba1-deaa-4b22-b97f-8f6b22768da3</id><title>Windows Community Toolkit: Use CameraPreview to Take Photos</title><updated>2018-07-22T08:33:49Z</updated><published>2018-07-22T08:33:49Z</published><link href="https://edi.wang/post/2018/7/22/uwp-camerapreview-take-photo" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;In UWP Apps, if we want to use the device's camera to take photos and save to a file, it is used to be some how complicated, the developer need to know about quite a lot things and also write quite a few code to get it down (As you can find the Camera examples from &lt;a href="https://github.com/Microsoft/Windows-universal-samples" target="_blank" rel="noopener"&gt;Microsoft offical sample code&lt;/a&gt;). In fact, in many cases, we just want to take a photo by the most easy and default options via the camera. In those cases, our focus is on the business logic of the App instead of spending a few hours just to get the camera code working.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Now, you can get this easily done by &lt;a href="https://github.com/Microsoft/WindowsCommunityToolkit" target="_blank" rel="noopener"&gt;&lt;strong&gt;Windows Community Toolkit&lt;/strong&gt;.&lt;/a&gt;&amp;nbsp;The&amp;nbsp;&lt;span style="color: #ff6600;"&gt;&lt;strong&gt;CameraPreview&lt;/strong&gt; &lt;/span&gt;control provides a straight forward way for us to use the camera and take photos without knowing the details.&lt;/p&gt;
&lt;h2&gt;1. Install via NuGet&lt;/h2&gt;
&lt;hr&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;PM&amp;gt; Install-Package Microsoft.Toolkit.Uwp.UI.Controls&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. Allow WebCam capability in your UWP App&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;You can do it from Visual Studio UI by opening &lt;strong&gt;Package.appxmanifest&lt;/strong&gt; file:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-eaa93406-8739-4f9a-985b-cb8939b0f35c.png" border="0" width="388" height="403" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;Or edit the file via code and add the &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;DeviceCapability&lt;/strong&gt; &lt;/span&gt;node:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;Capabilities&amp;gt;
  &amp;lt;Capability Name="internetClient" /&amp;gt;
  &amp;lt;uap:Capability Name="picturesLibrary" /&amp;gt;
  &amp;lt;DeviceCapability Name="webcam" /&amp;gt;
&amp;lt;/Capabilities&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. Create the App UI&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;First, add the namespace into your &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;Page&lt;/strong&gt; &lt;/span&gt;or &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;UserControl&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, add the&amp;nbsp;&lt;span style="color: #ff6600;"&gt;&lt;strong&gt;CameraPreview&lt;/strong&gt; &lt;/span&gt;control, it is just one line of XAML&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;controls:CameraPreview x:Name="CameraPreviewControl" PreviewFailed="CameraPreviewControl_OnPreviewFailed" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The&amp;nbsp;&lt;span style="color: #ff6600;"&gt;&lt;strong&gt;PreviewFailed&lt;/strong&gt; &lt;/span&gt;event handler is optional but suggestted in order to provide better user experience and also useful for debug.&lt;/p&gt;
&lt;p&gt;For demo purpose, I also add 3 buttons here&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="20,0,0,0"&amp;gt;
    &amp;lt;Button Content="Start" x:Name="BtnStart" Margin="0,0,0,10" Click="BtnStart_Click" /&amp;gt;
    &amp;lt;Button Content="Stop" x:Name="Stop" Margin="0,0,0,10" Click="Stop_Click"/&amp;gt;
    &amp;lt;Button Content="Capture" x:Name="BtnCapture" Click="BtnCapture_Click" /&amp;gt;
&amp;lt;/StackPanel&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. Code&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;First, let's cover the&amp;nbsp;&lt;span style="color: #ff6600;"&gt;&lt;strong&gt;PreviewFailed&lt;/strong&gt; &lt;/span&gt;event handler. I like to show a message dialog to the user about the failure detail:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private async void CameraPreviewControl_OnPreviewFailed(object sender, PreviewFailedEventArgs e)
{
    await new MessageDialog(e.Error, "ERROR").ShowAsync();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note, the&lt;span style="color: #ff6600;"&gt; &lt;strong&gt;async void&lt;/strong&gt;&lt;/span&gt; is &lt;span style="color: #ff0000;"&gt;&lt;strong&gt;only for event handlers&lt;/strong&gt; &lt;/span&gt;like this, use &lt;strong&gt;async Task&lt;/strong&gt; elsewhere.&lt;/p&gt;
&lt;p&gt;Now let's start the camera&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private async void BtnStart_Click(object sender, RoutedEventArgs e)
{
    await CameraPreviewControl.StartAsync();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;till this step, you will get the UI working and see the real time camera frame in your app.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-282877e3-eec7-47cb-ad1c-f31ae01fbe68.png" border="0" width="628" height="450" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;To stop the camera, just call &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;Stop()&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private void Stop_Click(object sender, RoutedEventArgs e)
{
    CameraPreviewControl.Stop();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So how can we take photo and save to local file system? We will need another event handler:&amp;nbsp;&lt;span style="color: #ff6600;"&gt;&lt;strong&gt;CameraPreviewControl.CameraHelper.FrameArrived&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In this example, I add the event handler in Start button's code:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private async void BtnStart_Click(object sender, RoutedEventArgs e)
{
    await CameraPreviewControl.StartAsync();
    CameraPreviewControl.CameraHelper.FrameArrived += CameraPreviewControl_FrameArrived;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the event handler, I wan to set the current video frame into a private field:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private VideoFrame _currentVideoFrame;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private void CameraPreviewControl_FrameArrived(object sender, FrameEventArgs e)
{
    _currentVideoFrame = e.VideoFrame;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when we click the Capture button, we need to save the current frame as picture into local file system.&amp;nbsp;The picture is presented as &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;SoftwareBitmap&lt;/strong&gt; &lt;/span&gt;object which we can access via&amp;nbsp;&lt;span style="color: #ff6600;"&gt;&lt;strong&gt;_currentVideoFrame?.SoftwareBitmap&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;To let the user pick a file save location, we will use the &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;FileSavePicker&lt;/strong&gt;&lt;/span&gt;, it will return a &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;StorageFile&lt;/strong&gt; &lt;/span&gt;object which represents the file we need to save the photo to. You can also choose file format, here I will use JPG because this is the most common format for photos.&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private async void BtnCapture_Click(object sender, RoutedEventArgs e)
{
    var softwareBitmap = _currentVideoFrame?.SoftwareBitmap;

    if (softwareBitmap != null)
    {
        if (softwareBitmap.BitmapPixelFormat != BitmapPixelFormat.Bgra8 || softwareBitmap.BitmapAlphaMode == BitmapAlphaMode.Straight)
        {
            softwareBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
        }

        var savePicker = new FileSavePicker
        {
            SuggestedStartLocation = PickerLocationId.Desktop
        };
        savePicker.FileTypeChoices.Add("Jpg Image", new[] { ".jpg" });
        savePicker.SuggestedFileName = "example.jpg";
        StorageFile sFile = await savePicker.PickSaveFileAsync();

        await WriteToStorageFile(softwareBitmap, sFile);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src="/image/img-bc63a84b-a006-4cd5-9731-9c92b038b56e.png" border="0" width="656" height="367" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;Last step, code for save the &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;SoftwareBitmap&lt;/strong&gt; &lt;/span&gt;object into &lt;span style="color: #ff6600;"&gt;&lt;strong&gt;StorageFile&lt;/strong&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private static async Task&amp;lt;FileUpdateStatus&amp;gt; WriteToStorageFile(SoftwareBitmap bitmap, StorageFile file)
{
    StorageFile sFile = file;
    if (sFile != null)
    {
        CachedFileManager.DeferUpdates(sFile);

        using (var fileStream = await sFile.OpenAsync(FileAccessMode.ReadWrite))
        {
            BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, fileStream);
            encoder.SetSoftwareBitmap(bitmap);
            await encoder.FlushAsync();
        }

        FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(sFile);
        return status;
    }
    return FileUpdateStatus.Failed;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to see some more details about the CameraPreivew control, please check the official GitHub:&amp;nbsp;&lt;a href="https://github.com/Microsoft/WindowsCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls/CameraPreview" target="_blank" rel="noopener"&gt;https://github.com/Microsoft/WindowsCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls/CameraPreview&lt;/a&gt;&amp;nbsp;&lt;/p&gt;</content></entry><entry><id>776aeaf9-a339-40a4-aac9-b9627fa5e477</id><title>Read System Certificates in UWP</title><updated>2018-07-02T04:42:16Z</updated><published>2018-07-02T04:42:16Z</published><link href="https://edi.wang/post/2018/7/2/read-cert-uwp" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;In Windows, we can view and manage the certificates using &lt;strong&gt;certmgr.msc&lt;/strong&gt;, which is a system management console included in Windows itself.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-08fddd08-060f-43da-af0e-79956355fd74.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;However, what if we want to view the certificates information in an UWP app? Here is the answer.&lt;/p&gt;
&lt;p&gt;First thing first, the method I use does not apply to UWP only. In fact it is from a WPF app I wrote. As Microsoft released .NET Standard 2.0, which allows me to reuse the core library shared between WPF and UWP, that is how I finally come up with an UWP demo app.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For reference, please see the sample app on my GitHub:&amp;nbsp;&lt;a href="https://github.com/EdiWang/Cert-Scanner"&gt;https://github.com/EdiWang/Cert-Scanner&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let's dig in into the code. The core piece of this demo is the following code.&lt;/p&gt;
&lt;p&gt;The namespace we use is "&lt;code&gt;System.Security.Cryptography.X509Certificates&lt;/code&gt;" so make sure you add the using statement if you want to try the code yourself.&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public class SystemStorageCertificationScanner : CertificationScanner
{
    public override IEnumerable&amp;lt;CertInfo&amp;gt; ScanCertificates()
    {
        foreach (StoreLocation loc in Enum.GetValues(typeof(StoreLocation)))
        {
            foreach (StoreName n in Enum.GetValues(typeof(StoreName)))
            {
                X509Store store = new X509Store(n, loc);
                store.Open(OpenFlags.ReadOnly);
                foreach (var storeCertificate in store.Certificates)
                {
                    var certInfo = new CertInfo()
                    {
                        Subject = storeCertificate.Subject,
                        FriendlyName = storeCertificate.FriendlyName,
                        Issuer = storeCertificate.Issuer,
                        Version = storeCertificate.Version,
                        Thumbprint = storeCertificate.Thumbprint,
                        StoreLocation = loc.ToString(),
                        ExpDate = DateTime.Parse(storeCertificate.GetExpirationDateString()),
                        Abstract = storeCertificate.ToString()
                    };
                    yield return certInfo;
                }
                store.Close();
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, &lt;code&gt;StoreLocation&lt;/code&gt; is an enum which only contains 2 members: &lt;code&gt;CurrentUser&lt;/code&gt;, &lt;code&gt;LocalMachine&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;StoreName&lt;/code&gt; is another enum which stands for different type names for the installed certificates. It's members are:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public enum StoreName
{
  AddressBook = 1,
  AuthRoot = 2,
  CertificateAuthority = 3,
  Disallowed = 4,
  My = 5,
  Root = 6,
  TrustedPeople = 7,
  TrustedPublisher = 8,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then we can get all the certificates by&amp;nbsp;enumerate every&amp;nbsp;&lt;code&gt;X509Store&lt;/code&gt; object and the certificates inside it. But please notice, we will have to open and close the&amp;nbsp;&lt;code&gt;X509Store&lt;/code&gt; everytime we do an operation on it.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CertInfo&lt;/code&gt; is a custom type I wrote just to make things easier to read and use.&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public class CertInfo
{
    public string Subject { get; set; }

    public string FriendlyName { get; set; }

    public string Issuer { get; set; }

    public string Thumbprint { get; set; }

    public int Version { get; set; }

    public string StoreLocation { get; set; }

    public DateTime ExpDate { get; set; }

    public bool IsExpired =&amp;gt; ExpDate &amp;lt; DateTime.Now;

    public string Abstract { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To polish the design, I added couple of interface and abstract class. They are just for design reference, in fact if you just want a straight forward method to read certificates, you won't need any of these.&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public interface ICertificationScanner
{
    IEnumerable&amp;lt;CertInfo&amp;gt; ScanCertificates();
}

public abstract class CertificationScanner : ICertificationScanner
{
    public abstract IEnumerable&amp;lt;CertInfo&amp;gt; ScanCertificates();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The UWP app I created is using &lt;a href="https://github.com/microsoft/windowsTemplateStudio" target="_blank" rel="noopener"&gt;Windows Template Studio&lt;/a&gt;, it provides me the Telerik Data Grid, which makes it easy to display the certificates list. I am also using MvvmLight as design pattern.&amp;nbsp;I won't repeat the steps for creating Apps in WTS because it is&amp;nbsp;irrelevant to this topic.&lt;/p&gt;
&lt;p&gt;Let's say you already have Telerik Data Grid in your app. Then, to display the result, the most simple way is add one line of XAML on the UI:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;tg:RadDataGrid ColumnDataOperationsMode="Flyout" x:Name="grid" ItemsSource="{x:Bind ViewModel.Source}" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and retrieve the data in ViewModel&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public class SystemCertsViewModel : ViewModelBase
{
    public SystemStorageCertificationScanner SysCertificationScanner { get; set; }

    public SystemCertsViewModel()
    {
        SysCertificationScanner = new SystemStorageCertificationScanner();
    }

    public ObservableCollection&amp;lt;CertInfo&amp;gt; Source =&amp;gt; SysCertificationScanner.ScanCertificates().ToObservableCollection();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here in this example, the&amp;nbsp;ToObservableCollection extension is provided my UWP Helper library. You can install it from NuGet.&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;PM&amp;gt; Install-Package Edi.Uwp.Helpers&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, the result screen is:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-4d8daeb2-4cd3-4a5b-a553-5324581ada68.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Finally, to get the full example,&lt;strong&gt;&amp;nbsp;please see my GitHub:&amp;nbsp;&lt;a href="https://github.com/EdiWang/Cert-Scanner"&gt;https://github.com/EdiWang/Cert-Scanner&lt;/a&gt;&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;</content></entry><entry><id>1017e5fd-c218-4b13-89b5-8792a9402269</id><title>Send Feedback in UWP Apps by Windows 10 Feedback Hub</title><updated>2018-04-19T06:35:50Z</updated><published>2018-04-19T06:35:50Z</published><link href="https://edi.wang/post/2018/4/19/send-feedback-uwp" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;After our app has been put on Microsoft Store, there are a lot of ways to get users to send feedback, such as email, store reviews, or even write our own API collect feedback. But in fact, Windows 10 Feedback Hub can also be used to send feedbacks for our own Apps.&lt;/p&gt;
&lt;p&gt;Those who are familiar with Windows Insider know that when Windows 10 is installed, the system has a Feedback Hub, which is usually used for the user's feedback on the product of Windows itself. In fact, the feedback hub can also be used by developers to collect users ' opinions.&lt;/p&gt;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="/image/img-850a41d9-dfb9-4e72-811a-330e180ddb4d.png" alt="" width="436" height="291" /&gt;&lt;/p&gt;
&lt;p&gt;So, how do you call this feedback hub in UWP? First, you need to install the Microsoft Official engagement SDK as follows:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Install this package in NuGet：Microsoft.Services.Store.Engagement&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;PM&amp;gt; Install-Package Microsoft.Services.Store.Engagement&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. If the "Microsoft Engagement SDK" does not show up in the project' Reference, like this, it means you will need some manual steps to get it working. &lt;span style="color: #ff0000;"&gt;This is important and it is missing in the official document.&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="/image/img-d8ca6e75-d4cd-413f-bba4-fc7584495ed8.png" alt="" width="457" height="538" /&gt;&lt;/p&gt;
&lt;p&gt;The way is to edit your project file (csproj) and add an SDKReference below the ItemGroup of the PackageReference, which is:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;SDKReference Include="Microsoft.Services.Store.Engagement, Version=10.0"&amp;gt;
  &amp;lt;Name&amp;gt;Microsoft Engagement Framework&amp;lt;/Name&amp;gt;
&amp;lt;/SDKReference&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="/image/img-830c31cf-602d-49f3-b509-42b5b18f7522.png" alt="" width="823" height="560" /&gt;&lt;/p&gt;
&lt;p&gt;Save the project file and restart VS, you should be good to go.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.&amp;nbsp;Add a feedback link to your App&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Take MVVM pattern as example, just add a &lt;code&gt;HyperLinkButton&lt;/code&gt; in your XAML:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;HyperlinkButton Content="Feedback" Command="{Binding CommandFeedback}" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And create the corresponding &lt;code&gt;RelayCommand&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public RelayCommand CommandFeedback { get; set; }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The implement of this Command will be:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;CommandFeedback = new RelayCommand(async () =&amp;gt;
{
    var launcher = Microsoft.Services.Store.Engagement.StoreServicesFeedbackLauncher.GetDefault();
    await launcher.LaunchAsync();
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your App needs to target Windows 10 below build 14271, you have to check if the SDK supports it first, by this method:&amp;nbsp;&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;Microsoft.Services.Store.Engagement.StoreServicesFeedbackLauncher.IsSupported()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because my App is targeting system build 16299, so I don't have to check the SDK support, it can run directly now:&lt;/p&gt;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="/image/img-cc60b866-84c0-4f14-ac04-2f18c1ad78c9.png" alt="" width="823" height="390" /&gt;&lt;/p&gt;
&lt;p&gt;This is how the Feedback Hub is invoked:&lt;/p&gt;
&lt;p&gt;&lt;img style="display: block; margin-left: auto; margin-right: auto;" src="/image/img-1ac7eca1-f081-485b-b538-16ec89f13742.png" alt="" width="823" height="228" /&gt;&lt;/p&gt;</content></entry><entry><id>9b473458-f402-4fe1-bdc5-8449786c6361</id><title>Customize Acrylic Brush in UWP Applications</title><updated>2018-03-29T12:43:11Z</updated><published>2018-03-29T12:43:11Z</published><link href="https://edi.wang/post/2018/3/29/customize-acrylic-uwp" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;Windows 10 Fall Creators Update (Build 16299) added acrylic brush, this is a UI brush that similar to Windows 7 Aero effect.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-df8f8483-5582-4860-8a9d-bf84e57f6fed.png" alt="" width="713" height="615" /&gt;&lt;/p&gt;
&lt;p&gt;A lot in box Windows Apps, such as Calculator are updated with the acrylic brush. However, the built in brushes will not always meet our own requirments. Especially when Windows automatically disable render of acrylic, such as low power mode, or with an inactive window, it will make our App look very ugly.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;For example, this is where normal arcylic will look like:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-46c15935-71b6-4d7b-9aa2-722052b9f134.png" alt="" width="823" height="499" /&gt;&lt;/p&gt;
&lt;p&gt;This is how it looks when the window is inactive:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-9d735d11-dad4-4a32-882e-156d2b2d42ac.png" alt="" width="823" height="498" /&gt;&lt;/p&gt;
&lt;p&gt;In this kind of scenario, we will have to build a customize arcylic brush, and set fall back color. As I did with my "Character Map UWP" App, it is one good example.&lt;/p&gt;
&lt;p&gt;Showing customized black acrylic in normal modes:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-2da1b94c-b011-4aa7-9e84-94799b8e7940.png" alt="" width="668" height="278" /&gt;&lt;/p&gt;
&lt;p&gt;When App goes full screen or inactive, show the system accent color:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-42dc873d-ad85-4a3c-be9a-b5fd84669a06.png" alt="" width="638" height="275" /&gt;&lt;/p&gt;
&lt;p&gt;It is done by creating a customized AcrylicBrush. Add this code in your XAML resource:&amp;nbsp;&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;AcrylicBrush x:Key="CMapUwpAcrylicBrush"
              BackgroundSource="HostBackdrop"
              TintColor="Black"
              TintOpacity="0.4"
              FallbackColor="{StaticResource SystemAccentColor}"/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, &lt;code&gt;TintColor&lt;/code&gt;&amp;nbsp;is for the normal acrylic color you want, I set it to black. &lt;code&gt;TintOpacity&lt;/code&gt;&amp;nbsp;stands for opactiy 0.4 means 40%. &lt;code&gt;FallbackColor&lt;/code&gt;&amp;nbsp;is the color when acrylic is not able to render, which I use system accent color.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;The complete XAML resource file is:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&amp;gt;
    &amp;lt;ResourceDictionary.ThemeDictionaries&amp;gt;
        &amp;lt;ResourceDictionary x:Key="Default"&amp;gt;
            &amp;lt;AcrylicBrush x:Key="CMapUwpAcrylicBrush"
                          BackgroundSource="HostBackdrop"
                          TintColor="Black"
                          TintOpacity="0.4"
                          FallbackColor="{StaticResource SystemAccentColor}"/&amp;gt;
        &amp;lt;/ResourceDictionary&amp;gt;

        &amp;lt;ResourceDictionary x:Key="HighContrast"&amp;gt;
            &amp;lt;SolidColorBrush x:Key="CMapUwpAcrylicBrush"
                             Color="{ThemeResource SystemColorWindowColor}"/&amp;gt;
        &amp;lt;/ResourceDictionary&amp;gt;

        &amp;lt;ResourceDictionary x:Key="Light"&amp;gt;
            &amp;lt;AcrylicBrush x:Key="CMapUwpAcrylicBrush"
                          BackgroundSource="HostBackdrop"
                          TintColor="Black"
                          TintOpacity="0.4"
                          FallbackColor="{StaticResource SystemAccentColor}"/&amp;gt;
        &amp;lt;/ResourceDictionary&amp;gt;
    &amp;lt;/ResourceDictionary.ThemeDictionaries&amp;gt;
&amp;lt;/ResourceDictionary&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then you will be able to use this acrylic brush wherever you need:&amp;nbsp;&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;Grid Background="{ThemeResource CMapUwpAcrylicBrush}"&amp;gt;&lt;/code&gt;&lt;/pre&gt;</content></entry><entry><id>8f6c0591-402a-40b9-8ea9-6faf5fb722b8</id><title>Apply Keyboard Short Cuts in UWP</title><updated>2018-01-24T05:11:02Z</updated><published>2018-01-24T05:11:02Z</published><link href="https://edi.wang/post/2018/1/24/uwp-keyboard-events" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;A greate Windows App requires not only mouse and touch screen friendly, but also need to think about keyboards. Especially for some common short cuts, like Undo (CTRL + Z). So that the App can provide better user experience.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;So how can we define short cut keys in UWP? Take my App &lt;em&gt;Tracing&lt;/em&gt; as example, I need to implement short cuts for Undo (CTRL + Z). First, we need to consider which Control is being focused by the user currently. If we want the whole UI to respond to that short cut, then the Control will be the UI Control placed at the most outter node of the &lt;code&gt;XAML&lt;/code&gt; page, usually it is the &lt;code&gt;Grid&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First, let's find the first &lt;code&gt;Grid&lt;/code&gt; element under &lt;code&gt;Page&lt;/code&gt;, define 2 events on it:&amp;nbsp;&lt;code&gt;KeyDown&lt;/code&gt;&amp;nbsp;and &lt;code&gt;KeyUp&lt;/code&gt;&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;Grid Background="{ThemeResource TracingAcrylicBrush}" KeyDown="LayoutRoot_KeyDown" KeyUp="LayoutRoot_KeyUp"&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because the short cut we want to use is a combined key (CTRL + Z), so we need to know if the user has pressed Ctrl key already. So we need to define a &lt;code&gt;bool&lt;/code&gt; variable to check if &lt;code&gt;Ctrl&lt;/code&gt; key is being pressed.&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private bool _isCtrlKeyPressed;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then define the event handler:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private void LayoutRoot_KeyUp(object sender, KeyRoutedEventArgs e)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private async void LayoutRoot_KeyDown(object sender, KeyRoutedEventArgs e)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The parameter &lt;code&gt;KeyRoutedEventArgs e&lt;/code&gt;&amp;nbsp;describes the information about which key the user is pressing, it is type of &lt;code&gt;Windows.System.VirtualKey&lt;/code&gt;&amp;nbsp;enum. So to check if Ctrl key is pressed, just see if &lt;code&gt;e.Key == VirtualKey.Control&lt;/code&gt;&amp;nbsp;. Now the logic to remember Ctrl key status is to set &lt;code&gt;_isCtrlKeyPressed&lt;/code&gt;&amp;nbsp;to true when Ctrl key is pressed, and restore to false when user release the key&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private void LayoutRoot_KeyUp(object sender, KeyRoutedEventArgs e)
{
    if (e.Key == VirtualKey.Control) _isCtrlKeyPressed = false;
}

private async void LayoutRoot_KeyDown(object sender, KeyRoutedEventArgs e)
{
    if (e.Key == VirtualKey.Control) _isCtrlKeyPressed = true;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to check if Z key is pressed to finish the combined key. It is also handed in the LayoutRoot_KeyDown event handler, after check if Ctrl key is pressed, then check &lt;code&gt;e.Key&lt;/code&gt; is Z or not, like this:&amp;nbsp;&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private async void LayoutRoot_KeyDown(object sender, KeyRoutedEventArgs e)
{
    if (e.Key == VirtualKey.Control) _isCtrlKeyPressed = true;
    else if (_isCtrlKeyPressed)
    {
        switch (e.Key)
        {
            case VirtualKey.Z: ViewModel.CommandUndo.Execute(null); break;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, your application UI should be able to respond to CTRL+Z combined key short cut.&lt;/p&gt;
&lt;p&gt;Simply, if you have other keys that can combined with Ctrl, just put them into swtich case statements like this:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;case VirtualKey.V: await PasteInkOrImageFromClipboard(); break;
case VirtualKey.Z: ViewModel.CommandUndo.Execute(null); break;
case VirtualKey.Y: ViewModel.CommandRedo.Execute(null); break;
case VirtualKey.S: ViewModel.CommandSaveCurrent.Execute(null); break;&lt;/code&gt;&lt;/pre&gt;</content></entry><entry><id>5d1af670-58c1-49f2-a123-b0249f17ba8f</id><title>Show Confirm Dialog When User Close UWP App</title><updated>2017-12-29T04:09:16Z</updated><published>2017-12-29T04:09:16Z</published><link href="https://edi.wang/post/2017/12/29/show-confirm-dialog-close-uwp" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;When our UWP Application deal with user data in it, e.g. like drawings or documents, we usually want to make sure user won't close the App by accident and lose their work. Just like what you see in a Office application, it will ask you if you want to save your document before close the App.&lt;/p&gt;
&lt;p&gt;For a long time, UWP could not do that in a normal way. Because it is not a general public API and it is still not well documented today. But there are some UWP Apps with this capibility like Microsoft's own "Paint 3D" App:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-850eb71e-a74f-46e1-88ad-d4d0e4c13803.png" border="0" alt="" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;I did some research today and finally find a way to do this. Let me share with you.&lt;/p&gt;
&lt;h2&gt;1. Add Restricted API&amp;nbsp;Capability&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;Open your&amp;nbsp;&lt;code&gt;Package.appxmanifest&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Add a namespace into &lt;code&gt;Package&lt;/code&gt; node:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to create App Package without error, we also need to &lt;code&gt;ignore&lt;/code&gt; the rescap namespace by adding it into&amp;nbsp;&lt;code&gt;IgnorableNamespaces&lt;/code&gt; property in the &lt;code&gt;Package&lt;/code&gt; node:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;IgnorableNamespaces="uap mp rescap genTemplate"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Package&lt;/code&gt; node will look like this:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" 
         xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" 
         xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" 
 
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
         IgnorableNamespaces="uap mp rescap"&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, in&amp;nbsp;&lt;code&gt;Capabilities&lt;/code&gt; node, add:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;rescap:Capability Name="confirmAppClose"/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Capabilities&lt;/code&gt; will look like this:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;Capabilities&amp;gt;
...
  &amp;lt;rescap:Capability Name="confirmAppClose"/&amp;gt;
...
&amp;lt;/Capabilities&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. Handling Close App Action&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;The close app action can now be handled by a preview API:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;Windows.UI.Core.Preview.SystemNavigationManagerPreview.GetForCurrentView().CloseRequested&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example, in your code, like &lt;code&gt;MainPage.xaml.cs&lt;/code&gt;, you can now use this API to detect if the user clicked "X" button and pop up the dialog like this:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public MainPage()
{
    this.InitializeComponent();

    Windows.UI.Core.Preview.SystemNavigationManagerPreview.GetForCurrentView().CloseRequested +=
        async (sender, args) =&amp;gt;
        {
            args.Handled = true;

            var result = await SaveConfirm.ShowAsync();
            if (result == ContentDialogResult.Primary)
            {
                // Save work;
            }
            else
            {
                App.Current.Exit();    
            }
        };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One thing to notice is that, &lt;code&gt;args.Handeled&lt;/code&gt; must be set to true, or your App will still close on clicking the "X" button.&lt;/p&gt;</content></entry><entry><id>abc6c12f-cc79-4d7c-b231-7fc28fb1457d</id><title>Automatically Set Text Color on Accent Background in UWP</title><updated>2017-10-17T09:15:30Z</updated><published>2017-10-17T09:15:30Z</published><link href="https://edi.wang/post/2017/10/17/automatically-set-text-color-on-accent-background-in-uwp" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;Windows 10 allows users to set accent color for the system, and in UWP apps, we usually honor those settings by using XAML pre-defined resource keys like&amp;nbsp;&lt;code&gt;{ThemeResource SystemControlBackgroundAccentBrush}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-df5e0c7b-bce8-46a8-ac3d-2c1506c0f110.png" alt="" width="565" height="483" /&gt;&lt;/p&gt;
&lt;p&gt;But regardless of how the user set default app mode to dark or light, when we apply text on accent colors, it may have some problems.&lt;/p&gt;
&lt;p&gt;For example, when the App is in light mode, the default text color is black, when the accent color is a light color like light yellow, black text looks fine on it. However, if the user's accent color is set to dark blue, applying black text on to a dark blue background will make the text difficult to see. Same thing happens to a dark mode app, the text will be white by default, and it is hard to see on light accent colors.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-886220d6-ee66-43eb-a6fd-aba1025e0a9c.png" alt="" width="660" height="405" /&gt;&lt;/p&gt;
&lt;p&gt;So we need a way to check which type of accent color the user is selecting, and dynamically change the text color based on the accent color type. And we should not hard code against Windows pre-defined colors, because Windows allow user to create custom colors. So here is how to do it:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private bool IsAccentColorDark()
{
    var uiSettings = new UISettings();
    var c = uiSettings.GetColorValue(UIColorType.Accent);
    bool isDark = (5 * c.G + 2 * c.R + c.B) &amp;lt;= 8 * 128;
    return isDark;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can set our text color based on the result:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;TestText.Foreground = new SolidColorBrush(IsAccentColorDark() ? Colors.White : Colors.Black);&lt;/code&gt;&lt;/pre&gt;
&lt;table class="table table-bordered"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dark Accent Color&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Light Accent Color&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="/image/img-1ee7395f-9cc2-45bf-9dcf-5b6feb371a9a.png" alt="" width="427" height="266" /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="/image/img-aa455430-9e16-4098-af7b-71b3c3d20cb5.png" alt="" width="369" height="261" /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;But this still have some problem, because we are hard coding the color values. A better solution is to use&amp;nbsp;RequestedTheme to let the system manage the text color automatically, it can covers high contract scenarios:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;TestText.RequestedTheme = IsAccentColorDark() ? ElementTheme.Dark : ElementTheme.Light;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Still, one problem remain. When the App is running, and the user changes accent color settings. The text color will not be automatically updated. To solve that, we need to write a converter:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public class SmartTextColorBasedOnAccentTypeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        return (bool)value ? ElementTheme.Dark : ElementTheme.Light;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add it on to the page&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;local:SmartTextColorBasedOnAccentTypeConverter x:Key="SmartTextColorBasedOnAccentTypeConverter" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And make a property in your xaml.cs file:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private bool _isDarkAccent;

public bool IsDarkAccent
{
    get =&amp;gt; IsAccentColorDark();
    set { _isDarkAccent = value; OnPropertyChanged(); }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And bind to it&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;&amp;lt;TextBlock x:Name="TestText"  Text="Some Text" 
           RequestedTheme="{x:Bind IsDarkAccent, 
           Converter={StaticResource SmartTextColorBasedOnAccentTypeConverter},
           Mode=OneWay}" /&amp;gt;        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, when the App is running, and the user changes accent color settings. The text color will be automatically updated to fit the current accent color type.&lt;/p&gt;</content></entry><entry><id>a25f50c1-0de1-40fa-b323-bd6f1c918778</id><title>Configure VSTS Build for UWP Apps</title><updated>2017-10-06T02:41:23Z</updated><published>2017-10-06T02:41:23Z</published><link href="https://edi.wang/post/2017/10/6/configure-vsts-build-for-uwp-apps" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><category term="DevOps" /><content>&lt;blockquote&gt;
&lt;p&gt;UWP Apps usually require a lot of time to compile a "release" package for submitting to Windows Store, and if you are working in a team, TFS/VSTS can help your team ensure that each check-in has a success build, and make it easier for deployment and testing.&amp;nbsp;Let's see a basic example of how to setup a CI build for a UWP App on VSTS.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Important Pre-condition&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;Before you do that, please ensure that your App is already build and running on your local machine.&lt;/p&gt;
&lt;p&gt;If you want the package can be used to upload to the Windows Store, you need to manually associate the App to the store and create App packages and validate the release on your machine for the first time.&lt;/p&gt;
&lt;p&gt;VSTS build on host agents can not automatically increase the build number in your App's manifest, you will need to do it manully in each check-in, or you can create a custom agent to do that (not discussed in this article)&lt;/p&gt;
&lt;h2&gt;Example App&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;My example App "&lt;strong&gt;QRCodeCreator&lt;/strong&gt;" is under project "&lt;strong&gt;Universal-Windows&lt;/strong&gt;", and there are many other Apps under the same parent directory. Usually in an enterprise, you won't put every App under a same Team Project. But if you do, there will be some different from the default build teamplate, which in this case, you can follow my steps.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-a91d3b3d-9361-4e39-825f-2c055f503dc9.png" border="0" alt="" width="686" height="779" loading="lazy"&gt;&lt;/p&gt;
&lt;h3&gt;Step 1&lt;/h3&gt;
&lt;p&gt;Go to "&lt;strong&gt;Build and Release&lt;/strong&gt;" under "&lt;strong&gt;Universal-Windows&lt;/strong&gt;", click "&lt;strong&gt;+New&lt;/strong&gt;" button.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-e82f5a99-1db1-4162-af30-cabc3a167a95.png" border="0" alt="" width="811" height="207" loading="lazy"&gt;&lt;/p&gt;
&lt;h3&gt;Step 2&lt;/h3&gt;
&lt;p&gt;Choose "&lt;strong&gt;Universal Windows Platform&lt;/strong&gt;" and click "&lt;strong&gt;Apply&lt;/strong&gt;"&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-5a2346d4-50ba-4511-a7ec-7da3a8011a78.png" border="0" alt="" width="811" height="585" loading="lazy"&gt;&lt;/p&gt;
&lt;h3&gt;Step 3&lt;/h3&gt;
&lt;p&gt;Set a Name, change Agent queue to "&lt;strong&gt;Hosted VS2017&lt;/strong&gt;", &lt;span style="color: #ff0000;"&gt;and select the "sln" path for this particular App. This is very important, otherwise VSTS will build every "sln" under "Universal-Windows".&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-2f4c48b2-0d42-424a-b800-4a352191222a.png" border="0" alt="" width="811" height="460" loading="lazy"&gt;&lt;/p&gt;
&lt;h3&gt;Step 4&lt;/h3&gt;
&lt;p&gt;In "&lt;strong&gt;Get sources&lt;/strong&gt;", change Server path to this particular App source folder (&lt;strong&gt;QRCodeCreator&lt;/strong&gt;), &lt;span style="color: #ff0000;"&gt;this is also very important, otherwise VSTS will get all content under "Universal-Windows" even it is only building "QRCodeCreator" solution.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-80821b5f-7b58-4c8a-a7db-7d0d8d9efb9d.png" border="0" alt="" width="811" height="540" loading="lazy"&gt;&lt;/p&gt;
&lt;h3&gt;Step 5&lt;/h3&gt;
&lt;p&gt;Click "&lt;strong&gt;Save &amp;amp; queue&lt;/strong&gt;" button, and test the build definition.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-37d83990-7656-4910-9a38-fac3b0bcc3e9.png" border="0" alt="" width="432" height="190" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;Double check if the environment configuration is correct. In this case, I want the build artifacts can be used to upload to the Windows Store, so I need to use "&lt;strong&gt;release&lt;/strong&gt;" mode on&lt;strong&gt; x86, x64 and ARM&lt;/strong&gt;. You can change this in the build definition settings according to your demands.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-ca85d4bc-e850-4612-9f43-a855897021cd.png" border="0" alt="" width="730" height="689" loading="lazy"&gt;&lt;/p&gt;
&lt;h3&gt;Step 6&lt;/h3&gt;
&lt;p&gt;After the build is queued, click the build number on the message will open the build watcher window.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-be56e9cb-5409-4264-9b05-72bf68293001.png" border="0" alt="" width="457" height="256" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;If everything is correct, you should see the build success after 10-20 minutes depending on your project size. I ususally takes more time to build on VSTS comparing to your local machine.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-e43a99d8-7361-458a-8145-612960650fa9.png" border="0" alt="" width="811" height="665" loading="lazy"&gt;&lt;/p&gt;
&lt;h3&gt;Step 7&lt;/h3&gt;
&lt;p&gt;Now, we have validated the build works. Let's configure the CI trigger.&lt;/p&gt;
&lt;p&gt;Back to the build definition, click "&lt;strong&gt;Triggers&lt;/strong&gt;", and enable "&lt;strong&gt;Continuous Integration&lt;/strong&gt;" trigger. &lt;span style="color: #ff0000;"&gt;We also need to change the Path specification to this particular App folder, or every check-in under "Universal Windows" will trigger this build, which is not our intention.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;img src="/image/img-d100bff1-36c0-4126-8010-1bec87ab1c39.png" border="0" alt="" width="581" height="610" loading="lazy"&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Step 8&lt;/h3&gt;
&lt;p&gt;The build number by VSTS will not automatically increase like you do it with Visual Studio manully. If you want to upload to the store, the build number must be higher than the old one already in the store. Now we need to go back to Visual Studio, open your project's manifest file, and manully increase the build number.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-abec19e8-3e9c-45c9-8e34-927e04042e69.png" border="0" alt="" width="811" height="421" loading="lazy"&gt;&lt;/p&gt;
&lt;h3&gt;Step 9&lt;/h3&gt;
&lt;p&gt;Now when you check-in the App source, a build will be triggered.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-d4fbba56-0d9d-46b8-8461-b2593ba31049.png" border="0" alt="" width="811" height="241" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;After it is done, go to "&lt;strong&gt;Artifacts&lt;/strong&gt;", now you can download or browse the App packages.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-29c1d2fb-b068-4e84-bc1d-641a61734ed9.png" border="0" alt="" width="794" height="419" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-69310c17-2167-4a19-bbfc-91505ad471cc.png" border="0" alt="" width="542" height="299" loading="lazy"&gt;&lt;/p&gt;
&lt;h3&gt;Step 10&lt;/h3&gt;
&lt;p&gt;Upload your wonderful App to Windows Store and change the world!!! You can see the "appxupload" file is successfully recognized by Windows Dev Center.&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-6c931d07-f6bd-40fa-865c-5f566ae40abd.png" border="0" alt="" width="823" height="565" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="background-color: #ff0000; color: #ffff00;"&gt;&lt;strong&gt;NOTE FOR CHINESE DEVELOPERS&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="color: #ff0000;"&gt;Downloading artifacts from VSTS is very highly result in broken packages sometimes&amp;nbsp;&lt;strong&gt;even with a VPN connection&lt;/strong&gt;, for example, a 27 MB package will stop at 790 KB / 11 MB or others. Advise to RDP into a oversea VM to download the artifacts. Or you can setup a FTP and configure add build task to upload the artifacts to the FTP server and manually download it.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Appendix&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you have problem when generating App packages for Windows Store, please check the build configuration according to this table:&lt;/p&gt;
&lt;table class="table table-bordered"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th class=""&gt;&lt;strong&gt;MSBuild Argument&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Value&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AppxPackageDir&lt;/td&gt;
&lt;td&gt;$(Build.ArtifactStagingDirectory)\AppxPackages&lt;/td&gt;
&lt;td&gt;Defines the folder to store the generated artifacts.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AppxBundlePlatforms&lt;/td&gt;
&lt;td&gt;$(Build.BuildPlatform)&lt;/td&gt;
&lt;td&gt;Allows you to define the platforms to include in the bundle.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AppxBundle&lt;/td&gt;
&lt;td&gt;Always&lt;/td&gt;
&lt;td&gt;Creates an appxbundle with the appx files for the platform specified.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style="background-color: #ffff00;"&gt;&lt;strong class=""&gt;UapAppxPackageBuildMode&lt;/strong&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td class=""&gt;&lt;span style="background-color: #ffff00;"&gt;StoreUpload&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style="background-color: #ffff00;"&gt;Defines the kind of appx package to generate. (Not included by default)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Reference:&amp;nbsp;&lt;a href="https://docs.microsoft.com/en-us/windows/uwp/packaging/auto-build-package-uwp-apps"&gt;https://docs.microsoft.com/en-us/windows/uwp/packaging/auto-build-package-uwp-apps&lt;/a&gt;&amp;nbsp;&lt;/p&gt;</content></entry><entry><id>d5c25692-16a5-4ff3-9d11-9fc59ab351af</id><title>Windows 10 UWP: Switching Languages in Your App</title><updated>2017-09-09T03:17:47Z</updated><published>2017-09-09T03:17:47Z</published><link href="https://edi.wang/post/2017/9/9/windows-10-uwp-switching-language" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;By default, a UWP App's UI language is automatically fits the system current language settings. However, what if the user need the ability to set a particular UI language just for your App without having to change system language?&lt;/p&gt;
&lt;p&gt;In my App, I supports Simplified Chinese and English. The user can override the system language in App's settings page:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-5684831a-e113-4f68-b196-9bf10b3676a4.png" alt="" width="389" height="166" /&gt;&lt;/p&gt;
&lt;p&gt;So how to do it?&lt;/p&gt;
&lt;p&gt;First, you need to have resource files as usual for multi-language Apps like this:&lt;/p&gt;
&lt;p&gt;&lt;img src="/image/img-7042dae6-5e3f-4b46-b60a-a0c3753bea0e.png" alt="" width="244" height="110" /&gt;&lt;/p&gt;
&lt;p&gt;Put resw files into "Strings\LanguageCode" folder is a conventsion by UWP Apps, it does not require any code to achieve the ablity to show different UI language according to system language.&lt;/p&gt;
&lt;p&gt;Then, adding a new class file for matching the language code and display name in order to show it in settings language dropdown list:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public class Language
{
    public string DisplayName { get; set; }

    public string LanguageCode { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create a property for UI binding&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;private ObservableCollection&amp;lt;Language&amp;gt; _languages;

public ObservableCollection&amp;lt;Language&amp;gt; Languages
{
    get =&amp;gt; _languages;
    set { _languages = value; RaisePropertyChanged(); }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Set values (usually in ViewModel's constructor)&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;Languages = new ObservableCollection&amp;lt;Language&amp;gt;
{
    new Language { DisplayName = "English", LanguageCode = "en-US" },
    new Language { DisplayName = "简体中文", LanguageCode = "zh-CN" }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To let user decide if they want override UI language or just follow system settings, we also need to add a new settings key to store the option. In my App's design, settings are managed by an AppSettings class. You can read my&lt;a href="/post/2017/9/8/uwp-read-write-settings" target="_blank" rel="noopener"&gt; previous post&lt;/a&gt; for how to do it.&lt;/p&gt;
&lt;p&gt;So, adding a new settings key in &lt;code&gt;AppSettings&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public bool UsePrimaryLanguageOverride
{
    get =&amp;gt; ReadSettings(nameof(UsePrimaryLanguageOverride), false);
    set
    {
        SaveSettings(nameof(UsePrimaryLanguageOverride), value);
        NotifyPropertyChanged();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we need another key to store what languages did the user select, by default, it is en-US to match the App's default language.&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public string PrimaryLanguageOverride
{
    get =&amp;gt; ReadSettings(nameof(PrimaryLanguageOverride), "en-US");
    set
    {
        SaveSettings(nameof(PrimaryLanguageOverride), value);
        NotifyPropertyChanged();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also, add a UI binding property for that&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;public Language SelectedLanguage
{
    get =&amp;gt; _selectedLanguage;
    set
    {
        _selectedLanguage = value;
        AppSettings.PrimaryLanguageOverride = value.LanguageCode;
        RaisePropertyChanged();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, making the UI:&lt;/p&gt;
&lt;pre class="language-markup"&gt;&lt;code&gt;&amp;lt;ToggleSwitch x:Name="UsePrimaryLanguageOverride" 
              x:Uid="UsePrimaryLanguageOverride" 
              IsOn="{Binding Source={StaticResource AppSettings}, Path=UsePrimaryLanguageOverride, Mode=TwoWay}"
              OnContent="#UsePrimaryLanguageOverride" 
              OffContent="#UsePrimaryLanguageOverride" /&amp;gt;

&amp;lt;ComboBox x:Name="CmbLanguage" 
          ItemsSource="{Binding Languages}" 
          DisplayMemberPath="DisplayName" 
          SelectedValuePath="LanguageCode" 
          SelectedItem="{Binding SelectedLanguage, Mode=TwoWay}" 
          IsEnabled="{Binding Source={StaticResource AppSettings}, Path=UsePrimaryLanguageOverride}" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the UI, it still need to remember what language did the user previously selected, and set the selected item on the &lt;code&gt;ComboBox&lt;/code&gt; according to that value. To do that, add code in your ViewModel:&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;var selectedLanguage = AppSettings.PrimaryLanguageOverride;
if (!string.IsNullOrEmpty(selectedLanguage))
{
    var f = Languages.FirstOrDefault(l =&amp;gt; l.LanguageCode == selectedLanguage);
    if (null != f)
    {
        SelectedLanguage = f;
    }
}
else
{
    SelectedLanguage = Languages.FirstOrDefault();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, the UI part is complete. How to let the App know what language to apply to the UI?&lt;/p&gt;
&lt;p&gt;It is very easy. Set the&amp;nbsp;&lt;code&gt;ApplicationLanguages.PrimaryLanguageOverride&lt;/code&gt; when App starts. To do that, modify App.xaml, and in the OnLaunched event handler, add the following code&lt;/p&gt;
&lt;pre class="language-csharp"&gt;&lt;code&gt;protected override async void OnLaunched(LaunchActivatedEventArgs e)
{
    var settings = new AppSettings();
    ApplicationLanguages.PrimaryLanguageOverride =
        settings.UsePrimaryLanguageOverride ?
            settings.PrimaryLanguageOverride :
            Windows.System.UserProfile.GlobalizationPreferences.Languages[0];

   ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now your app will have the ablity to let user switch custom languages!&lt;/p&gt;</content></entry><entry><id>ac5e9377-e797-4557-9e70-da073ad4be73</id><title>Windows 10 UWP: How to Read and Save Settings Easily</title><updated>2017-09-08T02:33:12Z</updated><published>2017-09-08T02:33:12Z</published><link href="https://edi.wang/post/2017/9/8/uwp-read-write-settings" hreflang="en-us" /><author><name>Edi Wang</name><email>Edi.Wang@outlook.com</email></author><category term="Windows Development" /><content>&lt;p&gt;In the UWP Application model, reading and saving settings are very similar to WinRT API. The class we are using is &lt;code&gt;ApplicationData.Current.LocalSettings&lt;/code&gt; It is using key-value-pair to store settings.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;LocalSettings&lt;/code&gt; will stay on the user's current computer, and not being synced with thier Microsoft account.&lt;/p&gt;
&lt;p&gt;The API to save settings is:&lt;/p&gt;
&lt;pre&gt;LocalSettings.Values[key] = value;&lt;/pre&gt;
&lt;p&gt;To read settings:&amp;nbsp;&lt;/p&gt;
&lt;pre&gt;if (LocalSettings.Values.ContainsKey(key))
{
    return LocalSettings.Values[key];
}&lt;/pre&gt;
&lt;p&gt;Please notice, we should first check if the key is already present.&lt;/p&gt;
&lt;p&gt;In order to use it in an easy way, we can write a class to manage those settings:&lt;/p&gt;
&lt;pre&gt;public class AppSettings : INotifyPropertyChanged
{
    public bool ShowTimeSheetSetting
    {
        get
        {
            return ReadSettings(nameof(ShowTimeSheetSetting), true);
        }
        set
        {
            SaveSettings(nameof(ShowTimeSheetSetting), value);
            NotifyPropertyChanged();
        }
    }

    public ApplicationDataContainer LocalSettings { get; set; }

    public AppSettings()
    {
        LocalSettings = ApplicationData.Current.LocalSettings;
    }

    private void SaveSettings(string key, object value)
    {
        LocalSettings.Values[key] = value;
    }

    private T ReadSettings&amp;lt;T&amp;gt;(string key, T defaultValue)
    {
        if (LocalSettings.Values.ContainsKey(key))
        {
            return (T)LocalSettings.Values[key];
        }
        if (null != defaultValue)
        {
            return defaultValue;
        }
        return default(T);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged([CallerMemberName]string propName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    }
}&lt;/pre&gt;
&lt;p&gt;Key Points:&lt;/p&gt;
&lt;p&gt;1. By taking advantage of C#6, the key is a type of &lt;code&gt;string&lt;/code&gt;, we can use &lt;code&gt;nameof&lt;/code&gt; to retrieve it's name. When we invoke event handlers, we can also use &lt;code&gt;?.&lt;/code&gt; for null check.&lt;/p&gt;
&lt;p&gt;2. Using generics to do the type convertion. If the property got a default value, return it. Because in our App, default values are ususally needed. In this example, I only added one settings of a &lt;code&gt;bool&lt;/code&gt; type: &lt;code&gt;ShowTimeSheetSetting&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;3. The operation that the AppSettings class is exposing is just the getter and setter on the property. Reading and Saving settings are automatically done internally. The user of this class don't have to know about how this is done, which means, if some day, the implementation for how to read and save settings changes, we just need to modify one place not everywhere in the code.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;4. Because we implemented &lt;code&gt;INotifyPropertyChanged&amp;nbsp;&lt;/code&gt;we can do two way bindings on XAML:&lt;/p&gt;
&lt;pre&gt;&amp;lt;Page.Resources&amp;gt;
    &amp;lt;core:AppSettings x:Key="AppSettings" /&amp;gt;
&amp;lt;/Page.Resources&amp;gt;
&lt;/pre&gt;
&lt;pre&gt;&amp;lt;ToggleSwitch OnContent="On" OffContent="Off" IsOn="{Binding Source={StaticResource AppSettings}, Path=ShowTimeSheetSetting, Mode=TwoWay}" /&amp;gt;&lt;/pre&gt;
&lt;p&gt;For other types of settings, such as &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;enum&lt;/code&gt;, we can of course added them as properties, and use them in xaml just like this!&lt;/p&gt;</content></entry></feed>