【问题标题】:How do I access a TextBlock which is inside my ListBox's DataTemplate (but not Binding) in XAML?如何在 XAML 中访问我的 ListBox 的 DataTemplate(但不是绑定)内的 TextBlock?
【发布时间】:2014-09-22 12:57:10
【问题描述】:

XAML

<ListBox x:Name="lsbQueue" Margin="0,0,0,10" Grid.RowSpan="2" Loaded="lsbQueue_Loaded" SelectionChanged="lsbQueue_SelectionChanged" ItemContainerStyle="{StaticResource ListBoxItemStyle1}" ItemsSource="{Binding}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel x:Name="stk" Orientation="Vertical">
                <!-- This is the bugger which I need to access behind the scenes-->
                <TextBlock x:Name="tbActive" FontSize="35" FontFamily="Segoe UI Symbol" Text="" Height="115" Margin="0,0,0,-110" Tag="Active"/>
                <!-- -->
                <TextBlock Text="{Binding Path=SongName}" FontSize="35" Width="388" FontWeight="Normal" Margin="60,0,0,0"/>
                <TextBlock Width="390" FontWeight="Thin" Margin="60,-5,0,10" Opacity="0.55">
                            <Run Text="{Binding Artist}" />
                            <Run Text=", " /> <!-- space -->
                            <Run Text="{Binding Album}" />
                </TextBlock>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

上面是我的列表框,它是在下面的代码的帮助下填充的:

C#

void GetQueue()
{
    var songs = new List<song>();

    for (int i = 0; i < MediaPlayer.Queue.Count; i++)
    {
        songs.Add(new song {
            SongName = MediaPlayer.Queue[i].Name.ToString(),
            Album = MediaPlayer.Queue[i].Album.Name.ToString(),
            Artist = MediaPlayer.Queue[i].Artist.ToString()
        });

    }
    lsbQueue.ItemsSource = songs.ToList();
    //lsbQueue.SelectedValue.ToString();
    GlobalVars._song = MediaPlayer.Queue.ActiveSongIndex;
    lsbQueue.SelectedIndex = GlobalVars._song;
    // .......
}

public class song
{
    public string SongName { get; set; }
    public string Album { get; set; }
    public string Artist { get; set; }
}

public class Song : List<song>
{
    public Song()
    {
        Add(new song { 
            SongName = "", 
            Album = "",
            Artist = ""
        });
    }
}

我尝试过使用 VisualTreeHelper 和其他扩展方法,可以在这里找到:

GeekChamp

Falafel Blog

但我没有成功。我几乎已经放弃了这个。有没有人有任何想法可以做什么。谢谢你。

如您所见 - 我可以成功获取媒体队列,但我想在“SelectedItem”的左侧显示一个视觉提示,如 TextBlock 中的播放字符 - tbActive。希望这会有所帮助!

【问题讨论】:

  • 您需要严格按照 GeekChamp 的教程进行操作。查看解决方案。
  • 嗨。抱歉,如果我无法让您知道我需要什么。实际上,我已经能够成功获取 Media Queue(当前在队列中的歌曲)。但是,我想在“Active Song”旁边显示一个正在播放的符号,tbActive 就是那个!我期待能够访问 tbActive 以希望更改其 Text 属性 - 但仅限于 SelectedItemSelectedIndex。谢谢。
  • 是的,上面有我名字的解决方案正是您想要的。 :)

标签: c# xaml windows-phone-8 datatemplate visualtreehelper


【解决方案1】:

由于 &lt;TextBlock&gt; 是您尝试访问的 DataTemplate 中的第一个条目,请使用 GeekChamp 教程中提供的函数。

<ListBox x:Name="lb" SelectionChanged="lb_SelectionChanged"/>

// namespaces
using System.Windows.Media;

private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
{
    var count = VisualTreeHelper.GetChildrenCount(parentElement);
    if (count == 0)
        return null;

    for (int i = 0; i < count; i++)
    {
        var child = VisualTreeHelper.GetChild(parentElement, i);

        if (child != null && child is T)
        {
            return (T)child;
        }
        else
        {
            var result = FindFirstElementInVisualTree<T>(child);
            if (result != null)
                return result;
        }
    }
    return null;
}

private void lb_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    // get the ListBoxItem by SelectedIndex OR index number
    //ListBoxItem lbi = (ListBoxItem) this.lb.ItemContainerGenerator.ContainerFromIndex(lb.SelectedIndex);

    // get the ListBoxItem by SelectedItem or object in your ViewModel
    ListBoxItem lbi = (ListBoxItem)this.lb.ItemContainerGenerator.ContainerFromItem(lb.SelectedItem);

    // get your textbox that you want
    TextBlock tbActive= FindFirstElementInVisualTree<TextBlock>(lbi);
}

【讨论】:

  • :( 它不起作用。我设置了一个断点,lbi 为空,因此即使 TextBlock 也为空:(
  • 选择的索引是多少?另外,如果您使用选定的项目,它在断点处等于什么?
  • Selected Index 是我从MediaPlayer.Queue.ActiveSongIndex 得到的当前正在播放的歌曲。请看一下我刚刚添加到我的问题中的图像。谢谢。
  • 好的,我们到了。索引和选定项目必须来自您指定为 ItemsSource 的集合。尝试一个常量 0 值,是否至少得到列表框第一个条目的文本块?
  • 因为您必须输入的 SelectedIndex 必须是 ItemsSource 的索引值...在您的情况下,您的 songs.ToList() 而不是您事后制作的随机列表。您的 ItemsSource 决定了列表框的输出,因此当您想要其中的任何内容时,您必须使用相同的列表。
【解决方案2】:

上述答案将引发异常 - 就像 Chubosaurus Software 建议 SelectedItem 将是“歌曲”,因此 TextBlock 也将是 null。而且它不会起作用。

【讨论】:

    【解决方案3】:

    您可以尝试使用 as 运算符从 ListBox 的 Selected Item 中获取 StackPanel,然后使用带有索引器的 Children 属性来访问您的 TextBlock。

    StackPanel temp = lsbQueue.SelectedItem as StackPanel;
    var textBlock = temp.Children[0] as TextBlock;
    

    你到底想完成什么?也许另一个 Binding + 可能的 ValueConverter 会是更好的解决方案......

    【讨论】:

    • 很确定lsbQueue.SelectedItem 将是song 而不是控件。这样做会引发错误,因为 temp 将是 null
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-16
    • 1970-01-01
    相关资源
    最近更新 更多