绑定ViewModel属性的值更新失败

时间:2015-09-11 14:47:54

标签: wpf mvvm custom-controls mvvm-light dependency-properties

我正在尝试将自定义控件属性绑定到其视图模型的属性及其失败。

我为设置StartDate定义了Dependency属性并更新了PropertyChangeCallback方法

public static readonly DependencyProperty StartDateProperty = 
           DependencyProperty.Register(StartDatePropertyName,
                                       typeof(DateTime),
                                       typeof(CustomDateTimeControl),
                                       new PropertyMetadata(DateTime.Now.AddYears(-7), 
                                                            OnStartDatePropertyChanged));

private static void OnStartDatePropertyChanged(DependencyObject d, 
                                               DependencyPropertyChangedEventArgs e)
{ 
       DateTime dtNewValue = (DateTime)e.NewValue;
        if (dtNewValue != DateTime.MinValue)
        {
            DateTimeControl dtCtrl = d as DateTimeControl;
            dtCtrl.StartDate = (DateTime)e.NewValue;
            dtCtrl.CoerceValue(StartDateProperty);
        }
 }

StartDate属性绑定到其ViewModel的开始日期,因为VM需要执行某些操作,然后将其用于定义自定义控件的下一个可用视图。

<Setter Property="StartDate" 
        Value="{Binding StartDate, 
                        Mode=OneWayToSource, 
                        UpdateSourceTrigger=PropertyChanged}" />

其中定义的DependencyProperty也是从mainWindow视图

设置的
<CustomDateTimeLib:CustomDateTimeControl  StartDate="01/01/2000 00:00:00"  />

绑定仅使用依赖项属性的默认值更新视图模型中的属性,但不使用在MainView中设置的值,即使依赖属性使用MainView中的值进行更新也是如此。

ViewModelLocator类

    public class ViewModelLocator
    {
    static ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            SimpleIoc.Default.Register<CalendarViewModel>();
        }

        /// <summary>
        /// Gets the Main property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public CustomDateTimeLib:CustomDateTimeControl CalendarVM
        {
            get
            {
                return ServiceLocator.Current.GetInstance<CustomDateTimeControl>();
            }
        }
}

App.Xaml

<Application x:Class="MvvmCustomTestApp.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:vm="clr-namespace:CustomDateTimeLib.ViewModel"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:ignore="http://www.galasoft.ch/ignore"
         StartupUri="MainWindow.xaml"
         mc:Ignorable="d ignore">

<Application.Resources>
    <!--Global View Model Locator-->
    <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
</Application.Resources>

CustomDateTimeControl类中的ApplyTemplate覆盖方法

 public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        CalendarViewModel vm = (CalendarViewModel)this.DataContext;
        vm.StartDate = this.StartDate;

}

还定义了StartDate的属性更改回调方法

1 个答案:

答案 0 :(得分:1)

如果我理解正确,您有一个要绑定到ViewModel属性的自定义DP,但是您还想从View中为此属性设置默认值。

对于MVVM或者当您使用绑定时,这不是一个理想的设置。 MVVM应该具有所有逻辑,包括&#34; X&#34;的默认值。在ViewModel图层中,View图层仅用于为用户提供与ViewModel(数据)图层交互的可视方式。

所以你的解决方案是:

  1. 在ViewModel中设置默认值
  2. 在您的依赖项属性中提供处理,如果值== DateTime.Min,则使用不同的默认值
  3. 如果您真的想让View提供默认值,请使用转换器(适用于.strings)或FallbackValue(适用于DateTime
  4. 使用第二个DP来定义应使用的默认值
  5. 向控件添加一个Loaded事件处理程序以读取DataContext并设置默认值
  6. 如果使用MVVM,选项1是最佳解决方案,因为应该在ViewModel中设置自定义DefaultValue之类的东西,而不是View。

    如果此默认值特定于此UserControl,则选项2最佳,并且在使用此控件的任何时候都是相同的。

    如果您确实坚持从视图层设置默认值,则选项3,4和5适用于任何原因。使用哪一个取决于您的情况。

    假设您使用#1,我希望您的最终XAML看起来像这样:

    DateTime?

    那就是它。

    上面的XAML代码中的<!-- assumes DataContext is of type DateTimeCtrlVM via inheritance or direct binding --> <CustomDateTimeLib:CustomDateTimeControl StartDate="{Binding StartDate}" /> 实际上会导致以下情况发生:

    • 使用默认值1/1/2000
    • 创建控件
    • 属性绑定<Setter>到VM属性,这意味着数据将仅从Target(Control)流向Source(ViewModel),因此1/1/2000的值将持久保存到您的VM

    因此,摆脱将属性绑定为OneWayToSource的Setter,使用上面显示的XAML绑定,并在ViewModel中设置默认值,它应该可以工作。