Silverlight DatePicker绑定损坏 - 我该怎么做才能解决这个问题?

时间:2012-01-20 10:07:21

标签: silverlight data-binding

我有一个非常简单的绑定问题,而DatePicker正在躲避我。

我有一个ListBox绑定到具有DateTime属性的对象列表。我有一个页面的编辑部分用于更改所选项目。这很好 - 当我更新DatePicker中的日期时,ListBox显示我更新的日期。

但是,当我选择另一个项目时,DatePicker控件也会错误地更新新项目上的日期。

这是我的代码:

C#:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace BindingTest
{
    public partial class MainPage
    {
        public MainPage()
        {
            InitializeComponent();

            var vm = new ViewModel();
            DataContext = vm;
        }
    }

    public class ViewModel : INotifyPropertyChanged
    {
        public ViewModel()
        {
            List = new ObservableCollection<Item>();

            for (var n = 0; n < 10; n++)
                List.Add(new Item { Date = DateTime.Now.AddDays(n) });
        }

        public ObservableCollection<Item> List { get; set; }

        private Item _selectedItem;
        public Item SelectedItem
        {
            get { return _selectedItem; }
            set { _selectedItem = value; OnPropertyChanged("SelectedItem"); }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }

    public class Item : INotifyPropertyChanged
    {
        private DateTime _date;
        public DateTime Date
        {
            get { return _date; }
            set { _date = value; OnPropertyChanged("Date"); }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
}

XAML:

<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"  x:Class="BindingTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <ListBox ItemsSource="{Binding List}" 
                 DisplayMemberPath="Date"
                 SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />

        <StackPanel Grid.Column="1" DataContext="{Binding SelectedItem}">
            <TextBlock Text="Date:" />
            <sdk:DatePicker SelectedDate="{Binding Date, Mode=TwoWay}" />
        </StackPanel>
    </Grid>
</UserControl>

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

我在Silverlight 3项目中遇到了一个非常类似的错误(请参阅我在Craig的回答中的评论)。经过大量的试验和错误,创建一个扩展的DatePicker解决了我的问题。不会赢得漂亮的奖品,但我想混乱的一个子类可能会变得一团糟。

xaml中的DataBinding:

<local:EvdDatePicker SelectedDateEx="{Binding ViewModelProperty, Mode=TwoWay}"/> 

DatePicker扩展名:

/// <summary>
/// Databinding on DatePicker.SelectedDate is seriously messed up (maybe because of synchronization with 
/// Text property?). This class extends the DatePicker and provides another property (SelectedDateEx)
/// to bind to. This offers decoupling and a backup of the date value that can be reverted to.
/// Additionally, selected date (of any EvdDatePicker instance) may only be changed at a defined interval.
/// </summary>
public class EvdDatePicker : DatePicker
{
    // allow changes only every half second (adjust if necessary)
    private static TimeSpan _changeLock = TimeSpan.FromMilliseconds(500);

    // holds date of last user change
    private static DateTime _lastChange;

    public EvdDatePicker()
    {
        this.SelectedDateChanged += new EventHandler<SelectionChangedEventArgs>(EvdDatePicker_SelectedDateChanged);
    }

    /// <summary>
    /// Catch cases where SelectedDate gets changed by mistake
    /// </summary>
    void EvdDatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
    {
        // measures if the change is likely caused by unwanted chain reactions
        if (_lastChange < DateTime.Now.Subtract(_changeLock))
        {
            this.SelectedDateEx = e.AddedItems.Count > 0 ? (DateTime?)e.AddedItems[0] : null;
            _lastChange = DateTime.Now; // store last change time
        }

        // reject change (revert to old value), if the values are not synchronized by now
        if (this.SelectedDate != this.SelectedDateEx)
            this.SelectedDate = this.SelectedDateEx;
    }

    /// <summary>
    /// Bind to this property instead of SelectedDate
    /// </summary>
    public DateTime? SelectedDateEx
    {
        get { return (DateTime?)GetValue(SelectedDateExProperty); }
        set { SetValue(SelectedDateExProperty, value); }
    }
    public static readonly DependencyProperty SelectedDateExProperty =
        DependencyProperty.Register("SelectedDateEx", typeof(DateTime?), typeof(EvdDatePicker), 
                                    new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedDateExChanged)));

    private static void OnSelectedDateExChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        EvdDatePicker p = (EvdDatePicker)d;

        // initial binding, propagate to SelectedDate property
        DateTime? newValue = (DateTime?)e.NewValue;
        if (p.SelectedDate != newValue)
            p.SelectedDate = newValue;
    }
}

答案 1 :(得分:0)

似乎解决此问题的最简单方法是延迟选择的更改,以便DatePicker在更改选择之前更新正确的绑定。