如何使用 DataTemplate 访问列表框中的特定项目?
Posted
技术标签:
【中文标题】如何使用 DataTemplate 访问列表框中的特定项目?【英文标题】:How to access a specific item in a Listbox with DataTemplate? 【发布时间】:2011-07-08 01:17:09 【问题描述】:我有一个 ListBox,包括一个带有 2 个 StackPanel 的 ItemTemplate。 我要访问的第二个 StackPanel 中有一个 TextBox。 (将其可见性更改为 true 并接受用户输入) 触发器应该是 SelectionChangedEvent。因此,如果用户单击 ListBoxItem,TextBlock 将变得不可见,而 TextBox 变得可见。
XAML 代码:
<ListBox Grid.Row="1" Name="ContactListBox" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ItemsSource="Binding Contacts" Margin="0,36,0,0" SelectionChanged="ContactListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="Edit Contact" Click="ContactMenuItem_Click"/>
<toolkit:MenuItem Header="Delete Contact" Click="ContactMenuItem_Click"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<Grid>
<Rectangle Fill="StaticResource PhoneAccentBrush"
Width="72" Height="72">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="/Images/defaultContactImage.png" Stretch="UniformToFill"/>
</Rectangle.OpacityMask>
</Rectangle>
</Grid>
<StackPanel>
<TextBox Text="Binding Name" TextWrapping="Wrap" Visibility="Collapsed"/>
<TextBlock Text="Binding Name" TextWrapping="Wrap" Style="StaticResource PhoneTextExtraLargeStyle" />
<TextBlock Text="Binding Number" TextWrapping="Wrap" Margin="12,-6,12,0" Style="StaticResource PhoneTextAccentStyle"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
我想有几种方法可以解决这个问题,但我没有尝试过。
我目前的做法是这样的
private void ContactListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
ListBoxItem listBoxItem = ContactListBox.SelectedItem as ListBoxItem;
DataTemplate listBoxTemplate = listBoxItem.ContentTemplate;
// How to access the DataTemplate content?
StackPanel outerStackPanel = listBoxTemplate.XXX as StackPanel;
StackPanel innerStackPanel = outerStackPanel.Children[1] as StackPanel;
TextBox nameBox = innerStackPanel.Children[0] as TextBox;
TextBlock nameBlock = innerStackPanel.Children[1] as TextBlock;
nameBox.Visibility = System.Windows.Visibility.Visible;
nameBlock.Visibility = System.Windows.Visibility.Collapsed;
【问题讨论】:
我喜欢这个解决方案,但是如果我的文本块很少并且我想让可见/折叠不是第一个而是前。 2号还是3号?换句话说如何进入具有指定名称的列表框控件? @sust86 listBoxTemplate.XXX 中的 XXX 是什么? 如果您想按名称进行迭代,请使用此解决方案:***.com/a/1759923/3934111 这是一篇 MSDN 文章,可能也有助于向仍然想知道的任何人解释这些东西:msdn.microsoft.com/en-us/library/bb613579(v=vs.110).aspx 【参考方案1】:谢谢你们的帮助!!最后我明白了。解决了 VisualTreeHelper 的问题。好厉害的功能^^
private void ContactListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
if (ContactListBox.SelectedIndex == -1)
return;
currentSelectedListBoxItem = this.ContactListBox.ItemContainerGenerator.ContainerFromIndex(ContactListBox.SelectedIndex) as ListBoxItem;
if (currentSelectedListBoxItem == null)
return;
// Iterate whole listbox tree and search for this items
TextBox nameBox = helperClass.FindDescendant<TextBox>(currentSelectedListBoxItem);
TextBlock nameBlock = helperClass.FindDescendant<TextBlock>(currentSelectedListBoxItem);
helperFunction
public T FindDescendant<T>(DependencyObject obj) where T : DependencyObject
// Check if this object is the specified type
if (obj is T)
return obj as T;
// Check for children
int childrenCount = VisualTreeHelper.GetChildrenCount(obj);
if (childrenCount < 1)
return null;
// First check all the children
for (int i = 0; i < childrenCount; i++)
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child is T)
return child as T;
// Then check the childrens children
for (int i = 0; i < childrenCount; i++)
DependencyObject child = FindDescendant<T>(VisualTreeHelper.GetChild(obj, i));
if (child != null && child is T)
return child as T;
return null;
【讨论】:
哦,它应该在这里:我喜欢这个解决方案,但是如果我的文本块很少并且我想让可见/折叠不是第一个而是前。 2号还是3号?换句话说如何进入具有指定名称的列表框控件?【参考方案2】:使用此编辑功能,您还可以按名称搜索控件(从 VB.NET 转换而来):
public T FindDescendantByName<T>(DependencyObject obj, string objname) where T : DependencyObject
string controlneve = "";
Type tyype = obj.GetType();
if (tyype.GetProperty("Name") != null)
PropertyInfo prop = tyype.GetProperty("Name");
controlneve = prop.GetValue((object)obj, null);
else
return null;
if (obj is T && objname.ToString().ToLower() == controlneve.ToString().ToLower())
return obj as T;
// Check for children
int childrenCount = VisualTreeHelper.GetChildrenCount(obj);
if (childrenCount < 1)
return null;
// First check all the children
for (int i = 0; i <= childrenCount - 1; i++)
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child is T && objname.ToString().ToLower() == controlneve.ToString().ToLower())
return child as T;
// Then check the childrens children
for (int i = 0; i <= childrenCount - 1; i++)
string checkobjname = objname;
DependencyObject child = FindDescendantByName<T>(VisualTreeHelper.GetChild(obj, i), objname);
if (child != null && child is T && objname.ToString().ToLower() == checkobjname.ToString().ToLower())
return child as T;
return null;
【讨论】:
【参考方案3】:我不能给你一个完整的答案...
但我认为您可以使用 VisualTreeHelper 来遍历任何控件的子项 http://blogs.msdn.com/b/kmahone/archive/2009/03/29/visualtreehelper.aspx
但是,对于您正在寻找的效果,我认为使用 SelectedItem Style 可能是一个更好的解决方案 - 例如看这篇文章-http://joshsmithonwpf.wordpress.com/2007/07/30/customizing-the-selected-item-in-a-listbox/
【讨论】:
感谢您对 VisualTreeHelper 的提示! :) 感谢我...点赞 :) 我真的认为你应该使用 SelectedItem 样式而不是使用代码来实现效果 - 从长远来看,这是最好的方式(我认为)跨度> 我试图...“投票需要 15 声望”好吧,我肯定会学习如何使用 Blend。但我是 Windows Phone 编程领域的新手,仍然试图弄清楚所有这些东西是如何工作的。我只是需要更多时间=) 啊 - 抱歉 - 你必须在网站上停留更长时间,然后再回来 :)【参考方案4】:使用ItemContainerGenerator
。
private void ContactListBox_SelectionChanged
(object sender, SelectionChangedEventArgs e)
if (e.AddedItems.Count == 1)
var container = (FrameworkElement)ContactListBox.ItemContainerGenerator.
ContainerFromItem(e.AddedItems[0]);
StackPanel sp = container.FindVisualChild<StackPanel>();
TextBox tbName = (TextBox) sp.FindName("tbName");
TextBlock lblName = (TextBlock)sp.FindName("lblName");
TextBlock lblNumber = (TextBlock)sp.FindName("lblNumber");
【讨论】:
太好了,我想使用这个解决方案。但是,显然 FrameworkElement 不包含“FindVisualChild”的定义。也许这是因为我正在为 windows phone 7 使用 silverlight?!仍在试图弄清楚如何解决这个问题。也许 VisualTreeHelper 可以帮助 = ) TY 反正【参考方案5】:由于 DataTemplate 是可以在代码中多次使用的通用模板,因此无法通过名称 (x:Name="numberTextBox") 访问它。
我通过制作控件集合解决了与此类似的问题 - 在填充列表框时,我将文本框控件添加到集合中。
string text = myCollectionOfTextBoxes[listbox.SelectedIndex].Text;
直到我找到一个更好的灵魂——标签属性。在您的 ListboxItem 中,您将 Tag 属性绑定到名称
Tag="Binding Name"
以及访问它
ListBoxItem listBoxItem = ContactListBox.SelectedItem as ListBoxItem;
string name = listBoxItem.Tag.ToString();
【讨论】:
我不确定我是否完全理解这种方法。但这仅在我需要知道 TextBox / TextBlock 的文本时才有用。使用此解决方案无法聚焦 TextBox 并接受用户输入,对吧? 那么你想拥有Button的行为吗? forums.create.msdn.com/forums/t/69801.aspx 看看这个。以上是关于如何使用 DataTemplate 访问列表框中的特定项目?的主要内容,如果未能解决你的问题,请参考以下文章
XAML - 如何从 ControlTemplate 中的子项访问父控件的 DataTemplate 属性?
使用 DataTemplate 时,ListView 仅显示列表中的最后一项
如何在复选框事件上访问嵌套listview datatemplate中的标签名称