views:

492

answers:

1

Hi, I'm using a datatemplate for a type that has got 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 creating the textbox and the button next to it which will show the openfiledialog . and dont forget that this is a datatemplate so as I know I dont have any codebehind for the datatemplate . I was thinking about a usercontrol but I dont if that's the best way or not ?

thank you all

+1  A: 

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(...)
Ray Burns