【问题标题】:How to check for a change in the 'OperationalStatus' property of a NetworkInterface Object?如何检查 NetworkInterface 对象的“OperationalStatus”属性的变化?
【发布时间】:2017-04-14 21:13:10
【问题描述】:

我想提一下,这个属性在内部不会改变,所以我不能使用下面的代码。根据是否在该 NIC 上建立了连接,它会从“Up”变为“Down”,反之亦然。所以这个属性是在程序外部改变的。

如果我有一个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; 作为对象进行演示吗?我会比“标记为欺骗”标志更欣赏这一点。谢谢!

【问题讨论】:

    标签: c# event-handling inotifypropertychanged network-interface


    【解决方案1】:

    我不知道通知NetworkInterface 对象状态更改的一般机制。但是,如果您真的只关心从UpDown 的状态变化,反之亦然,您可以订阅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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-21
      • 2017-08-18
      • 1970-01-01
      • 1970-01-01
      • 2014-03-16
      • 2019-06-09
      • 2014-04-18
      相关资源
      最近更新 更多