I'm using a DataTemplate for a type that has a property which is the file address. I need to create a TextBox
with a Button
which will open an OpenFileDialog
and then insert the selected file address into the TextBox
.
I wanna know what's the best way for c开发者_运维问答reating the TextBox
and the Button
next to it which will show the OpenFileDialog
. And don't forget that this is a DataTemplate
so as I know I don't have any codebehind for the DataTemplate
.
I was thinking about a UserControl
but I don't if that's the best way or not?
Thank you all
A UserControl is a perfectly acceptable solution, but I would be more likely to use either 1) a custom control, or 2) a RoutedUICommand.
Building a Custom Control
Create a simple control derived from TextBox:
public class TextBoxWithFileDialog : TextBox
{
static TextBoxWithFileDialog()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxWithFileDialog), new FrameworkPropertyMetadata(typeof(TextBoxWithFileDialog)));
CommandManager.RegisterClassCommandBinding(typeof(TextBoxWithFileDialog), new CommandBinding(
ApplicationCommands.Open,
(obj, e) => { e.Handled = true; ((TextBoxWithFileDialog)obj).ShowFileOpenDialog(); },
(obj, e) => { e.CanExecute = true; }));
}
void ShowFileOpenDialog()
{
var dialog = new Microsoft.Win32.OpenFileDialog
{
DefaultExt = ".txt"
};
if(dialog.ShowDialog()==true)
Text = dialog.FileName;
}
}
then in themes/Generic.xaml or a resource dictionary included from it add a style containing an appropriate ControlTemplate:
<Style TargetType="{x:Type TextBoxWithFileDialog}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBoxWithFileDialog}">
<DockPanel>
<Button Content="..." Command="Open" DockPanel.Dock="Right" />
<!-- copy original TextBox control template contents here -->
</DockPanel>
... close rest of tags ...
You can copy TextBox's existing ControlTemplate using Expression Blend or Reflector/BamlViewer).
For my own projects I would prefer to add a solution like this to my control library so I can use it anywhere I want. However this may be overkill if you're only going to use it once. In that case I would just:
Using a RoutedUICommand
public partial class MyWindow : Window
{
public Window()
{
InitializeComponent();
...
CommandManager.RegisterClassCommandBinding(typeof(TextBoxWithFileDialog), new CommandBinding(
ApplicationCommands.Open,
(obj, e) =>
{
e.Handled = true;
((MyWindow)obj).ShowFileOpenDialog((TextBox)e.Parameter);
},
(obj, e) => { e.CanExecute = true; }));
}
void ShowFileOpenDialog(TextBox textBox)
{
var dialog = new Microsoft.Win32.OpenFileDialog
{
DefaultExt = ".txt"
};
if(dialog.ShowDialog()==true)
textBox.Text = dialog.FileName;
}
}
This does not require a style or an additional class. Just name your textbox, and have the button refer to the textbox as its command parameter:
<TextBox x:Name="Whatever" ... />
<Button Content="..." Command="Open" CommandParameter="{Binding ElementName=Whatever}" />
That's all there is to it. Unfortunately it only works in one window, and putting it somewhere else would require cut-and-paste. That's why I prefer a custom control.
Note
If you're already using ApplicationCommands.Open elsewhere in your application, you might select a different command, or create your own:
public static readonly RoutedUICommand MyCommand = new RoutedUICommand(...)
精彩评论