[英]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方法來完成您的任務。
根據添加到問題的新代碼進行更新
設置Text
和ItemsSource
屬性的一種更好的方法是利用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.Text
和ComboBox.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.