简体   繁体   中英

Getting value of TextBlock inside ComboBox DataTemplate

I have the following XAML:

<ComboBox Height="23" HorizontalAlignment="Left" Grid.Row="6" Grid.Column="2"
          Name="cbo_team" VerticalAlignment="Top" Width="148"
          DataContext="{Binding ElementName=cbo_component, Path=SelectedItem}"
          SelectedIndex="0">
    <ComboBox.ItemsSource>
        <Binding XPath="Teams/Team/@id"
                 Converter="{StaticResource xmlConverter}">
            <Binding.ConverterParameter>
                <local:XmlConverterParameter
                    XPathTemplate="/Products/Teams/Team[{0}]"
                    XPathCondition="@id='{0}'" />
            </Binding.ConverterParameter>
        </Binding>
    </ComboBox.ItemsSource>
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding XPath=@name}" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

In C#, I'm trying to get the value of the TextBlock that is in the current selected item in the ComboBox . How do I do that? This question is pretty much the same, but the only answer doesn't help.

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ListBox ContactListBox = sender as ListBox;
    ListBoxItem listBoxItem = ContactListBox .ItemContainerGenerator.ContainerFromItem(ContactListBox.SelectedItem) as ListBoxItem;
    if (listBoxItem == null)
    {
        return;
    }
    TextBlock txtBlock = FindVisualChildByName<TextBlock>(listBoxItem, "ListTextBlock");
   MessageBox.Show(txtBlock.Text);                        
}

private static T FindVisualChildByName<T>(DependencyObject parent, string name) where T : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
    {
        var child = VisualTreeHelper.GetChild(parent, i);
        string controlName = child.GetValue(NameProperty) as string;
        if (controlName == name)
        {
            return child as T;
        }
        T result = FindVisualChildByName<T>(child, name);
        if (result != null)
            return result;
    }
    return null;
}

Others already suggested to use a SelectionChanged event. Didn't test the code below, but you may give it a try.

private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
    TextBlock tvContent = (sender as ComboBox).SelectedItem as TextBlock;

    string content = tvContent.Text;
}

Check this sample out. The textblock (below the combobox) is showing the value of the name attribute of the currently selected xml element in the combobox. A message box will popup with the same result from the lookup in the visual tree. The lookup fails on initial selection changed. Looks like comboboxitems are created after selected item is set.

XAML:

<Window x:Class="CBTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">

    <Window.Resources>
        <XmlDataProvider x:Key="UsersData" XPath="Users">
            <x:XData>
                <Users xmlns="">
                    <User name="Sally" />
                    <User name="Lucy" />
                    <User name="Linus" />
                    <User name="Charlie" />
                </Users>
            </x:XData>
        </XmlDataProvider>
    </Window.Resources>

    <StackPanel>

        <ComboBox 
            Name="_comboBox"
            ItemsSource="{Binding Source={StaticResource UsersData},XPath=*}"
            SelectedIndex="0"
            SelectionChanged="OnComboBoxSelectionChanged">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding XPath=@name}" Name="nameTextBlock" />
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

        <!-- Below shows how to get the value of selected item directly from the data. -->
        <TextBlock 
            DataContext="{Binding Path=SelectedItem, ElementName=_comboBox}"
            Text="{Binding XPath=@name}" />

    </StackPanel>

</Window>

Code behind, showing how to get the text directly by traversing the visual tree:

private void OnComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ComboBox comboBox = sender as ComboBox;
    ComboBoxItem comboBoxItem = comboBox.ItemContainerGenerator.ContainerFromItem(comboBox.SelectedItem) as ComboBoxItem;
    if (comboBoxItem == null)
    {
        return;
    }
    TextBlock textBlock = FindVisualChildByName<TextBlock>(comboBoxItem, "nameTextBlock");
    MessageBox.Show(textBlock.Text);
}

private static T FindVisualChildByName<T>(DependencyObject parent, string name) where T : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
    {
        var child = VisualTreeHelper.GetChild(parent, i);
        string controlName = child.GetValue(NameProperty) as string;
        if (controlName == name)
        {
            return child as T;
        }
        T result = FindVisualChildByName<T>(child, name);
        if (result != null)
            return result;
    }
    return null;
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var comboBox = (ComboBox)sender;
    ComboBoxItem comboAsTextblock = (ComboBoxItem)comboBox.SelectedItem;
    string comboBoxItemText = comboAsTextblock.Content.ToString();
    // comboBoxItemText is what you want :)
}

Sorry a little late to the party :) but the following works as well (ironically was in the same fix as you!!)

TextBlock tb1 = (TextBlock)cbo_team.SelectedItem;
MessageBox.Show(tb1.Text);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM