我有一个带有名为CanSeePhotos的布尔静态属性的类,这应该控制我的DataTemplate中图片的可见性。 出于调试目的,我将“CanSeePhotos”绑定到DataTemplate中的文本块。
我想做的是:
我的问题是,如果我在InitializeComponent()之后设置CanSeePhotos = true,那么数据仍显示为CanSeePhotos为false(如果我在它工作正常之前这样做)。这是为什么?如何修复它以便我可以在加载数据之前随时设置值?
以下是我在DataTemplate中绑定静态变量的方法:
<TextBlock Text="{Binding Source={x:Static DAL:LoggedInUser.CanSeePhotos}, Mode=OneWay}"/>
这是LoggedInUser类:
public class LoggedInUser
{
public static bool CanSeePhotos { get; set; }
}
编辑: 如果我将控件的可见性直接绑定到静态属性,它将根据属性的值显示/折叠:
Visibility="{Binding Source={x:Static DAL:LoggedInUser.CanSeePhotos}, Converter={StaticResource BooleanToVisibilityConverter}}"
但我需要像这样使用DataTrigger:
<DataTrigger Binding="{Binding Source={x:Static DAL:LoggedInUser.CanSeePhotos}}" Value="true">
<Setter TargetName="icon" Property="Source" Value="{Binding Photo}"/>
</DataTrigger>
在上面的情况中,如果属性为true,则setter永远不会被设置。
是什么给出了?
答案 0 :(得分:7)
这里有三个注意事项:
考虑事项1:该属性没有变更通知
可以在InitializeComponent()调用期间评估某些数据绑定,稍后再评估其他数据绑定。您正在请求在InitializeComponent()已经返回后设置CanSeePhotos的功能。如果没有任何更改通知,则在InitializeComponent()期间评估的任何绑定都将具有原始值,并且不会更新。之后评估的任何绑定(例如在DataBind优先级)将具有新值。要在所有情况下都能使用此功能,您需要进行某种更改通知。
使用以“{get; set;}”声明的.NET Framework属性将不起作用,因为该属性没有机制在其值发生更改时通知任何人。实际上有两种非常偷偷摸摸的方法可以从标准的.NET Framework属性(MarshalByRefObject和IL重写)获取通知,但它们对于您的情况来说太复杂了。
考虑2:属性是静态的
.NET Framework具有多个属性更改通知机制(DependencyProperty,INotifyPropertyChanged等),但没有任何内置机制支持静态属性的更改通知。因此,如果不创建用于发送更改信号的新机制,则不能使用静态属性(例如,您可以拥有一个包装属性的对象)。
考虑3:DataTriggers共享一个Binding
设置Visibility时,每次都在构建一个新的Binding,因此它获取LoggedInUser.CanSeePhotos的最新值。
创建DataTrigger时,WPF在加载触发器时构造单个Binding并将其用于每个对象。当加载包含DataTrigger的资源字典时,可以在应用程序启动时构建此Binding,因此它将始终获取CanSeePhotos的默认值。这是因为Source =将一个实际对象分配到绑定中(它的计算不是延迟的)。所以每个Binding都是用Source = true或Source = false构建的。
推荐的解决方案
将DependencyObject与DependencyProperty一起使用,并从静态属性引用它,如下所示:
public class LoggedInUser : DependencyObject
{
// Singleton pattern (Expose a single shared instance, prevent creating additional instances)
public static readonly LoggedInUser Instance = new LoggedInUser();
private LoggedInUser() { }
// Create a DependencyProperty 'CanSeePhotos'
public bool CanSeePhotos { get { return (bool)GetValue(CanSeePhotosProperty); } set { SetValue(CanSeePhotosProperty, value); } }
public static readonly DependencyProperty CanSeePhotosProperty = DependencyProperty.Register("CanSeePhotos", typeof(bool), typeof(LoggedInUser), new UIPropertyMetadata());
}
此类将始终具有一个实例,该实例将可用作LoggedInUser.Instance。所以它有点像静态类。区别在于,LoggedInUser.Instance具有DependencyProperty,因此当您修改属性时,它可以通知任何感兴趣的各方。 WPF的Binding将注册此通知,因此您的UI将会更新。
上面的代码将在XAML中使用:
Visibility="{Binding CanSeePhotos, Source={x:Static LoggedInUser.Instance}, Converter=...
如果你需要访问CanSeePhotos,你的代码隐藏就可以了,例如:
LoggedInUser.Instance.CanSeePhotos = true;