Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# FindVisualChild-获取ItemsControl中命名UI元素的属性_C#_Wpf_Xaml_Itemscontrol - Fatal编程技术网

C# FindVisualChild-获取ItemsControl中命名UI元素的属性

C# FindVisualChild-获取ItemsControl中命名UI元素的属性,c#,wpf,xaml,itemscontrol,C#,Wpf,Xaml,Itemscontrol,我使用ItemsControl在运行时生成UI元素。UI生成成功,但如果无法获取生成的UI项的任何属性,例如标签的“内容”,或组合框的选择编辑项。我试图通过使用和获取这些属性,但总是得到NullReferenceException XAML中的ItemsControl如下所示: <ItemsControl Name="ListOfVideos"> <ItemsControl.Background>

我使用
ItemsControl
在运行时生成UI元素。UI生成成功,但如果无法获取生成的UI项的任何属性,例如标签的“内容”,或组合框的
选择编辑项
。我试图通过使用和获取这些属性,但总是得到
NullReferenceException

XAML中的
ItemsControl
如下所示:

            <ItemsControl Name="ListOfVideos">
                <ItemsControl.Background>
                    <SolidColorBrush Color="Black" Opacity="0"/>
                </ItemsControl.Background>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid Margin="0,0,0,10">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="180"/>
                                <ColumnDefinition Width="400"/>
                                <ColumnDefinition Width="200"/>
                            </Grid.ColumnDefinitions>
                            <Image HorizontalAlignment="Left" Height="100" Width="175" x:Name="VideoThumbnailImage" Stretch="Fill" Source="{Binding VideoThumbnailURL}" Grid.Column="0"></Image>
                            <Label x:Name="VideoTitleLabel" Content="{Binding VideoTitleText}" Foreground="White" Grid.Column="1" VerticalAlignment="Top" FontSize="16" FontWeight="Bold"></Label>
                            <Label x:Name="VideoFileSizeLabel" Content="{Binding VideoTotalSizeText}" Foreground="White" FontSize="14" Grid.Column="1" Margin="0,0,0,35" VerticalAlignment="Bottom"></Label>
                            <Label x:Name="VideoProgressLabel" Content="{Binding VideoStatusText}" Foreground="White" FontSize="14" Grid.Column="1" VerticalAlignment="Bottom"></Label>
                            <ComboBox x:Name="VideoComboBox" SelectionChanged="VideoComboBox_SelectionChanged" Grid.Column="2" Width="147.731" Height="20" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,50" ItemsSource="{Binding VideoQualitiesList}"></ComboBox>
                            <Label Content="Video Quality" Foreground="White" FontSize="14" VerticalAlignment="Top" Grid.Column="2" HorizontalAlignment="Center"></Label>
                            <Label Content="Audio Quality" Foreground="White" FontSize="14" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,27" Grid.Column="2"></Label>
                            <Slider x:Name="VideoAudioSlider" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Bottom" Width="147.731" Maximum="{Binding AudioCount}"></Slider>
                        </Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

这就是我生成UI元素的方式

public class VideoMetadataDisplay
    {
        public string VideoTitleText { get; set; }
        public int AudioCount { get; set; }
        public string VideoThumbnailURL { get; set; }
        public string VideoStatusText { get; set; }
        public string VideoTotalSizeText { get; set; }
        public List<string> VideoQualitiesList { get; set; }
    }

public partial class PlaylistPage : Page
{
private void GetPlaylistMetadata()
        {

            List<VideoMetadataDisplay> newList = new List<VideoMetadataDisplay>();
            //populate the list
            ListOfVideos.ItemsSource = newList;
        }
}
public class Utils
    {
        public childItem FindVisualChild<childItem>(DependencyObject obj)
     where childItem : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                if (child != null && child is childItem)
                {
                    return (childItem)child;
                }
                else
                {
                    childItem childOfChild = FindVisualChild<childItem>(child);
                    if (childOfChild != null)
                        return childOfChild;
                }
            }
            return null;
        }
    }

private void VideoComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            UIElement CurrentItem = (UIElement)ListOfVideos.ItemContainerGenerator.ContainerFromItem(ListOfVideos.Items.CurrentItem);
            Utils utils = new Utils();
            ContentPresenter CurrentContentPresenter = utils.FindVisualChild<ContentPresenter>(CurrentItem);
            DataTemplate CurrentDataTemplate = CurrentContentPresenter.ContentTemplate;
            Label VideoTitle = (Label)CurrentDataTemplate.FindName("VideoTitleLabel", CurrentContentPresenter);
            string VideoTitleText = VideoTitle.Content.ToString();
            MessageBox.Show(VideoTitleText);
        }
公共类VideoMetadataDisplay
{
公共字符串VideoTitleText{get;set;}
公共整数音频计数{get;set;}
公共字符串VideoThumbnailURL{get;set;}
公共字符串VideoStatusText{get;set;}
公共字符串VideoTotalSizeText{get;set;}
公共列表VideoQualitiesList{get;set;}
}
公共部分类播放列表第页:第页
{
私有void getplaylaymetadata()
{
List newList=新列表();
//填充列表
ListOfVideos.ItemsSource=newList;
}
}
这就是我试图获取UI元素属性的方法

public class VideoMetadataDisplay
    {
        public string VideoTitleText { get; set; }
        public int AudioCount { get; set; }
        public string VideoThumbnailURL { get; set; }
        public string VideoStatusText { get; set; }
        public string VideoTotalSizeText { get; set; }
        public List<string> VideoQualitiesList { get; set; }
    }

public partial class PlaylistPage : Page
{
private void GetPlaylistMetadata()
        {

            List<VideoMetadataDisplay> newList = new List<VideoMetadataDisplay>();
            //populate the list
            ListOfVideos.ItemsSource = newList;
        }
}
public class Utils
    {
        public childItem FindVisualChild<childItem>(DependencyObject obj)
     where childItem : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                if (child != null && child is childItem)
                {
                    return (childItem)child;
                }
                else
                {
                    childItem childOfChild = FindVisualChild<childItem>(child);
                    if (childOfChild != null)
                        return childOfChild;
                }
            }
            return null;
        }
    }

private void VideoComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            UIElement CurrentItem = (UIElement)ListOfVideos.ItemContainerGenerator.ContainerFromItem(ListOfVideos.Items.CurrentItem);
            Utils utils = new Utils();
            ContentPresenter CurrentContentPresenter = utils.FindVisualChild<ContentPresenter>(CurrentItem);
            DataTemplate CurrentDataTemplate = CurrentContentPresenter.ContentTemplate;
            Label VideoTitle = (Label)CurrentDataTemplate.FindName("VideoTitleLabel", CurrentContentPresenter);
            string VideoTitleText = VideoTitle.Content.ToString();
            MessageBox.Show(VideoTitleText);
        }
公共类Utils
{
公共子项FindVisualChild(DependencyObject obj)
where-childItem:DependencyObject
{
for(int i=0;i

每次尝试运行此操作时,
FindVisualChild
总是返回其中一个标签(
VideoTitleLabel
),而不是返回当前活动项的
ContentPresenter
CurrentDataTemplate
随后为空,我无法从中获取任何UI元素。

不可能
FindVisualChild
返回一个
标签
实例
FindVisualChild
将结果强制转换为
ContentPresenter
。由于
Label
不是
ContentPresenter
,这将引发
InvalidCastException
。但在此之前,
child is childItem
将返回
false
,前提是
child
类型为
Label
,通用参数类型
childItem
类型为
ContentPresenter
,因此返回一个潜在的
null

短版 访问
数据模板
或查找控件以获取其绑定数据总是太复杂。直接访问数据源总是比较容易。
ItemsControl.SelectedItem
将返回所选项目的数据模型。你通常对容器不感兴趣

private void VideoComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
  var listView = sender as ListView;
  var item = listView.SelectedItem as VideoMetadataDisplay;
  MessageBox.Show(item.VideoTitleText);
}
您的版本(
FindVisualChild
改进)
FindVisualChild
的实现较弱。如果遍历遇到没有子节点的子节点,即参数
obj
null
,它将失败并引发异常。在调用
VisualTreeHelper.GetChildrenCount(obj)
之前,必须检查参数
obj
null
,以避免引用
null

此外,您不需要通过访问模板来搜索元素。您可以直接在可视化树中查找它。
我已经修改了您的
FindVisualChild
方法,以便按名称搜索元素。为了方便起见,我还将其转换为一种扩展方法:

扩展方法

public static class Utils
{
  public static bool TryFindVisualChildByName<TChild>(
    this DependencyObject parent,
    string childElementName,
    out TChild childElement,
    bool isCaseSensitive = false)
    where TChild : FrameworkElement
  {       
    childElement = null;

    // Popup.Child content is not part of the visual tree.
    // To prevent traversal from breaking when parent is a Popup,
    // we need to explicitly extract the content.
    if (parent is Popup popup)
    {
      parent = popup.Child;
    }

    if (parent == null)
    {
      return false;
    }

    var stringComparison = isCaseSensitive 
      ? StringComparison.Ordinal
      : StringComparison.OrdinalIgnoreCase;

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
    {
      DependencyObject child = VisualTreeHelper.GetChild(parent, i);
      if (child is TChild resultElement 
        && resultElement.Name.Equals(childElementName, stringComparison))
      {
        childElement = resultElement;
        return true;
      }

      if (child.TryFindVisualChildByName(childElementName, out childElement))
      {
        return true;
      }
    }

    return false;
  }
}

FindVisualChild
不可能返回一个
Label
实例
FindVisualChild
将结果强制转换为
ContentPresenter
。由于
Label
不是
ContentPresenter
,这将引发
InvalidCastException
。但在此之前,
child is childItem
将返回
false
,前提是
child
类型为
Label
,通用参数类型
childItem
类型为
ContentPresenter
,因此返回一个潜在的
null

短版 访问
数据模板
或查找控件以获取其绑定数据总是太复杂。访问d总是比较容易