mvvm pattern
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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)' < '14.0' ">
|
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
89
src/BlueControl.uwp/Services/BluetoothService.cs
Normal file
89
src/BlueControl.uwp/Services/BluetoothService.cs
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/BlueControl.uwp/Services/IBluetoothService.cs
Normal file
18
src/BlueControl.uwp/Services/IBluetoothService.cs
Normal 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);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/BlueControl.uwp/Services/IShellService.cs
Normal file
14
src/BlueControl.uwp/Services/IShellService.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/BlueControl.uwp/Services/UiShellService.cs
Normal file
30
src/BlueControl.uwp/Services/UiShellService.cs
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user