2010-05-14 4 views
6

모달 대화 상자로 작동하는 WPF 창을 만들고 동시에 같은 응용 프로그램의 특정 다른 창에서 선택한 작업을 쉽게 수행하려고합니다. 이 동작의 예는 Adobe Photoshop에서 볼 수 있습니다.이 대화 상자는 사용자가 스포이드 도구를 사용하여 이미지에서 선택을하면서 사실상 다른 모든 응용 프로그램 기능을 비활성화 할 수있는 몇 가지 대화 상자를 제공합니다.모달 및 비모수 모두 동작하는 창

앞으로는 비 모달적이고 항상 맨 위에있는 대화 상자를 만들고 대화 상자에 적용 할 수없는 응용 프로그램 기능을 프로그래밍 방식으로 사용하지 않도록 설정하는 것이 좋습니다. WPF에서 이것을 쉽게 구현할 수 있습니까? 아니면 제가 채택 할 수있는 디자인 패턴이있을 수도 있습니다.

+0

나는 올바른 길을 가고 있다고 생각합니다. 창을 열거 나 닫을 때 코드 숨김에서 컨트롤을 사용하거나 사용하지 않도록 설정하거나 XAML에서 DataTriggers를 사용하고 새 창이 열려 있는지 여부에 따라 다양한 컨트롤에 'IsEnabled'속성을 설정할 수 있습니다. –

답변

0

찾고있는 것은 Multiple Document Interface과 유사합니다. 이것은 WPF에서 기본적으로 사용할 수 없지만이를 지원하기위한 노력이 있습니다 (freecommercial).

응용 프로그램의 현재 상태를 확인하고 이에 대한 응답으로 UI 요소를 활성화/비활성화하는 것은 사용자의 책임입니다.

+0

MDI를 구축하고 있지만 MDI의 본질은 내가 설명한 동작을 지원하지 않습니다. 귀하의 두 번째 단락에 동의하지만 잠재적 인 골칫거리가 있습니다. 일부 ICommands를 비활성화하려면 프로그래밍 방식으로이 작업을 수행 할 방법이 필요하며 약간의 생각을 들여다 보면 많은 작업이 필요합니다. – Chris

0

프로그래밍 방식으로 특정 앱 기능을 사용 중지하는 항상 켜져있는 창은이를 수행하는 방법이라고 생각합니다. 이 양식이 열려있는 동안 활성화 할 수있는 기능의 "화이트리스트"를 유지하는 것이 더 쉬우 며 목록에없는 모든 것을 비활성화하십시오 (의 "블랙리스트"를 유지하는 것과 반대).을 사용할 수 없음).

2

예, 프로그래밍 방식으로 기능을 활성화/비활성화하는 전통적인 방법이 있지만 WPF는 WinForms 및 이전 기술에서 실제로 불가능했던 몇 가지 새로운 가능성을 열었습니다. 당신은 비밀리에 자동으로하는 비주얼로 사각형을 사용하여 그 내용이 효과적으로을 사용할 수 없도록 사진과 함께 윈도우의 내용을 대체 할 수

  • :

    나는이 작업을 수행하는 네 가지 WPF 특정 방법을 설명합니다 그것. 사용자에게는 윈도우가 변경되지 않은 것처럼 보이지만 실제 내용은 그림 아래에 표시되므로 히트 테스트에 사용할 수 있고 선택한 이벤트를 전달할 수도 있습니다.

  • 사용자 지정 첨부 속성을 사용하여 명시 적으로 재정의 된 경우를 제외하고 모든 TextBox가 TextBlocks가되는 모든 ResourceBictionary에 MergedDictionary를 추가 할 수 있습니다. 따라서 선택적으로 활성화/비활성화하는 모든 UI를 반복하는 대신 MergedDictionaries 컬렉션에서 개체를 추가하거나 제거하기 만하면됩니다.

  • InputManager를 사용하여 사용 중지 된 창의 특정 부분에서 실제 마우스 이벤트를 프로그래밍 방식으로 생성하고 처리하여 "승인"된 것으로 테스트하지 않은 마우스 이벤트를 허용하지 않을 수 있습니다."

  • 를 사용하여 데이터 바인딩과 스타일 앱을 반복, 활성화/오히려이 솔루션의 창

    의 사진과 함께 창 교체에 대한 그들을 통해

세부 사항을 반복하는 것보다 개별 컨트롤을 사용하지 않도록합니다 창을 열고 각 내용을 다음과 같이 원본 내용과 사각형이 포함 된 격자로 바꿉니다.

<Window ...> 
    <Grid> 
    <ContentPresenter x:Name="OriginalContent" /> 
    <Rectangle> 
     <Rectangle.Fill> 
     <VisualBrush Visual="{Binding ElementName=OriginalContent}" /> 
     </Rectangle.Fill> 
    </Rectangle> 
    </Grid> 
</Window> 

프로그래밍 방식으로 또는 Window에서 템플릿을 사용하여 수행 할 수 있지만 사용자 정의 컨트롤을 만들고 해당 템플릿을 사용하여 위의 구조를 만드는 것이 좋습니다. 이 작업이 완료되면, 당신은 단순히이 같은 창문을 코딩 할 수 있습니다 :

<Window ...> 
    <my:SelectiveDisabler> 
    <Grid x:Name="LayoutRoot"> ... </Grid> <!-- Original content --> 
    </my:SelectiveDisabler> 
</Window> 

사각형에 마우스 이벤트 핸들러를 추가하고 원본 콘텐츠에 클릭 된 것을 목적 결정하기 위해 ContentPresenter에에 VisualTreeHelper.HitTest를 호출하여. 이 시점에서 마우스 이벤트를 무시하거나 처리하기 위해 원본 내용으로 전달하거나 스포이드 컨트롤이나 객체 선택 기능의 경우에는 원하는 객체/정보를 추출하기 만하면됩니다. MergedDictionary 접근

자세한 사항은 분명히 당신은있는 ResourceDictionary를 사용하여 전체 UI가 윈도우의 리소스에 병합의 스타일을 다시 할 수 있습니다.

병합 된 ResourceDictionary에 암시 적 스타일을 만들어 모든 TextBox를 TextBlocks로 표시하고 모든 Buttons를 Border로 표시하는 등의 방법이 있습니다.이 방법은 자체 스타일을 가진 TextBox 또는 명시 적으로 설정된 ControlTemplate이 업데이트를 놓칠 수 있습니다. 또한 원하는대로 모든 개체를 가져올 수 없으며 명령 또는 클릭 이벤트가 명시 적으로 지정되고 스타일이 해당 이벤트를 재정의하지 않으므로 명령 또는 클릭 이벤트를 쉽게 제거 할 수 없습니다.

더 좋은 방법은 병합 된 ResourceDictionary의 스타일에 연결된 속성을 설정 한 다음 PropertyChangedCallback에서 코드 숨김을 사용하여 실제로 변경하려는 속성을 업데이트하는 것입니다. 첨부 된 "ModalMode"속성을 true로 설정하면 개체의 개인 DependencyProperty에있는 여러 속성 (템플릿, 명령, 클릭, IsEnabled 등)의 모든 로컬 값과 바인딩을 저장 한 다음 표준 값으로 덮어 씁니다 . 예를 들어 버튼의 Command 속성은 일시적으로 null로 설정됩니다. 첨부 된 "ModalMode"등록 정보가 false가되면 원래의 모든 로컬 값과 바인딩이 임시 저장소에서 다시 복사되고 임시 저장소가 지워집니다.

이 방법은 첨부 된 "IgnoreModalMode"속성을 추가하여 UI 부분을 선택적으로 활성화/비활성화하는 편리한 방법을 제공합니다. ModalMode 변경 사항을 적용하지 않으려는 UIElements에서는이 값을 True로 수동 설정할 수 있습니다. 그런 다음 ModalMode PropertyChangedCallback이이를 확인하고 true이면 아무것도하지 않습니다. 마우스를 캡처 할 경우, 마우스를 얻을 수

InputManager 접근 방식에

세부 사항이 이동에 상관없이 조정합니다. CompositionTarget.TransformToDevice()를 사용하여 화면 좌표로 변환 한 다음 각 후보 윈도우에서 CompositionTarget.TransformFromDevice()를 사용하십시오.마우스 좌표가 범위 내에 있다면, 비활성화 된 윈도우를 히트 - 테스트합니다 (이것은 윈도우가 비활성화되어있을 때에도 수행 할 수 있습니다). 사용자가 클릭 한 객체가 마음에 들면 InputManager.ProcesInput을 사용하여 마우스 이벤트를 발생시킵니다 비활성화되지 않은 것처럼 정확하게 다른 창에서 처리됩니다. 모든 항목 기본적으로 지금

<Setter Property="IsEnabled" Value="{Binding NonModal, Source={x:Static local:ModalModeTracker.Instance}}" /> 

:

바인딩 사용하여 데이터에

자세한 사항은이 같은 정적 값 등 버튼, 메뉴 아이템의 IsEnabled 속성을 결합하는 스타일을 사용할 수 있습니다 이 스타일은 NonModal 속성이 false가되면 자동으로 비활성화됩니다. 그러나 모든 개별 컨트롤은 모달 모드에서도 사용할 수 있도록 IsEnabled="true"으로 재정의 할 수 있습니다. MultiBinding 및 EDF ExpressionBinding을 사용하면 더 복잡한 바인딩을 통해 원하는 규칙을 설정할 수 있습니다.


이러한 접근 방식 중 비주얼 인터페이스를 통해 반복적으로 기능을 활성화 및 비활성화해야합니다. 실제로 선택할 수있는 기능은 모달 모드에서 실제로 제공하고자하는 기능과 나머지 UI 디자인 방식입니다.

WPF를 사용하면 WinForms 일보다 WPF가 훨씬 쉽게 만듭니다. WPF의 힘을 좋아하지 않습니까?

0

이 문제를 해결하는 가장 좋은 방법은 이전에 언급 한 InputManager 방식을 사용하는 것이라고 생각합니다. 이 디자인 패턴을 사용하면 툴바 버튼/메뉴 항목 등에 명령을 연결할 수 있으며 각각은 명령에 지정한 CanExecute 핸들러를 호출합니다. 이 핸들러에서 항상 맨 위의 넌 모달 윈도우가 열린 경우 명령을 활성화하지 않도록 설정합니다.

http://msdn.microsoft.com/en-us/library/ms752308.aspx