2012-01-20 6 views
4

私は、私を逃しているDatePickerに非常に単純なバインディングの問題があります。Silverlight DatePickerバインディングが壊れています - これを修正するには何ができますか?

私はListBoxをDateTimeプロパティを持つオブジェクトのリストにバインドしています。選択した項目を変更するページの編集部分があります。これはうまくいきます - DatePickerで日付を更新すると、ListBoxに更新日が表示されます。

ただし、別のアイテムを選択すると、DatePickerコントロールによって、新しいアイテムのDateも誤って更新されます。

ここに私のコードです:

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> 

私はこれをどのように修正することができますか?

答えて

0

これを解決する最も簡単な方法は、選択が変更される前にDatePickerが正しいバインディングを更新するように、選択の変更を遅らせることです。

+0

あなたは手の込んだことはできますか?私はdatepickers(celltemplateの方法で)を保持する列のDataGridを持っています。データグリッドは日付によって自動的にソートされ、その時点で他の行が新たに入力された値に変更されます。同じバグのように聞こえる。私はDispatcherTimerでソートメソッドを遅らせましたが、それは問題を解決しませんでした。 –

1

Silverlight 3プロジェクトで非常によく似たバグが発生しました(Craigの回答の私のコメントを参照)。多くの試行錯誤の末、拡張DatePickerを作成することで私の問題が解決しました。かなりの賞金を獲得することはできませんが、混乱のサブクラスが混乱することが予想されます。 XAMLで

データバインディング:

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

日付ピッカーの拡張子:

/// <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; 
    } 
}