WPF-数据模板绑定到静态成员

WPF-数据模板绑定到静态成员,wpf,datatemplate,Wpf,Datatemplate,我有一个名为CanSeePhotos的布尔静态属性类,它应该控制我的DataTemplate中图片的可见性。 出于调试目的,我将“CanSeePhotos”绑定到DataTemplate中的文本块 我想做的是: 初始化组件() 根据登录用户设置CanSeePhotos 加载数据并适当显示 我的问题是,如果在InitializeComponent()之后设置CanSeePhotos=true,那么数据仍然显示为false(如果我在正常工作之前这样做)。为什么呢?如何修复它,以便在加载数据之前在任意

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

我想做的是:

  • 初始化组件()
  • 根据登录用户设置CanSeePhotos
  • 加载数据并适当显示
  • 我的问题是,如果在InitializeComponent()之后设置CanSeePhotos=true,那么数据仍然显示为false(如果我在正常工作之前这样做)。为什么呢?如何修复它,以便在加载数据之前在任意点设置值

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

    <TextBlock Text="{Binding Source={x:Static DAL:LoggedInUser.CanSeePhotos}, Mode=OneWay}"/>
    
    编辑: 如果我将控件的可见性直接绑定到静态属性,它将根据属性的值显示/折叠:

    Visibility="{Binding Source={x:Static DAL:LoggedInUser.CanSeePhotos}, Converter={StaticResource BooleanToVisibilityConverter}}"
    
    但我需要使用这样的数据触发器:

    <DataTrigger Binding="{Binding Source={x:Static DAL:LoggedInUser.CanSeePhotos}}" Value="true">
       <Setter TargetName="icon" Property="Source" Value="{Binding Photo}"/>
    </DataTrigger>
    
    
    
    在上述情况下,如果属性为true,则永远不会设置setter


    给出了什么?

    这里有三个考虑因素:

    考虑事项1:物业没有变更通知

    某些数据绑定可能在InitializeComponent()调用期间进行计算,其他数据绑定将在稍后进行计算。您正在请求在InitializeComponent()返回后设置CanSeePhotos的功能。如果没有任何更改通知,则InitializeComponent()期间计算的任何绑定都将具有原始值,并且不会更新。之后计算的任何绑定(例如在数据绑定优先级)都将具有新值。为了在所有情况下都能做到这一点,您需要某种更改通知

    使用用“{get;set;}”声明的NET Framework属性将不起作用,因为该属性没有机制在其值更改时通知任何人。实际上,有两种非常隐蔽的方法可以从标准的NET Framework属性(MarshallByRefObject和IL重写)获取通知,但它们对于您的情况来说太复杂了

    考虑因素2:属性是静态的

    NET Framework有几种属性更改通知机制(DependencyProperty、INotifyPropertyChanged等),但没有一种内置机制支持对静态属性的更改通知。因此,如果不创建新的机制来发送更改信号,就不能使用静态属性(例如,可以有一个包装属性的对象)

    考虑事项3:数据触发器共享一个绑定

    设置可见性时,您每次都在构造一个新绑定,因此它会获取LoggedInUser.CanSeePhotos的最新值

    创建DataTrigger时,WPF在加载触发器时构造一个绑定,并对每个对象使用它。此绑定是在加载包含DataTrigger的资源字典时构造的,这可能是在应用程序启动时,因此它将始终获得CanSeePhotos的默认值。这是因为Source=将实际对象分配到绑定中(其计算不会延迟)。因此,每个绑定都是用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的绑定将注册此通知,因此您的UI将被更新

    上述代码在XAML中的使用方式如下:

    Visibility="{Binding CanSeePhotos, Source={x:Static LoggedInUser.Instance}, Converter=...
    
    在您的代码隐藏中,如果您需要访问CanSeePhotos,它将是,例如:

    LoggedInUser.Instance.CanSeePhotos = true;
    

    嗨,Ray,我了解依赖属性,但不想使用它们,因为在第一次检索数据后,CanSeehotos将永远不会更改。让我恼火的是,将对象的可见性绑定到DataTemplate中的静态属性可以很好地工作,但在DataTemplate的DataTrigger中不起作用。谢谢你的回答。我会试试的。谢谢你澄清你的问题。我在我的答案中添加了一个新的“问题3”,以澄清为什么DataTrigger不起作用,并在“问题1”中添加了一些解释,以解释为什么在场景中需要更改通知。希望这有帮助。+1,但是您在这里并不真正需要DependencyProperty,我认为实现INotifyPropertyChanged更好。虽然我个人更喜欢DependencyProperty,但INotifyPropertyChanged也需要付出同样的努力。我通常远离INotifyPropertyChanged,因为一旦添加了接口,就必须为每个属性实现通知,或者仔细记录哪些属性没有通知。而且,我知道没有办法将INotifyPropertyChanged和DependencyProperty混合在一起。也就是说,在这种情况下,我不认为会有太大的区别。在依赖性属性和InotifyProperty更改之间进行选择主要是偏好的问题。。。对我来说,DependencyProperty有一个主要缺点:需要继承DependencyObject。对于复杂的类层次结构,这可能是一个大问题。Kent Boogaart有一篇关于该主题的优秀文章:
    LoggedInUser.Instance.CanSeePhotos = true;