mvvm pattern

This commit is contained in:
2021-11-12 13:03:12 +00:00
parent ad0779c454
commit 8fb0b6238e
9 changed files with 232 additions and 59 deletions

View File

@@ -1,4 +1,6 @@
using System; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Toolkit.Mvvm.DependencyInjection;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -39,6 +41,15 @@ namespace BlueControl.uwp
/// <param name="e">Details about the launch request and process.</param> /// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs e) protected override void OnLaunched(LaunchActivatedEventArgs e)
{ {
Ioc.Default.ConfigureServices(
new ServiceCollection()
.AddSingleton<Services.IShellService, Services.UiShellService>((input) => new Services.UiShellService(Window.Current.Dispatcher))
.AddSingleton<Services.IBluetoothService, Services.BluetoothService>()
.BuildServiceProvider());
Frame rootFrame = Window.Current.Content as Frame; Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content, // Do not repeat app initialization when the Window already has content,

View File

@@ -123,6 +123,10 @@
<DependentUpon>MainPage.xaml</DependentUpon> <DependentUpon>MainPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\BluetoothService.cs" />
<Compile Include="Services\IBluetoothService.cs" />
<Compile Include="Services\IShellService.cs" />
<Compile Include="Services\UiShellService.cs" />
<Compile Include="ViewModels\MainPageViewModel.cs" /> <Compile Include="ViewModels\MainPageViewModel.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -151,9 +155,21 @@
</Page> </Page>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection">
<Version>6.0.0</Version>
</PackageReference>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform"> <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.2.12</Version> <Version>6.2.12</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Toolkit.Mvvm">
<Version>7.1.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.Xaml.Behaviors.Uwp.Managed">
<Version>2.0.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Views\" />
</ItemGroup> </ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' "> <PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion> <VisualStudioVersion>14.0</VisualStudioVersion>

View File

@@ -6,7 +6,20 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> xmlns:viewModels="using:BlueControl.uwp.ViewModels"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
>
<Page.DataContext>
<viewModels:MainPageViewModel x:Name="ViewModel"/>
</Page.DataContext>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Loaded">
<core:InvokeCommandAction Command="{x:Bind ViewModel.ReloadCommand}"/>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
<Grid> <Grid>
<TextBlock Text="{Binding Text}" FontSize="40" TextAlignment="Center" VerticalAlignment="Center"></TextBlock> <TextBlock Text="{Binding Text}" FontSize="40" TextAlignment="Center" VerticalAlignment="Center"></TextBlock>

View File

@@ -28,13 +28,13 @@ namespace BlueControl.uwp
/// </summary> /// </summary>
public sealed partial class MainPage : Page public sealed partial class MainPage : Page
{ {
private ViewModels.MainPageViewModel vm = new ViewModels.MainPageViewModel(); //private ViewModels.MainPageViewModel vm = new ViewModels.MainPageViewModel();
public MainPage() public MainPage()
{ {
this.vm.StaDispatcher = this.Dispatcher; //this.vm.StaDispatcher = this.Dispatcher;
this.DataContext = vm; //this.DataContext = vm;
this.InitializeComponent(); this.InitializeComponent();
this.Loading += async (sender, args) => await vm.ReloadAsync(); //this.Loading += async (sender, args) => await vm.ReloadAsync();
} }
} }

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Enumeration;
namespace BlueControl.uwp.Services
{
public class BluetoothService : IBluetoothService
{
private bool control = false;
public BluetoothService()
{
}
private BluetoothLEAdvertisementWatcher bleWatcher = null;
public async Task<bool> IsConnectedAsync(string deviceName)
{
return (from x in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelectorFromConnectionStatus(BluetoothConnectionStatus.Connected)) where x.Name == deviceName select x).Any();
}
public async Task<bool> IsPairedAsync(string deviceName)
{
return (from x in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelectorFromPairingState(true)) where x.Name == deviceName select x).Any();
}
public async Task UnpairAsync(string deviceName)
{
var device = (from x in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelectorFromPairingState(true)) where x.Name == deviceName select x).FirstOrDefault();
if (device != null)
await device.Pairing.UnpairAsync();
}
private Action<string> pinCreatedCallBack = null;
private void Custom_PairingRequested(DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args)
{
if (this.pinCreatedCallBack != null) pinCreatedCallBack(args.Pin);
args.Accept(args.Pin);
}
public async Task StartAutoPairingAsync(string deviceName, Action onFoundTryingToPair, Action<string> onPinCreated, Action onSuccess, Action onError)
{
pinCreatedCallBack = onPinCreated;
if (this.bleWatcher == null)
{
this.bleWatcher = new BluetoothLEAdvertisementWatcher();
this.bleWatcher.Received += async (sender, args) =>
{
try
{
if (!args.IsConnectable || control == true) return;
control = true;
var dev = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
if (dev.Name == deviceName && dev.DeviceInformation.Pairing.CanPair)
{
if (onFoundTryingToPair != null) onFoundTryingToPair();
System.Threading.Thread.Sleep(3000);
dev.DeviceInformation.Pairing.Custom.PairingRequested += Custom_PairingRequested;
var t = await dev.DeviceInformation.Pairing.Custom.PairAsync(DevicePairingKinds.DisplayPin, DevicePairingProtectionLevel.Encryption);
if (t.Status == DevicePairingResultStatus.Paired)
{
this.bleWatcher.Stop();
if (onSuccess != null) onSuccess();
}
else
if (onError != null) onError();
}
}
catch { }
control = false;
};
}
this.bleWatcher.Start();
}
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BlueControl.uwp.Services
{
public interface IBluetoothService
{
Task<bool> IsConnectedAsync(string deviceName);
Task<bool> IsPairedAsync(string deviceName);
Task UnpairAsync(string deviceName);
Task StartAutoPairingAsync(string deviceName, Action onFoundTryingToPair, Action<string> onPinCreated, Action onSuccess, Action onError);
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BlueControl.uwp.Services
{
public interface IShellService
{
Task UiStaRunAsync(Action action);
void CloseApplication();
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BlueControl.uwp.Services
{
public class UiShellService : IShellService
{
public async Task UiStaRunAsync(Action action)
{
if (StaDispatcher != null)
await StaDispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => action());
}
public Windows.UI.Core.CoreDispatcher StaDispatcher { get; set; }
public UiShellService(Windows.UI.Core.CoreDispatcher dispacher)
{
this.StaDispatcher = dispacher;
}
public void CloseApplication()
{
App.Current.Exit();
}
}
}

View File

@@ -1,9 +1,12 @@
using System; using Microsoft.Toolkit.Mvvm.DependencyInjection;
using Microsoft.Toolkit.Mvvm.Input;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input;
using Windows.Devices.Bluetooth; using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement; using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Enumeration; using Windows.Devices.Enumeration;
@@ -14,22 +17,18 @@ namespace BlueControl.uwp.ViewModels
public class MainPageViewModel : INotifyPropertyChanged public class MainPageViewModel : INotifyPropertyChanged
{ {
private const string SURFACE_KEYBOARD_NAME = "Surface Keyboard"; private const string SURFACE_KEYBOARD_NAME = "Surface Keyboard";
private readonly BluetoothLEAdvertisementWatcher bleWatcher = new BluetoothLEAdvertisementWatcher();
private bool control = false;
public Windows.UI.Core.CoreDispatcher StaDispatcher { get; set; }
public async Task StaExecuteAsync(Action action)
{
if (StaDispatcher != null)
await StaDispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => action());
}
private void CloseApplication(TimeSpan delta) private void CloseApplication(TimeSpan delta)
{ {
var dispatcherTimer = new DispatcherTimer(); var dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += (o, e) => App.Current.Exit(); dispatcherTimer.Tick += (o, e) => ShellService.CloseApplication();
dispatcherTimer.Interval = delta; dispatcherTimer.Interval = delta;
dispatcherTimer.Start(); dispatcherTimer.Start();
} }
@@ -40,48 +39,21 @@ namespace BlueControl.uwp.ViewModels
} }
private void Custom_PairingRequested(DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args)
{
StaExecuteAsync(() => this.Text = "Pin: " + Environment.NewLine + args.Pin);
args.Accept(args.Pin); private readonly Services.IShellService ShellService = Windows.ApplicationModel.DesignMode.DesignModeEnabled
} ? null : Ioc.Default.GetRequiredService<Services.IShellService>();
private readonly Services.IBluetoothService BluetoothService = Windows.ApplicationModel.DesignMode.DesignModeEnabled
? null : Ioc.Default.GetRequiredService<Services.IBluetoothService>();
public MainPageViewModel() public MainPageViewModel()
{ {
this.bleWatcher.Received += async (sender, args) => this.ReloadCommand = new RelayCommand(async () => await ReloadAsync());
{
try
{
if (!args.IsConnectable || control == true) return;
control = true;
var dev = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
if (dev.Name == SURFACE_KEYBOARD_NAME && dev.DeviceInformation.Pairing.CanPair)
{
await StaExecuteAsync(() => this.Text = "trying to pair... ");
System.Threading.Thread.Sleep(3000);
dev.DeviceInformation.Pairing.Custom.PairingRequested += Custom_PairingRequested;
var t = await dev.DeviceInformation.Pairing.Custom.PairAsync(DevicePairingKinds.DisplayPin, DevicePairingProtectionLevel.Encryption);
if (t.Status == DevicePairingResultStatus.Paired)
{
this.bleWatcher.Stop();
await StaExecuteAsync(() =>
{
this.Text = $"Paired and connected {Environment.NewLine} auto closing in 2 seconds ";
CloseApplication();
}
);
}
else
await StaExecuteAsync(() => this.Text = t.Status.ToString());
}
}
catch { }
control = false;
};
} }
@@ -110,22 +82,32 @@ namespace BlueControl.uwp.ViewModels
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
public ICommand ReloadCommand { get; private set; }
public async Task ReloadAsync() public async Task ReloadAsync()
{ {
this.Text = "Loading..."; this.Text = "Loading...";
IsConnected = IsConnected = await BluetoothService.IsConnectedAsync(SURFACE_KEYBOARD_NAME);
(from x in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelectorFromConnectionStatus(BluetoothConnectionStatus.Connected)) where x.Name == SURFACE_KEYBOARD_NAME select x).Any();
if (!IsConnected) if (!IsConnected)
{ {
var pairedDevice = if (await BluetoothService.IsPairedAsync(SURFACE_KEYBOARD_NAME))
(from x in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelectorFromPairingState(true)) where x.Name == SURFACE_KEYBOARD_NAME select x).FirstOrDefault(); await BluetoothService.UnpairAsync(SURFACE_KEYBOARD_NAME);
if (pairedDevice != null)
await pairedDevice.Pairing.UnpairAsync();
this.Text = $"....searching keyboard. {Environment.NewLine} Please confirm is in pairing mode"; this.Text = $"....searching keyboard. {Environment.NewLine} Please confirm is in pairing mode";
this.bleWatcher.Start(); await this.BluetoothService.StartAutoPairingAsync(
SURFACE_KEYBOARD_NAME,
() => this.ShellService.UiStaRunAsync(() => this.Text = "trying to pair... ")
, (pin) => this.ShellService.UiStaRunAsync(() => this.Text = $"pin:{Environment.NewLine + pin}")
, () =>
ShellService.UiStaRunAsync(() =>
{
this.Text = $"Paired and connected {Environment.NewLine} auto closing in 2 seconds ";
CloseApplication();
})
, () => ShellService.UiStaRunAsync(() => this.Text = "error trying again")
);
} }
else else
{ {