簡體   English   中英

從列表框中獲取Listboxitem

[英]Get Listboxitem from listbox

嗨,這應該很簡單,但是我不知道我做錯了什么。 我一直在互聯網上四處尋找,看到人們在做這項工作,即使遵循MSDN上的教程,對我來說仍然沒有任何效果。

我想遍歷ListBox,並獲取ListBoxItems,以便可以找到已添加到其中的DataTemplate。

這是我的代碼背后。

private void SetListBoxDataTemplate(ListBox MyListBox)
{
  try
  {
    foreach (CustomDataTemplateObject dataobject in MyListBox.Items)
    {
      ListBoxItem lbi = (ListBoxItem)(MyListBox.ItemContainerGenerator.ContainerFromItem(dataobject));
      ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(lbi);
      DataTemplate dt = myContentPresenter.ContentTemplate;
      TextBlock tb = (TextBlock)dt.FindName("ListBoxItemTextBlock1", myContentPresenter);
      ComboBox cb = (ComboBox)dt.FindName("ListBoxItemComboBox1", myContentPresenter);

      tb.Text = dataobject.Text;
      cb.ItemsSource = dataobject.ListColors;
    }
  }
  catch (Exception ex)
  {
    MessageBox.Show(""+ex);
  }
}

XAML看起來像這樣:

 <DataTemplate x:Key="ListBoxItemDataTemplate1">
        <StackPanel Orientation="Horizontal">
            <Border BorderBrush="Black" BorderThickness="1 1 0 1" MinWidth="50">
                <TextBlock Name="ListBoxItemTextBlock1" Background="{Binding ElementName=ListBoxItemComboBox1, Path=SelectedValue}" >
                </TextBlock>
            </Border>
            <ComboBox Name="ListBoxItemComboBox1" />
        </StackPanel>
    </DataTemplate>*

 <StackPanel>
    <ListBox Name="ListBoxTest1" ItemTemplate="{DynamicResource ListBoxItemDataTemplate1}" />
</StackPanel>

我嘗試將itemtemplate設置為static以查看其是否有效,並且在填充列表框后調用了我從后面的代碼調用的方法

我的dataobject不為null,但是,當我在后面的代碼中調用該行時,我的lbi最終為null。

有什么建議么? 提前致謝!

第一次更新

僅當我在構造函數中調用該方法時,才會出現此問題,這也許是因為它尚未初始化完整的group element部分。 但是,我想盡快這樣做。 我是否可能被迫在WindowLoaded事件中執行此操作?

第二次更新

代碼已更新,Rachel的答案可用於遍歷我的ListBoxItems,但是由於我目前無法訪問Datatemplate,因此Listbox尚未完全呈現。 因此MyListBox_GeneratorStatusChanged不適用於此問題,但它確實獲取了ListBoxItems。

WPF的主線程以不同的優先級運行項目。 在構造函數中運行的代碼均以“ Normal優先級運行,而諸如渲染ListBox及其項之類的操作則以“ Render優先級運行,該級別在所有“ Normal優先級操作完成之后發生。

這意味着您的整個構造方法(包括SetListBoxDataTemplate() )在呈現ListBox和生成項目之前SetListBoxDataTemplate()運行。

如果要在生成項目后運行一些代碼,請使用ItemsContainerGenerator.StatusChanged事件

// Constructor
MyListBox.ItemContainerGenerator.StatusChanged += MyListBox_GeneratorStatusChanged;

...

void MyListBox_GeneratorStatusChanged(object sender, EventArgs e)
{
    // return if containers have not been generated yet
    if (MyListBox.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
        return;

    // remove event
    MyListBox.ItemContainerGenerator.StatusChanged -= MyListBox_GeneratorStatusChanged;

    // your items are now generated
    SetListBoxDataTemplate(MyListBox);
}

無論如何,您正在嘗試使用該方法完成什么? 對於WPF來說有點不尋常,並且可能有一種更好的WPF方法來完成您的任務。

根據添加到問題的新代碼進行更新

設置TextItemsSource屬性的一種更好的方法是利用WPF的數據綁定。

您的DataTemplate應該如下所示:

<DataTemplate x:Key="ListBoxItemDataTemplate1">
    <StackPanel Orientation="Horizontal">
        <Border BorderBrush="Black" BorderThickness="1 1 0 1" MinWidth="50">
            <TextBlock Text="{Binding Text}" Background="{Binding ElementName=ListBoxItemComboBox1, Path=SelectedValue}" >
            </TextBlock>
        </Border>
        <ComboBox ItemsSource="{Binding ListColors}" />
    </StackPanel>
</DataTemplate>*

DataTemplate就像千篇一律。 它用於制作UI對象,但不屬於UI對象本身。 它所做的只是告訴WPF: “當您渲染該對象時,請使用此XAML進行渲染” 因此,呈現XAML的方式是

<ListBoxItem>
    <StackPanel>
        <Border>
            <TextBlock Text="{Binding Text}" />
        </Border>
        <ComboBox ItemsSource="{Binding ListColors}">
    </StackPanel> 
</ListBoxItem>

此外, ListBoxItem后面的DataContext是綁定到ListBox.ItemsSource的集合中的項目,該項目基於您的代碼應該是CustomDataTemplateObject 這樣就可以使用DataTemplate進行綁定

如果您是WPF的新手,並且努力了解DataContext工作原理,我建議閱讀我的這篇文章: 您所說的“ DataContext”是什么?

總而言之,WPF對應用程序具有兩層:UI層和數據層( DataContext )。 當您執行上述基本綁定時,您正在將數據從數據層拉到UI層。

因此,您的ListBoxItem具有數據層CustomDataTemplateObject ,並且TextBlock.TextComboBox.ItemsSource綁定正在從數據層提取數據以用於UI層。

我也強烈建議您使用Snoop之類的實用程序,該實用程序可讓您查看正在運行的WPF應用程序的整個可視樹,以查看項目的呈現方式。 它對於調試或了解WPF的工作原理非常有用。

您會混淆兩個工作並將它們混合在一起。 首先,訪問ListBoxItem

private void SetListBoxDataTemplate(ListBox MyListBox)
{
    foreach (ListBoxItem listBoxItem in MyListBox.Items)
    {
    }
}

現在您可以從ListBoxItem獲取DataTemplate

foreach (ListBoxItem listBoxItem in MyListBox.Items)
{
    ContentPresenter presenter = FindVisualChild<ContentPresenter>(listBoxItem);
    DataTemplate dataTemplate = presenter.ContentTemplate;
    if (dataTemplate != null)
    {
        // Do something with dataTemplate here
    }
}

可以在MSDN上的“ 如何:查找由DataTemplate生成的元素”頁中找到FindVisualChild方法。


更新>>>

要回答您的編輯,是的,構造函數現在嘗試訪問這些DataTemplate為時過早,因為到那時DataTemplate Framework不會將它們應用於所有對象。 最好使用FrameworkElement.Loaded事件來執行此類操作,因為這是在控件全部初始化可以調用的第一個事件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM