简体   繁体   English

C# UWP 在 ListView 的 ItemTemplate 中获取项目

[英]C# UWP Get Items in ListView's ItemTemplate

I am trying to access textblocks and textboxes in a listview, but cannot get them in C# code because they are inside an ItemTemplate and DataTemplate.我正在尝试访问列表视图中的文本块和文本框,但无法在 C# 代码中获取它们,因为它们位于 ItemTemplate 和 DataTemplate 中。 Here is a sample of the XAML code:这是 XAML 代码的示例:

<ListView x:Name="VehicleList" HorizontalAlignment="Center" Height="120" Margin="0" VerticalAlignment="Center" Width="1119" Background="{ThemeResource CheckBoxDisabledForegroundThemeBrush}" SelectionChanged="VehicleList_SelectionChanged">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid x:Name="VehicleGrid" Height="52" Width="1117" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20,0,0,0">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="318*"/>
                        <ColumnDefinition Width="425*"/>
                        <ColumnDefinition Width="366*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock x:Name="Year" Grid.Column="0" TextWrapping="Wrap" Text="{Binding Year}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="321" FontSize="26.667"/>
                    <TextBlock x:Name="Make" Grid.Column="1" TextWrapping="Wrap" Text="{Binding Make}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="425" FontSize="26.667" />
                    <TextBlock x:Name="Model" Grid.Column="2" TextWrapping="Wrap" Text="{Binding Model}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="366" FontSize="26.667"/>
                    <TextBox x:Name="AddYear" Grid.Column="0" TextWrapping="Wrap" Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="321" FontSize="26.667" Visibility="Collapsed"/>
                    <TextBox x:Name="AddMake" Grid.Column="1" TextWrapping="Wrap" Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="425" FontSize="26.667" Visibility="Collapsed"/>
                    <TextBox x:Name="AddModel" Grid.Column="2" TextWrapping="Wrap" Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="366" FontSize="26.667" Visibility="Collapsed"/>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

Is there anyway to get the items inside the DataTemplate?无论如何要获取DataTemplate中的项目?

Your problem is generic to all XAML flavors, same in WPF and Silverlight. 您的问题是所有XAML风格都通用的,在WPF和Silverlight中都是相同的。 The problem is your DataTemplate. 问题是您的DataTemplate。 Keep in mind that XAML will inject the contents of your DataTemplate once for each item in your list. 请记住,XAML将为列表中的每个项目注入一次DataTemplate的内容。 That means your names can only exist within the scope of an instance of your DataTemplate. 这意味着您的名称只能存在于DataTemplate实例的范围内。

If you have do code behind for your template, you might do better by creating a UserControl. 如果您的模板后面有代码,则可以通过创建UserControl来做得更好。 See below for an example: 参见以下示例:

<!-- most boiler plate code skipped -->
<UserControl x:Class="MyProject.VehicleListItem">
    <Grid x:Name="VehicleGrid" Height="52" Width="1117" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20,0,0,0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="318*"/>
            <ColumnDefinition Width="425*"/>
            <ColumnDefinition Width="366*"/>
        </Grid.ColumnDefinitions>
        <TextBlock x:Name="Year" Grid.Column="0" TextWrapping="Wrap" Text="{Binding Year}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="321" FontSize="26.667"/>
        <TextBlock x:Name="Make" Grid.Column="1" TextWrapping="Wrap" Text="{Binding Make}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="425" FontSize="26.667" />
        <TextBlock x:Name="Model" Grid.Column="2" TextWrapping="Wrap" Text="{Binding Model}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="366" FontSize="26.667"/>
        <TextBox x:Name="AddYear" Grid.Column="0" TextWrapping="Wrap" Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="321" FontSize="26.667" Visibility="Collapsed"/>
        <TextBox x:Name="AddMake" Grid.Column="1" TextWrapping="Wrap" Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="425" FontSize="26.667" Visibility="Collapsed"/>
        <TextBox x:Name="AddModel" Grid.Column="2" TextWrapping="Wrap" Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="366" FontSize="26.667" Visibility="Collapsed"/>
    </Grid>
</UserControl>

That let's you do everything you need to do from a UserControl that can be instantiated, has it's own code behind, etc. You can get that working exactly how you want, and then reference it when you need it in your list like this: 这样一来,您就可以从可实例化的UserControl进行所需的所有操作,在其背后添加自己的代码,等等。您可以完全按照所需的方式工作,然后在列表中按需引用它,如下所示:

<ListView x:Name="VehicleList" HorizontalAlignment="Center" Height="120" Margin="0" VerticalAlignment="Center" Width="1119" Background="{ThemeResource CheckBoxDisabledForegroundThemeBrush}" SelectionChanged="VehicleList_SelectionChanged">
    <ListView.ItemTemplate>
        <DataTemplate>
            <myProject:VehicleListItem/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

The ListView will assign a vehicle item to the DataContext of your user control and everything will work just like you designed it to. ListView将为您的用户控件的DataContext分配一个载具项目,并且一切将按您设计的目的工作。

There is a way to get at the visual tree in code behind but it is very convoluted. 有一种方法可以使代码隐藏在可视树中,但是它非常复杂。 Essentially you need to use the ListView.ItemContainerGenerator and call ContainerFromItem(dataItem) ( ref ) and then walk down the visual tree you get from that. 本质上,您需要使用ListView.ItemContainerGenerator并调用ContainerFromItem(dataItem)ref ),然后从中获得可视化树。 It's not only a serious pain to do, there's no guarantee all of the API will be accessible from WPF to UWP or SilverLight. 这不仅是一项艰巨的工作,而且不能保证所有API都可以从WPF到UWP或SilverLight进行访问。 The cleanest solution is to break up the code into independent pieces. 最干净的解决方案是将代码分成独立的部分。


Another solution, which probably is even more clean that what I proposed is to take advantage of your bound objects. 另一个解决方案可能比我建议的要干净的多,这是利用您的绑定对象。 ListView.SelectedItem returns your object that is bound to the DataTemplate . ListView.SelectedItem返回绑定到DataTemplate对象。 Just get the values from that object. 只需从该对象获取值即可。 If you have a ViewModel that includes properties for AddYear , AddMake , and AddModel then it makes a lot of the work easier to do since you aren't dealing with XAML at all. 如果您的ViewModel包含AddYearAddMakeAddModel属性,则由于您根本不用XAML,因此它使许多工作变得更容易。

If it's okay for you to do this on a button-click; 如果可以的话,只需单击一下按钮即可; you could use the CommandParameter or traverse the VisualTree like these two links suggest: 您可以使用CommandParameter或遍历VisualTree,如以下两个链接所示:

How to get text from TextBox inside ListViewItem's DataTemplate 如何从ListViewItem的DataTemplate中的TextBox获取文本

How to get the value out of a textbox in XAML? 如何从XAML的文本框中获取值?

UserControl 用户控件

It sounds like a UserControl is what you are looking for. 听起来您想要的是UserControl

ProjectAdd UserControl 项目添加用户控件

It should be easy since you already have the XAML design. 这应该很容易,因为您已经具有XAML设计。 The code behind will look something like this: 后面的代码如下所示:

public class VehicleView : UserControl
{
    // Year
    public static readonly DependencyProperty YearProperty =
        DependencyProperty.Register("Year", typeof(int), typeof(VehicleView),
            new PropertyMetadata());

    public int Year
    {
        get { return (int)GetValue(YearProperty); }
        set { SetValue(YearProperty, value); }
    }

    // Make
    public static readonly DependencyProperty MakeProperty =
        DependencyProperty.Register("Make", typeof(string), typeof(VehicleView),
            new PropertyMetadata("None"));

    public string Make
    {
        get { return (string)GetValue(MakeProperty); }
        set { SetValue(MakeProperty, value); }
    }

    // Model
    public static readonly DependencyProperty ModelProperty =
        DependencyProperty.Register("Model", typeof(string), typeof(VehicleView),
            new PropertyMetadata("None"));

    public string Model
    {
        get { return (string)GetValue(ModelProperty); }
        set { SetValue(ModelProperty, value); }
    }

    public VehicleView()
    {
        InitializeComponent();
    }
}

Binding words the same way. 绑定单词的方式相同。 Just name the UserControl with x:Name . 只需使用x:Name命名UserControl即可。 Something like: 就像是:

<UserControl x:Name="vehicleview"
             x:Class="MyProjectClass"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d">

    <Grid>
        <!-- Here's where your ListView goes. -->
        <TextBox Text="{Binding ElementName=vehicleview, Path=Model}"/>
    <Grid>

</UserControl>

As i can see you have used bindings. 如我所见,您已经使用绑定。

On VehicleList_SelectionChanged you can do the following VehicleList_SelectionChanged您可以执行以下操作

List<YouClass-Model> selectedItems = VehicleList.SelectedItems.Cast<YouClass-Model>().ToList();

or if you use ItemClicked EventHandler 或者如果您使用ItemClicked EventHandler

 YouClass-Model itemClicked = (YouClass-Model)e.ClickedItem)

That way you can load the binded data. 这样,您可以加载绑定的数据。 ex itemClicked.Model ex itemClicked.Model

Also make sure that you binded your data correctly 还要确保您正确绑定了数据

Data binding overview 数据绑定概述

INotifyPropertyChanged.PropertyChanged INotifyPropertyChanged.PropertyChanged

To get the UI control from the index or data, use listView.ContainerFromIndex or listView.ContainerFromItem . 要从索引或数据获取UI控件,请使用listView.ContainerFromIndexlistView.ContainerFromItem This is the accepted way in UWP. 这是UWP中公认的方式。

try this code:试试这个代码:

private void myListView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
    {
        ListItemData data = args.Item as ListItemData;
        ListViewItem a = args.ItemContainer as ListViewItem;
        var b = a.ContentTemplateRoot as Grid;  
        var txtBlock =b.FindName("txtTitle") as TextBlock;
        txtBlock.Text = data.Title;
        TextRange textRange = new TextRange()
        {
            StartIndex = 1,
            Length = 3
        };
        TextHighlighter highlighter = new TextHighlighter()
        {
            Background = new SolidColorBrush(Colors.Yellow),
            Ranges = { textRange }
        };
        txtBlock.TextHighlighters.Add(highlighter);
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM