diff --git a/.claude/skills/feature-review/references/conventions.md b/.claude/skills/feature-review/references/conventions.md
index 0715193403..fdfb50a29a 100644
--- a/.claude/skills/feature-review/references/conventions.md
+++ b/.claude/skills/feature-review/references/conventions.md
@@ -84,7 +84,19 @@ Reference: `HostsFileEditorView.xaml`, `FirewallView.xaml`.
`SelectedResults` is changed in place (no change notification): selection-dependent properties are raised
in `OnContextMenuOpened()` called from the view's `ContextMenu_Opened`.
- Two context menus: `RowContextMenu` (one row) and `MultiRowContextMenu` (several rows), switched by a
- `DataTrigger` on `SelectedItems.Count`. `Opened="ContextMenu_Opened"` sets the menu's `DataContext`.
+ `DataTrigger` on `SelectedItems.Count`.
+- A context menu is not part of the visual tree and doesn't inherit the `DataContext`: the menu gets
+ `DataContext="{Binding Data, Source={StaticResource BindingProxy}}"` in XAML, with
+ `` in the view's own resources, declared before
+ the menus. The bindings inside the menu are plain bindings (`{Binding EditEntryCommand}`). Don't set the
+ `DataContext` in `ContextMenu_Opened` (until the menu is opened, its bindings fail and are logged as XAML binding
+ errors). `Opened` is only for extra work, e.g. `OnContextMenuOpened()` or the custom commands of the IP Scanner.
+- No bindings that have no element to resolve against: no `VisualBrush` / `BitmapImage` with a binding in a style
+ setter or as a freezable resource. Bind the property of the element with a converter instead
+ (`VisualToVisualBrushConverter`, `ApplicationNameToIconBrushConverter`, `Image Source="{Binding Uri}"`). A static
+ `VisualBrush` (`Visual="{iconPacks:Material Kind=...}"`) is fine. `MenuItem`s created outside a menu (e.g. extra
+ items in an `x:Array`) are fine: the implicit `DefaultMenuItem` style sets the content alignment directly instead
+ of the MahApps binding to the parent. New `MenuItem` styles are `BasedOn="{StaticResource DefaultMenuItem}"`.
- Order: Enable / Disable (only the applicable one) → Edit... → Copy as... → Delete → separator → Copy
(submenu, `CopyMenuItem` style) → Export...
- Icons (16×16 `Rectangle`, `MahApps.Brushes.Gray3`, `VisualBrush`): Enable `Material ToggleSwitchOutline`,
diff --git a/Source/NETworkManager.Converters/ProfileToPortScannerPortsConverter.cs b/Source/NETworkManager.Converters/ProfileToPortScannerPortsConverter.cs
new file mode 100644
index 0000000000..b89fde8830
--- /dev/null
+++ b/Source/NETworkManager.Converters/ProfileToPortScannerPortsConverter.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Globalization;
+using System.Windows.Data;
+using NETworkManager.Profiles;
+
+namespace NETworkManager.Converters;
+
+///
+/// Convert a to the ports the Port Scanner scans for it (own ports, otherwise the ports
+/// of its group, port profiles with their current name).
+///
+public sealed class ProfileToPortScannerPortsConverter : IValueConverter
+{
+ ///
+ /// Convert a to the ports to scan (see
+ /// ).
+ ///
+ /// Object from type .
+ ///
+ ///
+ ///
+ /// Ports to scan, empty if neither the profile nor its group has ports.
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return value is not ProfileInfo profile
+ ? string.Empty
+ : Profiles.Application.PortScanner.GetPorts(profile, out _);
+ }
+
+ ///
+ /// !!! Method not implemented !!!
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/Source/NETworkManager.Models/Network/IPScanner.cs b/Source/NETworkManager.Models/Network/IPScanner.cs
index f62f11742b..88053c2601 100644
--- a/Source/NETworkManager.Models/Network/IPScanner.cs
+++ b/Source/NETworkManager.Models/Network/IPScanner.cs
@@ -28,6 +28,9 @@ public sealed class IPScanner(IPScannerOptions options)
///
private static readonly TimeSpan MaxHostStartInterval = TimeSpan.FromMilliseconds(10);
+ // Data sent with the ping, created once (see IPScannerOptions.ICMPBufferSize)
+ private readonly byte[] _icmpBuffer = new byte[options.ICMPBufferSize];
+
private int _progressValue;
private readonly InterlockedCounter _hostsUp = new();
private readonly InterlockedCounter _hostsDown = new();
@@ -211,7 +214,7 @@ private async Task ScanHostAsync(IPAddress ipAddress, ParallelOptions portScanPa
var portAnswered = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
var pingTask = PingProbe.PingAsync(ipAddress, options.ICMPTimeout, options.ICMPAttempts,
- options.ICMPBuffer, cancellationToken);
+ _icmpBuffer, cancellationToken);
var portScanTask = options.PortScanEnabled
? PortScanAsync(ipAddress, portScanParallelOptions, () => portAnswered.TrySetResult(), cancellationToken)
diff --git a/Source/NETworkManager.Models/Network/IPScannerOptions.cs b/Source/NETworkManager.Models/Network/IPScannerOptions.cs
index 54e08dba1a..39047590e9 100644
--- a/Source/NETworkManager.Models/Network/IPScannerOptions.cs
+++ b/Source/NETworkManager.Models/Network/IPScannerOptions.cs
@@ -27,9 +27,10 @@ public record IPScannerOptions
public required int ICMPTimeout { get; init; }
///
- /// Size of the buffer used in the ping in bytes.
+ /// Size of the buffer used in the ping in bytes. A size, not the buffer, so options with the same values are
+ /// equal (records compare arrays by reference).
///
- public required byte[] ICMPBuffer { get; init; }
+ public required int ICMPBufferSize { get; init; }
///
/// Resolve the hostname for an IP address.
diff --git a/Source/NETworkManager.Models/Network/Ping.cs b/Source/NETworkManager.Models/Network/Ping.cs
index fc06a056d2..fc64412f19 100644
--- a/Source/NETworkManager.Models/Network/Ping.cs
+++ b/Source/NETworkManager.Models/Network/Ping.cs
@@ -1,7 +1,6 @@
using System;
using System.Net;
using System.Net.NetworkInformation;
-using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using NETworkManager.Utilities;
@@ -26,9 +25,9 @@ public sealed class Ping
public int Timeout = 4000;
///
- /// The buffer to send with the ping request. Default is 32 bytes.
+ /// The size in bytes of the buffer to send with the ping request. Default is 32 bytes.
///
- public byte[] Buffer = new byte[32];
+ public int BufferSize = 32;
///
/// The Time to Live (TTL) value for the ping request. Default is 64.
@@ -123,6 +122,8 @@ public void SendAsync(IPAddress ipAddress, CancellationToken cancellationToken)
var errorCount = 0;
+ var buffer = new byte[BufferSize];
+
var options = new PingOptions
{
Ttl = TTL,
@@ -139,7 +140,7 @@ public void SendAsync(IPAddress ipAddress, CancellationToken cancellationToken)
var timestamp = DateTime.Now;
// Send ping
- var pingReply = ping.Send(ipAddress, Timeout, Buffer, options);
+ var pingReply = ping.Send(ipAddress, Timeout, buffer, options);
// Reset the error count (if no exception was thrown)
errorCount = 0;
@@ -152,15 +153,8 @@ public void SendAsync(IPAddress ipAddress, CancellationToken cancellationToken)
}
else
{
- if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
- OnPingReceived(new PingReceivedArgs(
- new PingInfo(timestamp, pingReply.Address, hostname,
- pingReply.Buffer.Length, pingReply.RoundtripTime, pingReply.Options!.Ttl,
- pingReply.Status)));
- else
- OnPingReceived(new PingReceivedArgs(
- new PingInfo(timestamp, pingReply.Address, hostname,
- pingReply.Buffer.Length, pingReply.RoundtripTime, pingReply.Status)));
+ OnPingReceived(new PingReceivedArgs(
+ PingInfo.FromSuccessfulReply(timestamp, pingReply, hostname)));
}
}
catch (PingException ex)
diff --git a/Source/NETworkManager.Models/Network/PingInfo.cs b/Source/NETworkManager.Models/Network/PingInfo.cs
index 4a15bf88cb..e3c5c5bcfc 100644
--- a/Source/NETworkManager.Models/Network/PingInfo.cs
+++ b/Source/NETworkManager.Models/Network/PingInfo.cs
@@ -122,6 +122,22 @@ public PingInfo(DateTime timestamp, IPAddress ipAddress, string hostname, int by
Status = status;
}
+ ///
+ /// Creates a from a successful ping reply. The TTL is only available for IPv4.
+ ///
+ /// Timestamp when the ping was sent.
+ /// Successful reply of the ping.
+ /// Hostname of the host.
+ /// Information of the ping.
+ internal static PingInfo FromSuccessfulReply(DateTime timestamp, PingReply pingReply, string hostname = null)
+ {
+ return pingReply.Address.AddressFamily == AddressFamily.InterNetwork
+ ? new PingInfo(timestamp, pingReply.Address, hostname, pingReply.Buffer.Length, pingReply.RoundtripTime,
+ pingReply.Options!.Ttl, pingReply.Status)
+ : new PingInfo(timestamp, pingReply.Address, hostname, pingReply.Buffer.Length, pingReply.RoundtripTime,
+ pingReply.Status);
+ }
+
///
/// Timestamp when the ping was sent.
///
diff --git a/Source/NETworkManager.Models/Network/PingProbe.cs b/Source/NETworkManager.Models/Network/PingProbe.cs
index b5dff7a4cc..cc109803bf 100644
--- a/Source/NETworkManager.Models/Network/PingProbe.cs
+++ b/Source/NETworkManager.Models/Network/PingProbe.cs
@@ -1,7 +1,6 @@
using System;
using System.Net;
using System.Net.NetworkInformation;
-using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
@@ -43,26 +42,7 @@ public static async Task PingAsync(IPAddress ipAddress, int timeoutMs,
// Success
if (pingReply is { Status: IPStatus.Success })
- {
- switch (ipAddress.AddressFamily)
- {
- case AddressFamily.InterNetwork:
- return new PingInfo(
- timestamp,
- pingReply.Address,
- pingReply.Buffer.Length,
- pingReply.RoundtripTime,
- pingReply.Options!.Ttl,
- pingReply.Status);
- case AddressFamily.InterNetworkV6:
- return new PingInfo(
- timestamp,
- pingReply.Address,
- pingReply.Buffer.Length,
- pingReply.RoundtripTime,
- pingReply.Status);
- }
- }
+ return PingInfo.FromSuccessfulReply(timestamp, pingReply);
// Failed
pingInfo = new PingInfo(timestamp, ipAddress, pingReply.Status);
diff --git a/Source/NETworkManager.Models/Network/PortScanner.cs b/Source/NETworkManager.Models/Network/PortScanner.cs
index 72be0ce9a0..370ac31b5e 100644
--- a/Source/NETworkManager.Models/Network/PortScanner.cs
+++ b/Source/NETworkManager.Models/Network/PortScanner.cs
@@ -19,6 +19,7 @@ public sealed class PortScanner
public PortScanner(PortScannerOptions options)
{
_options = options;
+ _icmpBuffer = new byte[options.ICMPBufferSize];
}
#endregion
@@ -69,6 +70,9 @@ public PortScanner(PortScannerOptions options)
private readonly PortScannerOptions _options;
+ // Data sent with the ping before the scan, created once (see PortScannerOptions.ICMPBufferSize)
+ private readonly byte[] _icmpBuffer;
+
///
/// Gets the number of ports scanned so far. Thread-safe; may be read from any thread while the scan is
/// running.
@@ -394,7 +398,7 @@ await Parallel.ForEachAsync(hosts, pingParallelOptions, async (host, ct) =>
private async Task IsReachableAsync(IPAddress ipAddress, int portCount, CancellationToken cancellationToken)
{
var pingInfo = await PingProbe.PingAsync(ipAddress, _options.ICMPTimeout, _options.ICMPAttempts,
- _options.ICMPBuffer, cancellationToken).ConfigureAwait(false);
+ _icmpBuffer, cancellationToken).ConfigureAwait(false);
if (pingInfo.Status == IPStatus.Success)
return true;
diff --git a/Source/NETworkManager.Models/Network/PortScannerOptions.cs b/Source/NETworkManager.Models/Network/PortScannerOptions.cs
index 961e868fdb..ce447114d9 100644
--- a/Source/NETworkManager.Models/Network/PortScannerOptions.cs
+++ b/Source/NETworkManager.Models/Network/PortScannerOptions.cs
@@ -33,7 +33,7 @@ public record PortScannerOptions
///
/// Ping every host before its ports are scanned (with , and
- /// ), a host that doesn't answer is not scanned.
+ /// ), a host that doesn't answer is not scanned.
///
public required bool PingHostsBeforeScan { get; init; }
@@ -49,9 +49,10 @@ public record PortScannerOptions
public required int ICMPTimeout { get; init; }
///
- /// Data sent with the ping before the scan (see ).
+ /// Size in bytes of the data sent with the ping before the scan (see ). A size,
+ /// not the buffer, so options with the same values are equal (records compare arrays by reference).
///
- public required byte[] ICMPBuffer { get; init; }
+ public required int ICMPBufferSize { get; init; }
///
/// Resolve the hostname for an IP address.
diff --git a/Source/NETworkManager.Models/Network/Traceroute.cs b/Source/NETworkManager.Models/Network/Traceroute.cs
index 0115c98963..d0f6337622 100644
--- a/Source/NETworkManager.Models/Network/Traceroute.cs
+++ b/Source/NETworkManager.Models/Network/Traceroute.cs
@@ -17,6 +17,9 @@ public sealed class Traceroute
private readonly TracerouteOptions _options;
+ // Data sent with the ping, created once (see TracerouteOptions.BufferSize)
+ private readonly byte[] _buffer;
+
#endregion
#region Constructor
@@ -24,6 +27,7 @@ public sealed class Traceroute
public Traceroute(TracerouteOptions options)
{
_options = options;
+ _buffer = new byte[options.BufferSize];
}
#endregion
@@ -55,7 +59,7 @@ public void TraceAsync(IPAddress ipAddress, CancellationToken cancellationToken)
{
stopwatch.Start();
- pingReply = ping.Send(ipAddress, _options.Timeout, _options.Buffer,
+ pingReply = ping.Send(ipAddress, _options.Timeout, _buffer,
new PingOptions { Ttl = i1, DontFragment = _options.DontFragment });
stopwatch.Stop();
diff --git a/Source/NETworkManager.Models/Network/TracerouteOptions.cs b/Source/NETworkManager.Models/Network/TracerouteOptions.cs
index 2233fb378f..1cbaf5e941 100644
--- a/Source/NETworkManager.Models/Network/TracerouteOptions.cs
+++ b/Source/NETworkManager.Models/Network/TracerouteOptions.cs
@@ -9,16 +9,16 @@ public class TracerouteOptions
/// Create an instance of with parameters.
///
/// Timeout in milliseconds after which a ping is considered lost.
- /// Size of the buffer used in the ping in bytes.
+ /// Size of the buffer used in the ping in bytes.
/// Maximum number of hops between the local and remote computer.
/// Do not fragment the ping packet.
/// Resolve the hostname for an IP address.
/// Check IP geolocation via ip-api.com.
- public TracerouteOptions(int timeout, byte[] buffer, int maximumHops, bool dontFragment, bool resolveHostname,
+ public TracerouteOptions(int timeout, int bufferSize, int maximumHops, bool dontFragment, bool resolveHostname,
bool checkIPApiIPGeolocation)
{
Timeout = timeout;
- Buffer = buffer;
+ BufferSize = bufferSize;
MaximumHops = maximumHops;
DontFragment = dontFragment;
ResolveHostname = resolveHostname;
@@ -33,7 +33,7 @@ public TracerouteOptions(int timeout, byte[] buffer, int maximumHops, bool dontF
///
/// Size of the buffer used in the ping in bytes.
///
- public byte[] Buffer { get; }
+ public int BufferSize { get; }
///
/// Maximum number of hops between the local and remote computer.
diff --git a/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs b/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs
index d3ea08f0bf..48ad2b3032 100644
--- a/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs
+++ b/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs
@@ -46,6 +46,14 @@ public static class GlobalStaticConfiguration
// ICMP config: maximum buffer of a ping (.NET's Ping throws for more than 65500 bytes)
public static int ICMPBufferMaximum => 65500;
+ ///
+ /// Limits the buffer size of a ping from the settings to the limits of the input (1 to
+ /// ). A value edited in the settings file would throw or make every ping fail.
+ ///
+ /// Buffer size in bytes from the settings.
+ /// Buffer size in bytes within the limits.
+ public static int LimitICMPBuffer(int size) => Math.Clamp(size, 1, ICMPBufferMaximum);
+
// Profile config
public static bool Profile_TagsMatchAny => true;
public static bool Profile_ExpandProfileView => true;
diff --git a/Source/NETworkManager/ViewModels/IPScannerViewModel.cs b/Source/NETworkManager/ViewModels/IPScannerViewModel.cs
index c390d379af..4b92b976ab 100644
--- a/Source/NETworkManager/ViewModels/IPScannerViewModel.cs
+++ b/Source/NETworkManager/ViewModels/IPScannerViewModel.cs
@@ -901,9 +901,7 @@ private static IPScannerOptions CreateScanOptions(int[] ports)
MaxPortThreads = SettingsManager.Current.IPScanner_MaxPortThreads,
ICMPAttempts = SettingsManager.Current.IPScanner_ICMPAttempts,
ICMPTimeout = SettingsManager.Current.IPScanner_ICMPTimeout,
- // Limits of the input (a value edited in the settings file would throw or make every ping fail)
- ICMPBuffer = new byte[Math.Clamp(SettingsManager.Current.IPScanner_ICMPBuffer, 1,
- GlobalStaticConfiguration.ICMPBufferMaximum)],
+ ICMPBufferSize = GlobalStaticConfiguration.LimitICMPBuffer(SettingsManager.Current.IPScanner_ICMPBuffer),
ResolveHostname = SettingsManager.Current.IPScanner_ResolveHostname,
PortScanEnabled = SettingsManager.Current.IPScanner_PortScanEnabled,
PortScanPorts = ports,
diff --git a/Source/NETworkManager/ViewModels/PingMonitorViewModel.cs b/Source/NETworkManager/ViewModels/PingMonitorViewModel.cs
index 1a91956a2b..15104c8bcc 100644
--- a/Source/NETworkManager/ViewModels/PingMonitorViewModel.cs
+++ b/Source/NETworkManager/ViewModels/PingMonitorViewModel.cs
@@ -571,9 +571,7 @@ public void Start()
var ping = new Ping
{
Timeout = SettingsManager.Current.PingMonitor_Timeout,
- // Limits of the input (a value edited in the settings file would throw or make every ping fail)
- Buffer = new byte[Math.Clamp(SettingsManager.Current.PingMonitor_Buffer, 1,
- GlobalStaticConfiguration.ICMPBufferMaximum)],
+ BufferSize = GlobalStaticConfiguration.LimitICMPBuffer(SettingsManager.Current.PingMonitor_Buffer),
TTL = SettingsManager.Current.PingMonitor_TTL,
DontFragment = SettingsManager.Current.PingMonitor_DontFragment,
WaitTime = SettingsManager.Current.PingMonitor_WaitTime
diff --git a/Source/NETworkManager/ViewModels/PortScannerViewModel.cs b/Source/NETworkManager/ViewModels/PortScannerViewModel.cs
index 37c0164617..1c2811f163 100644
--- a/Source/NETworkManager/ViewModels/PortScannerViewModel.cs
+++ b/Source/NETworkManager/ViewModels/PortScannerViewModel.cs
@@ -1286,9 +1286,7 @@ private static PortScannerOptions CreateScanOptions()
PingHostsBeforeScan = SettingsManager.Current.PortScanner_PingHostsBeforeScan,
ICMPAttempts = SettingsManager.Current.PortScanner_ICMPAttempts,
ICMPTimeout = SettingsManager.Current.PortScanner_ICMPTimeout,
- // Limits of the input (a value edited in the settings file would throw or make every ping fail)
- ICMPBuffer = new byte[Math.Clamp(SettingsManager.Current.PortScanner_ICMPBuffer, 1,
- GlobalStaticConfiguration.ICMPBufferMaximum)],
+ ICMPBufferSize = GlobalStaticConfiguration.LimitICMPBuffer(SettingsManager.Current.PortScanner_ICMPBuffer),
ResolveHostname = SettingsManager.Current.PortScanner_ResolveHostname,
ShowAllResults = SettingsManager.Current.PortScanner_ShowAllResults
};
diff --git a/Source/NETworkManager/ViewModels/ProfileViewModel.cs b/Source/NETworkManager/ViewModels/ProfileViewModel.cs
index b810aef2ee..f6993ae211 100644
--- a/Source/NETworkManager/ViewModels/ProfileViewModel.cs
+++ b/Source/NETworkManager/ViewModels/ProfileViewModel.cs
@@ -14,6 +14,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
+using System.Net;
using System.Security;
using System.Threading.Tasks;
using System.Windows.Data;
@@ -1010,12 +1011,21 @@ private set
///
/// Checks if the query type of the profile fits the host (own or inherited), see
- /// .
+ /// . Every address the lookup can parse is valid (also shortened IPv4
+ /// forms like "127.1"), like in the DNS Lookup.
///
private void ValidateDNSLookupQueryType()
{
- DNSLookup_QueryTypeIsValid = !DNSLookup_OverrideQueryType || DNSLookup_QueryType != QueryType.PTR ||
- IPAddressHelper.AreIPAddresses(DNSLookup_InheritHost ? Host : DNSLookup_Host);
+ if (!DNSLookup_OverrideQueryType || DNSLookup_QueryType != QueryType.PTR)
+ {
+ DNSLookup_QueryTypeIsValid = true;
+ return;
+ }
+
+ var hosts = ((DNSLookup_InheritHost ? Host : DNSLookup_Host) ?? string.Empty).Split(';',
+ StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
+
+ DNSLookup_QueryTypeIsValid = hosts.Length > 0 && hosts.All(x => IPAddress.TryParse(x, out _));
}
#endregion
diff --git a/Source/NETworkManager/ViewModels/TracerouteViewModel.cs b/Source/NETworkManager/ViewModels/TracerouteViewModel.cs
index 748b20836a..d125f1caba 100644
--- a/Source/NETworkManager/ViewModels/TracerouteViewModel.cs
+++ b/Source/NETworkManager/ViewModels/TracerouteViewModel.cs
@@ -420,9 +420,7 @@ await DNSClientHelper.ResolveAorAaaaAsync(Host,
{
var traceroute = new Traceroute(new TracerouteOptions(
SettingsManager.Current.Traceroute_Timeout,
- // Limits of the input (a value edited in the settings file would throw or make every ping fail)
- new byte[Math.Clamp(SettingsManager.Current.Traceroute_Buffer, 1,
- GlobalStaticConfiguration.ICMPBufferMaximum)],
+ GlobalStaticConfiguration.LimitICMPBuffer(SettingsManager.Current.Traceroute_Buffer),
SettingsManager.Current.Traceroute_MaximumHops,
true,
SettingsManager.Current.Traceroute_ResolveHostname,
diff --git a/Source/NETworkManager/ViewModels/WebConsoleSettingsViewModel.cs b/Source/NETworkManager/ViewModels/WebConsoleSettingsViewModel.cs
index bd52d3f4f2..45753fe5e2 100644
--- a/Source/NETworkManager/ViewModels/WebConsoleSettingsViewModel.cs
+++ b/Source/NETworkManager/ViewModels/WebConsoleSettingsViewModel.cs
@@ -149,6 +149,8 @@ private async Task DeleteBrowsingData()
IsDeleteBrowsingDataStatusMessageDisplayed = false;
+ CoreWebView2Controller webView2Controller = null;
+
try
{
// Create a temporary WebView2 instance to clear browsing data
@@ -157,12 +159,10 @@ private async Task DeleteBrowsingData()
var windowHwnd = new WindowInteropHelper(Application.Current.MainWindow).Handle;
- var webView2Controller = await webView2Environment.CreateCoreWebView2ControllerAsync(windowHwnd);
+ webView2Controller = await webView2Environment.CreateCoreWebView2ControllerAsync(windowHwnd);
await webView2Controller.CoreWebView2.Profile.ClearBrowsingDataAsync();
- webView2Controller.Close();
-
DeleteBrowsingDataStatusMessage = Strings.BrowsingDataSuccessfullyDeletedMessage;
}
catch (Exception ex)
@@ -172,6 +172,11 @@ private async Task DeleteBrowsingData()
DeleteBrowsingDataStatusMessage = Strings.BrowsingDataErrorMessage;
}
+ finally
+ {
+ // Also on an error, otherwise the cache folder stays locked until the application is closed
+ webView2Controller?.Close();
+ }
IsDeleteBrowsingDataStatusMessageDisplayed = true;
}
diff --git a/Source/NETworkManager/Views/FirewallView.xaml.cs b/Source/NETworkManager/Views/FirewallView.xaml.cs
index 037f561b81..776bbad65f 100644
--- a/Source/NETworkManager/Views/FirewallView.xaml.cs
+++ b/Source/NETworkManager/Views/FirewallView.xaml.cs
@@ -53,7 +53,7 @@ private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e
}
///
- /// Set data context for menus.
+ /// Updates the selection dependent menu items when a context menu is opened.
///
///
///
diff --git a/Source/NETworkManager/Views/PortScannerHostView.xaml b/Source/NETworkManager/Views/PortScannerHostView.xaml
index 8a820e112a..834c438ed3 100644
--- a/Source/NETworkManager/Views/PortScannerHostView.xaml
+++ b/Source/NETworkManager/Views/PortScannerHostView.xaml
@@ -23,6 +23,7 @@
+
@@ -33,7 +34,8 @@
-
+
+
diff --git a/Source/NETworkManager/Views/SNMPView.xaml b/Source/NETworkManager/Views/SNMPView.xaml
index aecf87e9d0..1fb606ce28 100644
--- a/Source/NETworkManager/Views/SNMPView.xaml
+++ b/Source/NETworkManager/Views/SNMPView.xaml
@@ -102,9 +102,6 @@
x:Name="ComboBoxOid"
ItemsSource="{Binding OidHistoryView}"
IsReadOnly="{Binding IsRunning}">
-
-
-