INotifyPropertyChanged的和静态属性(INotifyPropertyChange

2019-07-19 00:40发布

我在一个简单的问题追平自己在海里。 我有一个实现类INotifyPropertyChanged 。 一些实例属性干将使用静态特性,因此它们的值可以,如果静态属性的改变而改变? 这里有一个简单的例子。

class ExampleClass : INotifyPropertyChanged
{

    private static int _MinimumLength = 5;
    public static int MinimumLength
    {
        get
        {
            return _MinimumLength;
        }
        set
        {
            if (_MinimumLength != value)
            {
                _MinimumLength = value;
                //WHAT GOES HERE
            }
        }
    }

    private int _length = -1;
    public int length
    {
        get
        {
            return (_length > _MinimumLength) ? _length : _MinimumLength;
        }
        set
        {
            var oldValue = (_length > _MinimumLength) ? _length : _MinimumLength;
            if (_length != value)
            {
                _length = value;
                var newValue = (_length > _MinimumLength) ? _length : _MinimumLength;
                if (newValue != oldValue)
                {
                    OnPropertyChanged("length");
                }
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}

很明显,如果静态属性MinimumLength变化那么每个实例的属性length也可以改变。 但是应该如何静态属性信号可能变化的情况下? 它不能调用OnPropertyChanged因为这不是一成不变的。

我可以在所有实例的一流水平保持一个列表,并调用一个方法上的每个人,但不知何故,感觉有点小题大做。 或者,我可以拉的静态属性出到一个单独的类,但在逻辑上,他们住在一流水平。 是否有一个既定的模式为这个或者我应该有不同的考虑呢?

Answer 1:

如果你倾向于认为,设计的话,我会去像下面这样的解决方案:

public static int MinimumLength
{
    get { return _MinimumLength; }
    set
    {
        if (_MinimumLength != value)
        {
            _MinimumLength = value;
            OnGlobalPropertyChanged("MinimumLength");
        }
    }
}
static event PropertyChangedEventHandler GlobalPropertyChanged = delegate { };
static void OnGlobalPropertyChanged(string propertyName)
{
    GlobalPropertyChanged(
        typeof (ExampleClass), 
        new PropertyChangedEventArgs(propertyName));
}
public ExampleClass()
{
    // This should use a weak event handler instead of normal handler
    GlobalPropertyChanged += this.HandleGlobalPropertyChanged;
}
void HandleGlobalPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    switch (e.PropertyName)
    {
        case "MinimumLength":
            if (length > MinimumLength)
                length = MinimumLength;
            break;
    }
}

这是非常相当于保持实例的列表,但我觉得它更易于维护,更清晰。 此外,你真的需要使用弱事件处理策略,否则,你的情况下,将不会被垃圾收集,因为他们将永远与就像一个GC根的静态事件相关联。

您可以在下面的博客文章(这是我写的,所以我有偏见)阅读更多关于弱事件处理程序:

.NET弱事件处理程序-第一部分

.NET弱事件处理程序-第一部分

在一个不相关的音符你的代码是目前射击属性改变的时候,其实属性值并没有改变。 例如:

  1. 设置MinimumLength至5;
  2. 设定长度至10; (由于从缺省0-5的值变化事件触发)
  3. 设定长度11; (事件触发,但它不应该由于长度仍然5)


Answer 2:

您可以使用中提到的技术结合静态属性和实现INotifyPropertyChanged的 ,但也提出了一个通知对“长度”,例如,

class ExampleClass : INotifyPropertyChanged
{
    private static int _MinimumLength = 5;

    public int MinimumLength
    {
        get
        {
            return _MinimumLength;
        }
        set
        {
            if (_MinimumLength != value)
            {
                _MinimumLength = value;

                OnPropertyChanged("MinimumLength");
                OnPropertyChanged("length");
            }
        }
    }
    ...
}


Answer 3:

我面临着同样的问题。 这里是解决方案,我已经到位。

public class ZoomDataVm : ModelBase
{
    public ZoomDataVm()
    {
        // initialise the zoom
    }

    private double _zoomLevel;
    public double ZoomLevel
    {
        get { return _zoomLevel; }
        set
        {
            if (_zoomLevel != value)
            {
                _zoomLevel = value;
                RaisePropertyChanged(() => ZoomLevel);
                //
                // persist zoom info
            }
        }
    }
}

public class ZoomVm : ModelBase
{
    public static ZoomDataVm _instance;

    static ZoomVm()
    {
        _instance = new ZoomDataVm();
    }

    public ZoomDataVm Instance
    {
        get { return _instance; }
    }
}

然后,我用它在XAML像

<StackPanel>
    <StackPanel.Resources>
        <screenControls:ZoomVm x:Key="ZoomVm" />
    </StackPanel.Resources>
    <TextBlock Text="{Binding ElementName=uiScaleSliderContainer, Path=Tag}" Foreground="White" Margin="0,0,20,0" />
    <Control Name="uiScaleSliderContainer"
        Margin="0,0,0,0"
        VerticalAlignment="Center"
        HorizontalAlignment="Left"
        Tag="{Binding Source={StaticResource ZoomVm}, Path=Instance.ZoomLevel}">
        <Control.Template>
            <ControlTemplate>
                <Slider Orientation="Horizontal"
                    Width="400"
                    x:Name="uiScaleSlider"
                    ToolTip="Zoom"
                    Value="{Binding ElementName=uiScaleSliderContainer, Path=Tag}"
                    Minimum="0.1"
                    Maximum="2"
                    TickFrequency="0.1"
                    IsSnapToTickEnabled="True">
                </Slider>
            </ControlTemplate>
        </Control.Template>
    </Control>
</StackPanel>


文章来源: INotifyPropertyChanged and static properties