Many cool stuff
This commit is contained in:
parent
fd054d854b
commit
0e75065ff7
@ -14,9 +14,9 @@ indent_size = 2
|
|||||||
#### Core EditorConfig Options ####
|
#### Core EditorConfig Options ####
|
||||||
|
|
||||||
# Indentation and spacing
|
# Indentation and spacing
|
||||||
indent_size = 4
|
indent_size = 2
|
||||||
tab_width = 4
|
tab_width = 2
|
||||||
|
max_line_length = 140
|
||||||
# New line preferences
|
# New line preferences
|
||||||
end_of_line = crlf
|
end_of_line = crlf
|
||||||
insert_final_newline = false
|
insert_final_newline = false
|
||||||
|
@ -5,18 +5,18 @@ namespace SddpViewer;
|
|||||||
|
|
||||||
public partial class App : Application
|
public partial class App : Application
|
||||||
{
|
{
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnFrameworkInitializationCompleted()
|
||||||
|
{
|
||||||
|
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
{
|
{
|
||||||
AvaloniaXamlLoader.Load(this);
|
desktop.MainWindow = new MainWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnFrameworkInitializationCompleted()
|
base.OnFrameworkInitializationCompleted();
|
||||||
{
|
}
|
||||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
|
||||||
{
|
|
||||||
desktop.MainWindow = new MainWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnFrameworkInitializationCompleted();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,75 +1,106 @@
|
|||||||
namespace SddpViewer;
|
using System.Net;
|
||||||
|
|
||||||
|
namespace SddpViewer;
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
using Rssdp;
|
using Rssdp;
|
||||||
|
|
||||||
public partial class DiscoveredDeviceViewModel : ObservableObject
|
public partial class DiscoveredDeviceViewModel : ObservableObject
|
||||||
{
|
{
|
||||||
private readonly DiscoveredSsdpDevice _device;
|
private readonly DiscoveredSsdpDevice _device;
|
||||||
|
private SsdpDevice? _ssdpDevice;
|
||||||
|
|
||||||
public DiscoveredDeviceViewModel(DiscoveredSsdpDevice device)
|
public DiscoveredDeviceViewModel(DiscoveredSsdpDevice device)
|
||||||
{
|
{
|
||||||
_device = device;
|
_device = device;
|
||||||
ResponseHeader = GetResponseHeader();
|
ResponseHeader = GetResponseHeader();
|
||||||
}
|
DiscoveredAt = DateTime.Now;
|
||||||
|
IpAddress = EvaluateIpAddress(device);
|
||||||
|
MacAddress = EvaluateMacAddress();
|
||||||
|
HostName = EvaluateHostName();
|
||||||
|
}
|
||||||
|
|
||||||
private string GetResponseHeader()
|
public string HostName { get; set; }
|
||||||
{
|
|
||||||
return string.Join(
|
|
||||||
"," + Environment.NewLine,
|
|
||||||
_device.ResponseHeaders.Select(x => $"{{{x.Key} : {string.Join(";", x.Value)}}}")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ResponseHeader { get; }
|
public string MacAddress { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
public string IpAddress { get; set; }
|
||||||
/// 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>
|
public DateTime DiscoveredAt { get; }
|
||||||
/// Sets or returns the universal service name (USN) of the device.
|
|
||||||
/// </summary>
|
|
||||||
public string Usn => _device.Usn;
|
|
||||||
|
|
||||||
/// <summary>
|
[ObservableProperty]
|
||||||
/// Sets or returns a URL pointing to the device description document for this device.
|
public partial string ResponseHeader { get; set; }
|
||||||
/// </summary>
|
|
||||||
public Uri DescriptionLocation => _device.DescriptionLocation;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets or returns the length of time this information is valid for (from the <see cref="P:Rssdp.DiscoveredSsdpDevice.AsAt" /> time).
|
/// Sets or returns the type of notification, being either a uuid, device type, service type or upnp:rootdevice.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan CacheLifetime => _device.CacheLifetime;
|
public string NotificationType => _device.NotificationType;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets or returns the date and time this information was received.
|
/// Sets or returns the universal service name (USN) of the device.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTimeOffset AsAt => _device.AsAt;
|
public string Usn => _device.Usn;
|
||||||
|
|
||||||
[ObservableProperty]
|
/// <summary>
|
||||||
private string _friendlyName = "";
|
/// Sets or returns a URL pointing to the device description document for this device.
|
||||||
|
/// </summary>
|
||||||
|
public Uri DescriptionLocation => _device.DescriptionLocation;
|
||||||
|
|
||||||
[ObservableProperty]
|
/// <summary>
|
||||||
private SsdpDeviceIcon? _icon;
|
/// 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]
|
/// <summary>
|
||||||
private Uri? _presentationUrl;
|
/// Sets or returns the date and time this information was received.
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset AsAt => _device.AsAt;
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
private string _modelNumber = "";
|
public partial string FriendlyName { get; set; } = "";
|
||||||
|
|
||||||
public async Task GetFurtherInformationAsync()
|
[ObservableProperty]
|
||||||
{
|
public partial SsdpDeviceIcon? Icon { get; set; }
|
||||||
var ssdpDevice = await _device.GetDeviceInfo().ConfigureAwait(false);
|
|
||||||
FriendlyName = ssdpDevice.FriendlyName;
|
[ObservableProperty]
|
||||||
Icon = ssdpDevice.Icons.MinBy(x => x.Height);
|
public partial Uri? PresentationUrl { get; set; }
|
||||||
PresentationUrl = ssdpDevice.PresentationUrl;
|
|
||||||
ModelNumber = ssdpDevice.ModelNumber;
|
[ObservableProperty]
|
||||||
}
|
public partial string ModelNumber { get; set; } = "";
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
public partial string Version { get; set; } = "";
|
||||||
|
|
||||||
|
public async Task GetFurtherInformationAsync()
|
||||||
|
{
|
||||||
|
_ssdpDevice = await _device.GetDeviceInfo().ConfigureAwait(false);
|
||||||
|
FriendlyName = _ssdpDevice.ModelDescription;
|
||||||
|
Icon = _ssdpDevice.Icons.MinBy(x => x.Height);
|
||||||
|
PresentationUrl = _ssdpDevice.PresentationUrl;
|
||||||
|
ModelNumber = _ssdpDevice.ModelNumber;
|
||||||
|
Version = _ssdpDevice.SerialNumber?.Split(',').Last() ?? new Version().ToString();
|
||||||
|
HttpClient client = new HttpClient();
|
||||||
|
var response = await client.GetAsync(_ssdpDevice.ModelUrl).ConfigureAwait(false);
|
||||||
|
ResponseHeader = await response.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string EvaluateHostName() => Dns.GetHostEntry(IpAddress).HostName;
|
||||||
|
|
||||||
|
private string GetResponseHeader() =>
|
||||||
|
string.Join("," + Environment.NewLine, _device.ResponseHeaders.Select(x => $"{{{x.Key} : {string.Join(";", x.Value)}}}"));
|
||||||
|
|
||||||
|
private string EvaluateIpAddress(DiscoveredSsdpDevice device) => device.DescriptionLocation.Host;
|
||||||
|
|
||||||
|
private string EvaluateMacAddress()
|
||||||
|
{
|
||||||
|
var lookupResult = ArpLookup.Arp.Lookup(IPAddress.Parse(IpAddress));
|
||||||
|
return lookupResult is null ? "Unknown" : string.Join(":", lookupResult.GetAddressBytes().Select(b => $"{b:x2}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is DiscoveredDeviceViewModel viewModel && Equals(viewModel.Usn, Usn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<Window.DataContext>
|
<Window.DataContext>
|
||||||
<sddpViewer:MainWindowViewModel />
|
<sddpViewer:MainWindowViewModel />
|
||||||
</Window.DataContext>
|
</Window.DataContext>
|
||||||
<Grid ColumnDefinitions="*,*" RowDefinitions="Auto, *">
|
<Grid ColumnDefinitions="*,*" RowDefinitions="180, *">
|
||||||
<StackPanel Margin="10" Spacing="5">
|
<StackPanel Margin="10" Spacing="5">
|
||||||
<TextBlock Text="Device IP Address" />
|
<TextBlock Text="Device IP Address" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
@ -24,25 +24,36 @@
|
|||||||
SelectedItem="{Binding SelectedNetworkAdapter}" />
|
SelectedItem="{Binding SelectedNetworkAdapter}" />
|
||||||
<TextBlock Text="Notification filter" />
|
<TextBlock Text="Notification filter" />
|
||||||
<TextBox Text="{Binding NotificationFilter}" />
|
<TextBox Text="{Binding NotificationFilter}" />
|
||||||
<Button Command="{Binding SearchDevicesNowCommand}" Content="Search now" />
|
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||||
|
<Button Command="{Binding StartListeningCommand}" Content="Listen for devices" />
|
||||||
|
<Button Command="{Binding SearchDevicesNowCommand}" Content="Search now" />
|
||||||
|
<Button Command="{Binding ResearchCommand}" Content="Search more" />
|
||||||
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<Grid Grid.Row="0" Grid.Column="1">
|
||||||
|
<TextBox
|
||||||
|
IsReadOnly="True"
|
||||||
|
Text="{ReflectionBinding SelectedItem.ResponseHeader,
|
||||||
|
ElementName=DevicesDataGrid}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</Grid>
|
||||||
<DataGrid
|
<DataGrid
|
||||||
Grid.Row="1" Grid.ColumnSpan="2"
|
x:Name="DevicesDataGrid"
|
||||||
|
Grid.Row="1"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
AutoGenerateColumns="False"
|
AutoGenerateColumns="False"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
ItemsSource="{Binding SddpDevices}">
|
ItemsSource="{Binding SddpDevices}">
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn Binding="{Binding Usn}" Header="Usn" />
|
|
||||||
<DataGridTextColumn Binding="{Binding FriendlyName}" Header="Name" />
|
<DataGridTextColumn Binding="{Binding FriendlyName}" Header="Name" />
|
||||||
|
<DataGridTextColumn Binding="{Binding Usn}" Header="Usn" />
|
||||||
|
<DataGridTextColumn Binding="{Binding IpAddress}" Header="Ip address" />
|
||||||
|
<DataGridTextColumn Binding="{Binding HostName}" Header="Hostname" />
|
||||||
|
<DataGridTextColumn Binding="{Binding MacAddress}" Header="Mac address" />
|
||||||
|
<DataGridTextColumn Binding="{Binding Version}" Header="Version" />
|
||||||
|
<DataGridTextColumn Binding="{Binding DiscoveredAt}" Header="Discovered at" />
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
<DataGrid.RowDetailsTemplate>
|
|
||||||
<DataTemplate DataType="sddpViewer:DiscoveredDeviceViewModel">
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock Text="{Binding ResponseHeader}" />
|
|
||||||
</StackPanel>
|
|
||||||
</DataTemplate>
|
|
||||||
</DataGrid.RowDetailsTemplate>
|
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
@ -4,8 +4,8 @@ namespace SddpViewer;
|
|||||||
|
|
||||||
public partial class MainWindow : Window
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,85 +1,129 @@
|
|||||||
namespace SddpViewer;
|
using System.Collections.Specialized;
|
||||||
|
|
||||||
using Avalonia.Threading;
|
namespace SddpViewer;
|
||||||
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Avalonia.Threading;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
using Rssdp;
|
using Rssdp;
|
||||||
|
|
||||||
public sealed partial class MainWindowViewModel : ObservableObject, IDisposable
|
public sealed partial class MainWindowViewModel : ObservableObject, IDisposable
|
||||||
{
|
{
|
||||||
public MainWindowViewModel()
|
public MainWindowViewModel()
|
||||||
{
|
{
|
||||||
NetworkAdapters = NetworkAdapter.GetAvailableNetworkAdapter().ToArray();
|
NetworkAdapters = NetworkAdapter.GetAvailableNetworkAdapter().ToArray();
|
||||||
SelectedNetworkAdapter = NetworkAdapters.FirstOrDefault();
|
SelectedNetworkAdapter = NetworkAdapters.FirstOrDefault();
|
||||||
}
|
SddpDevices = new ObservableCollection<DiscoveredDeviceViewModel>();
|
||||||
|
SddpDevices.CollectionChanged += SddpDevices_OnCollectionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
private void LocatorOnDeviceUnavailable(object? sender, DeviceUnavailableEventArgs e)
|
private static async void SddpDevices_OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var existingDevice = SddpDevices.FirstOrDefault(
|
foreach (object eNewItem in e.NewItems ?? Array.Empty<object>())
|
||||||
x => string.Equals(x.Usn, e.DiscoveredDevice.Usn, StringComparison.Ordinal)
|
{
|
||||||
);
|
if (eNewItem is DiscoveredDeviceViewModel discoveredDeviceViewModel)
|
||||||
if (existingDevice is null)
|
|
||||||
return;
|
|
||||||
Dispatcher.UIThread.Invoke(() => SddpDevices.Remove(existingDevice));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void LocatorOnDeviceAvailable(object? sender, DeviceAvailableEventArgs e)
|
|
||||||
{
|
|
||||||
if (!e.IsNewlyDiscovered)
|
|
||||||
{
|
{
|
||||||
return;
|
await discoveredDeviceViewModel.GetFurtherInformationAsync();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw; // TODO handle exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var discoveredDeviceViewModel = new DiscoveredDeviceViewModel(e.DiscoveredDevice);
|
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;
|
||||||
|
Dispatcher.UIThread.Invoke(() => SddpDevices.Remove(existingDevice));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LocatorOnDeviceAvailable(object? sender, DeviceAvailableEventArgs e)
|
||||||
|
{
|
||||||
|
if (!e.IsNewlyDiscovered)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var discoveredDeviceViewModel = new DiscoveredDeviceViewModel(e.DiscoveredDevice);
|
||||||
|
if (!SddpDevices.Contains(discoveredDeviceViewModel))
|
||||||
|
Dispatcher.UIThread.Invoke(() => SddpDevices.Add(discoveredDeviceViewModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private IReadOnlyList<NetworkAdapter> _networkAdapters;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private NetworkAdapter? _selectedNetworkAdapter;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _deviceIpAddress = "192.168.42.193";
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _notificationFilter = "upnp:rootdevice";
|
||||||
|
|
||||||
|
private SsdpDeviceLocator? _locator;
|
||||||
|
|
||||||
|
public ObservableCollection<DiscoveredDeviceViewModel> SddpDevices { get; }
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task SearchDevicesNowAsync()
|
||||||
|
{
|
||||||
|
SddpDevices.Clear();
|
||||||
|
if (_locator is not null)
|
||||||
|
{
|
||||||
|
_locator.StopListeningForNotifications();
|
||||||
|
_locator.DeviceAvailable -= LocatorOnDeviceAvailable;
|
||||||
|
_locator.DeviceUnavailable -= LocatorOnDeviceUnavailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
await StartListening(async locator =>
|
||||||
|
{
|
||||||
|
foreach (var discoveredSsdpDevice in await locator.SearchAsync())
|
||||||
|
{
|
||||||
|
var discoveredDeviceViewModel = new DiscoveredDeviceViewModel(discoveredSsdpDevice);
|
||||||
Dispatcher.UIThread.Invoke(() => SddpDevices.Add(discoveredDeviceViewModel));
|
Dispatcher.UIThread.Invoke(() => SddpDevices.Add(discoveredDeviceViewModel));
|
||||||
await discoveredDeviceViewModel.GetFurtherInformationAsync();
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[ObservableProperty]
|
[RelayCommand]
|
||||||
private IReadOnlyList<NetworkAdapter> _networkAdapters;
|
private async Task ResearchAsync()
|
||||||
|
{
|
||||||
[ObservableProperty]
|
if (_locator is not null)
|
||||||
private NetworkAdapter? _selectedNetworkAdapter;
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
private string _deviceIpAddress = "192.168.42.193";
|
|
||||||
|
|
||||||
[ObservableProperty]
|
|
||||||
private string _notificationFilter = "upnp:rootdevice";
|
|
||||||
|
|
||||||
private SsdpDeviceLocator? _locator;
|
|
||||||
|
|
||||||
public ObservableCollection<DiscoveredDeviceViewModel> SddpDevices { get; } = new();
|
|
||||||
|
|
||||||
[RelayCommand]
|
|
||||||
private async Task SearchDevicesNowAsync()
|
|
||||||
{
|
{
|
||||||
SddpDevices.Clear();
|
await _locator.SearchAsync();
|
||||||
if (_locator is not null)
|
|
||||||
{
|
|
||||||
_locator.StopListeningForNotifications();
|
|
||||||
_locator.DeviceAvailable -= LocatorOnDeviceAvailable;
|
|
||||||
_locator.DeviceUnavailable -= LocatorOnDeviceUnavailable;
|
|
||||||
}
|
|
||||||
_locator = new SsdpDeviceLocator(SelectedNetworkAdapter?.IpAddress.ToString());
|
|
||||||
if (!string.IsNullOrWhiteSpace(NotificationFilter))
|
|
||||||
{
|
|
||||||
_locator.NotificationFilter = NotificationFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
_locator.DeviceAvailable += LocatorOnDeviceAvailable;
|
|
||||||
_locator.DeviceUnavailable += LocatorOnDeviceUnavailable;
|
|
||||||
_locator.StartListeningForNotifications();
|
|
||||||
await _locator.SearchAsync();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
[RelayCommand]
|
||||||
|
private async Task StartListening(Func<SsdpDeviceLocator, Task>? action = null)
|
||||||
|
{
|
||||||
|
_locator = new SsdpDeviceLocator(SelectedNetworkAdapter?.IpAddress.ToString());
|
||||||
|
if (!string.IsNullOrWhiteSpace(NotificationFilter))
|
||||||
{
|
{
|
||||||
_locator?.Dispose();
|
_locator.NotificationFilter = NotificationFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (action is not null)
|
||||||
|
{
|
||||||
|
await action.Invoke(_locator);
|
||||||
|
}
|
||||||
|
|
||||||
|
_locator.DeviceAvailable += LocatorOnDeviceAvailable;
|
||||||
|
_locator.DeviceUnavailable += LocatorOnDeviceUnavailable;
|
||||||
|
_locator.StartListeningForNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_locator?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,24 +6,22 @@ namespace SddpViewer;
|
|||||||
|
|
||||||
public record NetworkAdapter(string Name, IPAddress IpAddress)
|
public record NetworkAdapter(string Name, IPAddress IpAddress)
|
||||||
{
|
{
|
||||||
public string DisplayName => $"{Name} - {IpAddress}";
|
public string DisplayName => $"{Name} - {IpAddress}";
|
||||||
|
|
||||||
public static IEnumerable<NetworkAdapter> GetAvailableNetworkAdapter()
|
public static IEnumerable<NetworkAdapter> GetAvailableNetworkAdapter()
|
||||||
|
{
|
||||||
|
foreach (var nic in NetworkInterface.GetAllNetworkInterfaces())
|
||||||
{
|
{
|
||||||
foreach (var nic in NetworkInterface.GetAllNetworkInterfaces())
|
if (nic.OperationalStatus != OperationalStatus.Up)
|
||||||
{
|
continue;
|
||||||
if (nic.OperationalStatus != OperationalStatus.Up)
|
if (nic.NetworkInterfaceType == NetworkInterfaceType.Loopback)
|
||||||
continue;
|
continue;
|
||||||
if (nic.NetworkInterfaceType == NetworkInterfaceType.Loopback)
|
var physicalAddress = nic.GetIPProperties()
|
||||||
continue;
|
.UnicastAddresses.FirstOrDefault(x => x.Address.AddressFamily == AddressFamily.InterNetwork);
|
||||||
var physicalAddress = nic.GetIPProperties()
|
if (physicalAddress is not null)
|
||||||
.UnicastAddresses.FirstOrDefault(
|
{
|
||||||
x => x.Address.AddressFamily == AddressFamily.InterNetwork
|
yield return new NetworkAdapter(nic.Name, physicalAddress.Address);
|
||||||
);
|
}
|
||||||
if (physicalAddress is not null)
|
|
||||||
{
|
|
||||||
yield return new NetworkAdapter(nic.Name, physicalAddress.Address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,12 @@
|
|||||||
|
|
||||||
internal static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||||
// yet and stuff might break.
|
// yet and stuff might break.
|
||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args) =>
|
public static void Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
||||||
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
|
||||||
|
|
||||||
// Avalonia configuration, don't remove; also used by visual designer.
|
// Avalonia configuration, don't remove; also used by visual designer.
|
||||||
public static AppBuilder BuildAvaloniaApp() =>
|
public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure<App>().UsePlatformDetect().WithInterFont().LogToTrace();
|
||||||
AppBuilder.Configure<App>().UsePlatformDetect().WithInterFont().LogToTrace();
|
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,23 @@
|
|||||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||||
|
<LangVersion>preview</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="11.0.5" />
|
<PackageReference Include="ArpLookup" Version="2.0.3" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="11.0.5" />
|
<PackageReference Include="Avalonia" Version="11.2.5" />
|
||||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.5" />
|
<PackageReference Include="Avalonia.Desktop" Version="11.2.5" />
|
||||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.5" />
|
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.5" />
|
||||||
|
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.5" />
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.5" />
|
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.5" />
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
|
<PackageReference Include="CSharpier.MsBuild" Version="0.30.6">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="rssdp" Version="4.0.4" />
|
<PackageReference Include="rssdp" Version="4.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user