Code cleanup and try to use the RowDetailsTemplate

This commit is contained in:
Holger Börchers 2023-11-24 11:33:24 +01:00
parent 26281bbb5a
commit fd054d854b
8 changed files with 98 additions and 79 deletions

View File

@ -1,4 +1,3 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;

View File

@ -1,69 +1,75 @@
using System.Drawing;
using System.Linq;
namespace SddpViewer;
namespace SddpViewer
using System;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using Rssdp;
public partial class DiscoveredDeviceViewModel : ObservableObject
{
using System;
using System.Threading.Tasks;
private readonly DiscoveredSsdpDevice _device;
using CommunityToolkit.Mvvm.ComponentModel;
using Rssdp;
public partial class DiscoveredDeviceViewModel : ObservableObject
public DiscoveredDeviceViewModel(DiscoveredSsdpDevice device)
{
private readonly DiscoveredSsdpDevice device;
_device = device;
ResponseHeader = GetResponseHeader();
}
public DiscoveredDeviceViewModel(DiscoveredSsdpDevice device)
{
this.device = device;
}
private string GetResponseHeader()
{
return string.Join(
"," + Environment.NewLine,
_device.ResponseHeaders.Select(x => $"{{{x.Key} : {string.Join(";", x.Value)}}}")
);
}
/// <summary>
/// Sets or returns the type of notification, being either a uuid, device type, service type or upnp:rootdevice.
/// </summary>
public string NotificationType => this.device.NotificationType;
public string ResponseHeader { get; }
/// <summary>
/// Sets or returns the universal service name (USN) of the device.
/// </summary>
public string Usn => this.device.Usn;
/// <summary>
/// Sets or returns the type of notification, being either a uuid, device type, service type or upnp:rootdevice.
/// </summary>
public string NotificationType => _device.NotificationType;
/// <summary>
/// Sets or returns a URL pointing to the device description document for this device.
/// </summary>
public Uri DescriptionLocation => this.device.DescriptionLocation;
/// <summary>
/// Sets or returns the universal service name (USN) of the device.
/// </summary>
public string Usn => _device.Usn;
/// <summary>
/// Sets or returns the length of time this information is valid for (from the <see cref="P:Rssdp.DiscoveredSsdpDevice.AsAt" /> time).
/// </summary>
public TimeSpan CacheLifetime => this.device.CacheLifetime;
/// <summary>
/// Sets or returns a URL pointing to the device description document for this device.
/// </summary>
public Uri DescriptionLocation => _device.DescriptionLocation;
/// <summary>
/// Sets or returns the date and time this information was received.
/// </summary>
public DateTimeOffset AsAt => this.device.AsAt;
/// <summary>
/// Sets or returns the length of time this information is valid for (from the <see cref="P:Rssdp.DiscoveredSsdpDevice.AsAt" /> time).
/// </summary>
public TimeSpan CacheLifetime => _device.CacheLifetime;
[ObservableProperty]
private string _friendlyName = "";
/// <summary>
/// Sets or returns the date and time this information was received.
/// </summary>
public DateTimeOffset AsAt => _device.AsAt;
[ObservableProperty]
private SsdpDeviceIcon? _icon;
[ObservableProperty]
private string _friendlyName = "";
[ObservableProperty]
private Uri? _presentationUrl;
[ObservableProperty]
private SsdpDeviceIcon? _icon;
[ObservableProperty]
private string _modelNumber;
[ObservableProperty]
private Uri? _presentationUrl;
public async Task GetFurtherInformationAsync()
{
var ssdpDevice = await this.device.GetDeviceInfo().ConfigureAwait(false);
FriendlyName = ssdpDevice.FriendlyName;
Icon = ssdpDevice.Icons.MinBy(x=> x.Height);
PresentationUrl = ssdpDevice.PresentationUrl;
ModelNumber = ssdpDevice.ModelNumber;
[ObservableProperty]
private string _modelNumber = "";
}
public async Task GetFurtherInformationAsync()
{
var ssdpDevice = await _device.GetDeviceInfo().ConfigureAwait(false);
FriendlyName = ssdpDevice.FriendlyName;
Icon = ssdpDevice.Icons.MinBy(x => x.Height);
PresentationUrl = ssdpDevice.PresentationUrl;
ModelNumber = ssdpDevice.ModelNumber;
}
}

3
src/GlobalUsings.cs Normal file
View File

@ -0,0 +1,3 @@
// Global using directives
global using Avalonia;

View File

@ -1,25 +1,25 @@
<Window
Title="SDDP viewer"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d"
x:Class="SddpViewer.MainWindow"
x:CompileBindings="True"
x:DataType="sddpViewer:MainWindowViewModel"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sddpViewer="clr-namespace:SddpViewer"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
Title="SDDP viewer"
d:DesignHeight="450"
d:DesignWidth="800"
x:CompileBindings="True"
x:DataType="sddpViewer:MainWindowViewModel"
mc:Ignorable="d">
<Window.DataContext>
<sddpViewer:MainWindowViewModel />
</Window.DataContext>
<Grid RowDefinitions="Auto, *">
<Grid ColumnDefinitions="*,*" RowDefinitions="Auto, *">
<StackPanel Margin="10" Spacing="5">
<TextBlock Text="Device IP Address" />
<ComboBox
DisplayMemberBinding="{Binding DisplayName}"
HorizontalAlignment="Stretch"
DisplayMemberBinding="{Binding DisplayName}"
ItemsSource="{Binding NetworkAdapters}"
SelectedItem="{Binding SelectedNetworkAdapter}" />
<TextBlock Text="Notification filter" />
@ -27,10 +27,22 @@
<Button Command="{Binding SearchDevicesNowCommand}" Content="Search now" />
</StackPanel>
<DataGrid
AutoGenerateColumns="True"
Grid.Row="1"
Grid.Row="1" Grid.ColumnSpan="2"
Grid.Column="0"
AutoGenerateColumns="False"
IsReadOnly="True"
ItemsSource="{Binding SddpDevices}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Usn}" Header="Usn" />
<DataGridTextColumn Binding="{Binding FriendlyName}" Header="Name" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate DataType="sddpViewer:DiscoveredDeviceViewModel">
<StackPanel>
<TextBlock Text="{Binding ResponseHeader}" />
</StackPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
</Window>

View File

@ -1,11 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace SddpViewer;
using Avalonia.Threading;
namespace SddpViewer;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
@ -14,7 +10,7 @@ using CommunityToolkit.Mvvm.Input;
using Rssdp;
public partial class MainWindowViewModel : ObservableObject
public sealed partial class MainWindowViewModel : ObservableObject, IDisposable
{
public MainWindowViewModel()
{
@ -24,9 +20,11 @@ public partial class MainWindowViewModel : ObservableObject
private void LocatorOnDeviceUnavailable(object? sender, DeviceUnavailableEventArgs e)
{
var existingDevice = SddpDevices.FirstOrDefault(x =>
string.Equals(x.Usn, e.DiscoveredDevice.Usn, StringComparison.Ordinal));
if(existingDevice is null) return;
var existingDevice = SddpDevices.FirstOrDefault(
x => string.Equals(x.Usn, e.DiscoveredDevice.Usn, StringComparison.Ordinal)
);
if (existingDevice is null)
return;
Dispatcher.UIThread.Invoke(() => SddpDevices.Remove(existingDevice));
}
@ -79,4 +77,9 @@ public partial class MainWindowViewModel : ObservableObject
_locator.StartListeningForNotifications();
await _locator.SearchAsync();
}
public void Dispose()
{
_locator?.Dispose();
}
}

View File

@ -1,5 +1,3 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

View File

@ -1,9 +1,6 @@
using Avalonia;
using System;
namespace SddpViewer;
namespace SddpViewer;
class Program
internal static class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized

View File

@ -3,6 +3,7 @@
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>