Tôi đã quan sát một số hành vi không mong muốn hoặc ít nhất là không hoàn toàn phù hợp với nhu cầu của tôi về hộp văn bản được liên kết với textproperties khi tôi không thể sử dụng UpdateTrigger = PropertyChanged cho ràng buộc của tôi. Có lẽ nó không phải là một vấn đề với hộp văn bản nhưng sẽ xảy ra với các biên tập viên khác là tốt.Làm thế nào để đạt được tập trung-thiết lập lại để cập nhật BindingSource của TextBox trước khi bất kỳ hành động
Trong ví dụ của tôi (mã nguồn được đính kèm), tôi có một TabControl WPF ràng buộc với một số bộ sưu tập. Trên mỗi tab, bạn có thể chỉnh sửa một mục từ bộ sưu tập, theo nhiều cách khác nhau mà bạn có thể kích hoạt hành động lưu, thao tác này sẽ lưu các chỉnh sửa cho một số mô hình. Các hộp văn bản được liên kết với các thuộc tính của mỗi mục được (theo mục đích) được lưu giữ mặc định cập nhật kích hoạt 'OnFocusLost'. Điều này là do có một số xác thực tốn kém diễn ra khi một giá trị mới được thiết lập.
Bây giờ tôi thấy có ít nhất hai cách để kích hoạt hành động lưu của tôi theo cách như vậy, hộp văn bản được tập trung cuối cùng không cập nhật giá trị bị ràng buộc. 1) Thay đổi mục tab bằng cách nhấp chuột vào tiêu đề của nó và sau đó nhấp vào một số nút lưu. (thay đổi trở lại tab trước đó cho thấy giá trị mới thậm chí bị mất) 2) Kích hoạt lệnh lưu thông qua KeyGesture.
Tôi thiết lập một ứng dụng mẫu thể hiện hành vi. Nhấp vào "Lưu tất cả" sẽ hiển thị tất cả các giá trị của mục, nút lưu khác chỉ hiển thị mục hiện tại.
Q: Điều gì sẽ là cách tốt nhất để đảm bảo rằng tất cả các liên kết tài nguyên của tất cả các hộp văn bản của tôi sẽ được cập nhật trước khi các đối tượng bị ràng buộc được đính kèm? Tốt hơn là nên có một cách duy nhất để nắm bắt tất cả các vật sở hữu, tôi không thích bắt từng sự kiện khác nhau, vì tôi sẽ lo lắng đã quên một số sự kiện. Quan sát sự kiện thay đổi lựa chọn của điều khiển tab chẳng hạn sẽ giải quyết vấn đề 1) nhưng không giải quyết vấn đề 2).
Bây giờ để ví dụ:
XAML đầu tiên:
<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>
Và các lớp tương ứng
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; }
}
}
Để thuận tiện, tôi đã sử dụng Stop-Command, s.t. đối với hầu hết người dùng, nhấn [Esc] sẽ kích hoạt hành động. –