Thursday, August 9, 2018

Can I Port My Windows Desktop Application to .NET Core? Find Out and Prepare Today!

Did you know that soon you will be able to build and run your WPF (and UWP & WinForms) applications against .NET Core?

Desktop Packs

At the Microsoft Build conference in May, it was announced that the .NET team was working on some Windows-only "Desktop Packs" that could be installed on top of .NET Core v3.0. These packs would include:

  • WPF
  • WinForms
  • UWP
  • Entity Framework v6

This will bring the benefits of .NET Core to desktop client applications running on Windows. In my opinion, the biggest benefits of porting your desktop app to .NET Core will be significant performance gains and full access to Windows 10 APIs.

Obviously, in most cases, it won't be as simple as changing a project property and rebuilding your app. Project files will need to be upgraded to .NET Core format, and some legacy APIs will not be available, even in the Desktop Pack packages. This week, it has become more clear exactly which APIs will not be available in .NET Core 3.0 with Desktop Packs.

Portability Analyzer

On Wednesday, the .NET team released a Portability Analyzer tool to scan your .NET desktop applications and determine how ready they are to upgrade to .NET Core 3.0. The tool will scan your .NET binaries and dependencies and produce an Excel report (PortabilityReport.xlsx) with several tabs:

Portability Summary - This sheet contains a list of the assemblies scanned, their current .NET version target, and the % compatibility they are expected to have with .NET Core 3.0.

Details - This sheet provides details on exactly which target type and member are currently used by one of your assemblies that is not compatible with .NET Core 3.0. There is a column for Recommended Changes, but none of my incompatibilities had any recommendations.

Missing assemblies - If your assemblies reference any other assemblies which could not be resolved by the tool, they will be listed here.

My Thoughts

I ran the tool on a large application with a mix of WinForms and WPF windows. The folder contains over 900 DLLs. My thoughts:

First, I was pleasantly surprised at how fast the tool ran its analysis. It completed scanning this large application in less than a minute. I was expecting to go get a cup of coffee and a snack while it ran.

Second, the team has really included a lot of desktop APIs in these packs. I was not expecting so many of my DLLs to report at 100% compatible.

Third, many of the incompatible APIs are somewhat expected. Here are a few that came back in the report here:

  • Microsoft.VisualBasic.* - If you have VB apps, and use APIs in this namespace, expect a lot of lines to appear in your report.
  • System.Drawing.Design.* and System.Drawing.ImageConverter - Much of the System.Drawing namespaces was ported to .NET Core, but not everything. If you're doing anything advanced or uncommon, you'll probably find some issues here.
  • Things that are less common in modern development like System.Xml.XmlDataDocument, System.Runtime.Remoting.Messaging, and System.Activator.GetObject.

Console Tool

If you would prefer to run the analyzer against several applications and product individual reports for each, you can use a console analyzer with a batch file or PowerShell script instead. That version is available here, and instructions for using it are in the .NET team's post about the Portability Analyzer.

Wrap-Up

Go get your app ready for .NET Core 3.0 today! Your users will thank you later.


Tuesday, May 29, 2018

TechBash 2018 Early Bird Tickets Now Available!

4-day (with Workshop) and 3-day early bird tickets are now on sale for TechBash 2018. This year TechBash will be held October 2-5, with the 2nd being a pre-conference day of full-day workshops for 4-day ticket holders only. These workshops will be presented by top experts in each area. The topics from which to choose are ASP.NET Core 2.1, DevOps, Docker and Azure for Developers. Get more workshop info here.

Early bird tickets will save up to 25% off the Standard ticket price this year. Don't wait because these prices will only be available for a few weeks and space in each workshop is limited. This year's keynote presenter is Scott Hunter, leader of the Visual Studio and .NET Teams at Microsoft, and these other speakers have already been confirmed:

  • Jeremy Likness
  • Jessica Deen
  • Richard Taylor
  • Jeremy Clark
  • Anna Bateman
  • Brendan Enrick
  • John Wright
  • Ashley Grant
  • Ivana Veliskova
  • Steve Bohlen
  • Angel Thomas
  • Jim Wooley
  • Walt Ritscher
  • Paul Hacker
  • Jeff Fritz
  • Mitch Denny
  • Anoop Kumar

The full lineup will be announced soon. Get more info about TechBash here and buy your tickets today!

See you this fall at the Kalahari Resort in the Poconos!


Thursday, November 30, 2017

WPF Tip #20 - Extended WPF Toolkit - IconButton Control

It's time to explore a new control in the Extended WPF Toolkit, maintained on GitHub by Xceed and the WPF community. Today, we will take a quick look at the IconButton control, which is new to v3.2.0 of the toolkit (released on Sept. 25th).

IconButton derives from a WPF Button and adds the ability to optionally place an Image to the left or right of your button's Content. There are a handful of properties available on top of the existing Button properties - Icon and IconBackground plus properties to change the button's appearance when users mouse over or press the button:
  • MouseOverBackground
  • MouseOverForeground
  • MouseOverBorderBrush
  • MousePressedBackground
  • MousePressedForeground
  • MousePressedBorderBrush
These state-based properties are self-explanatory, so I created a brief example which uses only the Icon and IconLocation properties.

<xctk:IconButton Content="Launch Me" Padding="4" 
                  HorizontalAlignment="Center" VerticalAlignment="Center" 
                  IconLocation="Right">
     <xctk:IconButton.Icon>
         <Image Source="/WpfApp1;component/Images/Launchpad_Icon.png" 
                Width="16" Margin="4,0,0,0"/>
     </xctk:IconButton.Icon>

</xctk:IconButton>


The result is a window with a single "Launch Me" IconButton. There's an Apple-style launch icon to the right of the text set in the Content property. The image I used is a .png file in my project's Images folder set as a Resource. If you wanted to deploy the actual .png file, you would update the file to be "Content" and set the Image's Source property to "Images/Launchpad_Icon.png". This is the same practice you would use for any WPF image source.

All of these properties can be set up via MVVM, data binding and code in your ViewModels to load the image and set its location at runtime based on other application configuration or user preferences.

Here's is a look at the window at runtime:

wpf_xctk_iconbutton1

It's a simple control that can save you a little bit of control templating. If this is something you could use in your project, the toolkit is free and available on NuGet.

Happy coding!

del.icio.us Tags: ,

Thursday, September 7, 2017

WPF Tip #19 - Extended WPF Toolkit - Zoom in with the Magnifier Control

It's time to examine another control from the Extended WPF Toolkit, maintained on GitHub by Xceed and the WPF community. Today, we will look at an example of how easy it is to add a zoom feature to your WPF application with the Magnifier control.

Magnifier_magnifier_withborder

In the Xaml below, I have added a Magnifier to the top-level grid in my Window.

<Grid>

    <tk:MagnifierManager.Magnifier>
         <tk:Magnifier BorderBrush="MediumPurple"
                               BorderThickness="2"
                               Radius="80" 
                               ZoomFactor=".4" />
     </tk:MagnifierManager.Magnifier>

    <tk:CheckListBox ItemsSource="{Binding Sentences, IsAsync=True}"
                      SelectedItem="{Binding SelectedSentence}"
                      Command="{Binding ItemSelectedCommand}"/>


The CheckedListBox from Tip #18 is still in place, displaying results from my Bacon Ipsum generator from Tip #17. Running the application, we see my random list items with a zoom region that follows my mouse as I move it around the Window.

zoom.bacon

Pretty simple! Go check it out for yourself. You can easily add a bound visibility property to hide/show the control from a toolbar or other button in your app.

Happy coding!

del.icio.us Tags: ,,

Monday, August 14, 2017

WPF Tip #18 - Extended WPF Toolkit - Using the CheckedListBox Control

In today's tip, we're going to take a quick look at another control in the Extended WPF Toolkit, the CheckedListBox control.
CheckListBox_wpf
This control provides all of the functionality expected from a ListBox with the addition of checkboxes as a visual cue to indicate the selection state of each item.

Using the control is quite simple. Here's an example of the XAML required to display a CheckedListBox on a WPF window. It is binding to the same collection of Sentence objects used in Tip #17.

<tk:CheckListBox ItemsSource="{Binding Sentences, IsAsync=True}"
                  SelectedItem="{Binding SelectedSentence}"
                  Command="{Binding ItemSelectedCommand}"/>

ItemsSource binding to a collection to populate the list items. SelectedItem provides a way to find out the currently 'selected' item, the last item checked/unchecked. The Command will fire each time an item in the list is checked or unchecked, allowing ViewModel logic to act on this change.

Go give it a try in your WPF project. Happy coding!


del.icio.us Tags: ,

Wednesday, August 2, 2017

WPF Tip #17 - Extended WPF Toolkit - BusyIndicator Control

Welcome back to another Extended WPF Toolkit sample. In this sample, we'll take a look at the BusyIndicator control. This easy to use control provides a quick way to inform your users that a control or Window is currently being refreshed by a long-running process. This is a great way to both update your users of progress and keep them from interacting with the controls that are updating.
Here is a fun little example that wraps a WPF DataGrid in a BusyIndicator. This is the entirety of the XAML inside the root Grid on the application's main window.

<tk:BusyIndicator IsBusy="{Binding IsGridLoading}" BusyContent="Loading, please wait..." DisplayAfter="0">
     <DataGrid local:Commands.DataGridDoubleClickCommand="{Binding GridDoubleClickCommand}" ItemsSource="{Binding Sentences, IsAsync=True}"/>
</tk:BusyIndicator>

The DataGridDoubleClickCommand is a work-around to make the DataGrid's MouseDoubleClick event work with ICommand in when data binding in MVVM. More info here.

In the MainViewModel, there is an IsGridLoading boolean property that will be used to toggle the BusyIndicator on/off. The GridDoubleClickCommand invokes OnGridDoubleClicked() when the user double-clicks somewhere on the DataGrid at runtime. In this method, we're clearing and repopulating the Sentences ObservableCollection to which our DataGrid is bound. Notice the use of async/await. This is necessary to make the BusyIndicator appear. Without this, the UI will freeze during the update and never show the BusyIndicator control.

private async void OnGridDoubleClicked()
{
     //set the IsBusy before you start the thread
     IsGridLoading = true;
     RaisePropertyChanged(nameof(IsGridLoading));

     //no direct interaction with the UI is allowed from this method
     lock (_sentenceLock)
     {
         Sentences.Clear();
     }

     await BuildSentenceList(5, 15, 25, 50);

     //work has completed. you can now interact with the UI
     IsGridLoading = false;
     RaisePropertyChanged(nameof(IsGridLoading));
}

The _sentenceLock allows us to update our ObservableCollection on a background thread. You must also initialize the collection with this code in your constructor. This tells WPF to update the collection on the UI thread and which lock object to use. More info here.

BindingOperations.EnableCollectionSynchronization(Sentences, _sentenceLock);

Each row in the DataGrid will be populated with some random Bacon Ipsum data in the BuildSentenceList method. There is an API if you would like to remove the hard-coded array of words.

private async Task BuildSentenceList(int minWords, int maxWords,
     int minSentences, int maxSentences)

{
     var words = new[]{"bacon", "ipsum", "dolor", "tail", "amet", "swine",
         "chicken", "short", "loin", "jowl", "turkey", "ball", "tip",
         "beef", "shank", "rump", "t-bone", "ham", "porchetta", "filet",
         "pork", "jerky", "hock", "meatball", "biltong", "steak", "brisket"};

     var rand = new Random();
     int numSentences = rand.Next(maxSentences - minSentences)
                        + minSentences + 1;
     int numWords = rand.Next(maxWords - minWords) + minWords + 1;

     var result = new StringBuilder();

    Task t = Task.Run(() =>
     {
         for (int s = 0; s < numSentences; s++)
         {
             for (int w = 0; w < numWords; w++)
             {
                 if (w > 0)
                 {
                     result.Append(" ");
                 }
                 result.Append(words[rand.Next(words.Length)]);
             }
             result.Append(". ");

            lock (_sentenceLock)
                 Sentences.Add(new Sentence() {SentenceContent = result.ToString()});

            Thread.Sleep(100);

            result.Clear();
         }
     });

    await t;

}

When the code to populate the grid fires, thanks to the 100ms Thread.Sleep between each row generated, you can see the grid slowly populating with data behind the busy indicator.

baconipsum-loading

It's a great control. Just remember to update your data on a background thread!

Happy coding!


del.icio.us Tags: ,,,

Tuesday, July 25, 2017

WPF Tip #16 - Extended WPF Toolkit - ChildWindow & MessageBox Controls

Welcome to another Extended WPF Toolkit tip. In this tip, we will look at a couple of simple uses of the ChildWindow and MessageBox controls.

The ChildWindow control is a handy alternative to opening a separate dialog from the current application window, collecting a few pieces of data. The MessageBox operates similarly, but only presents some information and allows the user to respond, like any typical WinForm or WPF MessageBox.

In an MVVM world, opening another dialog typically either involves another View/ViewModel combination or a service to open a simple message/input dialog and return the result to the current View/ViewModel. This control is best used to replace a simple MessageBox service or when another View/ViewModel are being considered, but logically the data collected is limited and still belongs in the current ViewModel.

The use of the controls consists of a WindowContainer element containing one or more ChildWIndow and MessageBox elements. In this sample, the Window's main grid contains a WindowContainer with two ChildWindow elements and one MessageBox. They all begin with a Closed WindowState, and are opened with a button click. Here is a snippet of the view's XAML:

<StackPanel Grid.Row="2" Orientation="Horizontal" VerticalAlignment="Top">
     <Button Content="Toggle Window 1" Height="40" Width="120" Margin="2" Command="{Binding ButtonOneCommand}"/>
     <Button Content="Toggle Window 2" Height="40" Width="120" Margin="2" Command="{Binding ButtonTwoCommand}"/>
     <Button Content="Toggle Window 3" Height="40" Width="120" Margin="2" Click="ButtonBase_OnClick"/>
</StackPanel>

<tk:WindowContainer Grid.Row="2">
     <tk:ChildWindow WindowBackground="Blue"
                       Left="75"
                       Top="50"
                       Width="275"
                       Height="125" WindowState="{Binding WindowOneState}">
         <TextBlock Text="This is a child window" Padding="10"/>
     </tk:ChildWindow>

    <tk:ChildWindow WindowBackground="Green"
                       Left="175"
                       Top="125"
                       Width="275"
                       Height="125" WindowState="{Binding WindowTwoState}">
         <StackPanel>
             <TextBlock Text="This is a child window with a checkbox." Padding="10"/>
             <CheckBox Content="Check me!" Margin="8"/>
         </StackPanel>
     </tk:ChildWindow>

    <tk:MessageBox Caption="Toolkit Message" x:Name="SampleMsgBox"
                      Text="You have an alert!"/>

</tk:WindowContainer>

The MessageBox's button has a Click event handler to display the control:

private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
     SampleMsgBox.ShowMessageBox();
}

The two ChildWindows are opened with Commands attached to the first two buttons in our Window's ViewModel:

private void OnButtonOneClicked()
{
     if (WindowOneState == WindowState.Open)
         WindowOneState = WindowState.Closed;
     else
         WindowOneState = WindowState.Open;
    RaisePropertyChanged(nameof(WindowOneState));
}

public RelayCommand ButtonOneCommand { get; private set; }

private void OnButtonTwoClicked()
{
     if (WindowTwoState == WindowState.Open)
         WindowTwoState = WindowState.Closed;
     else
         WindowTwoState = WindowState.Open;
    RaisePropertyChanged(nameof(WindowTwoState));
}

public RelayCommand ButtonTwoCommand { get; private set; }

The ChildWindows can be closed again by using the close button on the element or by clicking it's Open button again. This second option is not available when the ChildWindow has IsModal set to true. You'll notice the WindowState property of the two ChildWindows is bound to the ViewModel. This two-way binding ensures the IF statements in the command methods will work properly regardless of how each window is closed.

Here is a look at the Window with the second ChildWindow open. This control contains a TextBlock and a CheckBox inside a StackPanel. The ChildWindow can contain only one direct child, like a Window or UserControl.

childwindows-wpf

There are tons or other uses for these controls and many properties I haven't touched on at all. Go explore them for yourself and download the toolkit today.

Happy coding!


del.icio.us Tags: ,,