2011-10-05 17 views
5

tôi thấy ví dụ này - Binding.UpdateSourceTrigger PropertySet UpdateSourceTrigger để Explicit trong ShowDialog (WPF MVVM)

trong ví dụ các UpdateSourceTrigger thiết lập để Explicit và sau đó trong mã xem ông gọi điện để UpdateSource của tên TextBox.

Nhưng nếu tôi sử dụng MVVM dp tôi không muốn có tên cho điều khiển và thuộc tính nguồn trong VM và không phải trong chế độ xem, vậy cách đúng để liên kết điều khiển với thuộc tính VM và đặt UpdateSourceTrigger là gì ?

Tôi muốn làm điều này bởi vì trong trường hợp của tôi ShowDialog của cửa sổ và tôi muốn điều đó nguồn sẽ cập nhật chỉ khi nhấp chuột người dùng "ok"

Cảm ơn trước!

Trả lời

9

Nếu bạn đang sử dụng MVVM đúng thì nhấp vào nút OK của bạn phải được xử lý bởi một số Command. Lệnh này phải đến từ ViewModel của bạn. Các thuộc tính ràng buộc Expliticly phải đến từ ViewModel của bạn một lần nữa. Vì vậy, những gì ngăn cản bạn.

  1. Không sử dụng Explicit ràng buộc nhưng sử dụng ràng buộc OneWay.
  2. Trong nút của bạn, hãy liên kết lệnh và liên kết tham số lệnh với thuộc tính Phụ thuộc ràng buộc OneWay.
  3. Trong trình xử lý Execute của Command (phải là một phương thức nào đó từ ViewModel của bạn), thay đổi thuộc tính của ViewModel bằng tham số sắp tới.
  4. Tăng số NotifyPropertyChanged cho thuộc tính đó từ ViewModel của bạn.

Ví dụ:

Giả sử tôi cần cập nhật văn bản của TextBox trở lại mô hình của tôi khi nhấp vào nút OK.

Vì vậy, tôi có lớp EmployeeViewModel có thuộc tính EmployeeName trong đó. Nơi nghỉ này có quầy thu đổi và người đặt đồ. Các setter tăng tài sản thay đổi thông báo. Mô hình khung nhìn cũng có một thuộc tính khác của loại ICommand có tên SaveNameCommand trả về một lệnh cho tôi thực hiện.

EmployeeViewModel là loại ngữ cảnh dữ liệu của chế độ xem của tôi. Myview có một số TextBox (được đặt tên là x: Name = "EmployeeNameTxBx") OneWay được liên kết với EmployeeName và một Nút là OK. Tôi liên kết tài sản Button.Command với tài sản EmployeeViewModel.SaveNameCommandButton.CommandParameter bị ràng buộc với thuộc tính EmployeeNameTxBx.Text.

 <StackPanel> 
      <TextBox x:Name="EmployeeNameTxBx" 
        Text="{Binding EmployeeName, Mode=OneWay}" /> 
      <Button Content="OK" 
        Command="{Binding SaveNameCommand}" 
        CommandParameter="{Bidning Text, ElementName=EmployeeNameTxBx}" /> 
     </StackPanel> 

Bên EmployeeViewModel của tôi, tôi có OnSaveNameCommandExecute(object param) phương pháp để thực hiện SaveNameCommand tôi.

Trong này thực hiện mã này ...

 var text = (string)param; 
    this.EmployeeName = text; 

Bằng cách này CHỈ OK nút nhấp chuột, cập nhật văn bản của TextBox trở lại vào EmployeeName tài sản của mô hình.

EDIT

Nhìn vào ý kiến ​​của bạn dưới đây, tôi thấy rằng bạn đang cố gắng để thực hiện Validation trên một giao diện người dùng. Bây giờ điều này thay đổi mọi thứ một chút.

IDataErrorInfo và xác thực có liên quan hoạt động CHỈ NẾU các điều khiển nhập của bạn (chẳng hạn như Hộp văn bản) là HaiWay bị ràng buộc. Vâng đó là cách nó được dự định. Vì vậy, bây giờ bạn có thể hỏi "Liệu điều này có nghĩa là toàn bộ khái niệm KHÔNG cho phép dữ liệu không hợp lệ chuyển sang mô hình là vô ích trong MVVM nếu chúng ta sử dụng IDataErrorInfo"?

Không thực sự!

Xem MVVM không thực thi quy tắc CHỈ dữ liệu hợp lệ sẽ trở lại. Nó chấp nhận dữ liệu không hợp lệ và đó là cách hoạt động của IDataErrorInfo và làm tăng các thông báo lỗi. Vấn đề là ViewModel chỉ là softcopy Chế độ xem của bạn để có thể là bẩn. Điều cần đảm bảo là độ bẩn này không phải là cam kết với các giao diện bên ngoài của bạn như dịch vụ hoặc cơ sở dữ liệu.

Luồng dữ liệu không hợp lệ như vậy nên bị hạn chế bởi ViewModel bằng cách kiểm tra dữ liệu không hợp lệ. Và dữ liệu đó sẽ đến nếu chúng tôi đã bật tính năng ràng buộc TwoWay. Vì vậy, xem xét rằng bạn đang thực hiện IDataErrorInfo sau đó bạn cần phải có TwoWay ràng buộc đó là hoàn toàn cho phép trong MVVM.

Cách tiếp cận 1:

gì nếu tôi wan để xác nhận một cách rõ ràng các mục nhất định về giao diện người dùng trên nút bấm?

Để sử dụng thủ thuật xác thực bị trì hoãn này. Trong ViewModel của bạn có một lá cờ được gọi là isValidating. Đặt mặc định là false.

Trong tài sản IDataErrorInfo.this bạn bỏ qua xác nhận bằng cách kiểm tra isValidating cờ ...

string IDataErrorInfo.this[string columnName] 
    { 
     get 
     { 
     if (!isValidating) return string.Empty; 

     string result = string.Empty; 
     bool value = false; 

     if (columnName == "EmployeeName") 
     { 
      if (string.IsNullOrEmpty(AccountType)) 
      { 
       result = "EmployeeName cannot be empty!"; 
       value = true; 
      } 
     } 
     return result; 
     } 
    } 

Sau đó, trong lệnh OK bạn thực hiện xử lý, kiểm tra tên nhân viên và sau đó nâng cao sự kiện thay đổi sở hữu thông báo cho các tài sản tương tự ...

private void OnSaveNameCommandExecute(object param) 
    { 
     isValidating = true; 
     this.NotifyPropertyChanged("EmployeeName"); 
     isValidating = false; 
    } 

Điều này kích hoạt xác thực CHỈ khi bạn nhấp OK. Hãy nhớ rằng EmployeeName sẽ CÓ chứa dữ liệu không hợp lệ để xác thực hoạt động.

Phương pháp 2:

gì nếu tôi muốn cập nhật một cách rõ ràng ràng buộc không có chế độ TwoWay trong MVVM?

Sau đó, bạn sẽ phải sử dụng Attached Behavior. Hành vi sẽ đính kèm vào nút OK và sẽ chấp nhận danh sách tất cả các mục cần được làm mới các liên kết của chúng.

 <Button Content="OK"> 
      <local:SpecialBindingBehavior.DependentControls> 
       <MultiBinding Converter="{StaticResource ListMaker}"> 
        <Binding ElementName="EmployeeNameTxBx" /> 
        <Binding ElementName="EmployeeSalaryTxBx" /> 
        .... 
       <MultiBinding> 
      </local:SpecialBindingBehavior.DependentControls> 
     </Button> 

Các ListMaker là một IMultiValueConverter mà chỉ đơn giản chuyển đổi giá trị vào một danh sách ...

 Convert(object[] values, ...) 
     { 
      return values.ToList(); 
     } 

Trong SpecialBindingBehavior của bạn có một tài sản thay đổi DependentControls xử lý ...

 private static void OnDependentControlsChanged(
      DependencyObject depObj, 
      DependencyPropertyChangedEventArgs e) 
     { 
      var button = sender as Button; 
      if (button != null && e.NewValue is IList) 
      { 
       button.Click 
        += new RoutedEventHandler(
         (object s, RoutedEventArgs args) => 
         { 
           foreach(var element in (IList)e.NewValue) 
           { 
           var bndExp 
            = ((TextBox)element).GetBindingExpression(
             ((TextBox)element).Textproperty); 

           bndExp.UpdateSource(); 
           } 
         }); 
      } 
     } 

Nhưng tôi vẫn sẽ đề nghị bạn sử dụng trước MVVM tinh khiết của tôi dựa ** Cách tiếp cận 1.

+0

lời cảm ơn đầu tiên cho câu trả lời chi tiết của bạn! và trở lại vấn đề của tôi, tôi đang sử dụng mvvm tinh khiết và tôi có lệnh trong vm của tôi và tôi đang sử dụng NotifyPropertyChanged. nhưng nếu tôi sử dụng OneWay ràng buộc và tôi có trong cửa sổ 10 textboxes của nó có nghĩa là tôi cần phải gửi trong các tham số lệnh 10 tên phần tử? và sau đó cập nhật chúng theo cách thủ công? không có cách nào để sử dụng ToWay ràng buộc? – Maya

+0

cũng ngay bây giờ tôi đang sử dụng IDataError để xác nhận văn bản trong hộp văn bản, nếu tôi sẽ sử dụng OneWay ràng buộc tôi vẫn có thể xác nhận văn bản? – Maya

+0

@Maya vui lòng xem mũi của tôi đã chỉnh sửa ở trên. –

1

Đây là câu hỏi cũ nhưng tôi vẫn muốn cung cấp phương pháp thay thế cho người dùng khác gặp khó khăn khi đặt câu hỏi này ... Trong chế độ xem của tôi, tôi không hiển thị trực tiếp các thuộc tính mô hình trong phương thức get/set Property. Tôi sử dụng các biến nội bộ cho tất cả các thuộc tính. Sau đó, tôi ràng buộc tất cả các thuộc tính hai chiều. Vì vậy, tôi có thể làm tất cả các xác nhận là "bình thường" bởi vì chỉ có các biến nội bộ được thay đổi. Trong hàm tạo mô hình khung nhìn, tôi có đối tượng mô hình làm tham số và tôi thiết lập các biến nội bộ cho các giá trị của mô hình của tôi. Bây giờ khi tôi bấm vào nút "Save" (-> Lưu Command lửa trong mô hình xem của tôi cháy) và không có lỗi, tôi đặt tất cả các thuộc tính của mô hình của tôi với các giá trị của biến nội bộ tương ứng. Nếu tôi nhấp vào nút "Canel/Undo" (-> Cancel-Command trong mô hình xem của tôi), tôi đặt các biến nội bộ cho các giá trị của mô hình không bị ảnh hưởng của tôi (sử dụng các bộ định dạng của thuộc tính mô hình khung sao cho NotifyPropertyChanged là được gọi và chế độ xem hiển thị các thay đổi = giá trị cũ).

Tuy nhiên, cách tiếp cận khác là triển khai hỗ trợ Memento trong mô hình, vì vậy trước khi bắt đầu chỉnh sửa, bạn gọi hàm trong mô hình để lưu giá trị hiện tại và nếu bạn hủy chỉnh sửa, bạn gọi hàm để khôi phục các giá trị đó. ..vì vậy, bạn sẽ có hỗ trợ hoàn tác/hủy ở mọi nơi không chỉ trong một mô hình xem ... Tôi đã triển khai cả hai phương pháp trong các dự án khác nhau và cả hai đều hoạt động tốt, tùy thuộc vào yêu cầu của dự án ...

Các vấn đề liên quan