Сценарий : В проекте Silverlight 4 MVVM у нас есть элемент управления ListBox
, содержащий элементы, выбранный элемент имеет двустороннюю привязку к соответствующему свойству в ViewModel. Другой элемент управления (например, я сократил его до одного TextBox
) - это данные, привязанные к содержимому выбранного элемента. Значение должно обновляться при отпуске / потеря фокуса.
Проблема : Когда значение в TextBox
изменяется, и мы оставляем это TextBox
нажатием клавиши Tab, все работает как нужно - значение обновляется. Однако, если пользователь щелкает по другому элементу в ListBox
, установщик SelectedItem запускается до того, как запускается содержимое установщика TextBox
, не оставляя шансов обработать пользовательский ввод.
В отладчике при добавлении точек останова к установщикам свойств можно видеть, что новый выбор ListView
применяется в первую очередь, до обработки обновления TextBox
.
Желаемое поведение : Нам нужно знать, что текущий выбранный элемент был изменен до того, как пользователь выбрал другой элемент. Не желательно иметь пользовательский триггер обновления, который бы уведомлял о каждом нажатии клавиши (мы знаем, что это возможно).
Можете ли вы помочь?
Код (очень простой пример):
ViewModel
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ItemViewModel : ViewModelBase
{
private string _content;
public ItemViewModel(string initContent)
{
_content = initContent;
}
public string Content
{
get
{
return _content;
}
set
{
if (_content != value)
{
_content = value;
OnPropertyChanged("Content");
}
}
}
}
public class MainViewModel : ViewModelBase
{
private ObservableCollection<ItemViewModel> _items =
new ObservableCollection<ItemViewModel>();
private ItemViewModel _selectedViewModel;
public ObservableCollection<ItemViewModel> Items
{
get
{
return _items;
}
}
public ItemViewModel SelectedItem
{
get
{
return _selectedViewModel;
}
set
{
if (_selectedViewModel != value)
{
_selectedViewModel = value;
OnPropertyChanged("SelectedItem");
}
}
}
}
XAML
<Grid x:Name="LayoutRoot" Background="White">
<ListBox Height="100"
HorizontalAlignment="Left"
Margin="12,12,0,0"
VerticalAlignment="Top"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
DisplayMemberPath="Content"
Width="220" />
<TextBox Height="23"
HorizontalAlignment="Left"
Margin="12,118,0,0"
Text="{Binding SelectedItem.Content, Mode=TwoWay}"
VerticalAlignment="Top"
Width="220" />
</Grid>
Код XAML позади
public MvvmTestView()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MvvmTestView_Loaded);
}
void MvvmTestView_Loaded(object sender, RoutedEventArgs e)
{
MainViewModel viewModel = new MainViewModel();
viewModel.Items.Add(new ItemViewModel("Hello StackOverflow"));
viewModel.Items.Add(new ItemViewModel("Thanks to Community"));
DataContext = viewModel;
}
ОБНОВЛЕНИЕ 1
Я представляю самостоятельно разработанное решение для вас, чтобы проверить, которое, вероятно, будет принятым, я все же хочу призвать вас комментировать и давать подсказки. Спасибо.