简体   繁体   中英

Problem using a binding on a dependency property WPF

I am trying to use the IsHighlighted dependency property on the CustomView class. It works as expected when I pass it a hard bool value, but it doesnt work when I pass it a binding. Anyone know why?

Also should I be calling OnPropertyChanged in the IsHighlighted setter?

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);
        }
    }
}

First remove line DataContext = this; . User control will inherit DataContext from his parent (in this case MainWindow.xaml and context will be MainViewModel ).

Another question is that you properly set DataContext to your MainWindow . Did you set DataContext of your MainWindow.xaml like

this.DataContext = new MainWindowViewModel();

If not, do it somewhere in MainWindow.cs (for example in constructor). The DataContext property is the default source of your bindings.

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

Second thing is, you need to call PropertyChanged in your MainWindowViewModel One property setter.

public bool One
{
    get { return _one; }
    set 
    { 
       _one = value; 
       OnPropertyChanged();
    }
}

I am expecting that your ViewModelBase is implementing the INotifyPropertyChanged interface. If not you will need to implement it. In your case, it will work without the INotifyPropertyChanged implementation because you set the One property in constructor. But when you want to change this property in some logic in your ViewModel, you will need to notify the view that the One property is changing/changed (you will do it with INotifyPropertyChanged` interface implementation).

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

One remark to these lines of code in Xaml.

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

A better way how to change the background is to create a ValueConverter like.

  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();
      }
  }

Usage:

<Grid Background="{Binding IsHighlighted, Converter={StaticResource BackgroundConverter}}">

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM