注意:我在用户控件中没有像StackOverflow上的其他类似文章一样的问题,我正在使用用户控件本身的属性。我正在基于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...
}
在我的页面中,我使用控件并绑定该属性:
<views:PresentationViewer x:Name="PresentationViewer" PresentationSlide="{Binding CurrentSlide, Mode=TwoWay}" />
这就是我设置网页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 < 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)));
}
}
请注意我打印CurrentSlide
属性更改通知的行。但是,不会调用User Control的属性的setter或getter。以下是调用OpenSlide
时的输出(输出自程序开始以来):
Binding已经处于双向模式。我的页面中的其他控件(标签等)也会被通知并更改其内容,例如Page计数器,所以我想这也不是ViewModel问题。我在自定义控件类中遗漏了什么吗?如何使Binding工作?
答案 0 :(得分:2)
如XAML Loading and Dependency Properties中所述,可能不会调用依赖项属性的CLR包装器,因此不会触发断点并且不会执行ShowSlideContent
方法。相反,框架直接调用依赖属性的GetValue
和SetValue
方法。
因为当前的WPF实现了XAML处理器的行为 对于属性设置完全绕过包装器,你不应该 将任何其他逻辑放入包装器的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()));