51: UWP gotchas and tips
Coming from years of experience with WinForms and WPF, UWP is weird. I am continuously having surprises (sometimes good, but sometimes poor) since working with UWP lately. Some of those gotchas are almost like in a way that they are designed purposely to screw you up. But, of course, there are some things better than its predecessors.
Here is a list of what I have learned:
Default Binding is OneTime
The default mode when using “x:Bind” is OneTime
Previously, if using Binding
, the default is “smart”, but mostly, it will be OneWay
. (Ref: https://docs.microsoft.com/en-us/dotnet/api/system.windows.data.binding.mode)
If we have a binding like this:
Visibility="{Binding PhotosLoaded}"
It will automatically refresh the visibility when the property is modified.
However, now we have to do if using x:Bind
:
Visibility="{x:Bind ViewModel.PhotosLoaded, Mode=OneWay}"
If we do not specify the Mode, it will be OneTime
and it will not refresh the visibility if the property is modified. At least, it could do something smart like before.
Titlebar can Disappear!
To trigger this, you would have to be like me, who tried to test the Acrylic material, and extend the entire view to the title bar by doing what Microsoft suggest to do:
https://docs.microsoft.com/en-us/windows/uwp/design/style/acrylic#extend-acrylic-into-the-title-bar
However, what they do NOT tell you is, once you try this, the Titlebar in your application will be gone forever. Even after you remove the piece of code.
It comes out, that piece of code will be written in registry (double face-palm!).
See this page how to resolve it:
https://stackoverflow.com/questions/46978907/application-title-bar-disappeared-uwp-app
Cannot access files by path anymore
This is probably understandable, for security reason. In UWP, we can no longer load DLL files using Assembly.Load
. Hence, it is impossible to do dynamic assembly loading in runtime, which is very useful in building WinForm and WPF applications, because it allows the application itself to extend features or even update UI components in runtime.
However, for file access, even with the proper capacity enabled, I still cannot directly access them when using Path. For example, the following code will fail:
StorageFile selectedFile = await fileOpenPicker.PickSingleFileAsync(); if (selectedFile != null) { BitmapImage image = new BitmapImage(BuildUri(selectedFile.Path));
It will throw out an exception immediately when trying to read the file using Path. The error message does not provide enough context. Reading this page also does not have the concrete answer on how to fix:
Finally, it comes out the correct way will be reading from the Stream
StorageFile selectedFile = await fileOpenPicker.PickSingleFileAsync(); if (selectedFile != null) { using (var stream = await selectedFile.OpenStreamForReadAsync()) {
For say if you want to display a list of selected images’ thumbnail, we will have to do this:
IReadOnlyList<StorageFile> selectedFiles = await fileOpenPicker.PickMultipleFilesAsync(); foreach (var file in selectedFiles) { var thumbnail = await file.GetThumbnailAsync(ThumbnailMode.PicturesView, 400); var bitmapImage = new BitmapImage(); bitmapImage.DecodePixelWidth = (int)(this.ActualWidth / 4); await bitmapImage.SetSourceAsync(thumbnail);
This extra security thing in UWP is simply annoying.
Personally I really don’t like this constraint. For example, if I want to write a shareware today (or just like the old days), I can use WPF and publish it through my website, without any of these security constraints.
However, I guess I will lose the possibility to publish to Microsoft Store, or even potentially it becomes available in other environments. After all, UWP stands for “Universal Windows Platform”, if I want it target to other devices, I probably want to live with those constraints.
Bool To Visibility, but Not Invert Bool To Visibility
It is interesting that UWP comes up with the idea of having a default converter that converts Boolean to Visibility. I think it makes sense, after all, we probably all have written a converter that does that.
However, if we have a control that needs the invert bool to visibility, meaning, if it’s false, then it is visible, otherwise it is collapsed. This is not supported, when trying:
Visibility="{x:Bind PhotosLoaded, Converter={StaticResource InvertBoolConverter}}
I believe the reason behind this is, if we do not specify any converter, UWP will automatically give it one since its input is Boolean but expected value is Visibility. But when we explicitly specify a converter, then UWP will not do anything. Therefore, the above line will throw an error message saying the type cannot be converted.
What we could do instead is having a helper function somewhere:
public static Visibility BoolToInvertedVisibility(this bool boolValue) => boolValue ? Visibility.Collapsed : Visibility.Visible;
Next in the XAML, we can bind to the function call:
Visibility="{x:Bind helper:VisibilityExtensions.BoolToInvertedVisibility(ViewModel.PhotosLoaded), Mode=OneWay}">
This new binding style is interesting, but also a surprise if I did not get help from someone else.
There are some other smaller gotchas, I may have another post later.
But this is the list for today.