2012-09-05 6 views
5

내 WPF 응용 프로그램에서 FolderBrowserDialog을 사용하려고합니다. 나는 윈도우 폼을 보는데별로 신경 쓰지 않는다.MVVM에서 WPF 응용 프로그램의 FolderBrowserDialog를 사용하는 방법

MVVM을 사용하고 있다는 것을 제외하고는 적절한 대답 (How to use a FolderBrowserDialog from a WPF application)과 함께 질문을 찾았습니다.

This 나는 윈도우 객체를 얻을 수 없다는 것을 제외하고는 "구현 됨"이었고 매개 변수없이 ShowDialog()을 호출했습니다.

내이 ViewModel this에서
var dlg = new FolderBrowserDialog(); 
System.Windows.Forms.DialogResult result = dlg.ShowDialog(this.GetIWin32Window()); 

날 창 컨텍스트를 얻을에 대한 GetIWin32Window() 방법이 없습니다 :

문제는 이것이다.

이 아이디어를 만드는 방법에 대한 아이디어가 있으십니까?

답변

4

먼저, 창을 필요로하지 않는 ShowDialog 서명을 사용할 수 있습니다.

var dlg = new FolderBrowserDialog(); 
DialogResult result = dlg.ShowDialog(); 

두 번째, 응용 프로그램의 기본 창을 소유 창으로 보낼 수 있습니다.

var dlg = new FolderBrowserDialog(); 
DialogResult result = dlg.ShowDialog(Application.Current.MainWindow.GetIWin32Window()); 

두 번째 옵션은 매우 MVVMish로 간주되지 않을 수 있습니다.

this question에있는 의 답변을 참조하여 ViewModel에 View에 대한 포인터를 삽입하는 방법 (이 방법이 좋은지 나쁜지는 확실하지 않지만 그 점을 저를 막을 수는 없습니다.))이 기술을 사용하면 실제로 View를 FolderBrowserDialog의 소유자로 만들고 싶다면 VM에서 해당 View에 액세스 할 수 있습니다.

@ChrisDD는 인터페이스를 정의하고 FolderBrowserDialog를 래핑하는 것이 옳습니다. 우리가 FolderBrowser 가져 오기 IFolderBrowserDialog를 사용하려는

public interface IFolderBrowserDialog 
    { 
    string Description { get; set; } 
    Environment.SpecialFolder RootFolder { get; set; } 
    string SelectedPath { get; set; } 
    bool ShowNewFolderButton { get; set; } 
    bool? ShowDialog(); 
    bool? ShowDialog(Window owner); 
    } 

    //Decorated for MEF injection 
    [Export(typeof(IFolderBrowserDialog))] 
    [PartCreationPolicy(CreationPolicy.NonShared)] 
    internal class WindowsFormsFolderBrowserDialog : IFolderBrowserDialog 
    { 
    private string _description; 
    private string _selectedPath; 

    [ImportingConstructor] 
    public WindowsFormsFolderBrowserDialog() 
    { 
     RootFolder = System.Environment.SpecialFolder.MyComputer; 
     ShowNewFolderButton = false; 
    } 

    #region IFolderBrowserDialog Members 

    public string Description 
    { 
     get { return _description ?? string.Empty; } 
     set { _description = value; } 
    } 

    public System.Environment.SpecialFolder RootFolder { get; set; } 

    public string SelectedPath 
    { 
     get { return _selectedPath ?? string.Empty; } 
     set { _selectedPath = value; } 
    } 

    public bool ShowNewFolderButton { get; set; } 

    public bool? ShowDialog() 
    { 
     using (var dialog = CreateDialog()) 
     { 
     var result = dialog.ShowDialog() == DialogResult.OK; 
     if (result) SelectedPath = dialog.SelectedPath; 
     return result; 
     } 
    } 

    public bool? ShowDialog(Window owner) 
    { 
     using (var dialog = CreateDialog()) 
     { 
     var result = dialog.ShowDialog(owner.AsWin32Window()) == DialogResult.OK; 
     if (result) SelectedPath = dialog.SelectedPath; 
     return result; 
     } 
    } 
    #endregion 

    private FolderBrowserDialog CreateDialog() 
    { 
     var dialog = new FolderBrowserDialog(); 
     dialog.Description = Description; 
     dialog.RootFolder = RootFolder; 
     dialog.SelectedPath = SelectedPath; 
     dialog.ShowNewFolderButton = ShowNewFolderButton; 
     return dialog; 
    } 
    } 

    internal static class WindowExtensions 
    { 
    public static System.Windows.Forms.IWin32Window AsWin32Window(this Window window) 
    { 
     return new Wpf32Window(window); 
    } 
    } 

    internal class Wpf32Window : System.Windows.Forms.IWin32Window 
    { 
    public Wpf32Window(Window window) 
    { 
     Handle = new WindowInteropHelper(window).Handle; 
    } 

    #region IWin32Window Members 

    public IntPtr Handle { get; private set; } 

    #endregion 
    } 

그런 다음 우리는 VM/명령을 : 그건 우리가 그것을 할 방법이다. 응용 프로그램에서 IFolderBrowserDialog.ShowDialog는 대화 상자를 표시합니다. 단위 테스트에서는 IFolderBrowserDialog를 모의 해 올바른 매개 변수로 호출되었는지 확인하고 테스트를 계속 진행할 수 있도록 선택된 폴더를 다시 출력합니다.

0

MVVM 방법 :

는 FolderBrowserDialog를위한 새로운 인터페이스를 정의한다. 새 클래스 &을 만들어 해당 인터페이스를 구현하십시오. 구현은 실제 FolderBrowserDialog 클래스로 수행됩니다.

MVVM을 특정 구현에 연결하지 않고 나중에 실제 논리를 테스트 할 수 있습니다.

+0

. 그는 현재보기의 IWin32Window를 검색 할 수 있도록 ViewModel을 프로그래밍하는 방법을 알고 싶어합니다. –

+0

예, 구현 세부 사항입니다. 내가 말했듯이, 당신이 인터페이스를 구현한다면, 구현은 원하는대로 할 수 있습니다. ViewModel은 아무 것도 알 필요가 없습니다. Application.Current.Windows.Where (x => x.IsActive = true)에 의해 현재 뷰를 얻을 수 있습니다. –

2

FolderBrowserDialog를 사용하기로 결정했다면이 디자인을 사용합니다.

먼저 뷰에 DependencyProperty를 만들어 해당 핸들을 표시하십시오.창문로드, 당신은 질문에 제공하는 확장 기능을 사용하여 핸들을 검색 할 수 있습니다 때

public static readonly DependencyProperty WindowHandleProperty = 
    DependencyProperty.Register("WindowHandle", typeof(System.Windows.Forms.IWin32Window), typeof(MainWindow), new PropertyMetadata(null)); 

// MainWindow.cs 
public System.Windows.Forms.IWin32Window WindowHandle 
{ 
    get { return (System.Windows.Forms.IWin32Window)GetValue(WindowHandleProperty); } 
    set { SetValue(WindowHandleProperty, value); } 
} 

이제, 당신이에 연결 : 그래서

// MainWindow.cs 
void MainWindow_Loaded(object sender, RoutedEventArgs e) 
{ 
    var binding = new Binding(); 
    binding.Path = new PropertyPath("WindowHandle"); 
    binding.Mode = BindingMode.OneWayToSource; 
    SetBinding(WindowHandleProperty, binding); 

    WindowHandle = this.GetIWin32Window(); 
} 

, 당신의 "를 사용하여 소스에 단방향 바인딩 WindowHandle "속성. 하나의 ViewModel가 짝을 하드 코딩하지이기 때문에

// ViewModel.cs 
private System.Windows.Forms.IWin32Window _windowHandle; 
public System.Windows.Forms.IWin32Window WindowHandle 
{ 
    get 
    { 
     return _windowHandle; 
    } 
    set 
    { 
     if (_windowHandle != value) 
     { 
      _windowHandle = value; 
      RaisePropertyChanged("WindowHandle"); 
     } 
    } 
} 

이 좋은 솔루션입니다 : 당신의 ViewModel이 WindowHandle 속성이한다면, 그것은 관련 뷰의 유효 IWin32Handle 최신 상태로 유지됩니다 하나의 특정보기. 동일한 ViewModel을 사용하여 여러 개의보기를 사용하는 경우 그냥 작동해야합니다. 새보기를 작성했지만 DependencyProperty를 구현하지 않으면, 이는 단지 null 핸들로 작동합니다.

편집 : 보조 노트로

, 당신은 실제로 단지 IWin32Owner 매개 변수를 제공하지 않는 테스트 한? 나에게는 여전히 응용 프로그램의 모달 대화 상자로 자동 열리고 사용자가 모든 응용 프로그램의 창과 상호 작용하지 못하도록 차단합니다. 그 대신 당신이해야 할 일이 있습니까?

0

mvvm 패턴 내에서 어떤 종류의 대화 상자도 처리하려면 Dialog-Service와 같은 종류의 대화 상자를 사용해야합니다. this post에서이 접근법과 관련된 몇 가지 힌트를 찾을 수 있습니다.

대화 상자 항목을 서비스에 넣으면 mvvm 패턴이 변경되지 않습니다. 이 서비스는 모든 대화 작성을 처리하고 결과를 제공 할 수 있습니다. 뷰 모델은 메소드를 호출하고 서비스가 제공하는 이벤트를 구독합니다.

서비스 (인터페이스)에 종속성 삽입을 사용하면 조롱을 통해 솔루션을 테스트 할 수있는 장점이 있습니다. 또는 wpf가있을 경우 formsbrowserdialog 양식을 바꿀 수 있습니다.

0

MVVM + 윈폼 FolderBrowserDialog 행동으로

public class FolderDialogBehavior : Behavior<Button> 
{ 
    public string SetterName { get; set; } 

    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     AssociatedObject.Click += OnClick; 
    } 

    protected override void OnDetaching() 
    { 
     AssociatedObject.Click -= OnClick; 
    } 

    private void OnClick(object sender, RoutedEventArgs e) 
    { 
     var dialog = new FolderBrowserDialog(); 
     var result = dialog.ShowDialog(); 
     if (result == DialogResult.OK && AssociatedObject.DataContext != null) 
     { 
      var propertyInfo = AssociatedObject.DataContext.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public) 
      .Where(p => p.CanRead && p.CanWrite) 
      .Where(p => p.Name.Equals(SetterName)) 
      .First(); 

      propertyInfo.SetValue(AssociatedObject.DataContext, dialog.SelectedPath, null); 
     } 
    } 
} 

사용

 <Button Grid.Column="3" Content="..."> 
      <Interactivity:Interaction.Behaviors> 
       <Behavior:FolderDialogBehavior SetterName="SomeFolderPathPropertyName"/> 
      </Interactivity:Interaction.Behaviors> 
    </Button> 

블로그 게시물 : 그는 여전히 적절한 모달 대화 상자로 표시하기 위해 FolderBrowserDialog에 IWin32Window를 전달해야 http://kostylizm.blogspot.ru/2014/03/wpf-mvvm-and-winforms-folder-dialog-how.html

관련 문제