2009-07-24 7 views
45

하나의 뷰에 TextBox과 그 아래에 하나의 숫자가 Button 인 뷰가 있습니다. 창이로드 될 때 TextBox에 포커스가 있기를 원합니다.WPF MVVM 포커스 필드로드시

MVVM을 사용하지 않는 경우 Loaded 이벤트에서 TextBox.Focus()을 호출하기 만하면됩니다. 그러나 내 ViewModel은 내보기에 대해 알지 못해서 내보기의 코드 숨김에 코드를 넣지 않고 어떻게이 작업을 수행 할 수 있습니까?

편집 : 답변을 읽은 후 나는이 그것을 제어 할 수 있기 때문에 아마 존 갤러웨이의 답변을 추천 할 것 초기 페이지 초점 이외 인 경우 뷰 XAML

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

에이 코드를 넣어하기로 결정 ViewModel

답변

44

당신이 연결된 속성 사용하면 XAML에서이 작업을 수행 할 수 있습니다 (그것은 나를 기분 좋게한다) 더 나은 기분 경우 : 당신이 경우 코드 숨김에서 할 수있는

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

아무것도 당신이 XAML에서 할 수 있습니다 속임수를 알아라. 다행히도, 당신은이 트릭을 구현할 필요가 없었습니다. MS가 당신을 위해 해 냈습니다.

+0

그게 내가 찾고 있었던 바로 그 것이다. 이 코드는 뷰에 속한다고 생각합니다. 어떤 이유로 xaml 코드의 코드보다 코드를 더 좋아합니다. –

+2

Galloway의 제안을 통해 ViewModel에서 포커스를 제어 할 수 있습니다 ... 또한이를 자세히 살펴볼 수도 있습니다. –

+3

다른 답변을 읽고 나면 코드가 ViewModel에 속하는지 확실하지 않습니다. 그것은 시야에 직접 묶여있는 것 같습니다. 아마 실제로 합리적인 다른 이벤트를 기반으로 포커스를 옮기는 더 복잡한 페이지가 있다면. 그것은 여전히 ​​가지고있는 좋은 속임수라고 말했다. –

14

이 경우 코드를보기에 넣는 것이 좋다고 생각합니다. 컨트롤에 포커스를 설정하면 응용 프로그램의 논리보다는 사용자 인터페이스의 동작에 영향을 미치므로보기의 책임이됩니다.

+1

. 보기에 코드를 추가 할 때마다 조금 더러워집니다. 이 경우 이해가가는 것 같습니다. –

+14

MVVM 철학을 "코드가없는 코드"에서 "최소 및 적절한 코드 숨김"으로 변경하면 내 인생이 훨씬 쉬워 졌다고 생각합니다. Anderson Imes가 언급 한 첨부 된 속성에 대해서는 들어 보지 못했습니다. 코드 뒤에 숨어있는 나쁜 맛에 대한 좋은 해결책 인 것처럼 들리 겠지만 합법적 인 * 논리 코드가 아닌 코드를 넣으면 두려워하지 않아도됩니다. UI. –

+4

나는 너와 합의했다. 나는보기에서 코드를 제거하는 것에 대해 종교적으로 생각하는 것이 타당하지 않다고 생각합니다. 중요한 것은 뷰의 코드가 매우 UI와 관련되어야한다는 것입니다. VM의 코드에는 모델과 관련된 상태 및 기타 논리가 포함됩니다. 리트머스 테스트는 코드를 테스트 할 수 있는지 여부입니다. 보기의 코드는 테스트 할 수 없습니다. –

4

포커스가있는 컨트롤을 "시각적으로 만"매우 중요하게 생각하므로 코드 뒤에있는 문제는 없습니다.

VM의 개념은보기에서 논리를 멀리 이동하고보기에 바인딩 할 수 있도록 데이터 바인딩 친숙한 버전의 모델을 제공하는 것입니다. 그렇다고해서 반드시 모두 코드가 VM에 있어야하며, 로직 코드와 UI에 직접 연결되어 있지 않은 코드가 있어야합니다.

8

사실, UI에 관심이 집중되어 있지 않습니까? MVVM은 관심사를 분리하는 것입니다. 모델에 속한 것은 모델에 있고, 뷰에 속한 것은 뷰에 있고, 함께 바인딩 모델과 뷰는 ViewModel에 있습니다 (이는 간략화 된 설명 임).

이것은 UI 로직이 View - TextBox.Focus()에 남아 있음을 의미합니다. 제 의견으로는이 문제를 해결하는 적절한 방법입니다.

10
  1. ViewModel에 현재 포커스가있는 요소를 나타내는 속성이 있습니다.
  2. FocusManager를 사용하여 해당 속성에 바인딩합니다.

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

귀하의 ViewModel

당신이보기 기능을 필요로하는 VM에 어떤 정보를 추가 할 수 있도록보기에 정보를 제공하기 위해서만 존재하는 번역기입니다.

+4

하지만 모든 요소의 이름을 지정하고 VM에서 해당 이름을 사용해야합니다. 보기에 바인딩 할 VM에 항목 모음이있는 경우에는 작동하지 않습니다. – Carlos

+7

IMHO, VM에는 실제 뷰 구현시 제어 이름이나 유형에 대한 정보가 없어야합니다. 대신 뷰에서 VM의 속성 변경 알림을 수신 한 다음 처리하도록 두었습니다. 예 : ActivateNameField가 true가됩니다. View는 관련 컨트롤을 찾고 포커스를 설정합니다. – Gishu

+1

비즈니스 논리가 관련되어있을 때 VM에 프로세스의 역할이 있어야한다는 것에 동의합니다. 디자인에서 "이 확인란을 선택하고 관리자 인 경우 OverrideReason 텍스트 상자에 포커스를 설정하면"논리가 VM에 속합니다. 트릭을 사용하면 속성 변경 내용을 반영하도록보기가 표시됩니다. – TheZenker

2

'WPF 초기 포커스 악몽'을 갖고 스택에 대한 몇 가지 답변을 바탕으로 다음과 같은 결과가 나에게 가장 적합한 솔루션임을 입증했습니다.

먼저 앱을 추가하십시오.XAML OnStartup() 다음은 :

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

그런 다음 App.xaml에 또한 'WindowLoaded'이벤트를 추가 :

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)); 

     })); 
    } 

스레딩 문제가 WPF 초기 초점으로 사용할 수 있어야 대부분 실패로 인해 일부 프레임 워크 경쟁 조건.

전체 솔루션에서 전 세계적으로 사용되는 다음 솔루션을 가장 잘 찾아 냈습니다. 내가 무슨 생각의 종류이 도움이

희망 ...

오란