programing

폴더 선택 대화상자 WPF

oldcodes 2023. 6. 3. 08:42
반응형

폴더 선택 대화상자 WPF

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

내 요구 사항:

  • 표준 폴더 트리를 보는 기능

  • 폴더 선택 기능

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

2010년까지(.Net 4.0)에는 표준 폴더 대화 상자가 없지만 버전 4.0에는 약간의 변경 사항이 있을 수 있습니다.

아니면 제가 할 수 있는 유일한 방법은 구식 학교를 이용하는 것입니다.WinForms대화? 유일한 7 스타일에 할 수 ?필요한 작업을 수행할 수 있는 유일한 방법이라면 어떻게 하면 Win9x가 아닌 Vista/7 스타일에 근접할 수 있습니까?

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

"(파일 대신) 폴더를 선택하는 것은 어떻습니까?WPF OpenFileDialog는 이를 지원하지 않습니다.한 가지 해결 방법은 Windows Forms의 FolderBrowseDialog 클래스를 사용하는 것입니다.또 다른 좋은 솔루션은 간단히 설명된 Windows API Code Pack을 사용하는 것입니다."

Microsoft® .NET Framework용 Windows API Code Pack에서 API Code Pack을 다운로드했습니다. 어디에 있습니까? 그런 다음 Microsoft에 대한 참조를 추가했습니다.윈도우즈 API CodePack.dll 및 마이크로소프트.Windows API 코드 팩.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
}

오래 전에 블로그에 이에 대해 썼습니다. 일반적인 파일 대화 상자에 대한 WPF의 지원은 정말 좋지 않습니다(또는 적어도 버전 4에서는 확인하지 않았습니다). 하지만 해결하기는 쉽습니다.

를 추가해야 브라우저를 할 수 . 그러면 현대식 메시지 상자와 폴더 브라우저가 제공됩니다.WinForms,FolderBrowserDialogWPF 파일 열기/저장 대화 상자가 아닌 다음 세 개의 게시물에 설명되어 있습니다(설명에 신경 쓰지 않고 솔루션을 3번째 게시물로 직접 이동하려면).

다행히도 열기/저장 대화상자는 Win32 API를 중심으로 매우 얇은 래퍼로 되어 있어 Vista/7 스타일(매니페스트를 설정한 후)을 얻기 위해 적합한 플래그를 사용하여 쉽게 호출할 수 있습니다.

프로젝트에 Windows API Code Pack-Shell 추가

using Microsoft.WindowsAPICodePack.Dialogs;

...

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

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

지침을 사용할 필요 없이 아래 코드를 복사하여 붙여넣으면 됩니다!

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

이 아이디어는 대화 상자의 제목을 변경하고, 파일을 숨기고, 결과 파일 이름을 쉽게 해결할 수 있기 때문입니다.

확실히 대단한 해킹이지만, 아마도 당신의 용도에 맞게 잘 작동할 것입니다.

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

// 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;
}

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

  • Acknowledge 버튼은 여전히 "Select directory"와 같은 것 대신 "Save"라고 표시되지만, mines와 같은 경우에는 디렉토리 선택을 "Save"하여 계속 작동합니다.
  • 입력 필드에는 여전히 "Directory name" 대신 "File name"이라고 표시되지만, 디렉토리는 파일의 일종이라고 할 수 있습니다.
  • 여전히 "Save as type" 드롭다운이 있지만 해당 값이 "Directory(*.this.directory)"로 표시되고 사용자가 다른 항목에 대해 변경할 수 없기 때문에...

대부분의 사람들은 이것들을 눈치채지 못할 것입니다. 하지만 저는 마이크로소프트가 그들의 머리를 빼낼 수 있다면 공식적인 WPF 방식을 사용하는 것을 분명히 선호하지만, 그것이 제 임시방편입니다.

FolderBrowserDialogSystem.Windows.Forms사용자가 폴더를 선택할 수 있는 대화 상자를 표시하는 데 권장되는 방법입니다.

최근까지 이 대화 상자의 모양과 동작이 다른 파일 시스템 대화 상자와 일치하지 않았기 때문에 사람들이 사용을 꺼리는 이유 중 하나입니다.

좋은 소식은FolderBrowserDialog 는 NET Core 3.0에서 "현대화"되었으므로 이제 해당 버전 이상을 대상으로 하는 Windows Forms 또는 WPF 앱을 작성하는 사용자에게 실행 가능한 옵션입니다.

.NET Core 3.0에서 Windows Forms 사용자 [sic]는 Windows Vista에 도입된 새로운 COM 기반 컨트롤입니다.NET Core 3.0의 FolderBrowserDialog

NET Core WPF 앱에서 참조하려면 프로젝트 파일을 편집하고 다음 행을 추가해야 합니다.

<UseWindowsForms>true</UseWindowsForms>

이것은 기존의 바로 뒤에 배치될 수 있습니다.<UseWPF>원소의

그런 다음 대화 상자를 사용하는 경우입니다.

using System;
using System.Windows.Forms;

...

using var dialog = new FolderBrowserDialog
{
    Description = "Time to select a folder",
    UseDescriptionForTitle = true,
    SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
                    + Path.DirectorySeparatorChar,
    ShowNewFolderButton = true
};

if (dialog.ShowDialog() == DialogResult.OK)
{
    ...
}

FolderBrowserDialog을 가지고 있습니다.RootFolder"찾아보기가 시작되는 루트 폴더를 설정"하는 속성이지만 제가 설정한 속성은 아무런 차이가 없었습니다.SelectedPath이러한 용도로 사용하기에 더 좋은 속성인 것 같았지만, 후행 백슬래시가 필요합니다.

그리고 또.ShowNewFolderButton속성도 무시되는 것 같습니다. 버튼은 항상 표시됩니다.

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

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

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

Ookii Dialogs for WPF에는 다음과 같은 기능이 있습니다.VistaFolderBrowserDialogWPF에 대한 폴더 브라우저 대화 상자의 전체 구현을 제공하는 클래스입니다.

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

Ookii 폴더 브라우저 대화 상자

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

이러한 대화 상자만 FileDialog입니다.WinForms의 일부이지만 실제로는 WinAPI 표준 OS 파일 대화 상자 주변의 래퍼일 뿐입니다.그리고 저는 그것이 못생겼다고 생각하지 않습니다. 그것은 실제로 OS의 일부이기 때문에 그것이 실행되는 OS처럼 보입니다.

다른 방법으로는, 당신을 도울 수 있는 것이 없습니다.무료(그리고 좋은 점이 없다고 생각) 또는 유료로 타사 구현을 찾아야 합니다.

, 한가만말씀면리드지,면▁just리드말씀만.WindowsAPICodePack 수 열수음CommonOpenFileDialog윈도우즈 76.1.7600에서.

C의 원래 질문에 대한 코멘트.Augusto Proiete는 Ookii 대화상자(https://github.com/ookii-dialogs/ookii-dialogs-wpf) 를 제안했습니다.그것이 제 상황에서 사용하게 된 것입니다.제 앱에서 사용한 방법은 다음과 같습니다.

var dialog = new VistaFolderBrowserDialog()
{
    Description = "Select Folder",
    RootFolder = Environment.SpecialFolder.Desktop,
    ShowNewFolderButton = true,
    UseDescriptionForTitle = true
};

var result = dialog.ShowDialog();

if (result.HasValue && result.Value)
{
    _mySelectedFolder = dialog.SelectedPath;
}

언급URL : https://stackoverflow.com/questions/4007882/select-folder-dialog-wpf

반응형