在依赖属性 WPF 上使用绑定时出现问题 [重复]

Posted

技术标签:

【中文标题】在依赖属性 WPF 上使用绑定时出现问题 [重复]【英文标题】:Problem using a binding on a dependency property WPF [duplicate] 【发布时间】:2022-01-13 22:16:56 【问题描述】:

我正在尝试在 CustomView 类上使用 IsHighlighted 依赖项属性。当我传递一个硬布尔值时它按预期工作,但是当我传递一个绑定时它不起作用。有人知道为什么吗?

我还应该在 IsHighlighted 设置器中调用 OnPropertyChanged 吗?

MainWindow.xaml

<StackPanel>

    <!-- The data context is set properly -->
    <TextBlock Text="Binding Text" FontSize="50"/>
    
    <!-- This works! -->
    <views:CustomView IsHighlighted="true"/>

    <!-- This does not! -->
    <views:CustomView IsHighlighted="Binding Path=One"/>

</StackPanel>

MainWindowViewModel.cs

public class MainWindowViewModel : ViewModelBase


    private string _text;

    public string Text
    
        get  return _text; 
        set  _text = value; 
    

    private bool _one;

    public bool One
    
        get  return _one; 
        set  _one = value; 
    

    public MainWindowViewModel()
    
        Text = "bound text!";
        One = true;
    

CustomView.xaml

<UserControl>
    <Grid Background="Binding Path=CurrentBackground, 
                               RelativeSource=RelativeSource FindAncestor, 
                               AncestorType=x:Type local:CustomView, AncestorLevel=1">
        <TextBlock Text="Binding IsHighlighted" FontSize="40"/>
    </Grid>
</UserControl>

CustomView.xaml.cs

public partial class CustomView : UserControl

    public CustomView()
    
        InitializeComponent();
        DataContext = this;
    

    public static readonly DependencyProperty IsHighlightedProperty =
        DependencyProperty.Register(
          name: "IsHighlighted",
          propertyType: typeof(bool),
          ownerType: typeof(CustomView)
        );

    public bool IsHighlighted
    
        get => (bool)GetValue(IsHighlightedProperty);
        set => SetValue(IsHighlightedProperty, value);
    

    public Brush CurrentBackground
    
        get 
        
            if (IsHighlighted)
                return new SolidColorBrush(Colors.Yellow); // highlighted
            else
                return new SolidColorBrush(Colors.White); // not highlighted
        
    


    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        
    

【问题讨论】:

IsHighlighted="Binding Path=One" 不起作用,因为当前 DataContext 对象 - 即 Binding 的源对象 - 没有公开 One 属性(或者应该将其称为 On?)。这是因为您已明确设置 DataContext 以保存对控件的引用,而不是 MainWindow 的视图模型。具有可绑定属性的控件永远不应显式设置其自己的 DataContex,因为这会破坏控件属性的任何标准、基于 DataContext 的绑定。 当您在调试模式下运行应用程序时,您应该已经注意到 Visual Studio 的输出窗口中出现数据绑定错误消息。 【参考方案1】:

首先删除行DataContext = this;。用户控件将从其父级继承 DataContext(在本例中为 MainWindow.xaml,上下文为 MainViewModel)。

另一个问题是您正确地将 DataContext 设置为您的MainWindow。你设置了DataContextMainWindow.xaml 喜欢吗

this.DataContext = new MainWindowViewModel();

如果没有,请在 MainWindow.cs 的某个地方执行此操作(例如在构造函数中)。 DataContext 属性是绑定的默认来源。

https://docs.microsoft.com/en-us/dotnet/api/system.windows.frameworkelement.datacontext?view=windowsdesktop-6.0

第二件事是,您需要在 MainWindowViewModel One 属性设置器中调用 PropertyChanged

public bool One

    get  return _one; 
    set 
     
       _one = value; 
       OnPropertyChanged();
    

我期待您的ViewModelBase 正在实现INotifyPropertyChanged 接口。如果没有,您将需要实施它。在您的情况下,它可以在没有 INotifyPropertyChanged 实现的情况下工作,因为您在构造函数中设置了 One 属性。但是当您想在 ViewModel 中的某些逻辑中更改此属性时,您需要通知视图 One 属性正在更改/更改(您将使用 INotifyPropertyChanged 接口实现来完成)。

https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifypropertychanged?view=net-6.0

对 Xaml 中这些代码行的注释。

<Grid Background="Binding Path=CurrentBackground, 
                           RelativeSource=RelativeSource FindAncestor, 
                           AncestorType=x:Type local:CustomView, AncestorLevel=1">

如何更改背景的更好方法是创建一个类似 ValueConverter 的方法。

  public class BackgroundConverter : IValueConverter
  
      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
      
         return (bool)value ? new SolidColorBrush(Colors.Yellow) : SolidColorBrush(Colors.White);
      

      public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
      
         throw new NotImplementedException();
      
  

用法:

<Grid Background="Binding IsHighlighted,
                   RelativeSource=RelativeSource AncestorType=local:CustomView,
                   Converter=StaticResource BackgroundConverter">

【讨论】:

比转换器更好的是 DataTrigger。在任何一种情况下,请注意背景属性与 IsHighlighted 的绑定也需要RelativeSource=RelativeSource AncestorType=local:CustomView 为什么绑定也需要RelativeSource=RelativeSource AncestorType=local:CustomView?它是 MainViewModel 的一个属性,所以你可以像 Background="Binding IsHighlighted, Converter=StaticResource BackgroundConverter" 一样直接绑定它。哦,我错过了什么? 阅读问题。 IsHighlighted 在 CurrentBackground 之前声明。 这是一个糟糕的建议。控件不应该知道特定的视图模型。它应该公开像 IsHighlighted 这样的可绑定属性。 我已经代表您这样做了。考虑以网格样式显示 DataTrigger,以了解如何在没有转换器的情况下实现这一点。

以上是关于在依赖属性 WPF 上使用绑定时出现问题 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

2019-11-29-WPF-依赖属性绑定不上调试方法

C# WPF 在单击重复操作时出现气球提示问题

WPF非依赖属性绑定的问题

在依赖表上插入 Access 数据库时出现问题 [重复]

WPF 控件模板不根据依赖属性绑定值更改

无法数据绑定滑块 WPF 的值 [重复]