Je développe une application WPF4 et, dans mon application, je dois laisser l'utilisateur sélectionner un dossier dans lequel l'application stockera quelque chose (fichiers, rapports générés, etc.).
Mes exigences:
Possibilité de voir l'arborescence de dossiers standard
Possibilité de sélectionner un dossier
Aspect WPF, cette boîte de dialogue doit ressembler à une application moderne conçue pour Windows Vista/7 et non pour Windows 2000 ou même pour Win9x.
Si j'ai bien compris, jusqu'en 2010 (.Net 4.0), il n'y aura pas de boîte de dialogue de dossier standard, mais peut-être y aura-t-il des changements dans la version 4.0?
Ou tout ce qui reste à faire est d'utiliser la boîte de dialogue WinForms à l'ancienne? Si c'est le seul moyen de faire ce dont j'ai besoin, comment puis-je le rapprocher du style Vista/7 et non de Win9x?
Sur certains forums, j'ai vu la mise en place de tels dialogues mais avec d'anciennes icônes laides de Windows 95. Cela n'a vraiment pas l'air sympa.
Il y a longtemps que j'en ai parlé sur mon blog, la prise en charge par WPF des dialogues de fichiers courants est vraiment mauvaise (ou du moins c'était en version 3.5, je n'ai pas vérifié la version 4) - mais il est facile de contourner ce problème.
Vous devez ajouter le manifeste correct à votre application - cela vous donnera un style moderne de boîtes de message et de navigateur de dossiers (WinForms FolderBrowserDialog), mais pas les boîtes de dialogue d'ouverture/enregistrement de fichier WPF. à propos de l'explication et que vous voulez seulement la solution aller directement à la 3ème):
Heureusement, les boîtes de dialogue d'ouverture/enregistrement sont très minces pour l'API Win32. Il est facile d'appeler avec les bons indicateurs pour obtenir le style Vista/7 (après avoir défini le manifeste).
Cookbook Windows Presentation Foundation 4.5 de Pavel Yosifovich à la page 155, à la section "Utilisation des boîtes de dialogue communes":
"Qu'en est-il de la sélection de dossiers (au lieu de fichiers)? WPF OpenFileDialog ne prend pas cela en charge. Une solution consiste à utiliser la classe FolderBrowseDialog de Windows Forms. Une autre bonne solution consiste à utiliser le. décrit sous peu. "
J'ai téléchargé l'API Code Pack de Code Pack de l'API Windows® pour Microsoft® .NET Framework Windows API Code Pack: où est-il? , puis ajouté des références à Microsoft.WindowsAPICodePack.dll et Microsoft.WindowsAPICodePack.Shell.dll à mon projet WPF 4.5.
Exemple:
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
}
Ajouter Le code API Windows Pack-Shell à votre projet
using Microsoft.WindowsAPICodePack.Dialogs;
...
var dialog = new CommonOpenFileDialog();
dialog.IsFolderPicker = true;
CommonFileDialogResult result = dialog.ShowDialog();
Comportement de 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);
}
}
}
Usage
<Button Grid.Column="3" Content="...">
<Interactivity:Interaction.Behaviors>
<Behavior:FolderDialogBehavior SetterName="SomeFolderPathPropertyName"/>
</Interactivity:Interaction.Behaviors>
</Button>
Blogpost: http://kostylizm.blogspot.ru/2014/03/wpf-mvvm-and-winforms-folder-dialog-how.html
Microsoft.Win32.OpenFileDialog est la boîte de dialogue standard utilisée par toutes les applications Windows. Votre utilisateur ne sera pas surpris par son apparence lorsque vous utilisez WPF dans .NET 4.0
Le dialogue a été modifié dans Vista. WPF dans .NET 3.0 et 3.5 utilisait toujours la boîte de dialogue héritée, mais celle-ci était corrigée dans .NET 4.0. Je peux seulement deviner que vous avez commencé ce fil parce que vous voyez ce vieux dialogue. Ce qui signifie probablement que vous exécutez un programme qui vise 3,5. Oui, le wrapper Winforms did récupère la mise à niveau et affiche la version de Vista. Classe System.Windows.Forms.OpenFileDialog, vous devez ajouter une référence à System.Windows.Forms.
Si vous ne souhaitez ni utiliser les Windows Forms ni modifier les fichiers de manifeste, j'ai proposé un piratage très simple à l'aide de la boîte de dialogue Enregistrer sous de WPF pour sélectionner un répertoire.
Aucune directive d'utilisation nécessaire, vous pouvez simplement copier-coller le code ci-dessous!
Il devrait toujours être très convivial et la plupart des gens ne le remarqueront jamais.
L'idée vient du fait que nous pouvons changer le titre de cette boîte de dialogue, cacher des fichiers et contourner le nom de fichier résultant assez facilement.
C'est un gros bidouillage, c'est sûr, mais peut-être que ça fera l'affaire pour votre usage ...
Dans cet exemple, j'ai un objet textbox pour contenir le chemin résultant, mais vous pouvez supprimer les lignes associées et utiliser une valeur de retour si vous le souhaitez ...
// 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;
}
Les seuls problèmes avec ce hack sont:
La plupart des gens ne le remarqueront pas, même si je préférerais définitivement utiliser un moyen officiel de WPF si Microsoft leur en retirait la tête, mais tant qu'ils ne le font pas, c'est ma solution temporaire.
D'après la réponse de Oyun, il est préférable d'utiliser une propriété de dépendance pour le nom de dossier. Cela permet (par exemple) la liaison à des sous-propriétés, ce qui ne fonctionne pas dans l'original. En outre, dans ma version ajustée, la boîte de dialogue montre sélectionne le dossier initial.
Utilisation en XAML:
<Button Content="...">
<i:Interaction.Behaviors>
<Behavior:FolderDialogBehavior FolderName="{Binding FolderPathPropertyName, Mode=TwoWay}"/>
</i:Interaction.Behaviors>
</Button>
Code:
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);
}
}
}
Le Ookii Dialogs for WPF a une classe VistaFolderBrowserDialog
qui fournit une implémentation complète d'un dialogue de navigateur de dossiers pour WPF.
Il existe également une version qui fonctionne avec Windows Forms .
Seul ce dialogue est FileDialog . Cela fait partie de WinForms, mais c’est en fait le seul encapsuleur qui entoure la boîte de dialogue de fichier du système d’exploitation standard WinAPI. Et je ne pense pas que c'est moche, c'est en fait une partie de l'OS, donc on dirait que l'OS sur lequel il est exécuté.
Autrement, il n'y a rien pour vous aider. Vous devez soit rechercher une implémentation tierce, soit gratuite (et je ne pense pas qu'il y en ait de bon) ou payante.