C# UWP 获取 ListView 的 ItemTemplate 中的 Items
C# UWP Get Items in ListView's ItemTemplate
我正在尝试访问列表视图中的文本块和文本框,但无法在 C# 代码中获取它们,因为它们位于 ItemTemplate 和 DataTemplate 中。这是 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>
有没有办法获取 DataTemplate 中的项目?
如果您可以通过单击按钮执行此操作;您可以使用 CommandParameter 或遍历 VisualTree,就像这两个链接建议的那样:
How to get the value out of a textbox in XAML?
您的问题对于所有 XAML 风格都是通用的,在 WPF 和 Silverlight 中也是如此。问题是您的数据模板。请记住,XAML 将为列表中的每个项目注入一次 DataTemplate 的内容。这意味着您的名称只能存在于 DataTemplate 实例的范围内。
如果您的模板有隐藏代码,则创建 UserControl 可能会做得更好。请参阅下面的示例:
<!-- 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>
这让您可以通过可以实例化的 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>
ListView 会将车辆项目分配给用户控件的 DataContext
,一切都会像您设计的那样工作。
有一种方法可以在代码隐藏中获取可视化树,但它非常复杂。本质上,您需要使用 ListView.ItemContainerGenerator
并调用 ContainerFromItem(dataItem)
(ref),然后沿着从中获得的可视化树走下去。这样做不仅非常痛苦,而且不能保证所有 API 都可以从 WPF 访问到 UWP 或 SilverLight。最干净的解决方案是将代码分解成独立的部分。
另一种解决方案,可能比我提出的利用绑定对象更干净。 ListView.SelectedItem
returns 您绑定到 DataTemplate
的对象。只需从该对象中获取值。如果您的 ViewModel 包含 AddYear
、AddMake
和 AddModel
的属性,那么它会使很多工作更容易完成,因为您不需要处理 XAML完全没有。
用户控件
听起来 UserControl
就是您要找的东西。
项目 → 添加用户控件
应该很容易,因为您已经有了 XAML 设计。后面的代码看起来像这样:
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();
}
}
以同样的方式绑定单词。只需将 UserControl 命名为 x:Name
。类似于:
<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>
据我所知,您使用了绑定。
在 VehicleList_SelectionChanged
上,您可以执行以下操作
List<YouClass-Model> selectedItems = VehicleList.SelectedItems.Cast<YouClass-Model>().ToList();
或者如果您使用 ItemClicked 事件处理程序
YouClass-Model itemClicked = (YouClass-Model)e.ClickedItem)
这样你就可以加载绑定的数据了。例如 itemClicked.Model
还要确保您正确绑定了数据
要从索引或数据中获取 UI 控件,请使用 listView.ContainerFromIndex
或 listView.ContainerFromItem
。这是 UWP 中接受的方式。
试试这个代码:
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);
}
我正在尝试访问列表视图中的文本块和文本框,但无法在 C# 代码中获取它们,因为它们位于 ItemTemplate 和 DataTemplate 中。这是 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>
有没有办法获取 DataTemplate 中的项目?
如果您可以通过单击按钮执行此操作;您可以使用 CommandParameter 或遍历 VisualTree,就像这两个链接建议的那样:
How to get the value out of a textbox in XAML?
您的问题对于所有 XAML 风格都是通用的,在 WPF 和 Silverlight 中也是如此。问题是您的数据模板。请记住,XAML 将为列表中的每个项目注入一次 DataTemplate 的内容。这意味着您的名称只能存在于 DataTemplate 实例的范围内。
如果您的模板有隐藏代码,则创建 UserControl 可能会做得更好。请参阅下面的示例:
<!-- 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>
这让您可以通过可以实例化的 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>
ListView 会将车辆项目分配给用户控件的 DataContext
,一切都会像您设计的那样工作。
有一种方法可以在代码隐藏中获取可视化树,但它非常复杂。本质上,您需要使用 ListView.ItemContainerGenerator
并调用 ContainerFromItem(dataItem)
(ref),然后沿着从中获得的可视化树走下去。这样做不仅非常痛苦,而且不能保证所有 API 都可以从 WPF 访问到 UWP 或 SilverLight。最干净的解决方案是将代码分解成独立的部分。
另一种解决方案,可能比我提出的利用绑定对象更干净。 ListView.SelectedItem
returns 您绑定到 DataTemplate
的对象。只需从该对象中获取值。如果您的 ViewModel 包含 AddYear
、AddMake
和 AddModel
的属性,那么它会使很多工作更容易完成,因为您不需要处理 XAML完全没有。
用户控件
听起来 UserControl
就是您要找的东西。
项目 → 添加用户控件
应该很容易,因为您已经有了 XAML 设计。后面的代码看起来像这样:
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();
}
}
以同样的方式绑定单词。只需将 UserControl 命名为 x:Name
。类似于:
<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>
据我所知,您使用了绑定。
在 VehicleList_SelectionChanged
上,您可以执行以下操作
List<YouClass-Model> selectedItems = VehicleList.SelectedItems.Cast<YouClass-Model>().ToList();
或者如果您使用 ItemClicked 事件处理程序
YouClass-Model itemClicked = (YouClass-Model)e.ClickedItem)
这样你就可以加载绑定的数据了。例如 itemClicked.Model
还要确保您正确绑定了数据
要从索引或数据中获取 UI 控件,请使用 listView.ContainerFromIndex
或 listView.ContainerFromItem
。这是 UWP 中接受的方式。
试试这个代码:
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);
}