Pod System.Windows.Controls
widzę PrintDialog
Jednak nie mogę znaleźć natywnego FileDialog
. Czy muszę utworzyć odniesienie do System.Windows.Forms
lub jest tam inny sposób?Czy WPF ma rodzime okno dialogowe pliku?
Odpowiedz
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.
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;
}
};
};
}
}
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
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;
}
};
};
}
}
Czy mógłbyś przemyśleć, co należy zrobić z manifestem, aby uzyskać nową wersję motywu Windows? –
@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