Могу ли я получить доступ из кода (ResourceDictionary) к именованному элементу управления?

Можно ли получить доступ из кода (ResourceDictionary) к именованному элементу управления?

Например, для меня необходимо создать множество диалогов для выбора папок. Диалог может содержать несколько строк для каждой папки, которая должна быть выбрана. Каждая строка состоит из: Label (Имя), TextBox (Выбранный путь) и Кнопка (открывает FileBrowserDialog).

Итак, теперь я хочу получить доступ к TextBox, когда FileBrowserDialog закончен. Но я не могу получить доступ к "SelectedFolderTextBox" из CodeBehind.

Есть ли лучший способ достичь того, что я хочу сделать?

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
    }
}

2 ответа

Решение

Если у вас есть повторяющаяся группа элементов управления и немного связанных функций, имеет смысл создать элемент управления многократного использования:

Добавьте UserControl через диалоговое окно "Добавить элемент" проекта и используйте этот xaml и код:

<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 доступен из-за кода. Свойства зависимости Title а также FullPath позволяет настраивать элементы управления для различного использования и создавать привязки с моделью представления (то, что вы не можете сделать с группой элементов управления, объявленной как ресурс). пример

посмотреть модель:

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

Посмотреть:

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>

Вы должны быть в состоянии разыграть sender аргумент Button а затем бросить Parent собственность Button к StackPanel и найти элементы управления в Children коллекция StackPanel, Что-то вроде этого:

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;

        Button clickedButton = sender as Button;
        StackPanel sp = clickedButton.Parent as StackPanel;
        if (sp != null)
        {
            TextBox SelectedFolderTextBox = sp.Children.OfType<TextBox>().FirstOrDefault(x => x.Name == "SelectedFolderTextBox");
            if (SelectedFolderTextBox != null)
                SelectedFolderTextBox.Text = selectedPath;
        }
    }
}
Другие вопросы по тегам