web-dev-qa-db-ja.com

フォルダーの選択ダイアログWPF

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

私の要件:

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

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

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

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

それとも、やるべきことは、昔ながらのWinFormsダイアログを使用するだけですか?それが必要なことを行う唯一の方法である場合、Win9xではなくVista/7スタイルに近づけるにはどうすればよいですか?

いくつかのフォーラムで、そのようなダイアログの実装を見ましたが、Windows 95のような古いいアイコンを使用しました。本当に見た目が良くありません。

61
Mike B.

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

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

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

21
Nir

Windows Presentation Foundation 4.5 Cookbook Pavel Yosifovichによる155ページの「コモンダイアログボックスの使用」セクションの説明:

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

API Code Packをダウンロードしました Microsoft®.NET Framework用のWindows®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
}
100
T Powers

Windows API Code Pack-Shell をプロジェクトに追加します

using Microsoft.WindowsAPICodePack.Dialogs;

...

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

Windowsフォームを使用したり、マニフェストファイルを編集したくない場合は、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)」と表示され、ユーザーはそれを他の何かに変更することはできません。

ほとんどの人はこれらに気づきませんが、Microsoftがロバから頭を出すなら公式のWPFの方法を使用することを間違いなく望みますが、気が付くまで、それは私の一時的な修正です。

6
Olivier St-L

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

5
Oyun

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

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

5
Hans Passant

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

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

enter image description here

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

2
Caio Proiete

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

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

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

1
Euphoric