[英]INotifyPropertyChanged and static properties
我把自己綁在一個簡單的問題上。 我有一個實現INotifyPropertyChanged
的類。 某些實例屬性的getter使用靜態屬性,因此如果靜態屬性發生變化,它們的值可能會發生變化? 這是一個簡化的例子。
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
因為它不是靜態的。
我可以在所有實例的類級別保留一個列表,並在每個實例上調用一個方法,但不知何故,這感覺就像是矯枉過正。 或者我可以將靜態屬性拉出到單例類中,但邏輯上它們仍然存在於類級別。 是否有既定的模式或者我應該以不同的方式考慮這個問題?
如果您傾向於維護該設計,那么我將使用如下解決方案:
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根。
您可以在以下博客文章中閱讀有關弱事件處理程序的更多信息(由我編寫,因此我有偏見):
在一個不相關的注釋中,您的代碼當前觸發屬性已更改,而實際上屬性值未更改。 例如:
您可以使用Binding靜態屬性中提到的技術並實現INotifyPropertyChanged,但也可以針對“length”發出通知,例如
class ExampleClass : INotifyPropertyChanged
{
private static int _MinimumLength = 5;
public int MinimumLength
{
get
{
return _MinimumLength;
}
set
{
if (_MinimumLength != value)
{
_MinimumLength = value;
OnPropertyChanged("MinimumLength");
OnPropertyChanged("length");
}
}
}
...
}
我遇到了同樣的問題。 這是我已經實施的解決方案。
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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.