简体   繁体   English

如何检查NetworkInterface对象的'OperationalStatus'属性中的更改?

[英]How to check for a change in the 'OperationalStatus' property of a NetworkInterface Object?

I want to mention that this property does NOT change internally so I can't use the code below. 我想提一下,此属性不会在内部更改,因此我不能使用下面的代码。 It changes from "Up" to "Down" or vice versa based on if theres a connection established on that NIC. 根据在该NIC上建立的连接,它从“上”更改为“下”,反之亦然。 So this property is changed external to the program. 因此,此属性在程序外部更改。

If I have a static NetworkInterface Object, and I want to do something (say show a message box) when the OperationalStatus property of that object changes from up to down, how would I do so? 如果我有一个static NetworkInterface对象,并且当该对象的OperationalStatus属性从上向下更改时,我想做些事情(例如显示一个消息框),我该怎么做? My current idea is to have a timer check every few seconds for a change in the property but I'd much rather have a response for the situation ASAP. 我目前的想法是每隔几秒钟就有一个计时器检查该属性的变化,但我宁愿尽快对此情况做出响应。 Also this seems sort of amateur. 同样,这似乎是业余爱好者。

Oh and I know this exists for property changes: 哦,我知道这存在于属性更改中:

    private string _status;

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

However since this property is changing externally from the program the set content won't ever be executed. 但是,由于此属性是从程序外部更改的,因此将永远不会执行设置的内容。 Anyone know a good fix for this? 有人知道一个好的解决办法吗?

Also, I think INotifyPropertyChanged might be helpful here but I've never used it before and the examples I've seen so far are sort of difficult for me to wrap my head around. 另外,我认为INotifyPropertyChanged在这里可能会有所帮助,但我以前从未使用过,到目前为止,我所看到的示例让我难以理解。 If this is the case, would you mind demonstrating using static NetworkInterface card; 如果这样,您可以介意使用static NetworkInterface card;演示吗static NetworkInterface card; as the object? 作为对象? I'd appreciate that much more than a "marked as dupe" flag. 我要感谢的不仅仅是“标记为欺骗”标志。 Thank you! 谢谢!

I'm am not aware of a general mechanism to be informed of changes to the status of a NetworkInterface object. 我不知道要通知NetworkInterface对象状态变化的一般机制。 However, if you really only do care about the status changing from Up to Down and vice a versa, you can subscribe to the NetworkChange.NetworkAvailabilityChanged event, and rescan the network interfaces status when the event is raised. 但是,如果您确实只在乎状态从Up变为Down ,反之亦然,则可以订阅NetworkChange.NetworkAvailabilityChanged事件,并在事件发生时重新扫描网络接口的状态。

It still requires examining all of the interfaces, but at least it happens only at a time when you know that at least one of them has changed. 它仍然需要检查所有接口,但是至少仅在您知道其中至少一个接口已更改时才发生。 This is much better than some kind of polling approach. 这比某种轮询方法要好得多。

Here is a short little WPF program that makes use of the event to maintain a list of known network interfaces, and to display in the window the interface name and its current operational status. 这是一个简短的WPF小程序,它利用该事件维护已知网络接口的列表,并在窗口中显示接口名称及其当前操作状态。 Adapters that are new — that is, they were not known the previous time the event was raised — are shown with a green background, those which have had a change in the OperationalStatus property value are shown with a yellow background, and those which are no longer present are shown with a red background (until the next time the event is raised, at which time they are removed completely). 新的适配器(即,在上一次引发事件时不为人所知)以绿色背景显示,那些在OperationalStatus属性值中已更改的适配器以黄色背景显示,而没有适配器。出现时间较长的内容会以红色背景显示(直到下次引发该事件时,才将其完全删除)。

The main work is done in the MainViewModel class: 主要工作在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());
    }
}

The above contains the code that is the actual answer to your question, ie the subscription to and handling of the NetworkChange.NetworkAvailabilityChanged event. 上面包含的代码是对您问题的实际答案,即对NetworkChange.NetworkAvailabilityChanged事件的订阅和处理。 The rest of this program is just there to provide a way for that code to operate and do something useful. 该程序的其余部分仅是提供一种方法来运行该代码并执行一些有用的操作。

The program uses a NetworkInterfaceModel class to track the status of each interface: 该程序使用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;
    }
}

Both of these "model" classes rely on an inherited class that provides the base functionality for implementing INotifyPropertyChanged : 这两个“模型”类都依赖于一个继承的类,该类提供了实现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));
    }
}

And of course, no WPF program is complete without the XAML describing the actual presentation of the data: 当然,没有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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM