IT TIP

폴더 선택 대화 상자 WPF

itqueen 2020. 11. 29. 12:47
반응형

폴더 선택 대화 상자 WPF


WPF4 애플리케이션을 개발하고 내 앱에서 사용자가 애플리케이션이 무언가를 저장할 폴더 (파일, 생성 된 보고서 등)를 선택할 수 있도록해야합니다.

내 요구 사항 :

  • 표준 폴더 트리를 볼 수있는 기능

  • 폴더 선택 기능

  • WPF 모양과 느낌,이 대화 상자는 Windows 2000 또는 Win9x가 아닌 Windows Vista / 7 용으로 설계된 최신 응용 프로그램의 일부처럼 보여야합니다.

내가 이해하는대로 2010 (.Net 4.0)까지는 표준 폴더 대화 상자가 없지만 버전 4.0에서 일부 변경 사항이있을 수 있습니까?

아니면 나머지 할 일은 구식 WinForms 대화 상자를 사용하는 것입니까? 필요한 작업을 수행하는 유일한 방법 인 경우 어떻게 Win9x가 아닌 Vista / 7 스타일에 더 가깝게 만들 수 있습니까?

일부 포럼에서 나는 그러한 대화 상자의 구현을 보았지만 Windows 95와 같은 오래된 추악한 아이콘을 보았습니다. 정말보기 좋지 않습니다.


나는 오래 전에 내 블로그에 그것에 대해 썼다. 일반적인 파일 대화 상자에 대한 WPF의 지원은 정말 나쁘다 (또는 적어도 3.5 버전이었습니다.

응용 프로그램에 올바른 매니페스트를 추가해야합니다. 그러면 최신 스타일의 메시지 상자와 폴더 브라우저 (WinForms FolderBrowserDialog)가 제공되지만 WPF 파일 열기 / 저장 대화 상자는 제공되지 않습니다.이 내용은 해당 3 개 게시물에 설명되어 있습니다. 설명에 대한 해결책이 3rd로 직접 이동하기를 원합니다) :

다행히도 열기 / 저장 대화 상자는 Vista / 7 스타일 (매니페스트 설정 후)을 얻기 위해 올바른 플래그로 쉽게 호출 할 수있는 Win32 API 주변의 매우 얇은 래퍼입니다.


"공통 대화 상자 사용"섹션의 155 페이지에있는 Pavel Yosifovich의 Windows Presentation Foundation 4.5 Cookbook 은 다음과 같이 말합니다.

"(파일 대신) 폴더 선택은 어떻습니까? WPF OpenFileDialog는이를 지원하지 않습니다. 한 가지 해결책은 Windows Forms의 FolderBrowseDialog 클래스를 사용하는 것입니다. 또 다른 좋은 해결책은 곧 설명 할 Windows API 코드 팩을 사용하는 것입니다."

Microsoft® .NET Framework 용 Windows® API 코드 팩에서 API 코드 팩을 다운로드했습니다. Windows API 코드 팩 : 어디에 있습니까? , 그런 다음 Microsoft.WindowsAPICodePack.dll 및 Microsoft.WindowsAPICodePack.Shell.dll에 대한 참조를 WPF 4.5 프로젝트에 추가했습니다.

예:

using Microsoft.WindowsAPICodePack.Dialogs;

var dlg = new CommonOpenFileDialog();
dlg.Title = "My Title";
dlg.IsFolderPicker = true;
dlg.InitialDirectory = currentDirectory;

dlg.AddToMostRecentlyUsedList = false;
dlg.AllowNonFileSystemItems = false;
dlg.DefaultDirectory = currentDirectory;
dlg.EnsureFileExists = true;
dlg.EnsurePathExists = true;
dlg.EnsureReadOnly = false;
dlg.EnsureValidNames = true;
dlg.Multiselect = false;
dlg.ShowPlacesList = true;

if (dlg.ShowDialog() == CommonFileDialogResult.Ok) 
{
  var folder = dlg.FileName;
  // Do something with selected folder string
}

프로젝트에 Windows API 코드 팩-셸 추가

using Microsoft.WindowsAPICodePack.Dialogs;

...

var dialog = new CommonOpenFileDialog();
dialog.IsFolderPicker = true;
CommonFileDialogResult result = dialog.ShowDialog();

Windows Forms를 사용하거나 매니페스트 파일을 편집하지 않으려면 실제로 디렉터리를 선택하기 위해 WPF의 SaveAs 대화 상자를 사용하여 매우 간단한 해킹을 생각해 냈습니다.

using 지시문이 필요하지 않습니다. 아래 코드를 복사하여 붙여 넣기 만하면됩니다!

여전히 매우 사용자 친화적이어야하며 대부분의 사람들은 눈치 채지 못할 것입니다.

이 아이디어는 대화 상자의 제목을 변경하고 파일을 숨기고 결과 파일 이름을 매우 쉽게 처리 할 수 ​​있다는 사실에서 비롯됩니다.

확실히 큰 해킹이지만 아마도 당신의 사용에 잘 맞을 것입니다 ...

이 예제에서는 결과 경로를 포함 할 텍스트 상자 개체가 있지만 원하는 경우 관련 줄을 제거하고 반환 값을 사용할 수 있습니다.

// Create a "Save As" dialog for selecting a directory (HACK)
var dialog = new Microsoft.Win32.SaveFileDialog();
dialog.InitialDirectory = textbox.Text; // Use current value for initial dir
dialog.Title = "Select a Directory"; // instead of default "Save As"
dialog.Filter = "Directory|*.this.directory"; // Prevents displaying files
dialog.FileName = "select"; // Filename will then be "select.this.directory"
if (dialog.ShowDialog() == true) {
    string path = dialog.FileName;
    // Remove fake filename from resulting path
    path = path.Replace("\\select.this.directory", "");
    path = path.Replace(".this.directory", "");
    // If user has changed the filename, create the new directory
    if (!System.IO.Directory.Exists(path)) {
        System.IO.Directory.CreateDirectory(path);
    }
    // Our final value is in path
    textbox.Text = path;
}

이 해킹의 유일한 문제는 다음과 같습니다.

  • 확인 버튼은 "디렉토리 선택"과 같은 대신 "저장"이라고 표시되지만 광산과 같은 경우에는 디렉토리 선택을 "저장"하여 여전히 작동합니다.
  • 입력 필드에는 여전히 "디렉토리 이름"대신 "파일 이름"이 표시되지만 디렉토리는 파일 유형이라고 말할 수 있습니다.
  • 여전히 "파일 형식"드롭 다운이 있지만 그 값은 "디렉터리 (* .this.directory)"로 표시되며 사용자가 다른 항목으로 변경할 수 없으며 저에게 적합합니다.

대부분의 사람들은 이것을 알아 차리지 못할 것입니다. 비록 마이크로 소프트가 그들의 머리에서 머리를 떼어 내면 공식 WPF 방식을 사용하는 것을 확실히 선호 할 것이지만, 그들이 그렇게 할 때까지 그것은 나의 임시 수정입니다.


Microsoft.Win32.OpenFileDialog는 Windows의 모든 응용 프로그램에서 사용하는 표준 대화 상자입니다. .NET 4.0에서 WPF를 사용할 때 사용자는 그 모습에 놀라지 않을 것입니다.

대화 상자는 Vista에서 변경되었습니다. .NET 3.0 및 3.5의 WPF는 여전히 레거시 대화 상자를 사용했지만 .NET 4.0에서 수정되었습니다. 이전 대화 상자를보고 있기 때문에이 스레드를 시작했다고 추측 할 수 있습니다. 이는 3.5를 대상으로하는 프로그램을 실제로 실행하고 있음을 의미합니다. 예, Winforms 래퍼 업그레이드를 받았으며 Vista 버전을 보여줍니다. System.Windows.Forms.OpenFileDialog 클래스의 경우 System.Windows.Forms에 대한 참조를 추가해야합니다.


MVVM + WinForms 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>

블로그 게시물 : http://kostylizm.blogspot.ru/2014/03/wpf-mvvm-and-winforms-folder-dialog-how.html


Oyun의 대답에 따라 FolderName에 대한 종속성 속성을 사용하는 것이 좋습니다. 예를 들어 원본에서는 작동하지 않는 하위 속성에 바인딩 할 수 있습니다. 또한 조정 된 버전에서는 대화 상자에 초기 폴더가 선택됩니다.

XAML에서의 사용법 :

<Button Content="...">
   <i:Interaction.Behaviors>
      <Behavior:FolderDialogBehavior FolderName="{Binding FolderPathPropertyName, Mode=TwoWay}"/>
    </i:Interaction.Behaviors>
</Button>

암호:

using System.Windows;
using System.Windows.Forms;
using System.Windows.Interactivity;
using Button = System.Windows.Controls.Button;

public class FolderDialogBehavior : Behavior<Button>
{
    #region Attached Behavior wiring
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Click += OnClick;
    }

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

    #region FolderName Dependency Property
    public static readonly DependencyProperty FolderName =
            DependencyProperty.RegisterAttached("FolderName",
            typeof(string), typeof(FolderDialogBehavior));

    public static string GetFolderName(DependencyObject obj)
    {
        return (string)obj.GetValue(FolderName);
    }

    public static void SetFolderName(DependencyObject obj, string value)
    {
        obj.SetValue(FolderName, value);
    }
    #endregion

    private void OnClick(object sender, RoutedEventArgs e)
    {
        var dialog = new FolderBrowserDialog();
        var currentPath = GetValue(FolderName) as string;
        dialog.SelectedPath = currentPath;
        var result = dialog.ShowDialog();
        if (result == DialogResult.OK)
        {
            SetValue(FolderName, dialog.SelectedPath);
        }
    }
}

WPF에 대한 Ookii 대화 상자는VistaFolderBrowserDialogWPF의 폴더 브라우저 대화 상자의 완전한 구현을 제공하는 클래스.

https://github.com/caioproiete/ookii-dialogs-wpf

enter image description here

Windows Forms에서 작동하는 버전도 있습니다 .


그러한 대화 상자 만 FileDialog 입니다. WinForms의 일부이지만 실제로는 WinAPI 표준 OS 파일 대화 상자를 둘러싼 유일한 래퍼입니다. 그리고 나는 그것이 실제로 OS의 일부인 추악하다고 생각하지 않으므로 OS가 실행되는 것처럼 보입니다.

Other way, there is nothing to help you with. You either need to look for 3rd party implementation, either free (and I don't think there are any good) or paid.

참고URL : https://stackoverflow.com/questions/4007882/select-folder-dialog-wpf

반응형