2011-12-23 43 views
5

Tất cả các menu/contextmenus/thanh công cụ tôi sử dụng trong WPF được khai báo trong mã ViewModel khá nhiều như thế này:MenuMục tắt bàn phím trong 'MVVM' thuần túy?

MenuService.Add(new MenuItem() 
    { 
    Header = "DoStuff", 
    Command = new relayCommand(DoStuff,() => CanDoStuffExecute()) 
    // some more properties like parent item/image/... 
    }); 

Các MenuService cung cấp một điểm ràng buộc duy nhất mà là một danh sách cây của MenuItem và bị ràng buộc để Menu của thực tế ItemsSource in xaml.

Điều này hoạt động rất tốt và bây giờ tôi muốn thêm phím tắt theo cùng một cách thuận tiện. Lý tưởng nhất là MenuItem sẽ nhận được một loại tài sản của System.Windows.Input.KeyGesture vì vậy tôi chỉ có thể viết

Shortcut = new KeyGesture(Key.D, ModifierKeys.Control) 

đó sẽ dẫn đến việc chỉ huy của mặt hàng đó được kêu gọi nhấn Ctrl + D trong cửa sổ sở hữu menu, và đó cũng sẽ dẫn đến tự động hiển thị "Ctrl + D" trong menu.

Tuy nhiên tôi bị mất ở đây: Tôi muốn thiết lập bộ sưu tập MenuItem.InputBindings thông qua dữ liệu nhưng nó chỉ có được. Làm thế nào tôi có thể nhận được các mục vào nó? Hoặc là có một khuôn khổ MVVM đã hỗ trợ một cái gì đó như thế này? Hầu hết q & tôi tìm thấy trên các phím tắt là tất cả về cách thiết lập các phím tắt thông qua xaml, đó là không có sự giúp đỡ.

Cập nhật

Tìm kiếm 'relaycommand vs routeduicommand và 'relaycommand keygesture' vv đã tiết lộ đầy đủ thông tin để đưa ra một giải pháp làm việc mặc dù hacky. Chắc chắn có những cách khác và tốt hơn ngoài kia, nhưng hiện tại đây là ưu tiên cực thấp đối với tôi và thực hiện công việc một cách hoàn hảo. Tôi bổ sung thêm hai tính đến lớp MenuItem như thế này:

//Upon setting a Gesture, the original command is replaced with a RoutedCommand 
//since that automatically gives us proper display of the keyboard shortcut. 
//The RoutedCommand simply calls back into the original Command. 
//It also sets the CommandBinding property, which still has to be added to the 
//CommandBindingCollection of either the bound control or one of it ancestors 
public InputGesture Gesture 
{ 
    set 
    { 
    var origCmd = Command; 
    if(origCmd == null) 
     return; 
    var routedCmd = new RoutedCommand(Header, 
     typeof(System.Windows.Controls.MenuItem), 
     new InputGestureCollection { value }); 
    CommandBinding = new CommandBinding(routedCmd, 
     (sender, args) => origCmd.Execute(args.Parameter), 
     (sender, args) => { args.CanExecute = origCmd.CanExecute(args.Parameter); }); 
    Command = routedCmd; 
    } 
} 

//CommandBinding created when setting Gesture 
public CommandBinding CommandBinding { get; private set; } 

Vì vậy, điều này mang lại các chức năng tôi yêu cầu ban đầu (tức là thêm phím tắt trong mã nơi họ có thể dễ dàng cấu hình vv). Tất cả những gì còn lại là đăng ký các lệnh. Tại thời điểm này được thực hiện đơn giản bằng cách thêm tất cả chúng vào Application.Current.MainWindow.CommandBindings.

Trả lời

3

Điều này không thực sự đủ điều kiện làm 'câu trả lời' (tôi không thể thêm nhận xét rõ ràng) - nhưng tôi khuyên bạn nên làm gì, không phải là phương pháp dự định trong WPF. Bạn đang làm điều này theo cách Windows Forms (và như trong nhiều bộ công cụ khác) - xác định mã UX của bạn. Bạn đã đi xa như bạn đã làm, nhưng bây giờ bạn đã chạy vào một bức tường gạch: các cử chỉ quan trọng hoàn toàn là UX, chắc chắn không được quy định trong mã-đằng sau. Sự xuất hiện (như là một chức năng của mô hình khung nhìn), và sự tương tác của người dùng với nó (các cách tạo ra một lệnh đã cho) là cho định nghĩa XAML.

Giá trị thuộc tính và Lệnh dành cho mô hình chế độ xem của bạn để bạn có thể sử dụng lại mô hình chế độ xem này cho các chế độ xem khác và cũng dễ dàng tạo đơn vị kiểm tra cho nó. Làm thế nào để thực hiện các phím tắt trên bàn phím của bạn trong mô hình xem giúp kiểm tra? Và để sử dụng trong các chế độ xem khác, người ta có thể cho rằng các phím tắt thực tế có thể không áp dụng cho chế độ xem mới, vì vậy đó không phải là nơi thuộc về. Tất nhiên, bạn có thể có những lý do khác - nhưng tôi khuyên bạn nên xem xét việc xác định những điều này trong XAML.

-Nhập, để đáp ứng với bạn comment-

Bạn đang hoàn toàn đúng - và tôi đã nhìn thấy một số dự án WPF UX khá lớn mà cố gắng hết sức để tránh bất kỳ mã và vết thương lên không cần thiết tù. Tôi cố gắng chỉ sử dụng cách tiếp cận nào mang lại kết quả làm việc và đơn giản như tôi có thể đạt được.

Đây là đoạn mã mẫu đơn giản tạo MenuItem ..

<Menu x:Name="miMain" DockPanel.Dock="Top"> 
    <MenuItem Command="{Binding Path=MyGreatCommand}" Header="DoSomething"/> 

Điều đó tạo trình đơn. Tại đây, MyGreatCommand là một ICommand và chỉ đơn giản là thuộc tính trên mô hình chế độ xem. Tôi thường đặt rằng trong vòng một DockPanel, để xử lý các StatusBar vv

Để gán cử chỉ quan trọng ..

<Window.InputBindings> 
    <KeyBinding Key="X" Modifiers="ALT" Command="{Binding Path=MyGreatCommand}"/> 

Tuy nhiên, kể từ khi bạn nói rằng bạn đã tìm kiếm câu trả lời và chỉ tìm thấy XAML - Tôi cho rằng bạn đã thử phương pháp này. Tôi đã sử dụng RoutedUICommand s thay vì người dùng định nghĩa ICommand s, để nhận được cử chỉ chính phù hợp tốt đẹp đó trong văn bản tiêu đề, nhưng tôi chưa tìm thấy cách thực hiện cả hai. Nếu bạn nhấn mạnh khi tạo các lệnh và các cử chỉ chính tất cả trong mã, bạn có thể phải tạo RoutedUICommand s.

Tại sao bạn muốn đặt các cử chỉ chính ngoài XAML của bạn?

Nếu bạn muốn có một số menu-mục để chỉ xuất hiện khi một số bang giữ ảnh hưởng trong phạm vi xem mô hình của bạn, sau đó bạn có thể ràng buộc Visibility tài sản của một menu-item (có thể chứa menu-các mặt hàng khác) để Collapsed hoặc Visible .

+0

Bạn có thể cung cấp một số mẫu mã không? Bạn có nghĩa là tôi nên xác định trình đơn hoàn chỉnh trong xaml? Hay chỉ là lối tắt? Tôi muốn xem như thế nào .. Tôi cần những thứ như một trình đơn 'Tools' toàn cầu, trong đó bổ sung có thể thêm menu con theo ý muốn - có thể thậm chí được thực hiện trong xaml? Ngoài ra, nó có thể, nó sẽ loại bỏ mã với xaml, không? Bây giờ tất cả những gì tôi cần để thêm một lệnh menu là mã như được hiển thị. Đó là ngắn và tiện dụng vì nó có thể nhận được và nó hoạt động rất tốt. Btw tường gạch của bạn hoạt động theo 2 hướng: Tôi chưa thấy một ứng dụng quy mô lớn mà không có mảnh UX nào được định nghĩa trong mã .. Đó là một huyền thoại. – stijn

+0

Bạn hoàn toàn đúng - và tôi đã nhìn thấy một số dự án WPF UX khá lớn đã cố gắng thực sự khó khăn để tránh bất kỳ mã nào - và vết thương không cần thiết gây khó chịu. Tôi cố gắng chỉ sử dụng phương pháp tiếp cận nào hoạt động và đơn giản nhất. Đây là đoạn trích mẫu (xin lỗi vì thiếu tiếng tăm - Tôi không chắc chắn cách định dạng trang này trên trang web này) .. '

JamesWHurst

+1

chỉnh sửa câu trả lời của bạn, dán mã, chọn nó và nhấp vào nút * Mã mẫu * .. – stijn

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