【问题标题】:WPF - DataTemplate binding to static memberWPF - DataTemplate 绑定到静态成员
【发布时间】:2010-12-13 23:26:26
【问题描述】:

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

我想做的是:

  1. 初始化组件()
  2. 根据登录用户设置 CanSeePhotos
  3. 加载数据并适当显示

我的问题是,如果我在 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 永远不会被设置。

什么给了?

【问题讨论】:

    标签: wpf datatemplate


    【解决方案1】:

    这里有三个注意事项:

    注意事项一:该物业无变更通知

    某些数据绑定可能会在 InitializeComponent() 调用期间进行评估,而其他数据绑定将在稍后进行评估。您正在请求在 InitializeComponent() 已经返回后设置 CanSeePhotos 的能力。如果没有任何更改通知,在 InitializeComponent() 期间评估的任何绑定都将具有原始值并且不会被更新。之后评估的任何绑定(例如 DataBind 优先级)都将具有新值。为了在所有情况下都能正常工作,您需要某种更改通知。

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

    注意事项2:属性是静态的

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

    注意事项 3:DataTrigger 共享一个 Binding

    在设置 Visibility 时,您每次都在构造一个新的 Binding,因此它会获取 LoggedInUser.CanSeePhotos 的最新值。

    创建 DataTrigger 时,WPF 会在触发器加载时构造单个 Binding 并将其用于每个对象。这个 Binding 是在加载包含 DataTrigger 的资源字典时构建的,可能是在应用启动时,所以它总是会获取 CanSeePhotos 的默认值。这是因为 Source= 将实际对象分配到绑定中(其计算不会延迟)。所以每个 Binding 都是用 Source=true 或 Source=false 构造的。

    推荐解决方案

    使用带有 DependencyProperty 的 DependencyObject 并从静态属性中引用它,如下所示:

    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;
    

    【讨论】:

    • 嗨,Ray,我了解依赖属性,但不想使用它们,因为在第一次检索数据后,CanSeehotos 将永远不会更改。让我失望的是,将对象的可见性绑定到 DataTemplate 中的静态属性可以正常工作,但它在 DataTemplate 的 DataTrigger 中不起作用。感谢您的回答。我会试试的。
    • 感谢您澄清您的问题。我在我的答案中添加了一个新的“问题 3”,以阐明为什么 DataTrigger 不起作用,并在“问题 1”中添加了一些解释,以解释为什么在您的场景中需要更改通知。希望这会有所帮助。
    • +1,但是您在这里并不需要 DependencyProperty,恕我直言,实施 INotifyPropertyChanged 更好
    • 虽然在这种情况下我个人更喜欢 DependencyProperty,但 INotifyPropertyChanged 的​​工作量也差不多。我通常远离 INotifyPropertyChanged,因为一旦你添加了接口,你必须为 每个 属性实现通知,或者仔细记录哪些属性不通知。另外,我知道没有办法混合 INotifyPropertyChanged 和 DependencyProperty。也就是说,在这种情况下,我认为不会有太大的不同。
    • 在 DependencyProperty 和 INotifyPropertyChanged 之间进行选择主要是一个偏好问题...对我来说,DependencyProperty 有一个主要缺点:您需要继承 DependencyObject。对于复杂的类层次结构,这可能是一个大问题。 Kent Boogaart 有一篇关于这个主题的优秀文章:kentb.blogspot.com/2009/03/view-models-pocos-versus.html
    猜你喜欢
    • 1970-01-01
    • 2013-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    • 1970-01-01
    • 2011-02-11
    • 1970-01-01
    相关资源
    最近更新 更多