2009-09-27 11 views

Odpowiedz

60

WPF ma wbudowane okna dialogowe plików (ale nie macierzystych). W szczególności są one w nieco nieoczekiwanej przestrzeni nazw Microsoft.Win32 (choć nadal stanowią część WPF). Zobacz zwłaszcza klasy OpenFileDialog i SaveFileDialog.

Należy jednak pamiętać, że te klasy są tylko programami otaczającymi funkcjonalność Win32, co sugeruje nadrzędny obszar nazw. Oznacza to jednak, że nie trzeba wykonywać żadnych współdziałań WinForm lub Win32, co sprawia, że ​​jest nieco przyjemniejszy w użyciu. Niestety, okna dialogowe są domyślnie ustawione w "starym" motywie Windows i potrzebujesz małego hacka w app.manifest, aby zmusić go do użycia nowego.

+3

Czy mógłbyś przemyśleć, co należy zrobić z manifestem, aby uzyskać nową wersję motywu Windows? –

+2

@Sebastian: Oczywiście - jest to szczegółowe na tym blogu: http://www.nbdtech.com/blog/archive/2008/06/16/The-Application-Manifest-Needed-for-XP-and-Vista-Style -File.aspx. – Noldorin

15

Można utworzyć prostą właściwość dołączoną, aby dodać tę funkcję do ramki TextBox. dialogowe Otwórz plik może być używany jak to:

<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> 

Kod dla 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; 
      } 

     }; 
     }; 
    } 
} 
3

użyłem rozwiązania przedstawionego przez Gregor S. i działa dobrze, chociaż musiałam przekonwertować go do rozwiązania VB.NET, tutaj jest moja konwersja, jeśli pomaga nikomu ...

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 
2

Dzięki Gregor S dla schludnego rozwiązania.

W Visual Studio 2010 wygląda jednak na to, że projektant ulegnie awarii - więc zmodyfikowałem kod w klasie OpenFileDialogEx. Kod XAML pozostaje taki sam:

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