如何检查网络接口对象的'OperationalStatus'属性是否更改?



我想提一下,此属性不会在内部更改,所以我不能使用以下代码。它从"向上"更改为"向下",反之亦然,具体取决于该 NIC 上是否建立了连接。因此,此属性在程序外部更改。

如果我有一个static NetworkInterface对象,并且我想在该对象的OperationalStatus属性从上到下更改时执行某些操作(例如显示消息框),我将如何操作?我目前的想法是每隔几秒钟检查一次计时器以更改属性,但我宁愿尽快对这种情况做出响应。这似乎有点业余。

哦,我知道这适用于属性更改:

private string _status;
public string status
{
get { return _status; }
set
{
if (value != _status)
{
_status = value;
MessageBox.Show("VPN status changed to: ", _status);
}
}
}

但是,由于此属性从程序外部更改,因此永远不会执行设置的内容。有人知道这个问题的好方法吗?

另外,我认为INotifyPropertyChanged在这里可能会有所帮助,但我以前从未使用过它,到目前为止我看到的示例对我来说有点难以理解。如果是这种情况,您介意演示如何使用static NetworkInterface card;作为对象吗?我更欣赏的是"标记为欺骗"的标志。谢谢!

我不知道有一般机制可以通知NetworkInterface对象状态的变化。但是,如果您确实只关心状态从Up更改为Down,反之亦然,则可以订阅NetworkChange.NetworkAvailabilityChanged事件,并在引发事件时重新扫描网络接口状态。

它仍然需要检查所有接口,但至少只有在您知道其中至少一个接口已更改时才会发生。这比某种轮询方法要好得多。

下面是一个简短的小型 WPF 程序,它利用该事件来维护已知网络接口的列表,并在窗口中显示接口名称及其当前操作状态。新的适配器(即,在上次引发事件时不知道它们)以绿色背景显示,OperationalStatus属性值已更改的适配器以黄色背景显示,不再存在的适配器以红色背景显示(直到下次引发事件, 此时它们将被完全删除)。

主要工作是在MainViewModel类中完成的:

class MainModel : NotifyPropertyChangedBase
{
private readonly Dictionary<string, NetworkInterfaceModel> _cache = new Dictionary<string, NetworkInterfaceModel>();
private IReadOnlyList<NetworkInterfaceModel> _interfaces;
public IReadOnlyList<NetworkInterfaceModel> Interfaces
{
get { return _interfaces; }
private set { _UpdateField(ref _interfaces, value); }
}
public MainModel()
{
NetworkChange.NetworkAvailabilityChanged += _OnNetworkAvailabilityChanged;
_RebuildInterfaceList();
}
private void _OnNetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
foreach (NetworkInterfaceModel model in _interfaces)
{
if (model.PostEventStatus == PostEventStatus.Removed)
{
_cache.Remove(model.Name);
}
else
{
// Assume removed, until proven otherwise while rebuilding list
model.SetRemoved();
}
}
_RebuildInterfaceList();
}
private void _RebuildInterfaceList()
{
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces())
{
NetworkInterfaceModel model;
if (!_cache.TryGetValue(networkInterface.Name, out model))
{
model = new NetworkInterfaceModel(networkInterface);
_cache.Add(model.Name, model);
}
else
{
model.Reset();
model.OperationalStatus = networkInterface.OperationalStatus;
}
}
Interfaces = Array.AsReadOnly(_cache.Values.OrderBy(m => m.Name).ToArray());
}
}

上面包含的代码是您的问题的实际答案,即订阅和处理NetworkChange.NetworkAvailabilityChanged事件。该程序的其余部分只是为该代码提供一种操作和做一些有用的事情的方法。

该程序使用NetworkInterfaceModel类来跟踪每个接口的状态:

enum PostEventStatus
{
Added,
NoChange,
Changed,
Removed
}
class NetworkInterfaceModel : NotifyPropertyChangedBase
{
private string _name;
private OperationalStatus _status;
private PostEventStatus _postEventStatus = PostEventStatus.Added;
public NetworkInterfaceModel(NetworkInterface networkInterface)
{
_name = networkInterface.Name;
_status = networkInterface.OperationalStatus;
}
public string Name
{
get { return _name; }
set { _UpdateField(ref _name, value); }
}
public OperationalStatus OperationalStatus
{
get { return _status; }
set { _UpdateField(ref _status, value, _OnOperationalStatusChanged); }
}
public PostEventStatus PostEventStatus
{
get { return _postEventStatus; }
set { _UpdateField(ref _postEventStatus, value); }
}
public void Reset()
{
PostEventStatus = PostEventStatus.NoChange;
}
public void SetRemoved()
{
PostEventStatus = PostEventStatus.Removed;
}
private void _OnOperationalStatusChanged(OperationalStatus obj)
{
PostEventStatus = PostEventStatus.Changed;
}
}

这两个"模型"类都依赖于一个继承的类,该类提供实现INotifyPropertyChanged的基本功能:

class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void _UpdateField<T>(ref T field, T newValue,
Action<T> onChangedCallback = null,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, newValue))
{
return;
}
T oldValue = field;
field = newValue;
onChangedCallback?.Invoke(oldValue);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

当然,如果没有描述数据实际表示形式的 XAML,任何 WPF 程序都是不完整的:

<Window x:Class="TestSO43419337OperationalStatusChange.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:l="clr-namespace:TestSO43419337OperationalStatusChange"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<l:MainModel/>
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type l:NetworkInterfaceModel}">
<Border BorderBrush="Black" BorderThickness="1">
<Border.Style>
<p:Style TargetType="Border">
<p:Style.Triggers>
<DataTrigger Binding="{Binding PostEventStatus}" Value="{x:Static l:PostEventStatus.Added}">
<Setter Property="Background" Value="LightGreen"/>
</DataTrigger>
<DataTrigger Binding="{Binding PostEventStatus}" Value="{x:Static l:PostEventStatus.Changed}">
<Setter Property="Background" Value="Yellow"/>
</DataTrigger>
<DataTrigger Binding="{Binding PostEventStatus}" Value="{x:Static l:PostEventStatus.Removed}">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</p:Style.Triggers>
</p:Style>
</Border.Style>
<Grid Margin="3">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Name: " Grid.Row="0" Grid.Column="0"/>
<TextBlock Text="{Binding Name}" Grid.Row="0" Grid.Column="1"/>
<TextBlock Text="Operational Status: " Grid.Row="1" Grid.Column="0"/>
<TextBlock Text="{Binding OperationalStatus}" Grid.Row="1" Grid.Column="1"/>
</Grid>
</Border>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Interfaces}" HorizontalContentAlignment="Stretch"/>
</Grid>
</Window>

相关内容

  • 没有找到相关文章

最新更新