web-dev-qa-db-fra.com

WPF a-t-il une boîte de dialogue de fichier natif?

Sous System.Windows.Controls, Je peux voir un PrintDialog Cependant, je n'arrive pas à trouver un FileDialog natif. Dois-je créer une référence à System.Windows.Forms ou existe-t-il un autre moyen?

46
Sebastian Gray

WPF possède des boîtes de dialogue de fichiers intégrées (mais pas natives ). Plus précisément, ils se trouvent dans l'espace de noms Microsoft.Win32 Légèrement inattendu (bien qu'il fasse toujours partie de WPF). Voir les classes OpenFileDialog et SaveFileDialog en particulier.

Notez cependant que ces classes ne sont que des wrappers autour de la fonctionnalité Win32, comme le suggère l'espace de noms parent. Cela signifie cependant que vous n'avez pas besoin de faire d'interopérabilité WinForms ou Win32, ce qui le rend un peu plus agréable à utiliser. Malheureusement, les boîtes de dialogue sont par défaut de style dans le "vieux" thème Windows, et vous avez besoin d'un petit hack dans app.manifest Pour le forcer à utiliser le nouveau.

60
Noldorin

Vous pouvez créer une simple propriété attachée pour ajouter cette fonctionnalité à un TextBox. La boîte de dialogue d'ouverture de fichier peut être utilisée comme ceci:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <TextBox i:OpenFileDialogEx.Filter="Excel documents (.xls)|*.xls" Grid.Column="0" />
    <Button Grid.Column="1">Browse</Button>
</Grid>

Le code pour OpenFileDialogEx:

public class OpenFileDialogEx
{
    public static readonly DependencyProperty FilterProperty =
      DependencyProperty.RegisterAttached("Filter",
        typeof (string),
        typeof (OpenFileDialogEx),
        new PropertyMetadata("All documents (.*)|*.*", (d, e) => AttachFileDialog((TextBox) d, e)));

    public static string GetFilter(UIElement element)
    {
      return (string)element.GetValue(FilterProperty);
    }

    public static void SetFilter(UIElement element, string value)
    {
      element.SetValue(FilterProperty, value);
    }

    private static void AttachFileDialog(TextBox textBox, DependencyPropertyChangedEventArgs args)
    {                  
      var parent = (Panel) textBox.Parent;

      parent.Loaded += delegate {

        var button = (Button) parent.Children.Cast<object>().FirstOrDefault(x => x is Button);

        var filter = (string) args.NewValue;

        button.Click += (s, e) => {
          var dlg = new OpenFileDialog();
          dlg.Filter = filter;

          var result = dlg.ShowDialog();

          if (result == true)
          {
            textBox.Text = dlg.FileName;
          }

        };
      };
    }
}
15
Gregor Slavec

J'ai utilisé la solution présentée par Gregor S. et cela fonctionne bien, même si j'ai dû la convertir en une solution VB.NET, voici ma conversion si elle aide quelqu'un ...

Imports System
Imports Microsoft.Win32

Public Class OpenFileDialogEx
    Public Shared ReadOnly FilterProperty As DependencyProperty = DependencyProperty.RegisterAttached("Filter", GetType(String), GetType(OpenFileDialogEx), New PropertyMetadata("All documents (.*)|*.*", Sub(d, e) AttachFileDialog(DirectCast(d, TextBox), e)))
    Public Shared Function GetFilter(element As UIElement) As String
        Return DirectCast(element.GetValue(FilterProperty), String)
    End Function

    Public Shared Sub SetFilter(element As UIElement, value As String)
        element.SetValue(FilterProperty, value)
    End Sub


    Private Shared Sub AttachFileDialog(textBox As TextBox, args As DependencyPropertyChangedEventArgs)
        Dim parent = DirectCast(textBox.Parent, Panel)
        AddHandler parent.Loaded, Sub()

          Dim button = DirectCast(parent.Children.Cast(Of Object)().FirstOrDefault(Function(x) TypeOf x Is Button), Button)
          Dim filter = DirectCast(args.NewValue, String)
            AddHandler button.Click, Sub(s, e)
               Dim dlg = New OpenFileDialog()
               dlg.Filter = filter
               Dim result = dlg.ShowDialog()
               If result = True Then
                   textBox.Text = dlg.FileName
               End If
            End Sub
        End Sub
    End Sub
End Class
3
Jbtatro

Merci à Gregor S pour une solution soignée.

Dans Visual Studio 2010, il semble cependant que le concepteur plante - j'ai donc modifié le code de la classe OpenFileDialogEx. Le code XAML reste le même:

public class OpenFileDialogEx
{
    public static readonly DependencyProperty FilterProperty =
        DependencyProperty.RegisterAttached(
            "Filter",
            typeof(string),
            typeof(OpenFileDialogEx),
            new PropertyMetadata("All documents (.*)|*.*", (d, e) => AttachFileDialog((TextBox)d, e))
        );


    public static string GetFilter(UIElement element)
    {
        return (string)element.GetValue(FilterProperty);
    }

    public static void SetFilter(UIElement element, string value)
    {
        element.SetValue(FilterProperty, value);
    }

    private static void AttachFileDialog(TextBox textBox, DependencyPropertyChangedEventArgs args)
    {
        var textBoxParent = textBox.Parent as Panel;
        if (textBoxParent == null)
        {
            Debug.Print("Failed to attach File Dialog Launching Button Click Handler to Textbox parent panel!");
            return;
        }


        textBoxParent.Loaded += delegate
        {
            var button = textBoxParent.Children.Cast<object>().FirstOrDefault(x => x is Button) as Button;
            if (button == null)
                return;

            var filter = (string)args.NewValue;

            button.Click += (s, e) =>
            {
                var dlg = new OpenFileDialog { Filter = filter };

                var result = dlg.ShowDialog();

                if (result == true)
                {
                    textBox.Text = dlg.FileName;
                }
            };
        };
    }
}
2
Daniel Scott