2009-11-26 39 views
9

Tôi có một ứng dụng cần mở hộp thoại từ nút mà người dùng nhập một số thông tin.Mở hộp thoại trong WPF MVVM

Tại thời điểm tôi làm điều đó như thế này (trong đó hoạt động tốt)

  • Nút nhấp chuột tạo ra một lệnh trong ViewModel.
  • ViewModel tăng sự kiện mà Trình điều khiển lắng nghe.
  • Controller hoạt động ra các chi tiết của cửa sổ mới (ví dụ View, ViewModel & mô hình) và mở nó (ShowDialog)
  • Khi cửa sổ bị đóng Controller thêm kết quả cho EventArgs và trả về cho ViewModel
  • ViewModel chuyển thông tin đến Model.

Có rất nhiều bước nhưng tất cả đều có ý nghĩa và không có nhiều cách nhập.

Mã này trông như thế này (cửa sổ yêu cầu tên người dùng)

ViewModel:

AskUserNameCommand = DelegateCommand(AskUserNameExecute); 
... 

public event EventHandler<AskUserEventArgs> AskUserName; 

void AskUserNameExecute(object arg) { 
    var e = new AskUserNameEventArgs(); 
    AskUserName(this, e); 
    mModel.SetUserName(e.UserName); 
} 

Bộ điều khiển:

mViewModel.AskUserName += (sender,e) => { 
    var view = container.Resolve<IAskUserNameView>(); 
    var model = container.Resolve<IAskUserNameModel>(); 
    var viewmodel = container.Resolve<IAskUserNameViewModel>(view, model); 
    if (dlg.ShowDialog() ?? false) 
     e.UserName = model.UserName; 
} 

Câu hỏi của tôi là cách giao tiếp ngang hoạt động trong Mẫu MVVM. Bằng cách nào đó, có vẻ như sai khi cho phép bộ điều khiển tham gia vào việc truyền dữ liệu giữa các mô hình.

Tôi đã xem xét mẫu hòa giải để cho phép các mô hình truyền thông trực tiếp. Không thích ý tưởng đó vì nó làm cho mô hình phụ thuộc vào các chi tiết thực hiện của GUI. (ví dụ: nếu hộp thoại được thay thế bằng hộp văn bản, mô hình cần phải thay đổi)

+1

Bạn có có một cái nhìn tại các câu hỏi sau http: //stackoverflow.com/questions/454868/handling-dialogs-in-wpf-with-mvvm http://stackoverflow.com/questions/ 1667888/wpf-mvvm-dialog-example http: // stackoverflow.com/questions/1792814/using-mvvm-foundation-messenger-to-show-dialog – Guge

+0

Có, tôi đã xem chúng nhưng tất cả chúng đều đề xuất một mẫu phát sóng để giải quyết một ví dụ nào đó. – adrianm

+0

'Nút bấm tạo ra một lệnh trong ViewModel.', Điều này có nghĩa là gì? 'ViewModel đặt ra một sự kiện mà Bộ điều khiển lắng nghe', bộ điều khiển nào ?! –

Trả lời

0

Tôi đã gặp các vấn đề tương tự. Đây là cách tôi đã giải quyết chúng, và tại sao tôi đã làm những gì tôi đã làm.

Giải pháp của tôi:

MainWindowViewModel của tôi có một loại tài sản của ModalViewModelBase gọi phương thức. Nếu mã của tôi cần một chế độ xem nhất định là phương thức, nó sẽ đặt tham chiếu đến nó trong thuộc tính này. MainWindowView xem tài sản này thông qua cơ chế INotifyPropertyChanged. Nếu Modal được đặt thành một số VM, lớp MainWindowView sẽ lấy VM và đặt nó trong cửa sổ ModalView nơi UserControl thích hợp sẽ được hiển thị thông qua ma thuật của DataTemplates, cửa sổ được hiển thị bằng cách sử dụng ShowDialog. ModalViewModelBase có thuộc tính cho DialogResult và thuộc tính được gọi là IsFinished. Khi IsFinished được đặt thành true bởi VM phương thức, khung nhìn đóng lại.

Tôi cũng có một số thủ thuật đặc biệt để thực hiện những việc tương tác như thế này từ chủ đề nền mà muốn hỏi người dùng về đầu vào.

Lý do của tôi:

Nguyên tắc chế độ xem là chế độ xem khác bị tắt, trong khi phương thức được hiển thị. Đây là một phần của logic của View mà về cơ bản là vô vị. Đó là lý do tại sao tôi có một thuộc tính cho nó trong MainWindowViewModel. Tôi phải tiếp tục, tôi nên làm cho mọi tài sản hoặc lệnh khác cho tất cả các VM khác trong VM chính ném ngoại lệ, trong khi ở chế độ phương thức, nhưng tôi cảm thấy điều này là quá mức.

Cơ chế Xem thực sự từ chối người dùng bất kỳ hành động nào khác, không phải được thực hiện bằng cửa sổ bật lên và showdialog, có thể là bạn đặt chế độ xem trong cửa sổ hiện tại, nhưng vô hiệu hóa tất cả các chế độ khác hoặc một số điều khác. Logic liên quan đến chế độ xem này thuộc về chính chế độ xem. (Đó là một nhà thiết kế điển hình không thể viết mã cho logic này, có vẻ là một mối quan tâm thứ cấp. Tất cả chúng ta đều cần giúp đỡ một số lần.)

Vì vậy, đó là cách tôi đã thực hiện nó. Tôi cung cấp nó chỉ như một gợi ý, có lẽ có những cách suy nghĩ khác về nó, và tôi hy vọng bạn sẽ nhận được nhiều câu trả lời hơn nữa.

+0

Đó là một cách thú vị nhưng tôi không nói cách thức truyền dữ liệu hoạt động. Làm cách nào để người dùng nhập vào từ Hộp thoại (Xem) Mô hình đến Mô hình Chính (Xem) khi hộp thoại bị đóng? – adrianm

+0

MainViewModel vẫn có tham chiếu đến DialogViewModel sau khi khung nhìn hộp thoại đóng. – Guge

+0

ok, đó là nhiều hơn hoặc ít hơn cùng một điều như tôi làm nhưng bạn làm điều đó trong viewmodel. – adrianm

0

Tôi đã sử dụng EventAggregator từ Prism v2 trong các trường hợp tương tự. Điều tốt về mồi là, bạn không phải sử dụng toàn bộ khung công tác trong ứng dụng MVVM của bạn. Bạn có thể trích xuất chức năng EventAggregator và sử dụng nó cùng với thiết lập hiện tại của bạn.

+0

EventAggregator là tốt đẹp nhưng nó là một dịch vụ phát sóng. Tôi không thể tìm thấy một cách dễ dàng để cấu hình nó để gọi một thể hiện cụ thể của một người nghe. Giả sử người dùng mở hộp thoại, đóng hộp thoại và mở lại. Bây giờ tôi có hai trường hợp xem/viewmodel/mô hình mà lắng nghe sự kiện cho đến khi GC bắt đầu làm sạch. Điều này có thể được giải quyết nếu người nghe hủy đăng ký khỏi sự kiện nhưng điều đó dẫn đến một số loại mẫu IDisposable trong ViewModel/Model. – adrianm

+0

@adrianm bạn chính xác. Nếu mong muốn của bạn là để tin nhắn của bạn được gửi đến một trường hợp cụ thể thì Event Aggregator không thích hợp. –

12

tôi không giống như hầu hết những đề nghị hiện nay vì một lý do này hay cách khác, vì vậy tôi nghĩ tôi sẽ liên kết đến một câu hỏi gần như giống hệt với câu trả lời tôi làm như:

Open File Dialog MVVM

Cụ thể là câu trả lời của Cameron MacFarland là chính xác những gì tôi làm. Một dịch vụ cung cấp thông qua một giao diện để cung cấp IO và/hoặc tương tác người dùng là con đường để đi đây, vì những lý do sau đây:

  • Đó là kiểm chứng
  • Nó tóm tắt đi thi của bất kỳ hộp thoại nào để chiến lược xử lý các loại vật thể này có thể được thay đổi mà không ảnh hưởng đến mã thành phần
  • Không dựa trên bất kỳ mẫu giao tiếp nào. Rất nhiều gợi ý bạn thấy ở đó dựa vào người hòa giải, như Event Aggregator. Các giải pháp này dựa vào việc thực hiện giao tiếp hai chiều với các đối tác ở phía bên kia của hòa giải viên, vừa khó thực hiện vừa là một hợp đồng rất lỏng lẻo.
  • Chế độ xemMô hình vẫn tự động. Tôi, giống như bạn, không cảm thấy phải giao tiếp giữa bộ điều khiển và ViewModel. ViewModel sẽ vẫn tự động nếu không có lý do nào khác làm giảm khả năng kiểm tra.

Hy vọng điều này sẽ hữu ích.

+0

Cảm ơn, điều đó khiến tôi suy nghĩ. Tôi không muốn tiêm ioc-container vào viewmodel vì vậy tôi có thể sẽ tạo ra một số loại IControllerService mà viewmodel có thể gọi. Sẽ sạch hơn nhiều so với thông tin liên lạc dựa trên sự kiện mà tôi có ngay bây giờ. – adrianm

+0

Nếu bạn đang sử dụng IoC, tôi sẽ chỉ tuyên bố một cái gì đó giống như IDialogService của bạn như là một phụ thuộc. Tôi thường nghĩ về IoC như là một danh mục các dịch vụ có sẵn cho tất cả các đối tượng cấu thành. –

2

tôi sử dụng cách tiếp cận this cho hộp thoại có mvvm.

tất cả những gì tôi phải làm bây giờ là gọi những điều sau đây từ chế độ xem của tôi để làm việc với hộp thoại.

var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM); 
Các vấn đề liên quan