我有一个非常简单的绑定问题,而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>
我该如何解决这个问题?
答案 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在更改选择之前更新正确的绑定。