views:

4455

answers:

4

I want the user to select a directory where a file that I will then generate will be saved. I know that in WPF I should use the OpenFileDialog from Win32, but unfortunately the dialog requires file(s) to be selected - it stays open if I simply click OK without choosing one. I could "hack up" the functionality by letting the user pick a file and then strip the path to figure out which directory it belongs to but that's unintuitive at best. Has anyone seen this done before?

+2  A: 

Check out this question.

Dave Swersky
+12  A: 

You should use the FolderBrowserDialog class for this. Don't mind that it's in the System.Windows.Forms namespace.

var dialog = new System.Windows.Forms.FolderBrowserDialog();
System.Windows.Forms.DialogResult result = dialog.ShowDialog();

If you want the window to be modal over some WPF window, see the question How to use a FolderBrowserDialog from a WPF application.

Heinzi
Thank you, I guess I asked 15 minutes too early.
Alexandra
+2  A: 

Kevin Moore's Bag-o-Tricks include a WPF sample FolderPicker that lets you select a folder.

Manga Lee
+3  A: 

I created a UserControl which is used like this:

  <UtilitiesWPF:FolderEntry Text="{Binding Path=LogFolder}" Description="Folder for log files"/>

The xaml source looks like this:

<UserControl x:Class="Utilities.WPF.FolderEntry"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
    <DockPanel>
        <Button Margin="0" Padding="0" DockPanel.Dock="Right" Width="Auto" Click="BrowseFolder">...</Button>
        <TextBox Height="Auto" HorizontalAlignment="Stretch" DockPanel.Dock="Right" 
           Text="{Binding Text, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
    </DockPanel>
</UserControl>

and the code-behind

public partial class FolderEntry {
    public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(FolderEntry), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    public static DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(string), typeof(FolderEntry), new PropertyMetadata(null));

    public string Text { get { return GetValue(TextProperty) as string; } set { SetValue(TextProperty, value); }}

    public string Description { get { return GetValue(DescriptionProperty) as string; } set { SetValue(DescriptionProperty, value); } }

    public FolderEntry() { InitializeComponent(); }

    private void BrowseFolder(object sender, RoutedEventArgs e) {
        using (FolderBrowserDialog dlg = new FolderBrowserDialog()) {
            dlg.Description = Description;
            dlg.SelectedPath = Text;
            dlg.ShowNewFolderButton = true;
            DialogResult result = dlg.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK) {
                Text = dlg.SelectedPath;
                BindingExpression be = GetBindingExpression(TextProperty);
                if (be != null)
                    be.UpdateSource();
            }
        }
    }
 }
adrianm
+1, nice example on how to write a UserControl. One question: Why do you need `be.UpdateSource`? Shouldn't change notifications be automatic in dependency properties?
Heinzi
Textbox bindings are only updated on the lostfocus event.
adrianm
You could specify in the binding when to fire the updates. By default it's on the LostFocus but you can tell it to fire updates on PropertyChanged as well.
Alexandra
The binding will then also be updated for every keystroke. If the user does some kind of validation on update (e.g. Directory.Exist) it might cause problems.
adrianm