2009-07-24 31 views
45

Tôi có Chế độ xem có một đơn TextBox và một số Button ở bên dưới. Khi tải cửa sổ tôi muốn rằng TextBox để có tiêu điểm.Trường tập trung WPF MVVM trên tải

Nếu tôi không sử dụng MVVM, tôi chỉ cần gọi TextBox.Focus() trong sự kiện Đã tải. Tuy nhiên ViewModel của tôi không biết về quan điểm của tôi vì vậy làm thế nào tôi có thể thực hiện điều này mà không cần đưa mã vào codebehind của quan điểm của tôi?

EDIT: Sau khi đọc câu trả lời tôi đã quyết định đặt mã này trong giao diện XAML

<DockPanel FocusManager.FocusedElement="{Binding ElementName=MessageTextBox}">  
    <TextBox Name="MessageTextBox" Text="{Binding Message}"/> 
</DockPanel> 

Nếu đây là bất cứ điều gì khác hơn là tập trung trang đầu tiên tôi có lẽ sẽ khuyên bạn nên trả lời Jon Galloway kể từ khi nó có thể được điều khiển từ ViewModel.

Trả lời

44

Nếu nó làm cho bạn cảm thấy tốt hơn (nó làm cho tôi cảm thấy tốt hơn), bạn có thể làm điều này trong XAML sử dụng một tài sản gắn liền:

http://msdn.microsoft.com/en-us/library/system.windows.input.focusmanager.focusedelement.aspx

Bất cứ điều gì bạn có thể làm trong codebehind bạn có thể làm trong XAML nếu bạn biết các thủ thuật. May mắn thay, bạn không phải thực hiện thủ thuật này - MS đã làm điều đó cho bạn.

+0

Đó chính xác là những gì tôi đang tìm kiếm. Tôi nghĩ rằng mã này không thuộc về quan điểm và vì lý do nào đó tôi thích nó tốt hơn trong xaml so với mã phía sau. –

+2

Đề xuất của Galloway cho phép bạn kiểm soát tiêu điểm từ ViewModel ... bạn cũng có thể xem xét kỹ hơn điều đó. –

+3

Sau khi đọc một số câu trả lời khác, tôi không chắc mã đó thuộc về ViewModel hay không. Có vẻ như nó được gắn trực tiếp với chế độ xem. Nếu tôi có một trang phức tạp hơn đã thực sự di chuyển tiêu điểm dựa trên các sự kiện khác có thể có ý nghĩa. Điều đó nói rằng nó vẫn là một mẹo tốt đẹp để có. –

14

Trong trường hợp này, tôi nghĩ rằng bạn nên đặt mã vào chế độ xem. Việc đặt tiêu điểm thành điều khiển ảnh hưởng đến hành vi của giao diện người dùng thay vì logic của ứng dụng và do đó là trách nhiệm của chế độ xem.

+1

Đó là loại gì tôi nghĩ. Tôi chỉ cảm thấy một chút bẩn mỗi khi tôi nghĩ về việc thêm mã vào khung nhìn. Trong trường hợp này, nó có vẻ hợp lý. –

+14

Tôi nghĩ rằng một khi tôi thay đổi triết lý MVVM từ "không có mã sau" thành "mã tối thiểu và thích hợp sau", cuộc sống của tôi trở nên dễ dàng hơn rất nhiều. Tôi đã không nghe nói về tài sản đính kèm mà Anderson Imes đã đề cập, và nó có vẻ như một giải pháp tốt cho hương vị xấu mà mã phía sau cung cấp cho bạn, nhưng đừng sợ đặt * hợp pháp *, mã phi logic trong Giao diện người dùng. –

+4

Tôi đồng ý với bạn. Tôi không nghĩ rằng nó có ý nghĩa để có được tôn giáo về việc loại bỏ mã từ xem. Điều quan trọng là mã trong chế độ xem phải rất liên quan đến giao diện người dùng. Mã trong máy ảo chứa trạng thái và logic khác liên quan đến mô hình. Bài kiểm tra litmus là liệu mã có thể/nên được kiểm tra hay không. Không thể kiểm tra mã trong chế độ xem. –

4

Tôi muốn xem xét việc kiểm soát tập trung là rất nhiều "chỉ hình ảnh", do đó, sẽ không có bất kỳ vấn đề nào xảy ra với mã phía sau.

Ý tưởng về máy ảo là di chuyển logic ra khỏi Chế độ xem và cung cấp phiên bản thân thiện với dữ liệu của mô hình của bạn để chế độ xem liên kết với. Điều này không nhất thiết có nghĩa là tất cả các mã phải nằm trong máy ảo, chỉ là mã logic và bất kỳ thứ gì không được gắn trực tiếp với giao diện người dùng.

8

Thực ra, không tập trung vào mối quan tâm về giao diện người dùng? MVVM là về tách mối quan tâm - những gì thuộc về mô hình là trong mô hình, những gì thuộc về xem là trong xem, và những gì ràng buộc mô hình và xem với nhau là trong ViewModel (đây là khóa học mô tả quá kích thước).

Điều này có nghĩa, logic giao diện người dùng đó vẫn còn trong Chế độ xem - TextBox.Focus() là, theo ý kiến ​​của tôi, cách thích hợp để thực hiện điều này.

10
  1. Có một thuộc tính trong ViewModel của bạn cho biết phần tử hiện đang được tập trung.
  2. Sử dụng FocusManager để liên kết với thuộc tính đó.

    <Window FocusManager.FocusedElement="{Binding ElementName=ViewModel.FocusedItem}"/> 
    

ViewModel của bạn là một người phiên dịch mà tồn tại chỉ để cung cấp thông tin cho người xem, vì vậy bạn có thể thêm bất cứ thông tin để VM rằng View cần để hoạt động.

+4

Nhưng sau đó bạn phải đặt tên cho tất cả các phần tử của bạn và sử dụng tên đó trong VM. Điều này sẽ không hoạt động nếu bạn có một bộ sưu tập các mục trong VM mà khung nhìn được gắn kết. – Carlos

+7

IMHO, máy ảo sẽ không có thông tin về tên hoặc loại kiểm soát trong quá trình triển khai chế độ xem thực tế. Thay vào đó, tôi muốn cho phép khung nhìn lắng nghe thông báo thay đổi thuộc tính từ máy ảo và sau đó cho phép nó xử lý nó. ví dụ. ActivateNameField chuyển thành true .. khung nhìn tìm điều khiển thích hợp và đặt trọng tâm cho nó. – Gishu

+1

Tôi đồng ý rằng VM phải có vai trò trong quá trình khi có liên quan đến logic nghiệp vụ. Khi thiết kế gọi cho "khi họ chọn hộp kiểm này và họ là quản trị viên, sau đó đặt trọng tâm vào hộp văn bản OverrideReason" thì logic thuộc về VM. Bí quyết giúp cho Chế độ xem tôn trọng thay đổi về tài sản. – TheZenker

2

Sau khi có 'cơn ác mộng tập trung ban đầu WPF' và dựa trên một số câu trả lời trên ngăn xếp, sau đây đã chứng minh cho tôi là giải pháp tốt nhất.

Trước tiên, hãy thêm ứng dụng của bạn.XAML OnStartup() sau:

EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent, 
      new RoutedEventHandler(WindowLoaded)); 

Sau đó, thêm sự kiện 'WindowLoaded' cũng trong App.xaml:

void WindowLoaded(object sender, RoutedEventArgs e) 
    { 
     var window = e.Source as Window; 
     System.Threading.Thread.Sleep(100); 
     window.Dispatcher.Invoke(
     new Action(() => 
     { 
      window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); 

     })); 
    } 

Vấn đề phân luồng phải được sử dụng như WPF tập trung ban đầu chủ yếu là thất bại do một số khuôn khổ điều kiện chủng tộc.

Tôi đã tìm thấy giải pháp sau tốt nhất vì nó được sử dụng trên toàn cầu cho toàn bộ ứng dụng.

Hy vọng nó sẽ giúp ...

Oran