[英]INotifyPropertyChanged and static properties
I'm tying myself in knots over a simple problem. 我把自己绑在一个简单的问题上。 I have a class that implements INotifyPropertyChanged
. 我有一个实现INotifyPropertyChanged
的类。 Some of the instance properties' getters use static properties and thus their values may change if the static property changes? 某些实例属性的getter使用静态属性,因此如果静态属性发生变化,它们的值可能会发生变化? Here's a simplified example. 这是一个简化的例子。
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));
}
}
}
Clearly if the static property MinimumLength
changes then every instance's property length
may also change. 显然,如果静态属性MinimumLength
发生变化,那么每个实例的属性length
也可能会发生变化。 But how should the static property signal the possible change to the instances? 但静态属性应该如何表示对实例的可能更改? It cannot call OnPropertyChanged
since that is not static. 它不能调用OnPropertyChanged
因为它不是静态的。
I could keep a list at the class level of all the instances and call a method on each one, but somehow that feels like overkill. 我可以在所有实例的类级别保留一个列表,并在每个实例上调用一个方法,但不知何故,这感觉就像是矫枉过正。 Or I could pull the static properties out into a singleton class but logically they live at the class level. 或者我可以将静态属性拉出到单例类中,但逻辑上它们仍然存在于类级别。 Is there an established pattern for this or should I be thinking about this differently? 是否有既定的模式或者我应该以不同的方式考虑这个问题?
If you're inclined to maintain that design then I would go with a solution like the following: 如果您倾向于维护该设计,那么我将使用如下解决方案:
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;
}
}
This is pretty much equivalent to maintaining a list of instances but I find it more maintainable and clearer. 这几乎等同于维护实例列表,但我发现它更易于维护和清晰。 Also, you really need to use a weak event handler strategy, otherwise, your instances will not be garbage collected because they will always be associated with the static event which acts like a GC root. 此外,您确实需要使用弱事件处理程序策略,否则,您的实例将不会被垃圾收集,因为它们将始终与静态事件关联,静态事件的行为类似于GC根。
You can read more about weak event handlers in the following blog posts (which were written by me so I'm biased): 您可以在以下博客文章中阅读有关弱事件处理程序的更多信息(由我编写,因此我有偏见):
.NET Weak Event Handlers – Part I .NET弱事件处理程序 - 第一部分
.NET Weak Event Handlers – Part I .NET弱事件处理程序 - 第一部分
In an unrelated note your code is currently firing property changed when in fact the property value did not change. 在一个不相关的注释中,您的代码当前触发属性已更改,而实际上属性值未更改。 For example: 例如:
You could use the technique mentioned in Binding static property and implementing INotifyPropertyChanged but also raise a notification against "length", eg 您可以使用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");
}
}
}
...
}
i was faced to the same problem. 我遇到了同样的问题。 Here is the solution i have put in place. 这是我已经实施的解决方案。
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; }
}
}
Then i use it in the XAML like that 然后我就像那样在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.