Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/256.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用户控件DependencyPropertyChanged事件触发,但绑定的viewmodel未更新。。。什么';发生什么事了?_C#_Wpf_Datepicker_Dependency Properties - Fatal编程技术网

C# 用户控件DependencyPropertyChanged事件触发,但绑定的viewmodel未更新。。。什么';发生什么事了?

C# 用户控件DependencyPropertyChanged事件触发,但绑定的viewmodel未更新。。。什么';发生什么事了?,c#,wpf,datepicker,dependency-properties,C#,Wpf,Datepicker,Dependency Properties,我最近偶然发现了WPFs DatePicker控件。基本上,当您: 通过样式设置DatePickers控件模板 将IsEnabled绑定到ViewModel上的属性 运行程序并启用日期选择器 下拉日历弹出窗口 禁用日期选择器,然后重新启用它 再次下拉日历弹出窗口 我知道这是一个非常特殊的场景,但在我的应用程序中,这种情况经常发生。一个完全由控件组成的整个用户控件从禁用开始,用户选择一条记录(填写表单)、编辑、保存、重复。第二次运行时,从日期选择器中选择日历会使其崩溃 我将DatePicker控件

我最近偶然发现了WPFs DatePicker控件。基本上,当您:

  • 通过样式设置DatePickers控件模板
  • 将IsEnabled绑定到ViewModel上的属性
  • 运行程序并启用日期选择器
  • 下拉日历弹出窗口
  • 禁用日期选择器,然后重新启用它
  • 再次下拉日历弹出窗口
  • 我知道这是一个非常特殊的场景,但在我的应用程序中,这种情况经常发生。一个完全由控件组成的整个用户控件从禁用开始,用户选择一条记录(填写表单)、编辑、保存、重复。第二次运行时,从日期选择器中选择日历会使其崩溃

    我将DatePicker控件模板设置为在禁用时显示禁用的文本框的样式,以便更好地适应其余禁用外观的外观(我对组合框也做了相同的设置,没有问题)

    因此,知道这是我的问题的原因,我开始创建自己的用户控件来处理日期选择器的禁用外观。它只是包装一个日期选择器,提供一些依赖属性来绑定到我关心的日期选择器属性,并在禁用时用文本框交换用户控件的模板。这样我就可以得到我想要的外观,而不必被采摘者的错误绊倒

    我的问题是,当我在用户控件上选择新日期时,DependencyPropertyChanged事件将以新值触发,但这些值永远不会到达我绑定到的外部viewmodel。我已经从各个方面考虑过了,但这对我来说毫无意义:

    禁用日期选择器代码隐藏

    public partial class DisableableDatePicker : UserControl
    {
        public static readonly DependencyProperty SelectedDateProperty = DependencyProperty.Register("SelectedDate", typeof(DateTime?), typeof(DisableableDatePicker), new PropertyMetadata(DateChanged));
    
        private static void DateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Console.WriteLine(((DateTime)e.NewValue).ToString("yyyy-MM-dd"));
        }
    
        public DateTime? SelectedDate
        {
            get { return (DateTime?)GetValue(SelectedDateProperty); }
            set { SetValue(SelectedDateProperty, value); }
        }
    
        public static readonly DependencyProperty DisplayDateEndProperty = DependencyProperty.Register("DisplayDateEnd", typeof(DateTime?), typeof(DisableableDatePicker));
        public DateTime? DisplayDateEnd
        {
            get { return (DateTime?)GetValue(DisplayDateEndProperty); }
            set { SetValue(DisplayDateEndProperty, value); }
        }
    
        public static readonly DependencyProperty DisplayDateStartProperty = DependencyProperty.Register("DisplayDateStart", typeof(DateTime?), typeof(DisableableDatePicker));
        public DateTime? DisplayDateStart
        {
            get { return (DateTime?)GetValue(DisplayDateStartProperty); }
            set { SetValue(DisplayDateStartProperty, value); }
        }
    
        public static readonly DependencyProperty BlackoutDatesProperty = DependencyProperty.Register("BlackoutDates", typeof(List<DateTime>), typeof(DisableableDatePicker));
        public List<DateTime> BlackoutDates
        {
            get { return (List<DateTime>)GetValue(BlackoutDatesProperty); }
            set { SetValue(BlackoutDatesProperty, value); }
        }
    
        public DisableableDatePicker()
        {
            InitializeComponent();
    
            ClearValue(SelectedDateProperty);
            ClearValue(DisplayDateEndProperty);
            ClearValue(DisplayDateStartProperty);
            ClearValue(BlackoutDatesProperty);
            ClearValue(IsEnabledProperty);
        }
    }
    
    因此,当我在ViewModels getter和setter中放置断点时,getter被正确地命中,但setter从未被调用。我觉得这很奇怪,因为我的dependency属性报告它看到了新的值

    这个谜题的最后一个部分是我如何绑定停电日期。我希望能够绑定到一个简单的日期列表。为了方便地执行此操作,我在附加属性中添加了以下内容:

     public static readonly DependencyProperty BlackoutDatesProperty =
        DependencyProperty.RegisterAttached("BlackoutDates", typeof(List<DateTime>),
        typeof(DependencyPropertyHost), 
        new FrameworkPropertyMetadata(null, OnBlackoutDatesChanged));
    
    public static List<DateTime> GetBlackoutDates(DependencyObject d)
    {
        return (List<DateTime>)d.GetValue(BlackoutDatesProperty);
    }
    
    public static void SetBlackoutDates(DependencyObject d, List<DateTime> value)
    {
        d.SetValue(BlackoutDatesProperty, value);
    }
    
    private static void OnBlackoutDatesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        DatePicker datePicker = d as DatePicker;
        if (e.NewValue != null && datePicker != null)
        {
            List<DateTime> blackoutDates = (List<DateTime>)e.NewValue;
            var toRemove = datePicker.BlackoutDates.Select
                                                    (x => x.Start).Except
                                                    (blackoutDates.Select(y => y)).ToList();
            foreach (DateTime date in toRemove)
            {
                datePicker.BlackoutDates.Remove(datePicker.BlackoutDates.Single(x => x.Start == date));
            }
            foreach (DateTime date in blackoutDates)
            {
                if (!datePicker.BlackoutDates.Contains(date) && 
                    date >= datePicker.DisplayDateStart && 
                    date <= datePicker.DisplayDateEnd && 
                    datePicker.SelectedDate != date)
                {
                    datePicker.BlackoutDates.Add(new CalendarDateRange(date));
                }
            }
        }
    }
    
    公共静态只读从属属性BlackoutDatesProperty=
    从属财产。注册(“停电日期”,类型(列表),
    类型(DependencyPropertyHost),
    新的FrameworkPropertyMetadata(null,OnBlackoutDatesChanged));
    公共静态列表GetBlackoutDates(DependencyObject d)
    {
    返回(列表)d.GetValue(BlackoutDatesProperty);
    }
    公共静态void SetBlackoutDates(DependencyObject d,列表值)
    {
    d、 设置值(BlackoutDatesProperty,value);
    }
    BlackoutDateSchanged上的私有静态无效(DependencyObject d、DependencyPropertyChangedEventArgs e)
    {
    DatePicker DatePicker=d作为日期选择器;
    if(e.NewValue!=null&&datePicker!=null)
    {
    列表停电日期=(列表)e.NewValue;
    var toRemove=datePicker.BlackoutDates.Select
    (x=>x.Start)。除了
    (blackoutDates.Select(y=>y)).ToList();
    foreach(删除中的日期时间日期)
    {
    删除(datePicker.BlackoutDates.Single(x=>x.Start==date));
    }
    foreach(blackoutDates中的日期时间日期)
    {
    如果(!datePicker.BlackoutDates.Contains(date)&&
    日期>=datePicker.DisplayDateStart&&
    
    日期默认情况下,依赖项属性是单向绑定的。这意味着它将从视图模型中读取,但不会写入。您有两个选项来修复此问题

    选项1:在绑定中,将模式设置为双向

    <view:DisableableDatePicker Margin="0,0,0,3" 
        SelectedDate="{Binding HighlightDate}" 
        DisplayDateStart="{Binding StartDate}" 
        DisplayDateEnd="{Binding EndDate}" 
        IsEnabled="{Binding IsEditing}" 
        BlackoutDates="{Binding BlackoutDates, Mode=TwoWay}" />
    
    
    
    选项2:在代码隐藏中将默认绑定模式设置为双向

     public static readonly DependencyProperty BlackoutDatesProperty =
        DependencyProperty.RegisterAttached("BlackoutDates", typeof(List<DateTime>),
        typeof(DependencyPropertyHost), 
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,  OnBlackoutDatesChanged));
    
    公共静态只读从属属性BlackoutDatesProperty=
    从属财产。注册(“停电日期”,类型(列表),
    类型(DependencyPropertyHost),
    新的FrameworkPropertyMetadata(空,FrameworkPropertyMetadata选项.bindstwoway默认,OnBlackoutDatesChanged));
    
    在这里,我想我已经掌握了WPF的诀窍……然后像依赖项属性的默认绑定模式这样简单的东西让我追了好几天。感谢您快速简单的回复!
     public static readonly DependencyProperty BlackoutDatesProperty =
        DependencyProperty.RegisterAttached("BlackoutDates", typeof(List<DateTime>),
        typeof(DependencyPropertyHost), 
        new FrameworkPropertyMetadata(null, OnBlackoutDatesChanged));
    
    public static List<DateTime> GetBlackoutDates(DependencyObject d)
    {
        return (List<DateTime>)d.GetValue(BlackoutDatesProperty);
    }
    
    public static void SetBlackoutDates(DependencyObject d, List<DateTime> value)
    {
        d.SetValue(BlackoutDatesProperty, value);
    }
    
    private static void OnBlackoutDatesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        DatePicker datePicker = d as DatePicker;
        if (e.NewValue != null && datePicker != null)
        {
            List<DateTime> blackoutDates = (List<DateTime>)e.NewValue;
            var toRemove = datePicker.BlackoutDates.Select
                                                    (x => x.Start).Except
                                                    (blackoutDates.Select(y => y)).ToList();
            foreach (DateTime date in toRemove)
            {
                datePicker.BlackoutDates.Remove(datePicker.BlackoutDates.Single(x => x.Start == date));
            }
            foreach (DateTime date in blackoutDates)
            {
                if (!datePicker.BlackoutDates.Contains(date) && 
                    date >= datePicker.DisplayDateStart && 
                    date <= datePicker.DisplayDateEnd && 
                    datePicker.SelectedDate != date)
                {
                    datePicker.BlackoutDates.Add(new CalendarDateRange(date));
                }
            }
        }
    }
    
    <view:DisableableDatePicker Margin="0,0,0,3" 
        SelectedDate="{Binding HighlightDate}" 
        DisplayDateStart="{Binding StartDate}" 
        DisplayDateEnd="{Binding EndDate}" 
        IsEnabled="{Binding IsEditing}" 
        BlackoutDates="{Binding BlackoutDates, Mode=TwoWay}" />
    
     public static readonly DependencyProperty BlackoutDatesProperty =
        DependencyProperty.RegisterAttached("BlackoutDates", typeof(List<DateTime>),
        typeof(DependencyPropertyHost), 
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,  OnBlackoutDatesChanged));