Tôi đang xây dựng một ứng dụng bằng cách sử dụng mẫu thiết kế MVVM và tôi muốn sử dụng các RoutedUICommands được định nghĩa trong lớp ApplicationCommands. Vì thuộc tính CommandBindings của View (đọc UserControl) không phải là DependencyProperty nên chúng ta không thể ràng buộc CommandBindings được định nghĩa trong ViewModel cho View trực tiếp. Tôi đã giải quyết điều này bằng cách định nghĩa một lớp View trừu tượng liên kết với chương trình này, dựa trên giao diện ViewModel, đảm bảo mọi ViewModel có một ObservableCollection của CommandBindings. Điều này tất cả các công trình tốt, tuy nhiên, trong một số kịch bản tôi muốn thực hiện logic được định nghĩa trong các lớp khác nhau (View và ViewModel) cùng một lệnh. Ví dụ, khi lưu một tài liệu.RoutedUICommand PreviewExecuted Bug?
Trong ViewModel mã tiết kiệm tài liệu vào đĩa:
private void InitializeCommands()
{
CommandBindings = new CommandBindingCollection();
ExecutedRoutedEventHandler executeSave = (sender, e) =>
{
document.Save(path);
IsModified = false;
};
CanExecuteRoutedEventHandler canSave = (sender, e) =>
{
e.CanExecute = IsModified;
};
CommandBinding save = new CommandBinding(ApplicationCommands.Save, executeSave, canSave);
CommandBindings.Add(save);
}
Thoạt nhìn mã trước đó là tất cả tôi muốn làm, nhưng TextBox trong Xem mà tài liệu được ràng buộc, chỉ cập nhật Nguồn của nó khi nó mất tiêu điểm của nó. Tuy nhiên, tôi có thể lưu tài liệu mà không bị mất tiêu điểm bằng cách nhấn Ctrl + S. Điều này có nghĩa là tài liệu được lưu trước các thay đổi được cập nhật trong nguồn, bỏ qua hiệu quả các thay đổi. Nhưng kể từ khi thay đổi UpdateSourceTrigger thành PropertyChanged không phải là một lựa chọn khả thi vì lý do hiệu suất, cái gì khác phải buộc cập nhật trước khi lưu. Vì vậy, tôi nghĩ, cho phép sử dụng các sự kiện PreviewExecuted để buộc các cập nhật trong trường hợp PreviewExecuted, như vậy:
//Find the Save command and extend behavior if it is present
foreach (CommandBinding cb in CommandBindings)
{
if (cb.Command.Equals(ApplicationCommands.Save))
{
cb.PreviewExecuted += (sender, e) =>
{
if (IsModified)
{
BindingExpression be = rtb.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
}
e.Handled = false;
};
}
}
Tuy nhiên, gán một handler cho sự kiện PreviewExecuted dường như để hủy bỏ sự kiện này hoàn toàn, ngay cả khi tôi thiết lập một cách rõ ràng Xử lý bất động sản để sai. Vì vậy, eventhandler executeSave mà tôi đã định nghĩa trong mẫu mã trước đó không được thực hiện nữa. Lưu ý rằng khi tôi thay đổi cb.PreviewExecuted thành cb.Executed cả hai đoạn mã làm thực thi, nhưng không theo đúng thứ tự.
Tôi nghĩ đây là lỗi trong .Net, vì bạn có thể thêm trình xử lý vào PreviewExecuted và Executed và yêu cầu chúng được thực thi theo thứ tự, miễn là bạn không đánh dấu sự kiện là đã xử lý.
Có ai có thể xác nhận hành vi này không? Hoặc là tôi sai? Có cách giải quyết cho lỗi này không?
Cốt truyện dày ... Vì vậy, tôi nhìn vào mã nguồn mà bạn đề cập và họ làm như vậy điều trong OnCanExecute với PreviewCanExecute. Tuy nhiên, có một sự khác biệt quan trọng giữa các CanExecuteRoutedEventArgs từ OnCanExecute và ExecutedRoutedEventArgs từ OnExecuted. Như bạn mong đợi các CanExecuteRoutedEventArgs chứa một tài sản ContinueRouting mà không chính xác điều đó, nhưng đối với một số lý do ExecutedRoutedEventArgs phải làm mà không có. Tôi thực sự thực sự không thể có được đầu của tôi xung quanh sự lựa chọn này từ Microsoft. – elmar
Tôi nghĩ rằng ContinueRouting không tham gia vào quá trình đó - hãy xem EDIT 2 của tôi trong bài đăng. Tại sao họ lại làm theo cách này ...Nhìn vào hai phần của phương thức CommandBinding.OnExecuted(), chúng hầu như giống hệt nhau - nó có thể là trường hợp điển hình của sao chép/dán :) và sau đó nó là một lỗi. Nghiêm túc mà nói, tôi không nghĩ đó là trường hợp. Tôi thực sự muốn biết lý do của họ đằng sau điều này là gì. –