73

WPF4アプリケーションを開発し、アプリで、アプリケーションが何か(ファイル、生成されたレポートなど)を格納するフォルダーをユーザーが選択できるようにする必要があります。

私の要件:

  • 標準のフォルダツリーを表示する機能

  • フォルダを選択する機能

  • WPFのルックアンドフィール。このダイアログは、Windows 2000やWin9xではなく、Windows Vista/7用に設計された最新のアプリケーションの一部のように見える必要があります。

私が理解しているように、2010(.Net 4.0)までは、標準のフォルダーダイアログはありませんが、バージョン4.0にはいくつかの変更があるのでしょうか。

または、残りのすべてのことは、古い学校のWinFormsダイアログを使用することですか?それが必要なことを行う唯一の方法である場合、Win9xではなくVista / 7スタイルに近づけるにはどうすればよいですか?

いくつかのフォーラムで、私はそのようなダイアログの実装を見ましたが、Windows95のような古い醜いアイコンがあります。それは本当に見栄えがよくありません。

4

12 に答える 12

112

「一般的なダイアログボックスの使用」のセクションの155ページにあるPavelYosifovichによるWindowsPresentationFoundation4.5クックブックは次のように述べています

「(ファイルの代わりに)フォルダーの選択はどうですか?WPF OpenFileDialogはそれをサポートしていません。1つの解決策はWindowsフォームのFolderBrowseDialogクラスを使用することです。もう1つの良い解決策は、簡単に説明するWindowsAPIコードパックを使用することです。」

Microsoft®.NETFramework用のWindows®API コードパックからAPIコードパックをダウンロードしましたWindowsAPIコードパック:どこにありますか?次に、Microsoft.WindowsAPICodePack.dllおよびMicrosoft.WindowsAPICodePack.Shell.dllへの参照をWPF4.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
}
于 2013-07-18T01:19:48.823 に答える
21

私はずっと前にブログでそれについて書きました、一般的なファイルダイアログのWPFのサポートは本当に悪いです(または少なくともバージョン4でチェックしなかった3.5でした)-しかしそれを回避するのは簡単です。

アプリケーションに正しいマニフェストを追加する必要があります。これにより、最新のスタイルのメッセージボックスとフォルダーブラウザー(WinForms FolderBrowserDialog)が提供されますが、WPFファイルの開く/保存ダイアログは提供されません。これはこれらの3つの投稿で説明されています(気にしない場合)説明について、解決策を直接3番目に進めたいだけです):

幸い、開く/保存ダイアログはWin32 APIの非常に薄いラッパーであり、適切なフラグを使用して簡単に呼び出して、Vista / 7スタイルを取得できます(マニフェストを設定した後)。

于 2010-10-24T15:18:01.703 に答える
18

WindowsAPIコードパックシェルをプロジェクトに追加します

using Microsoft.WindowsAPICodePack.Dialogs;

...

var dialog = new CommonOpenFileDialog();
dialog.IsFolderPicker = true;
CommonFileDialogResult result = dialog.ShowDialog();
于 2016-07-23T13:53:33.113 に答える
11

Windowsフォームを使用したり、マニフェストファイルを編集したりしたくない場合は、実際にディレクトリを選択するためにWPFの[名前を付けて保存]ダイアログを使用する非常に簡単なハックを思いつきました。

ディレクティブを使用する必要はありません。以下のコードをコピーして貼り付けるだけです。

それでも非常にユーザーフレンドリーであり、ほとんどの人は気付かないはずです。

このアイデアは、そのダイアログのタイトルを変更したり、ファイルを非表示にしたり、結果のファイル名を非常に簡単に回避したりできるという事実に基づいています。

それは確かに大きなハックですが、多分それはあなたの使用法のためにうまく仕事をするでしょう...

この例では、結果のパスを含むテキストボックスオブジェクトがありますが、必要に応じて、関連する行を削除して戻り値を使用できます...

// 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の方法を使用することを好みますが、彼らがそうするまで、それは私の一時的な修正です。

于 2018-05-09T20:54:35.473 に答える
6

fromのFolderBrowserDialogクラスSystem.Windows.Formsは、ユーザーがフォルダーを選択できるダイアログを表示するための推奨される方法です。

最近まで、このダイアログの外観と動作は他のファイルシステムダイアログと一致していませんでした。これが、人々がこのダイアログを使用することを躊躇した理由の1つです。

幸いなことに、これはFolderBrowserDialog NET Core 3.0で「最新化」されたため、そのバージョン以降を対象とするWindowsフォームまたはWPFアプリを作成するユーザーにとって実行可能なオプションになりました。

.NET Core 3.0では、Windowsフォームユーザー[原文のまま] WindowsVistaで導入された新しいCOMベースのコントロール: NETCore3.0のFolderBrowserDialog

NET Core WPFアプリで参照System.Windows.Formsするには、プロジェクトファイルを編集し、次の行を追加する必要があります。

<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プロパティも無視されているようで、ボタンは常に表示されます。

于 2020-12-08T14:02:17.697 に答える
5

動作としての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

于 2014-04-02T16:45:52.690 に答える
4

Microsoft.Win32.OpenFileDialogは、Windows上のすべてのアプリケーションが使用する標準のダイアログです。.NET 4.0でWPFを使用する場合、ユーザーはその外観に驚かないでしょう。

ダイアログはVistaで変更されました。.NET 3.0および3.5のWPFは引き続きレガシーダイアログを使用していましたが、それは.NET4.0で修正されました。古いダイアログが表示されているので、このスレッドを開始したと推測できます。これはおそらく、3.5を対象とするプログラムを実際に実行していることを意味します。はい、Winformsラッパーアップグレードを取得し、Vistaのバージョンを表示します。System.Windows.Forms.OpenFileDialogクラスでは、System.Windows.Formsへの参照を追加する必要があります。

于 2010-10-24T11:43:58.190 に答える
3

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);
        }
    }
}
于 2015-03-09T15:13:41.997 に答える
3

WPFのOokiiDialogsには、WPFVistaFolderBrowserDialogのフォルダーブラウザーダイアログの完全な実装を提供するクラスがあります。

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

大木井フォルダブラウザダイアログ

Windowsフォームで動作するバージョンもあります。

于 2018-10-04T03:20:43.493 に答える
1

そのようなダイアログだけがFileDialogです。WinFormsの一部ですが、実際にはWinAPI標準OSファイルダイアログのラッパーのみです。そして、私はそれが醜いとは思わない、それは実際にはOSの一部なので、それが実行されているOSのように見える。

他の方法では、あなたを助けるものは何もありません。サードパーティの実装を探す必要があります。無料(そして私は良いものはないと思います)または有料のどちらかです。

于 2010-10-24T11:44:28.113 に答える
0

一言で言えば、Windows76.1.7600ではWindowsAPICodePack開くことができません。CommonOpenFileDialog

于 2020-10-28T07:00:42.897 に答える
0

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;
}
于 2021-04-01T01:50:21.593 に答える