WPF - Retrieve Child DataTemplate Control From Cus

2019-06-07 06:43发布

问题:

In my application, I have a ListBox with a custom DataTemplate. The XAML is as follows:

<ListBox Name="lstTasks">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" VerticalAlignment="Top">
                <CheckBox Name="chkIsChecked" VerticalAlignment="Top" IsChecked="{Binding Path=IsChecked, Mode=TwoWay}"/>
                <RichTextBox Name="rtbTask" HorizontalAlignment="Left" Height="50" VerticalAlignment="Top" Width="450"
                             BorderBrush="{DynamicResource {x:Static SystemColors.ActiveCaptionTextBrushKey}}" Margin="0,0,0,10"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

I use a custom class called CheckBoxItem as my ListBoxItems. If I wanted to add an item to the ListBox, I'd use the following code as an example:

lstTasks.Items.Add(new CheckBoxItem("", false));

If I wanted to retrieve this item from the ListBox, I'd use the following code:

CheckBoxItem CheckBoxItem = (CheckBoxItem)lstTasks.Items[0];

I have no problem with data binding; it works fine. My issue is with retrieving one of the children in the DataTemplate. In the application, users can edit the contents of the RichTextBox within each CheckBoxItem. I want to be able to save the contents of the RichTextBox to an external file. I've already created methods for getting the RTF text and storing it in a String, but I can't seem to get access to the RichTextBox for any given CheckBoxItem.

I've searched online for quite some time but couldn't seem to find anything that helped. Using the VisualTree does not work because CheckBoxItems are not DependencyObjects and cannot be casted to them. As a result, I'm pretty stuck and would very much appreciate any insight on this issue.

One idea I had was to keep track of all the RichTextBoxes in a collection of some sort. I'd handle their Loaded event and then add them to the collection there, but I'd really prefer not to do this, as it seems like it's an unnecessary use of memory.

Thanks in advance for any help!

回答1:

There is no easy way for that. But knowing that you already came accross VisualTree stuff before maybe you have seen most of the codes in following example. And possibly what you missed is the first line, that shows you how to get ListBoxItem from CheckBoxItem. Having ListBoxItem on hand, means you have a DependencyObject to start using that VisualTree stuff technique to find RichTextBox :

var myListBoxItem = (lstTasks.ItemContainerGenerator.ContainerFromItem(lstTasks.Items[0]));

// Getting the ContentPresenter of myListBoxItem
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(myListBoxItem);

// Finding richtextbox from the DataTemplate that is set on that ContentPresenter
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
RichTextBox myTextBlock = (RichTextBox)myDataTemplate.FindName("rtbTask", myContentPresenter);

And implementation of FindVisualChild as shown in MSDN :

private childItem FindVisualChild<childItem>(DependencyObject obj) where childItem : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(obj, i);
        if (child != null && child is childItem)
            return (childItem)child;
        else
        {
            childItem childOfChild = FindVisualChild<childItem>(child);
            if (childOfChild != null)
                return childOfChild;
        }
    }
    return null;
}