WPF - DataTemplate绑定到静态成员

Gus*_*nti 4 wpf datatemplate

我有一个带有名为CanSeePhotos的布尔静态属性的类,这应该控制我的DataTemplate中图片的可见性.出于调试目的,我将"CanSeePhotos"绑定到DataTemplate中的文本块.

我想做的是:

  1. 的InitializeComponent()
  2. 根据登录用户设置CanSeePhotos
  3. 加载数据并适当显示

我的问题是如果我在InitializeComponent()之后设置CanSeePhotos = true,那么数据仍然显示为CanSeePhotos为false(如果我在它工作正常之前这样做).这是为什么?如何修复它以便我可以在加载数据之前的任何时候设置值?

这是我如何绑定到我的DataTemplate中的静态变量:

<TextBlock Text="{Binding Source={x:Static DAL:LoggedInUser.CanSeePhotos}, Mode=OneWay}"/>
Run Code Online (Sandbox Code Playgroud)

这是LoggedInUser类:

public class LoggedInUser
{
    public static bool CanSeePhotos { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

编辑:如果我将控件的可见性直接绑定到静态属性,它将根据属性的值显示/折叠:

Visibility="{Binding Source={x:Static DAL:LoggedInUser.CanSeePhotos}, Converter={StaticResource BooleanToVisibilityConverter}}"
Run Code Online (Sandbox Code Playgroud)

但我需要像这样使用DataTrigger:

<DataTrigger Binding="{Binding Source={x:Static DAL:LoggedInUser.CanSeePhotos}}" Value="true">
   <Setter TargetName="icon" Property="Source" Value="{Binding Photo}"/>
</DataTrigger>
Run Code Online (Sandbox Code Playgroud)

在上面的情况下,如果属性为true,则setter永远不会被设置.

是什么赋予了?

Ray*_*rns 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());

}
Run Code Online (Sandbox Code Playgroud)

该类将始终具有一个实例,该实例将可用作LoggedInUser.Instance.所以它有点像静态类.区别在于,LoggedInUser.Instance具有DependencyProperty,因此当您修改属性时,它可以通知任何感兴趣的各方.WPF的Binding将注册此通知,因此您的UI将更新.

上面的代码将在XAML中像这样使用:

Visibility="{Binding CanSeePhotos, Source={x:Static LoggedInUser.Instance}, Converter=...
Run Code Online (Sandbox Code Playgroud)

在您的代码隐藏中如果您需要访问CanSeePhotos,它将是,例如:

LoggedInUser.Instance.CanSeePhotos = true;
Run Code Online (Sandbox Code Playgroud)