Я наблюдал какое-то неожиданное или, по крайней мере, не совсем идеальное совпадение с моими требованиями к текстовым полям, связанным с textproperties, когда я не могу использовать, используя UpdateTrigger = PropertyChanged для моей привязки. Вероятно, это не проблема с текстовым полем, но будет происходить и с другими редакторами.
В моем примере (исходный код прилагается) у меня есть WPF TabControl, связанный с некоторой коллекцией. На каждой вкладке вы можете редактировать элемент из коллекции, различными способами вы можете инициировать сохранение-действие, которое должно сохранить изменения в какой-либо модели. Текстовые поля, привязанные к свойствам каждого элемента, (специально) сохраняются в стандартном триггере обновления "OnFocusLost". Это связано с тем, что при установке нового значения происходит некоторая дорогостоящая проверка.
Теперь я обнаружил, что есть как минимум два способа инициировать мое действие сохранения таким образом, что последнее сфокусированное текстовое поле не обновляет связанное значение. 1) Изменение элемента табуляции с помощью щелчка мыши по его заголовку, а затем нажатия кнопки сохранения. (переход на предыдущую вкладку показывает, что новое значение даже потеряно) 2) Запуск команды сохранения с помощью KeyGesture.
Я настраиваю пример приложения, демонстрирующего поведение. Нажав "Сохранить все", вы увидите все значения элементов, другая кнопка сохранения отобразит только текущий элемент.
Q:. Каким будет лучший способ убедиться, что все bindingsources всех моих текстовых полей будут обновлены до того, как будут связаны связанные объекты? Предпочтительно, должен быть единственный способ, который улавливает все возможности, мне не нравится ловить каждое событие по-разному, так как я опасаюсь забыть некоторые события. Наблюдение за событием с изменением выбора элемента управления табло, например, могло бы решить проблему 1), но не выдавать 2).
Теперь к примеру:
XAML сначала:
<Window x:Class="TestOMat.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:TestOMat="clr-namespace:TestOMat"
Title="TestOMat" x:Name="wnd">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="dtPerson" DataType="{x:Type TestOMat:Person}">
<StackPanel Orientation="Vertical">
<StackPanel.CommandBindings>
<CommandBinding Command="Close" Executed="CmdSaveExecuted"/>
</StackPanel.CommandBindings>
<TextBox Text="{Binding FirstName}"/>
<TextBox Text="{Binding LastName}"/>
<Button Command="ApplicationCommands.Stop" CommandParameter="{Binding}">Save</Button>
</StackPanel>
</DataTemplate>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.CommandBindings>
<CommandBinding Command="ApplicationCommands.Stop" Executed="CmdSaveAllExecuted"/>
</Grid.CommandBindings>
<TabControl ItemsSource="{Binding ElementName=wnd, Path=Persons}" ContentTemplate="{StaticResource dtPerson}" SelectionChanged="TabControl_SelectionChanged"/>
<Button Grid.Row="1" Command="ApplicationCommands.Stop">Save All</Button>
</Grid></Window>
И соответствующий класс
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace TestOMat
{
/// <summary>
/// Interaction logic for TestOMat.xaml
/// </summary>
public partial class TestWindow : Window
{
public TestWindow()
{
InitializeComponent();
}
private List<Person> persons = new List<Person>
{
new Person {FirstName = "John", LastName = "Smith"},
new Person {FirstName = "Peter", LastName = "Miller"}
};
public List<Person> Persons
{
get { return persons; }
set { persons = value; }
}
private void CmdSaveExecuted(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)
{
Person p = e.Parameter as Person;
if (p != null)
{
MessageBox.Show(string.Format("FirstName={0}, LastName={1}", p.FirstName, p.LastName));
e.Handled = true;
}
}
private void CmdSaveAllExecuted(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)
{
MessageBox.Show(String.Join(Environment.NewLine, Persons.Select(p=>string.Format("FirstName={0}, LastName={1}", p.FirstName, p.LastName)).ToArray()));
e.Handled = true;
}
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Console.WriteLine(String.Format("Selection changed from {0} to {1}", e.RemovedItems, e.AddedItems));
// Doing anything here only avoids loss on selected-tab-change
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}