数据绑定不适用于具有依赖项属性的用户控件的自定义属性(输出窗口是干净的)
注意:我没有像UserOverflow上的其他类似文章那样使用User Control中的控件有问题,我正在使用User Control本身的属性。 我正在基于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... }
在我的页面中,我使用控件并绑定该属性:
这是我设置Page的DataContext
:
public MainPage() { this.InitializeComponent(); this.ViewModel = new MainPageViewModel(); this.DataContext = this.ViewModel; }
这是我的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 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))); } }
请注意我打印CurrentSlide
属性更改通知的行。 但是,不会调用User Control属性的setter或getter。 这是调用OpenSlide
时的输出(输出是从程序开始的):
绑定已经处于双向模式。 我的页面中的其他控件(标签等)也会被通知并更改其内容,例如Page计数器,所以我猜这也不是ViewModel问题。 我在自定义控件类中遗漏了什么吗? 如何使Binding工作?
如XAML加载和依赖项属性中所述 ,可能不会调用依赖项属性的CLR包装器,因此不会ShowSlideContent
断点并且不会执行ShowSlideContent
方法。 相反,框架直接调用依赖属性的GetValue
和SetValue
方法。
由于属性设置的XAML处理器行为的当前WPF实现完全绕过包装器,因此不应将任何其他逻辑放入自定义依赖项属性的包装器的集定义中。 如果将这样的逻辑放在set定义中,那么当在XAML中而不是在代码中设置属性时,将不会执行逻辑。
为了对更改的属性值做出反应,您必须使用属性元数据注册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(); }
或者,使用lambda表达式:
public static readonly DependencyProperty PresentationSlideProperty = DependencyProperty.Register( nameof(PresentationSlide), typeof(ISlide), typeof(PresentationViewer), new PropertyMetadata(null, (o, e) => ((PresentationViewer)o).ShowSlideContent()));