简体   繁体   English

数据绑定不适用于具有依赖项属性的用户控件的自定义属性(“输出”窗口很干净)

[英]Data Binding not working for User Control's custom Property with Dependency Property (Output window is clean)

Note: I am not having problem with controls inside User Control like other similar articles on StackOverflow, I am having with a Property of the User Control itself. 注意:我在用户控件内的控件没有问题,就像在StackOverflow上的其他类似文章一样,我在使用用户控件本身的属性。 I am making a Custom Control based on Canvas, with a Dependency Property (using propdb template): 我正在基于Canvas制作一个具有依赖项属性的自定义控件(使用propdb模板):

public sealed partial class PresentationViewer : Canvas
{

    #region Properties

    public ISlide PresentationSlide
    {
        get
        {
            Debug.WriteLine("Get PresentationSlide");
            return (ISlide)GetValue(PresentationSlideProperty);
        }
        set
        {
            Debug.WriteLine("Set PresentationSlide");
            SetValue(PresentationSlideProperty, value);
            this.ShowSlideContent();
        }
    }

    // Using a DependencyProperty as the backing store for PresentationSlide.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty PresentationSlideProperty =
        DependencyProperty.Register(nameof(PresentationSlide), typeof(ISlide), typeof(PresentationViewer), new PropertyMetadata(null));

    #endregion

    // Other codes...
}

In my Page, I use the control and bind that property: 在我的页面中,我使用控件并绑定该属性:

    <views:PresentationViewer x:Name="PresentationViewer" PresentationSlide="{Binding CurrentSlide, Mode=TwoWay}" />

This is how I set the Page's DataContext : 这就是我设置页面的DataContext

    public MainPage()
    {
        this.InitializeComponent();

        this.ViewModel = new MainPageViewModel();
        this.DataContext = this.ViewModel;
    }

And this is the code of my MainPageViewModel : 这是我的MainPageViewModel的代码:

public class MainPageViewModel : INotifyPropertyChanged
{

    // Other codes...

    public ISlide CurrentSlide
    {
        get
        {
            return this.CurrentPresentation?.Slides[this.CurrentSlideIndex];
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OpenSlide(int index)
    {
        if (index < 0)
        {
            index = 0;
        }

        if (index > this.TotalSlides - 1)
        {
            index = this.TotalSlides - 1;
        }

        this.currentSlideIndexField = index;

        this.PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.CurrentSlideIndex)));

        System.Diagnostics.Debug.WriteLine("Current Slide notified");
        this.PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.CurrentSlide)));

        this.PropertyChanged(this, new PropertyChangedEventArgs(nameof(this.PageCounter)));
    }

}

Notice the line where I print the notification of CurrentSlide property change. 请注意我在其中打印CurrentSlide属性更改通知的行。 However, no setter or getter of the User Control's property is called. 但是,不会调用用户控件属性的设置方法或获取方法。 Here is the output when OpenSlide is called (the output is since the beginning of the program): 这是调用OpenSlide时的输出(该输出自程序开始以来):

在此处输入图片说明

The Binding is already in two-way mode. 绑定已经处于双向模式。 And other control in my page (Label, etc...) are also notified and changed their content, such as the Page counter, so I guess it is not the ViewModel problem too. 页面中的其他控件(标签等)也将得到通知并更改其内容,例如页面计数器,因此我想这也不是ViewModel问题。 Am I missing something in my Custom Control class? 我的自定义控件类中缺少什么吗? How can I make the Binding work? 如何使绑定工作?

As explained in XAML Loading and Dependency Properties , the CLR wrapper of a dependency property may not be called, so your breakpoints aren't hit and the ShowSlideContent method isn't executed. XAML加载和依赖项属性中所述 ,可能不会调用依赖项属性的CLR包装器,因此不会出现断点,并且不会执行ShowSlideContent方法。 Instead, the framework directly calls the dependency property's GetValue and SetValue methods. 相反,框架直接调用依赖项属性的GetValueSetValue方法。

Because the current WPF implementation of the XAML processor behavior for property setting bypasses the wrappers entirely, you should not put any additional logic into the set definitions of the wrapper for your custom dependency property. 由于XAML处理器当前针对属性设置的行为的WPF实现完全绕过了包装器,因此您不应为自定义依赖项属性在包装器的集合定义中添加任何其他逻辑。 If you put such logic in the set definition, then the logic will not be executed when the property is set in XAML rather than in code. 如果将这样的逻辑放在集合定义中,则当在XAML中而不是在代码中设置属性时,将不会执行该逻辑。

In order to react on changed property values, you'll have to register a PropertyChangedCallback with property metadata: 为了对更改后的属性值做出反应,您必须使用属性元数据注册一个PropertyChangedCallback

public ISlide PresentationSlide
{
    get { return (ISlide)GetValue(PresentationSlideProperty); }
    set { SetValue(PresentationSlideProperty, value); }
}

public static readonly DependencyProperty PresentationSlideProperty =
    DependencyProperty.Register(
        nameof(PresentationSlide),
        typeof(ISlide),
        typeof(PresentationViewer),
        new PropertyMetadata(null, PresentationSlidePropertyChanged));

private static void PresentationSlidePropertyChanged(
    DependencyObject o, DependencyPropertyChangedEventArgs e)
{
    ((PresentationViewer)o).ShowSlideContent();
}

Or, with a lambda expression: 或者,使用lambda表达式:

public static readonly DependencyProperty PresentationSlideProperty =
    DependencyProperty.Register(
        nameof(PresentationSlide),
        typeof(ISlide),
        typeof(PresentationViewer),
        new PropertyMetadata(null,
            (o, e) => ((PresentationViewer)o).ShowSlideContent()));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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