Search code examples
c#wpfcontrolsresourcedictionaryxname

Can I get access from code behind (of a ResourceDictionary) to a named control?


Is it possible to get access from a code behind (of a ResourceDictionary) to a named control?

E.g. for me it is necessary to create lots of folder picking dialogs. A dialog may contain several rows for each folder that has to be chosen. Each row consists of: Label (Name), TextBox (Chosen Path) and a Button (opens FileBrowserDialog).

So now I want to access the TextBox when the FileBrowserDialog is finished. But I can not access the "SelectedFolderTextBox" from CodeBehind.

Is there a better way to achieve what I want to do?

XAML

<ResourceDictionary ...>
    ...

    <StackPanel x:Key="FolderSearchPanel"
                x:Shared="False">
        <Label Content="Foldername"/>
        <TextBox x:Name="SelectedFolderTextBox" 
                 Text="C:\Folder\Path\"/>
        <Button Content="..."
                Click="Button_Click"/>
    </StackPanel>
</ResourceDictionary>

CodeBehind

private void Button_Click(object sender, RoutedEventArgs e)
{
    // Initialize and show
    var dialog = new System.Windows.Forms.FolderBrowserDialog();
    System.Windows.Forms.DialogResult result = dialog.ShowDialog();

    // Process result
    if (result == System.Windows.Forms.DialogResult.OK)
    {
        string selectedPath = dialog.SelectedPath;

        SelectedFolderTextBox.Text = selectedPath;  // THIS DOES NOT WORK
                                                    // since I don't have access to it
                                                    // but describes best, what I want to do
    }
}

Solution

  • when you have a repeated group of controls and a bit of associated functionality it makes sense to create a reusable control:

    Add UserControl via project "Add Item" dialog and use this xaml and code:

    <UserControl x:Class="WpfDemos.FolderPicker"
                 x:Name="folderPicker"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 d:DesignHeight="75" d:DesignWidth="300">
        <StackPanel>
            <Label Content="{Binding Path=Title, ElementName=folderPicker}"/>
            <TextBox x:Name="SelectedFolderTextBox" 
                     Text="{Binding Path=FullPath, ElementName=folderPicker,
                                    UpdateSourceTrigger=PropertyChanged}"/>
            <Button Content="..." Click="PickClick"/>
        </StackPanel>
    </UserControl>
    
    public partial class FolderPicker : UserControl
    {
        public FolderPicker()
        {
            InitializeComponent();
        }
    
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
            "Title", typeof (string), typeof (FolderPicker), new PropertyMetadata("Folder"));
    
        public string Title
        {
            get { return (string) GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }
    
        public static readonly DependencyProperty FullPathProperty = DependencyProperty.Register(
            "FullPath", typeof (string), typeof (FolderPicker), new FrameworkPropertyMetadata(@"C:\", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    
        public string FullPath
        {
            get { return (string) GetValue(FullPathProperty); }
            set { SetValue(FullPathProperty, value); }
        }
    
        private void PickClick(object sender, RoutedEventArgs e)
        {
            using (var dialog = new System.Windows.Forms.FolderBrowserDialog())
            {
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    FullPath = dialog.SelectedPath;
            }
        }
    }
    

    TextBox is accessible from code-behind. Dependency properties Title and FullPath allows to customize control for different usages and create bindings with a view model (something you can't do with controls group declared as resource). Example

    view model:

    public class MyViewModel
    {
        public string Src { get; set; }
        public string Target { get; set; }
    }
    

    view:

    public MyWindow()
    {
        InitializeComponent();
        this.DataContext = new MyViewModel { Src = "C:", Target = "D:" }
    }
    
    <StackPanel>
        <wpfDemos:FolderPicker Title="Source"      FullPath="{Binding Path=Src}"   />
        <wpfDemos:FolderPicker Title="Destination" FullPath="{Binding Path=Target}"/>
    </StackPanel>