如何在XAML中访问一个在ListBox的DataTemplate中(但不是绑定)的TextBlock?

4

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和其他扩展方法,可以在此处找到:GeekChampFalafel Blog。但是我没有成功。我几乎放弃了这个问题。是否有人有任何想法可以做到这一点。谢谢。
如您所见 - 我可以成功获取媒体队列,但我想在“SelectedItem”的左侧显示可视提示,就像TextBlock-tbActive中的播放字符一样。希望这会有所帮助!

你需要严格按照GeekChamp的教程操作。请查看解决方案。 - Chubosaurus Software
嗨。如果我没能让你知道我需要什么,我很抱歉。实际上,我已经成功获取了媒体队列(当前在队列中的歌曲)。但是,我想展示一个正在播放的符号——就在“活动歌曲”旁边,而 tbActive 正是这样的符号!我希望能够访问 tbActive,以便改变其 Text 属性——但只有 SelectedItemSelectedIndex 的属性可以更改。 谢谢。 - CriticalError
是的,带有我的名字的解决方案正好符合您的要求。 :) - Chubosaurus Software
3个回答

1

由于 <TextBlock> 是您要访问的 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 也是空的 :( - CriticalError
选定的索引是什么数字?如果使用了选定项,在断点处它等于什么? - Chubosaurus Software
选择的索引是当前播放的歌曲,我从MediaPlayer.Queue.ActiveSongIndex中获取。请查看我刚刚添加到问题中的图片。谢谢。 - CriticalError
它确实获取了TextBlock!但是为什么当我显式设置索引时它可以工作,而当由MediaPlayer指定时却不能工作呢?:( - CriticalError
1
因为你必须输入的SelectedIndex必须是ItemsSource的索引值...在你的情况下,是songs.ToList()而不是你事后随意创建的列表。你的ItemsSource决定了列表框的输出,所以当你想要从中获取任何内容时,你必须使用相同的列表。 - Chubosaurus Software
显示剩余6条评论

1
上面的答案会抛出异常 - 就像 Chubosaurus Software建议的那样,SelectedItem将是一个'Song',因此TextBlock也将是null。但这样不起作用。

0
你可以尝试使用 as 运算符从 ListBox 的选定项中获取 StackPanel,然后使用 Children 属性和索引器来访问你的 TextBlock。
StackPanel temp = lsbQueue.SelectedItem as StackPanel;
var textBlock = temp.Children[0] as TextBlock;

你想要实现什么目标?也许另一个绑定加上可能的值转换器会是更好的解决方案...

非常确定 lsbQueue.SelectedItem 将是 song 而不是控件。因此这样做会抛出错误,因为 temp 将为 null - Chubosaurus Software

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接