2011-03-03 79 views
13

我有一个ListBox,包含一个带有2个StackPanel的ItemTemplate。 我想访问的第二个StackPanel中有一个TextBox。 (将其可见性更改为true并接受用户输入) 触发器应该是SelectionChangedEvent。所以,如果用户点击一个ListBoxItem,TextBlock变得不可见并且TextBox变得可见。如何使用DataTemplate访问Listbox中的特定项目?

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; 

    } 
+1

我喜欢这个解决方案,但是如果我没有几个文本块,并且我想让可见/折叠不是第一个,而是前一个。第二还是第三?换句话说,如何进入带有指定名称的列表框控件? – dargod 2012-08-29 14:36:22

+0

@ sust86什么是listBoxTemplate.XXX中的** XXX **? – ROMAN 2014-02-27 12:58:45

+0

如果要按名称迭代,请使用此解决方案: http:// stackoverflow。com/a/1759923/3934111 – 2015-05-07 21:14:39

回答

27

感谢您的帮助家伙!最后我得到了它。用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; 
    } 
+0

哦,它应该在这里:我喜欢这个解决方案,但是如果我有几个文本块,并且我想让可见/折叠不是第一个但是前一个。第二还是第三?换句话说,如何进入带有指定名称的列表框控件? – dargod 2012-08-29 14:41:06

2

我不能给你一个完整的答案...

但我认为你可以使用VisualTreeHelper通过任何孩子迭代控制 http://blogs.msdn.com/b/kmahone/archive/2009/03/29/visualtreehelper.aspx

然而,对于你正在寻找的效果,那么我认为使用SelectedItem风格可能是一个更好的解决方案 - 例如看到这篇文章 - http://joshsmithonwpf.wordpress.com/2007/07/30/customizing-the-selected-item-in-a-listbox/

+0

感谢您使用VisualTreeHelper提示! :) – sust86 2011-03-04 09:08:48

+0

为了感谢我...击中了upvote :)而且我真的认为你应该使用SelectedItem风格而不是使用代码来实现你的效果 - 从长远来看,它是最好的方式(我认为) – Stuart 2011-03-04 09:32:15

+1

我试图...... “投票要求15声望” 那么,即时通讯肯定要学习如何使用Blend。但即时消息在Windows手机编程现场,仍然试图找出所有这些东西是如何工作的。我只是需要更多的时间=) – sust86 2011-03-04 16:42:36

1

使用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"); 
    } 
} 
+1

太好了,我想使用这个解决方案。但是,显然FrameworkElement不包含“FindVisualChild”的定义。也许这是因为我正在使用silverlight for windows phone 7?!仍试图找出如何解决这个问题。也许VisualTreeHelper可以帮助=)无论如何 – sust86 2011-03-03 15:35:22

1

因为DataTemplate中是可以在代码中多次使用一个通用的模板,也没有办法通过名称来访问它(X:NAME =“数字框”)。

我通过制作控件集合解决了类似的问题 - 当Listbox被填充时,我将Textbox控件添加到集合中。

string text = myCollectionOfTextBoxes[listbox.SelectedIndex].Text; 

直到我发现一个更好的灵魂 - 标签属性。在你的一个ListBoxItem您Tag属性绑定到名称

Tag="{Binding Name}" 

和访问它

ListBoxItem listBoxItem = ContactListBox.SelectedItem as ListBoxItem; 

string name = listBoxItem.Tag.ToString(); 
+0

我不知道我完全理解这种方法。但是这只会在我需要知道TextBox/TextBlock的文本时才有用。没有办法将TextBox集中并接受用户输入的解决方案,对吧? – sust86 2011-03-03 15:24:43

+0

所以你想要有Button的行为? http://forums.create.msdn.com/forums/t/69801.aspx看看这个。 – 2011-03-03 16:10:16

3

有了这个编辑功能,您还可以按名称搜索控制(从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; 
} 
相关问题