Archive for August 2015
UWP: How to implement Drag and Drop functionality
One more new feature, which is available for Windows 10 developers, is Drag and Drop support. Starting with Windows 10 you can implement Drag and Drop functionality between UI parts of your application or use external sources/targets including Win 32 applications.
Let’s start with Drag operation. In order to show how Drag operation works, I simply added an image from the application package to the main page.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Image Source="Assets\drone.jpg" Name="image" CanDrag="True" DragStarting="Image_DragStarting" Margin="100" VerticalAlignment="Top" HorizontalAlignment="Left"></Image> </Grid>
You can see two important attributes there that activate Drag operation: CanDrag and DragStarting. CanDrag attribute is just a flag which enables the feature for all UIElement controls but DragStaring attribute contains name for event handler. Thanks to this event handler you can define any content to drag. In my case I implemented the following handler:
private async void Image_DragStarting(UIElement sender, DragStartingEventArgs args) { List<IStorageItem> files = new List<IStorageItem>(); StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/drone.jpg")); files.Add(file); args.DragUI.SetContentFromDataPackage(); args.Data.RequestedOperation = DataPackageOperation.Copy; args.Data.SetStorageItems(files); }
In this event handler I used StorageFile class in order to pass my image like a file and thanks to Data property of DragStartingEventArgs parameter I packaged the file to the object of DataPackage class. DataPackage class is very popular among different features in Universal Windows Platform and usually you need to pass it to the operation system and OS allows to select the target application. But in case of Drag functionality user selects the target directly. So, we just need to prepare the DataPackage and that’s all.
Additionally I used two important properties there: DragUI and RequestedOperation. Thanks to the RequestedOperation I can assign the right operation and user should not be able to select anything from system menu – just drag and drop. Thanks to DragUI I can apply the content which will be shown during Drag operation. If you don’t use DragUI property, user will see the same image with the same width and height like in your application. It’s not very cozy to drag a huge image especially if you don’t use RequestedOperation – the system menu will be behind the image. That’s why you can assign any other content using DragUI or use SetContentFromDataPackage method in order to ask API to prepare appropriate icon for you based on content in DataPackage.
Just run the application and drag and drop the image to the file explorer – image will be copied to the selected folder.
Let’s see how to implement an opposite task – Drop functionality. I want to accept several images. So, I am going to use ListView in order to show my items.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" AllowDrop="True" Drop="Grid_Drop" DragEnter="Grid_DragEnter"> <ListView Margin="50" Name="listView"> <ListView.ItemTemplate> <DataTemplate> <Grid> <Image Source="{Binding Source}" Width="200" Margin="10"></Image> </Grid> </DataTemplate> </ListView.ItemTemplate> </ListView> </Grid>
You can see that I am using AllowDrop to activate the Drop functionality, DragEnter – to setup allowed operations (Copy) and Drop – to get content from DataPackage and show it using ListView.
In order to create items source for images I created BitmapItem class:
class BitmapItem { public ImageSource Source { get; set; } }
In the next step I implemented DragEnter event handler in order to notify the system about supported operations.
private void Grid_DragEnter(object sender, DragEventArgs e) { e.AcceptedOperation = DataPackageOperation.Copy; }
Finally, I am using DataPackageView in order to get reference to the content. DataPackageView can contain anything but I want to work with files only, so I call GetStorageItemsAsync in order to get references to files there and use BitmapImage to prepare the image files for Image objects.
private async void Grid_Drop(object sender, DragEventArgs e) { var files=await e.DataView.GetStorageItemsAsync(); List<BitmapItem> items = new List<BitmapItem>(); foreach(StorageFile file in files) { try { BitmapImage bi = new BitmapImage(); bi.SetSource(await file.OpenAsync(FileAccessMode.Read)); items.Add(new BitmapItem() { Source = bi }); } catch { } } listView.ItemsSource = items; }
I am too lazy, so I decided to avoid any checking – I simply use empty catch block if user passed non-image file(s).
That’s all. You can see that it’s easy to implement Drag and Drop functionality and you can make experiments with different content types there or implement the same functionality inside the same application (drag and drop content from one part of application to another).
XAML tools in Visual Studio 2015
Visual Studio is the best editor forever. So, it’s very hard to implement something new that can excite me but developers of Visual Studio 2015 made it and today I want to talk about several features related to XAML editor.
The first feature there is “peek window”. The feature can be used not just in XAML editor but in case of XAML it’s really valuable because it allows to do a lot of things that were not possible before. This feature allows to inject “dependent code” windows directly to my current window.
Thanks to that I can easily check styles even in generic.xaml, review definitions of controls, modify event handlers etc. And in order to do it I should not close my primary window.
You can call “peek window” using context menu or you can find this window using some features of Visual Studio 2015. For example, Visual Studio 2015 contains updated template editor. If you want to create a new template for any control you can use context menu and select Edit Template->Edit a Copy
If you use Application resources or Resource Dictionary, Visual Studio redirects you to the appropriate file. But in case if Visual Studio 2015 you continue to work with new template using the same window, editing the template in the designer and checking and modifying code using “peek window”.
Visual Studio 2015 applies color border to the visual editor in template editor mode.
One more feature in XAML editor is its ability to add named regions in XAML code like in C#. You can use the following syntaxes in order to create a marked region inside your XAML
As in C# you can collapse it:
You can use this feature in many ways: mark the existing code for some reason or create some templates for future work.
I showed three new features in XAML editor: peek window, updated template editor and marked XAML blocks. Let’s use these features to make coding more smoothly.
Tailored views or one more way to create Universal interfaces (part 2)
In the previous post I showed how to create tailored views for known families of devices. But if you want to apply tailored views based on your custom logic you can make it as well.
First of all you need to follow naming rules in order to associate a new view with the existing code-behind file. In order to do it just use the following rule: <initial page name>.<any extension>.xaml. Don’t use “DeviceFamily-“ for your own extensions – probably it is reserved by Visual Studio and you will get runtime error if you use it. For example, if you create a new view for MainPage.xaml you can use MainPage.Raspberry.xaml name.
Once you add a new view to your project you can see that Visual Studio will generate one more InitializeComponent method.
At this step Visual Studio doesn’t check anything – just adds a new method, which should be used for different device families. Of course, if you use predefined device family, InitializeComponent method with parameter will be called “automatically” but in case of your own logic you can call it directly from your code. Of course, you need to change existing constructor of the page and call InitializeComponent in the following way:
this.InitializeComponent(new System.Uri("ms-appx:///MainPage.Raspberry.xaml"));
Using this approach you can implement any custom logic in your constructor and apply different views based on different devices, parameters etc.
UWP: Back button is everywhere
One more thing which was not available for universal interfaces is the back button. You know that all Windows Phone devices have hardware or software back button. So, when you develop Windows Phone 8.x applications you need to handle that button but in case of Windows 8.x applications you need to create your own back button from scratch. Of course, Microsoft published design guide how to create and handle back button in Windows 8.x applications but the approach was very different compared to the Windows Phone.
Starting with Windows 10 developers can use the same approach everywhere.
If you want to handle the back button in any page you need to implement the following code:
protected async override void OnNavigatedTo(NavigationEventArgs e) { SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible; SystemNavigationManager.GetForCurrentView().BackRequested += MainPage_BackRequested; base.OnNavigatedTo(e); }
Thanks to these two lines of code you can activate the back button if it’s not available (in case of a desktop, for example) and apply an event handler for the BackRequested event. BackRequested event handler is all you need in order to handle software or hardware back button. The simplest implementation can look like:
private void MainPage_BackRequested(object sender, BackRequestedEventArgs e) { if (this.Frame.CanGoBack) this.Frame.GoBack(); }
Let’s see what happens in the desktop mode if you run code above.
You can see that the back button is added to the application title and users can click it like the back button on phone devices.
In order to see how the back button works in the tablet mode (if you don’t have a tablet) you need to open the Settings window, navigate to the Tablet mode menu item there and switch Windows to the tablet mode (or click Notification Hub button and use the shortcut there):
If you resize Setting window to the minimum size you can see that the back button is implemented there in the same way.
Once you switch Windows to the tablet mode you can see that the back button is displayed on the taskbar (outside your interface) but it still works fine.
So, the back button is everywhere and with the help of the Universal Windows Platform developers can use the same approach to implement the back button user experience.
Live Visual Tree in Visual Studio
In this post I am going to talk about a cool tool in Visual Studio – Live Visual Tree. This tool is available for Store and WPF applications including Store applications for Windows 8.x.
Live Visual Tree allows to observe XAML visual tree in runtime, review properties of elements there and even change properties in runtime in order to check how changes will affect interface without restarting application itself. There are lots of scenarios when you need to use a tool like this and I have already adopted this tool for the following tasks:
· If you have a huge number of visual states in your interface it’s really hard to understand while a state is not fired. Thanks to Live Visual Tree you can check properties of all controls and see what happens applying changes to these properties – check if a state is applied and how the result looks like;
· Visual designer in Visual Studio works fine but if you have lots of bindings you can use Live Visual Tree to change something in runtime and see how it affects the design of the running application with active bindings and data there;
· Live Visual Tree allows to visualize layout in order to show alignments and space for UI elements. It allows to find some mistakes which you cannot find in design mode due to absence of real data;
· Checking count of elements in each container you can find potential problem with performance;
· Live Visual Tree allows to check XAML tree not just for your applications – you can easily attach debugger to any running “XAML application” and see XAML visual tree there and apply any changes in the same way;
In order to open the Live Visual Tree window for your application you need to run your application in the Debug Mode and you can find the Live Visual Tree using Debug->Windows menu item. The second window, which is associated with the Live Visual Tree, is Live Property Explorer. Using the Live Visual Tree you can navigate between XAML elements and using Live Property Explorer you can check, change and create properties there.
You can see that Live Visual Tree provides information about number of XAML elements inside each container. Pay special attention that you can see elements from XAML visual tree only. So, Live Visual Tree contains visible elements only, and if interface changes from one state to another you can see that Live Visual Tree is changing in runtime.
Live Property Explorer shows default values for properties, values which were inherited from other controls and local values of control properties itself. Of course, you can modify local values only. If a value has been assigned to a property previously you can modify it but you can add any other available properties and assign values to them as well.
In Live Visual Tree window you can find two useful buttons. The first one allows to select any element in the running application in order to find it in the XAML tree. It’s very useful when you want to locate a place of a button and other controls that have tap event handler. The second one allows to visualize layout. Once you select any element you will be able to see layout there.
As I mentioned earlier you can attach Visual Studio to any existing “XAML window”. For example, you can run the settings window and select Attach to Process in Debug menu of Visual Studio 2015. In the Attach to Process dialog select SystemSettings process and you will be able to see the structure of the window. You even can change current settings and check layout of the window.
So, Live Visual Tree is a very powerful tool which can help to make your application better.
New features of C# 6
Visual Studio 2015 is released and it’s time to talk about Visual Studio 2015 features and about related to it features. And in this post I decided to talk about C# 6.0 as about a programming language. So I am not going to discuss Roslyn and some editor features – just new language features. All these features are already available and you can use them right now. Let’s start.
Default value for property
The simplest feature of C# 6.0 is ability to assign default value to auto properties.
class Cat { public ConsoleColor Color { get; set; } = ConsoleColor.Black; }
Non-auto implemented properties cannot have initializer like this.
Getter-only auto properties
The next feature of C# 6.0 relates to a setter method of property. There are many scenarios when you don’t want to make a public setter but you still want to make an auto implemented property. In the previous version of C# you could make something like this:
public ConsoleColor Color { get; private set; }
But this approach doesn’t block ability of using the setter in other methods of the class but it can violate some business rules. That’s why C# 6.0 introduces a way to use properties with getters only:
public ConsoleColor Color { get; }
You can initialize properties like this in constructors or using a default initializer:
public ConsoleColor Color { get; } = ConsoleColor.Black;
But you cannot change getter-only properties in other methods of the same class.
using static
Everybody knows that keyword using allows to declare namespaces which compiler uses to identify the full name of types in your code. Thanks to using you can avoid full names for types like System.Net.Mail.SmtpClient. Instead you can use SmtpClient if you declare System.Net.Mail with using.
using static allows to do the same thing but for static methods rather than types. It allows to use static methods even without class name similar to global functions. For example we can create code like this:
using static System.Math; using static System.Console; class Program { static void Main(string[] args) { double angle = PI / 2; WriteLine("sin(x)={0}", Sin(angle)); } }
We used two using static constructions and thanks to that we can use PI, Sin and WriteLine static methods without explicit class name specification.
Interpolated string
In the previous code we used formatting approach which allows us to build output string using parameters. Of course, if you have lots of parameters it’s easy to make a mistake there: to declare wrong indexes for parameters, to miss some parameters or to specify parameters in the wrong order. Thanks to C# 6.0 I can inject parameters directly to a string. For example, my WriteLine method looks like:
WriteLine($"sin(x)={Sin(angle)}");
You can see that we used $ symbol in order to declare the string with the parameters inside. Once we specify $ we continue to use parametrized string but instead of indexes we use expressions directly. And you can continue to use formatting symbols:
WriteLine($"sin(x)={Sin(angle):n3}");
Expression-body (bodied) methods
I don’t know why but the next feature is scaring me. Let’s declare the following method:
public void PrintSin(double angle) { WriteLine($"sin(x)={Sin(angle)}"); }
You can see that this method contains just single expression. Using C# 6.0 we can rewrite this method in the following way:
public void PrintSin(double angle)=>WriteLine($"sin(x)={Sin(angle)}");
nameof
Even after applying of expression-body method, interpolated string and using static we still can use one more new feature of C# 6.0 there – it’s nameof operator.
public void PrintSin(double angle)=>WriteLine($"sin({nameof(angle)})={Sin(angle)}");
nameof allows to return the name of a variable. It’s very useful in case when you hardcoded names of the variables in debug messages, log messages etc. Thanks to nameof you can easy apply refactoring practices to your variables.
Operator “?”
The next feature is very useful for all types of applications. Let’s see the following code
class Program { static JustClass obj; static void Main(string[] args) { obj = new JustClass() { data = 10 }; if ((obj!=null)&&(obj.data!=null)&&(obj.data.DataValue>3)) { WriteLine("a very complex if"); } } class JustClass { public Data data { get; set; } = null; } class Data { public int DataValue { get; set; } } }
Pay special attention to the if statement. Even in this easiest case we have a very complex if. There are three conditions and two of them test value for null. In C# 6.0 we can simplify this code:
if (obj?.data?.DataValue > 3) { WriteLine("a very complex if"); }
It’s the same code but we simplify null conditions using ? operator. You cannot use this operator if you have just one condition. In other words, right after this operator there should be .<data field> but it is still possible to make lot’s of if operators more clear.
Indexer initializer
Just run this code:
class Program { static JustClass obj; static void Main(string[] args) { obj = new JustClass() {[10] = 5,[1] = 7 }; Console.ReadLine(); } class JustClass { public int this[int i] { get { return i; } set { Debug.WriteLine(value.ToString()); } } } }
You can see that class JustClass has an indexer inside. In C# 6.0 I can use indexers in order to initialize objects. For example, in my code I initialized element with index 10 and index 1. Of course, my example doesn’t have much sense but the idea should be clear.
Conditional exceptions
Finally, let’s play with the following code:
static void Main(string[] args) { try { throw new Exception("File not found"); } catch(Exception ex) when (ex.Message.Contains("File")) { throw ex; } catch (Exception ex) { throw ex; } }
You can see that thanks to when keyword we can catch exceptions based on results of expressions.
That’s all about language. Next time I will write about IDE and some features there.
Visual Studio Code and Visual Studio Online
Visual Studio Code has lots of different advantages like:
· It’s very fast and doesn’t require much resources. Even on my Windows laptop, where I have Visual Studio Enterprise installed, I like to use Visual Studio Code to open JavaScript or TypeScript files just to check something using formatting features. It’s as fast as opening a text file in Notepad but I have fully featured IDE;
· It supports more than 30 programming languages. So, I can easy use it together with Unity 3D to edit C# and JavaScript files or I can edit HTML markup and TypeScript files;
· It supports different operation systems like Linux and MacOS. Therefore, you can continue to use Visual Studio Code running Unity3D projects on Mac or when you create web sites or server-side components using Node.js;
But today I am going to talk about another important advantage, which is integration with Git. Since even I am the only person in the team I will use version control system in any case. Of course, Git is just a platform and it requires a provider, if you are not going to setup your own infrastructure. And if you are planning to create an open source project which will be uploaded to a public repository, probably, you will use GitHub as a provider. GitHub allows you to create an unlimited number of public repositories for free. But once you want to create a private repository or want to have access to number of tools which help you to support Software Development Life Cycle, it’s better to use Visual Studio Online.
Visual Studio Online allows you to have up to 5 developers per your account for free and you can create any number of projects there and use some additional features like Sprint planning tools, Task and Kanban boards, virtual team room etc. And, of course, Visual Studio Online supports Git and thanks to that you can use Visual Studio Code and Visual Studio Online together.
If you still don’t have an account for Visual Studio Online, it’s time to get one for free.
Once you get access to Visual Studio Online you can create a project. In this case project means everything that is related to application lifecycle management: dashboards, repository, team room etc. Pay special attention that Visual Studio Online supports two types of version control including Git. Because we are going to use Visual Studio Code we need to select Git:
Once the project is created you need to do one more thing inside Visual Studio Online – open your profile and use Security tab to apply Alternate authentication credentials. By default Visual Studio Online uses LiveID to make authentication but Git tools don’t support LiveID. So, without this step you will not be able to setup Git on your PC.
One more step on the server side is getting URL that you can use as a remote repository in Git. Just navigate to the project and open CODE tab. You will see the URL – just copy it for next step.
That’s all done on server side.
I assume that you already installed Git on your PC and know how to run the command line. First of all you need to provide Git your user name which you defined in Visual Studio Online as an alternate credential:
git config –global user.name sbaidachni
If you still have not created a local repository, you can do it by using the following commands:
git init
This command will make the current folder a local git repository.
Finally, you can add the reference to our remote repository:
git remote add origin https://canadaapps.visualstudio.com/DefaultCollection/_git/VSCodeProject
That’s all. Just open the local folder using Visual Studio Code and you should see that most of menu items of Git tab are already enabled for you:
You can start coding and commit all changes to Visual Studio Online.
Win2D: How to use graphics without knowledge in DirectX
Direct2D is a very good technology but using of it requires some knowledge in DirectX. Yes, DirectX is cool but lots of developers who build business applications have never used DirectX in their entire life. That’s why many of them ask about Direct2D features like about a separate Windows Runtime API, which is ready for non-game developers. Win2D is such an API.
Win2D is a Windows Runtime API which is available for C++ and C# developers and brings GPU optimized 2D graphic to Windows 8.x/Windows 10 XAML applications.
The best way to start working with Win2D is to visit Win2D Team Blog where you can find links to the documentation, sample code, source code (Win2D is an open source project) etc. But if you want to understand the full power of Win2D it is better to start develop something using this API. So, let’s look at some useful classes there and learn how to start developing with Win2D.
Since Win2D is an open source project and is not a part of Universal Windows Platform by default, you need to use NuGet package manager to add the latest version of Win2D libraries (use Win2D.uwp).
NuGet will add a reference to Microsoft.Graphics.Canvas assembly what contains all Win2D classes. So, it’s easy to open this assembly and find all namespaces and classes at the same place.
Just open Microsoft.Graphics.Canvas.UI.Xaml namespace and find all XAML controls there. You can see that there are two classes based on UserControl: CanvasAnimatedControl and CanvasControl. Additionally, there is CanvasSwapChainPanel class which is derived from Grid class. Let’s see these classes in more details.
First of all you need to add Microsoft.Graphics.Canvas.UI.Xaml namespace to your XAML file:
xmlns:canvas="using:Microsoft.Graphics.Canvas.UI.Xaml"
Right after that you can use the controls there and we will start with the simplest one, CanvasControl.
<canvas:CanvasControl Draw="CanvasControl_Draw"></canvas:CanvasControl>
CanvasControl is a place for drawing but we need some places to implement drawing algorithms. That’s why CanvasControl has two important events: Draw and CreateResources. Let’s start with Draw event and look at the code below:
int i = 0; private void CanvasControl_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args) { i++; CanvasTextFormat format = new CanvasTextFormat() { FontSize = 96, FontWeight = FontWeights.Bold }; args.DrawingSession.DrawText($"Hello {i}", 200, 100, Colors.Green, format); }
In this event handler we used DrawText method to print text. You can find lots of different methods inside CanvasDrawingSession class and it’s easy to use. Pay special attention that I injected integer variable to the output string. Thanks to this variable we can see when our event handler works. Just run the application and try to work with the window for some time. You will see that Draw event fires when it’s needed for Windows to redraw the window. So, if you change window size your counter will increase but if you don’t touch widow at all the counter will remain the same.
That’s why CanvasControl works fine for “static” content.
The second important event for CanvasControl is CreateResources event. Let’s look at our code again and you can see that the application creates CanvasTextFormat object each time when Draw event handler is invoked. Of course, this object is not very complex but in case of real scenarios developers need to make lots of objects first before they can start drawing and additionally developers should guarantee that all objects will be created before event handler is invoked. There are two ways to initialize all needed objects: assign Draw event handler dynamically (right after initialization methods) or use CreateResources event handler. The second method is more straightforward and implements some stuff for asynchronous programming.
Let’s modify our XAML page:
<canvas:CanvasControl Draw="CanvasControl_Draw" CreateResources="CanvasControl_CreateResources"></canvas:CanvasControl>
And here is code:
CanvasLinearGradientBrush brush; CanvasTextFormat format; private void CanvasControl_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args) { brush = new CanvasLinearGradientBrush(sender, Colors.Red, Colors.Green); brush.StartPoint = new Vector2(50, 50); brush.EndPoint = new Vector2(300, 300); format = new CanvasTextFormat() { FontSize = 96, FontWeight = FontWeights.Bold }; } int i = 0; private void CanvasControl_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args) { i++; args.DrawingSession.DrawText($"Hello {i}", 50, 50, brush, format); }
You can see that I used CanvasControl_CreateResources method to make a brush for my text.
Using CreateResource event handler you can guarantee that Draw event will not be fired up to the event handler is completed.
In the previous example we used synchronous event handler for CreateResource method but even for simple image loading action you need to call asynchronous APIs. Of course advanced C# developers will add async keyword before the event handler signature but this approach doesn’t work for CreateResources event handler. Instead of async keyword you should use the following approach:
CanvasImageBrush brush; CanvasTextFormat format; private void CanvasControl_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args) { args.TrackAsyncAction(CreateResources(sender).AsAsyncAction()); } async Task CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender) { brush = new CanvasImageBrush(sender); brush.Image= await CanvasBitmap.LoadAsync(sender, "Assets/drone.jpg"); format = new CanvasTextFormat() { FontSize = 96, FontWeight = FontWeights.Bold }; } int i = 0; private void CanvasControl_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args) { i++; args.DrawingSession.DrawText($"Hello {i}", 50, 50, brush, format); }
You can see that we used parameter of event handler to call TrackAsyncAction method and this method can get async method as a parameter.
Ok. Thanks to CanvasControl we can draw “static” content and it’s fine for many scenarios. For example, you can use this control to apply effects to images, you can create graphs or high performance text rendering application. But you cannot use CanvasControl for developing simple 2D games or similar applications which should present “dynamic” content. In order to make it, Win2D provides another control: CanvasAnimatedControl.
We can use almost the same code, slightly modifying it:
<canvas:CanvasAnimatedControl Draw="CanvasAnimatedControl_Draw" CreateResources="CanvasAnimatedControl_CreateResources"></canvas:CanvasAnimatedControl> CanvasImageBrush brush; CanvasTextFormat format; async Task CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedControl sender) { brush = new CanvasImageBrush(sender); brush.Image= await CanvasBitmap.LoadAsync(sender, "Assets/drone.jpg"); format = new CanvasTextFormat() { FontSize = 96, FontWeight = FontWeights.Bold }; } int i = 0; private void CanvasAnimatedControl_Draw(Microsoft.Graphics.Canvas.UI.Xaml.ICanvasAnimatedControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedDrawEventArgs args) { i++; args.DrawingSession.DrawText($"Hello {i}", 50, 50, brush, format); } private void CanvasAnimatedControl_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args) { args.TrackAsyncAction(CreateResources(sender).AsAsyncAction()); }
You can see the same text but counter will increase very fast (every 16.6 ms or 60 steps per second). So, CanvasAnimatedControl is better to create a large number of dynamic objects that are flying, firing, jumping etc. Of course, it’s not enough to have just Draw method because in real games you need to guarantee timing and have the same speed on all devices. So, a game loop is more complex than a simple Draw method. But developers of Win2D know about it and you can find some more events and useful properties in CanvasAnimatedControl class.
Let’s review those properties and events slightly modifying the previous Draw even handler:
private void CanvasAnimatedControl_Draw(Microsoft.Graphics.Canvas.UI.Xaml.ICanvasAnimatedControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedDrawEventArgs args) { i++; args.DrawingSession.DrawText($"Hello {i}", 50, 50, brush, format); sender.Paused = true; }
You can see that we used Paused property to make pause in our game loop. And if you don’t touch the application you can see that the counter is frozen but once you resize the window the counter will grow fast. It happens because in the pause mode draw method is called once Windows needs to redraw the window. So, it’s better to use Draw event handler only for drawing. If you need to change any data in the game loop then it is better to use Update event. Update event handler will be called before Draw method and in case of pause Update event handler will be frozen.
private void CanvasAnimatedControl_Update(Microsoft.Graphics.Canvas.UI.Xaml.ICanvasAnimatedControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedUpdateEventArgs args) { i++; }
In general, Draw+Update event handlers should be called every 16.6 ms but if you have a slow device and running timeframe is greater, Update call may be passed. So, you can see several Draw calls before Update call. It allows saving same speed of the game but you can see some drawing problems. If it happens not very often it’s not very critical but in some cases you can decrease the elapsed time for each step (for example, 30 frames per second). You can easily do it using TargetElapsedTime property.
Additionally, you can use events like GameLoopStarting and GameLoopStopped. These events fire before and after the game loop and can be used for scene initialization and for destroying all objects from memory respectively.
Pay special attention that all event handlers fire in separate gaming loop. So, any actions there will not block interface thread. But developers should think how to pass the data to the gaming thread from the interface one. The best way is calling RunOnGameLoopThreadAsync method from the interface thread:
await myCanvas.RunOnGameLoopThreadAsync(()=> {/*call something here*/});
The last control in Microsoft.Graphics.Canvas.UI.Xaml namespace is CanvasSwapChainPanel. If you know something about game development you should have heard about the swap chains. The main idea is have two or more buffers (pages) for your game. The first page you use for presenting an updated scene on the screen while updating the second one behind the scene. You should not use CanvasSwapChainPanel class or CanvasSwapChain with CanvasAnimatedControl because the last one uses swap chains internally. But if you want to implement your own CanvasAnimatedControl or a similar control you can use both classes.
var swapChain = new CanvasSwapChain(device, width, height, dpi); swapChainPanel.SwapChain = swapChain; //draw swapChain.Present();
Ok, right now we have some knowledge how to draw something and what are the differences between controls there. So, it’s time to talk about other useful classes and I am going to start with image effects.
Image effect is the most growing category in Win2D and just several days ago they added 10 more effects but we are still waiting for some classes, which help to create our own custom effects. In any case Win2D API already contains more than 50 effects, so, you definitely can find some useful filters there. Here is an example how to apply two effects to the same image:
GrayscaleEffect effect; GaussianBlurEffect blurEffect; async Task CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender) { effect = new GrayscaleEffect(); var bitmap=await CanvasBitmap.LoadAsync(sender, "Assets/drone.jpg"); effect.Source = bitmap; blurEffect = new GaussianBlurEffect(); blurEffect.BlurAmount = 5; blurEffect.Source = effect; } private void myCanvas_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args) { args.DrawingSession.DrawImage(blurEffect); } private void myCanvas_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args) { args.TrackAsyncAction(CreateResources(sender).AsAsyncAction()); }
In this example I used blur and grayscale filters. Since I don’t have any other logic I used CreateResources event handler.
If you use the same effect for the same image you can simply apply this effect in advance and reuse it later. But in many cases you need to build more complex objects which should contain not just effect but some drawing etc. In this case you can use CanvasCommandList class in order to prepare and preserve your object for future use. I just slightly modified the previous example:
GrayscaleEffect effect; GaussianBlurEffect blurEffect; CanvasCommandList cl; async Task CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender) { cl = new CanvasCommandList(sender); using (CanvasDrawingSession clds = cl.CreateDrawingSession()) { effect = new GrayscaleEffect(); var bitmap = await CanvasBitmap.LoadAsync(sender, "Assets/drone.jpg"); effect.Source = bitmap; blurEffect = new GaussianBlurEffect(); blurEffect.BlurAmount = 5; blurEffect.Source = effect; clds.DrawImage(blurEffect); } } private void myCanvas_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args) { args.DrawingSession.DrawImage(cl); } private void myCanvas_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args) { args.TrackAsyncAction(CreateResources(sender).AsAsyncAction()); }
In this example we created our own CanvasDrawingSession and used it to draw all needed objects and to apply filters there. Right after that we destroyed CanvasDrawingSession and preserved CanvasCommandList for future use (making global reference on it). Thanks to this approach you can create all complex objects in advance and later draw them as images.
When I told about image effects I didn’t mention geometry and text but you can apply effects to these entities as well. In order to do in you need to use CanvasRenderTarget class for converting vector data to pixels:
private void myCanvas_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args) { var myBitmap = new CanvasRenderTarget(sender, 300, 300); using (var ds = myBitmap.CreateDrawingSession()) { ds.DrawText("Hello", 0, 0, Colors.Green, new CanvasTextFormat() {FontSize=96, FontWeight=FontWeights.Bold }); } var blur = new GaussianBlurEffect { BlurAmount = 10, Source = myBitmap }; args.DrawingSession.DrawImage(blur); }
Running this code you will see the following window:
I think this is enough for the first look at Win2D. I missed lots of classes that help to work outside XAML or allow working with images pixel by pixel but I hope that it’s easy to understand using documentation because Win2D is easy.
Arduino shield for Raspberry Pi 2 or How to solve problems with PWM, analog input and not burn down the apartment with a soldering iron
I have already published some posts where I told about Raspberry, Arduino and other boards as about boards for your own prototypes. Using these boards you can easily create something before you invite real engineers, who will make a custom board for you based on your needs. And it’s clear that all existing boards have some limitations because it’s simply not possible to create something universal that can satisfy everybody (something small, Windows 10 powered, with 60 analog pins, WiFi on board and what will not require much power). That’s why you can find lots of different micro boards on the market and Microsoft published general requirement for supported hardware but doesn’t focus on specific boards. So, once you make a prototype using available hardware you may start to think about a board which implements all needed features.
But previous paragraph doesn’t answer the question: how to create a prototype using Windows 10 IoT Core and using available boards on the market such as Raspberry Pi 2 if I still cannot use PWM, Analog signals and even some type of digital signals (pulseIn implementation)? The short answer is: keep calm and think about different boards as just a different type of brain.
I am not so strong in biology but I like to catch crabs. If you cook a crab, try to find the brain inside. Frankly speaking, I am not sure if it’s there but according to rumors in Internet it exists. In any case, if somebody asks me to implement a crab, I think that I will use just several capacitors, sensors and the simplest transistors but I will not use any CPUs at all. It’s a simple binary shifter: move all type while food sensor send low signal and change the direction if too much light (light sensor is sending low signal) is available (just go deeper). In Ukraine I keep some hamsters. I am sure that they have brain and I think that ATMega 328P-PU (Arduino Uno chip) will work fine for hamster implementation. In case of dogs it’s better to have something more advanced, faster and with ability to run some scenarios in background – I think that ARM Cortex A7 CPU should be good for this task.
So, select the brain you need. Pay special attention that the same things can have different types of brain due to different number of features. For example, I have a dream to build a drone that will able to find and destroy other drones. Of course, I need a way to use OpenCV, to implement lots of different algorithms etc. In my case, ARM Cortex A7 is must. But if you want to implement a simple RC drone and use CPU just for stabilization algorithm – ATMega will work much better.
Ok. You decided to use Cortex A7 CPU and found Raspberry PI 2 on the market which supports Windows 10 IoT Core. Thanks to Windows 10 I can develop my software very quickly using well known APIs and tools (like Visual Studio). Let’s imagine that you want to build the same drone which will intercept other drones. Of course, it’s easy to use camera, OpenCV and other technologies but stabilization algorithms should be there as well. You need a way to use PWM in order to power brushless motors, read digital signals from RC controller (like manual pilot system etc.). So, we just returned to the initial question: where is PWM…?
Raspberry Pi 2 doesn’t support software PWM. Of course, you can emulate it using software but quality of this emulation will be low and I think that the drone will be self-destructed during the first flight. But I still don’t understand why you don’t ask me about other features which are not available for Raspberry: where is embedded gyroscope? where is embedded WiFi? Where is embedded toaster?
Usually, if you need some sensors you simply buy and attach them to the board. Using I2C, SPI, Serial, you can communicate with all external stuff and implement that you need. So, if you need PWM or analog input, simply attach it.
BTW: By accident I found a Raspberry shield for copters. It’s expensive but it exists
I made some research and even published the post about analog input for Raspberry but finally I decided that the best solution for PWM, Analog and digital inputs is Arduino. It was adopted by huge number of developers and it’s easy to find how to implement you code which should work with particular external sensors, shields etc. Of course, Raspberry PI and Arduino board have different form factors and Arduino board cannot be stacked on Raspberry, so I decided to build my own Arduino from scratch and build it like a shield for Raspberry.
Visiting http://www.bc-robotics.com/ which is physically located in Vancouver Island I bought the following things:
· ATMega 328P-PU with bootloader (you can buy it without bootloader but you need another Arduino to flash bootloader there)
· Some 22 pF capacitors, 0.1uF capacitors and one 10uF capacitor
Additionally, you need to make sure that you have different resistors (at least 10 kOhm and 220 Ohm) at least one led, a button and Serial to USB converter. In case of a converter you need to make sure that it has DTR pin (not just RX and TX) because I have a converter which has CTS pins, so I bought a new oneL
Finally, I spent around 20 Canadian dollars for components. I believe that I could have bought all this things for 10-15 dollars but I am not ready to wait a month for a package from China. In case of BC Robotics I got all these things in 48 hours.
On the next step you need to find a schema how to build own Arduino from scratch. I used this one: http://shrimping.it/blog/shrimp/. I decided to use Protected Shrimp but I simply removed the button from the circuit in order to save some space.
Just one advice there: assemble everything using a breadboard because Raspberry Proto Strip Board has similar architecture. Once you have tested your circuit it’s possible to move all components to the strip board one by one.
In 30 minutes I got this:
Now you can use USB to Serial in order to apply all needed software to your Arduino. It depends on the method you select to make a connection between Arduino and Raspberry. For example, you can use StandardFirmata sketch, which is installed with Arduino SDK and you can use I2C or Serial communications.
In case of my drone, probably, I will create my own software for Arduino because I want to implement all stabilization algorithms there and I have another important tasks for Raspberry. Because I discovered some problems with serial pins on Raspberry + Windows 10 (you still can use USB to Serial converter but….) I decided to connect Raspberry and Arduino I2C pins using simple wires. Once I select the right communication protocol I will use soldering iron to fix connection between Raspberry and Arduino.
Finally, I have ordered one more Strip Board to make one more shield with all needed sensors which will be connected to Arduino. And right after that I may forget about hardware and pay all my attention to software where I will use C#, Universal Windows Platform and Visual Studio – all things that I like!
In summary I want to emphasize two things:
· There are no problems with specific hardware features – just do it!
· If I decide to create a commercial version of my drone, I will hire some engineers and ask them to make my own board which will be ready for Windows 10 IoT core and will contain all needed sensors.