Category Archives: Windows 10

MAUI setting the apps dimensions on a Windows Desktop

I have a MAUI application, designed to an extent as mobile-first. In other words it looks good on a mobile, phone or tablet device in full screen mode. But I really want the app to work and look good (on start up) on Windows Desktop. Ofcourse Windows will just give my main app window a size and I need to do whatever I can to ensure the app looks good.

It’s be so much simpler if I could just set the dimensions of my main window (at start up) to something that looks good. If the user resizes, that’s fine but just starting with a good default makes everything look better.

Okay so that’s the problem at hand, how to solve this?

The first thing is, I thought, I could just change the Platforms/Windows/App.xaml.cs, but nothing obvious there to allow this. If we look at App.xaml.cs we can override the CreateWindow method, so let’s do that – here’s the code

public partial class App : Application
{
  public App()
  {
    InitializeComponent();
    MainPage = new AppShell();
  }

  protected override Window CreateWindow(IActivationState? activationState)
  {
    var window = base.CreateWindow(activationState);

#if WINDOWS
    if (DeviceInfo.Idiom == DeviceIdiom.Desktop)
    {
      window.Width = 500;
      window.Height = 700;
    }
#endif

    return window;
  }
}

It’s pretty self-explanatory, we use conditional compilate using #if WINDOWS to only include the code for a Windows build, but as I also have a Windows tablet I figured I’d also check that the idiom is Desktop before I try to set the window dimensions. All pretty straight forward – although not quite.

The problem is that strangely ANDROID and the likes exist a defines, but seemingly not WINDOWS. We can fix this ourselves in one of two ways.

  • Open the .csproj file and for the net7.0-windowsxxx PropertyGroups add the following
    <DefineConstants>$(DefineConstants);WINDOWS</DefineConstants>
    
  • Open the project’s properties, locate the Build | General then for the “Conditional compilation symbols” for net7.0-windowsxxx entries, add
    $(DefineConstants);WINDOWS
    

This doesn’t fully solve things, well it does but Visual Studio will show the code in Create Window as grayed out as if the conditional compilation directive is excluding the code from the build – it’s not, but it looks that way.

Anyway, now we are able to size the main Window on Windows at start-up.

Is your Universal Windows application running on a device which supports this hardware ?

Just going through some old draft posts and found this one, which might be of use to somebody. Let’s call it a Quick Post as there’s not too much substance…

When writing a Universal Windows application we’re basically trying to write code that will work on multiple devices. But different devices have different capabilities. For example a mobile phone has a back button, so we might want to handle the back button BackPressed event in some way, but this event is not available when the application is run on a desktop machine.

Obviously it’d be no good using #define to enable/disable code as we want the application’s code to be universal and run “as-is” on multiple devices. So we need a method call at runtime to tell us whether the device supports the BackButton. Or more specifically whether it supports the HardwareButtons input mechanism.

So to check whether we can hook up code to the BackPressed event we might code the following

if(ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
{
   HardwareButtons.BackPressed += HandleBackPressed;
}

File explorer extended search in Windows

File Explorer has (as we all know) a search box in the top right, ofcourse we can enter some text and File Explorer will search for filenames with that text and text within files, but there are more options to tailor our search.

See Common File Kinds.

Let’s look at some examples

File name search

If we prefix our search term with file: like this

file: MyFile
file:.sln

Then we only get search results for all files with the text as part of the filename or file extension.

File content search

If we prefix our search term with content: like this

content: SomeContent

Then we only get search results from within files (i.e. text search).

Kind

We can use the kind option along with file type, such as text, music etc. See Common File Kinds.

kind:text

The above list all text files.

Other file options

We can also use the following, other file options, for example finding

datemodified:lastweek
modified:lastweek
modified:05/10/2022
size:>500

The first two options are the same and list files modified last week. The size option lists files with a size larger than 500 bytes.

See also File Kind: Everything.

Boolean Operators

As you can see we can also use Boolean Operators.

Adaptive triggers in a universal app.

Adaptive triggers are part of the Universal Windows application and part of Windows 10.

With a universal app. you can begin writing an application which can target multiple Windows platforms/devices, for example mobile, tablet and desktop.

When writing UI code for a variety of devices you’ll come across the problem where, for example, a button on a desktop needs to be place elsewhere when used on a mobile phone and so on.

Adaptive triggers allow us to customize layout based upon the dimensions of the device we’re running on. But wait ! This statement is slightly misleading. The trigger actually has nothing to do with the device and everything to do with the Window size of the application on the device. So in reality an AdaptiveTrigger is more like a responsive design feature in that when the Window is expanded, it’s possible one layout is used and when the Window is reduce in size maybe another layout is used.

To define an AdaptiveTrigger we use the VisualStateManager and create StateTriggers, which contain our AdaptiveTrigger(s).

For example, let’s define VisualState and AdapterTriggers for a desktop with a minimum width of 1024 pixels and a phone with minimum width of 320 pixels and we’ll a the button display differently for each device.

Note: the x:Name is there just for descriptive purposes in this example.

<Grid>
   <VisualStateManager.VisualStateGroups>
      <VisualStateGroup>
         <VisualState x:Name="DeskTop">
            <VisualState.Setters>
               <Setter Target="button.(FrameworkElement.HorizntalAlignment)" Value="Left" />
            </VisualState.Setters>
            <VisualState.StateTriggers>
              <AdaptiveTrigger MinWindowWidth="1024" />
           </VisualState.StateTriggers>
         </VisualState>
         <VisualState x:Name="Phone">
            <VisualState.Setters>
               <Setter Target="button.(FrameworkElement.HorizntalAlignment)" Value="Right" />
            </VisualState.Setters>
            <VisualState.StateTriggers>
              <AdaptiveTrigger MinWindowWidth="320" />
           </VisualState.StateTriggers>
         </VisualState>
      </VisualStateGroup>
   </VisualStateManager.VisualStateGroups>
</Grid>

Removing the Windows 10 search highlights icon

At some point in the upgrades for Windows 10 we ended up with some silly little image on the search text box on the Windows 10 desktop. Turns out this is some form “Search Highlights” functionality. First thing I wanted to do is remove it and whilst I did this on one machine, I just booted my laptop and noticed the stupid thing on this machine, so…

To remove this…

  • Right mouse click on the task bar
  • Select the Search submenu
  • Uncheck the Show search highlights

Setting up a Haskel development environment on Windows 10

I wanted to try out Haskell on Windows 10 and figured I’d probably use Visual Code for writing code, here’s the steps to get everything installed and configured.

The simplest way to get everything installed seems to be using chocolatey, see Getting Started.

  1. Install chocolatey
  2. Run Powershell in admin mode and then run choco install haskell-dev
  3. Finally, from Powershell run refreshenv

If all of these steps worked, then just run ghc from the Powershell or a command prompt and you should see some output from ghc.

Let’s now set-up Visual Code (I’ll assume you’ve already got Visual Code installed). There’s a few plugins/extensions for Visual Code for use with Haskell. From Visual Code extensions option…

  • Add Haskell syntax highlighter
  • Also add Haskell-linter
  • To configure the linter, from Visual Code select, File | Preferences | Settings, switch to the code view and add the following
    "haskell.hlint.executablePath": "C:\\ProgramData\\chocolatey\\lib\\ghc\\tools\\ghc-8.10.1\\bin\\ghc.exe"
    

    Chocolatey installs the files into C:\ProgramData\chocolatey\lib, however if you’ve installed ghc by some other means of within another folder then replace the folder with your location.

Finally, let’s write a Haskell “Hello World”. Within Visual Code create the file HelloWorld.hs and add the following code

main = putStrLn "Hello, world!"

Open the Visual Code integrated terminal or open your preferred terminal/shell and from the folder that you saved your HelloWorld.hs file, run

ghc HelloWorld.hs

If all goes to plan you’ll compile the Haskell file to a HelloWorld.exe and you’re done for now.

Using the Windows Subsystem for Linux

Whilst I have Linux machines available to me, they’re not always powered up or the remoting

See Windows Subsystem for Linux Installation Guide for Windows 10 for details on installing the WSL.

For completeness here’s the steps I took.

  • Run PowerShell as Admin and then execute the following

    Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
    
  • Go to the Microsoft Store and type Run Linux on Windows into the search text box. In the store currently, there’s the options of Ubuntu, openSUSE Leap 42, SUSE Linux Enterprise Server 12, Debian and Kali Linux.

    Install your preferred distro – I went for Ubuntu simply because that’s what I have on most of my Linux boxes.

  • Once installed you’ll need to go to the command prompt | Properties and select the Options tab. From here ensure that Use legacy console (requires relaunch) is unchecked.

Once everything is initialized you’ll be in the user’s (whatever user name you created) home folder – on Windows this folder is stored in C:\Users\{username}\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs\home

We can access the C drive using

cd /mnt/c

Running the Linux from Windows

When you want to run the Windows Subsystem for Linux going forward, simply execute

wsl

Enumerating available devices in UWP

In my previous post (Displaying the device picker in a UWP application) I showed how to reuse the UWP device picker flyout within an application.

However, it’s possible that the developer would prefer to offer devices in some alternate UI or, of course, simply locate a known device for an application to use. In the previous post I looked at filtering for Bluetooth devices and those are what I’m after for a little application I’m writing in which I do not require the DevicePicker UI.

Filtering

Before I get into code to enumerate the devices, I’ll first expand on the lines of code from my previous post, that look like this

BluetoothDevice.GetDeviceSelectorFromPairingState(false)

Each of the lines like this one actually returns a string which is an Advanced Query Syntax (AQS) language query. So for example this line will produce the following string (formatted to make it more readable)

System.Devices.DevObjectType:=5 AND 
System.Devices.Aep.ProtocolId:=\"{E0CBF06C-CD8B-4647-BB8A-263B43F0F974}\" AND 
(System.Devices.Aep.IsPaired:=System.StructuredQueryType.Boolean#False OR
System.Devices.Aep.Bluetooth.IssueInquiry:=System.StructuredQueryType.Boolean#True)

For completeness, here’s the results of each of the other GetDeviceSelectorFromPairingState calls

BluetoothLEDevice.GetDeviceSelectorFromPairingState(false)

System.Devices.DevObjectType:=5 AND 
System.Devices.Aep.ProtocolId:=\"{BB7BB05E-5972-42B5-94FC-76EAA7084D49}\" AND 
(System.Devices.Aep.IsPaired:=System.StructuredQueryType.Boolean#False OR 
System.Devices.Aep.Bluetooth.IssueInquiry:=System.StructuredQueryType.Boolean#True)

BluetoothLEDevice.GetDeviceSelectorFromPairingState(true)

System.Devices.DevObjectType:=5 AND 
System.Devices.Aep.ProtocolId:=\"{BB7BB05E-5972-42B5-94FC-76EAA7084D49}\" AND 
(System.Devices.Aep.IsPaired:=System.StructuredQueryType.Boolean#True OR 
System.Devices.Aep.Bluetooth.IssueInquiry:=System.StructuredQueryType.Boolean#False)

BluetoothDevice.GetDeviceSelectorFromPairingState(true)

System.Devices.DevObjectType:=5 AND 
System.Devices.Aep.ProtocolId:=\"{E0CBF06C-CD8B-4647-BB8A-263B43F0F974}\" AND 
(System.Devices.Aep.IsPaired:=System.StructuredQueryType.Boolean#True OR 
System.Devices.Aep.Bluetooth.IssueInquiry:=System.StructuredQueryType.Boolean#False)

Hence we could now create our own AQS query to search for devices.

See Using Advanced Query Syntax Programmatically for more information on AQS.

Enumerating over devices (simple approach)

A simple approach to enumerating over all the available devices is to use the DeviceInformation.FindAllAsync() method, which is async/await compatible, hence we simply use it like this

var devices = await DeviceInformation.FindAllAsync();

// output all devices
foreach (var device in devices)
{
   Debug.WriteLine(device.Name);
}

Obviously this is a little over the top if we’re looking for a specific device or set of devices. In such cases we can create an AQS query and pass this into one of the FindAllAsync overloads. Hence to recreate my previous post’s query looking for all Bluetooth devices we might prefer to use

var devices = await DeviceInformation.FindAllAsync(
    BluetoothDevice.GetDeviceSelectorFromPairingState(
        false));

Whilst this solution to the problem of locating devices may fulfil many of the developer’s requirements, an area it fails on is that once the developer has a list of devices they do not have a way to tell when devices are turned off/disabled/or otherwise no longer available. In such situations it’s better to watch for device changes.

Watching for device changes

The DeviceInformation.CreateWatcher method allows the developer to query for devices and via events, watch for items to be added, updated or removed. This would suit an RX type of implementation.

Here’s some code that demonstrates possible usage of the CreateWatcher

try
{
   deviceWatcher = DeviceInformation.CreateWatcher(
      BluetoothDevice.GetDeviceSelectorFromPairingState(false), 
      null,
      DeviceInformationKind.Device);

      deviceWatcher.Added += (watcher, args) =>
      {
         Debug.WriteLine($"Added {args.Name}");
      };
      deviceWatcher.Updated += (watcher, args) =>
      {
         Debug.WriteLine($"Updated {args.Id}");
      };
      deviceWatcher.Removed += (watcher, args) =>
      {
         Debug.WriteLine($"Removed {args.Id}");
      };
      deviceWatcher.EnumerationCompleted += (watcher, args) => 
      { 
         Debug.WriteLine("No more devices found"); 
      };
      deviceWatcher.Start();
}
catch (ArgumentException ex)
{
   Debug.WriteLine(ex.Message);
}

Again we’re using the AQS created via the GetDeviceSelectoryFromPairingState method and in this simplistic example, we simply subscribe to the Added/Updated/Removed and EnumerationCompleted events to output what devices have been added etc. We also need to be aware of possible ArgumentExceptions, such as incorrectly formatted GUID’s etc. See DeviceInformation Class for a more complete example of this usage.

Displaying the device picker in a UWP application

Developers can use the UWP device picker flyout control within their application to allow the user to select a device from a list of available devices. The list can be filtered to display only particular types of devices.

For example, here’s how to display the DevicePicker flyout without filtering, i.e. showing all available devices

var devicePicker = new DevicePicker();
devicePicker.Show(new Rect(x, y, width, height));

In this case we simply create a DevicePicker and call the Show method which is passed a rectangle where you want the picker to flyout from.

There’s an overload Show method which allows a placement as well.

If you run this code in your application you’ll find that devices are enumerated over and displayed as they are found, so obviously this may take a little bit of time to enumerate all devices.

In most cases we probably want to filter the DevicePicker for a certain type of device. For example if we want to locate all Bluetooth devices we would use the following

var devicePicker = new DevicePicker();

devicePicker.Filter
   .SupportedDeviceSelectors.Add(
      BluetoothLEDevice.GetDeviceSelectorFromPairingState(false));
devicePicker.Filter
   .SupportedDeviceSelectors.Add(
      BluetoothLEDevice.GetDeviceSelectorFromPairingState(true));
devicePicker.Filter
   .SupportedDeviceSelectors.Add(
      BluetoothDevice.GetDeviceSelectorFromPairingState(false));
devicePicker.Filter
   .SupportedDeviceSelectors.Add(
      BluetoothDevice.GetDeviceSelectorFromPairingState(true));

devicePicker.Show(new Rect(x, y, width, height));

In this case we’ve filtered the DevicePicker so it will only display BluetoothLE devices and Bluetooth devices both in a paired (the true parameter) or unpaired (the false parameter).

Obviously we’re going to want to get at the device information or the selected device, when using the Show method, we will need to subscribe to the DevicePicker’s DeviceSelected event, for example

devicePicker.DeviceSelected += (picker, args) =>
{
   // outputs the selected device name
   Debug.WriteLine(args.SelectedDevice.Name);
};

We can also respond to a couple of other events such as the DevicePickerDismissed and DisconnectButtonClicked.

As an alternate to the event approach, we could switch from using the Show method to use the async/await implementation which combines the Show and the DeviceSelected into he PickSingleDeviceAsync method, i.e.

var device = await 
   devicePicker.PickSingleDeviceAsync(
      new Rect(x, y, width, height));
// outputs the selected device name
Debug.WriteLine(device.Name);

Where’s the Windows 10 mobile emulator?

So I’ve been working on some ideas on cross platform .NET development using Visual Studio 2015 and Xamarin. I have the Windows UWP application working fine on Windows 10 but wanted to see how it would look on Windows 10 phone – surprisingly I found the Windows 10 phone emulator didn’t exist as part of the Visual Studio installation (possibly I missed a check box when install or the likes) but it’s easy enough to get.

Just go to Downloads and tools for Windows 10 in the Other download options section there’s a Download the emulator link. From here we can download and install the Windows 10 mobile emulator.

Take a look as Test with the Microsoft Emulator for Windows 10 Mobile Test with the Microsoft Emulator for Windows 10 Mobile also which gives some useful information on using the emulator in different scenarios/configurations.