Xamarin.Forms 在运行时访问 DataTemplate 内的视图
Access Views inside a DataTemplate at runtime in Xamarin.Forms
我想知道是否有办法在 Xamarin.Forms 的 ListView 中获取对 DataTemplate 内视图的引用。
假设我有这个 xaml:
<ListView x:Name="ProductList" ItemsSource="{Binding Products}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee" x:Name="ProductStackLayout"
Orientation="Vertical" Padding="5" Tapped="ListItemTapped">
<Label Text="{Binding Name}"
Style="{DynamicResource ProductPropertiesStyle}"/>
<Label Text="{Binding Notes}" IsVisible="{Binding HasNotes}"
Style="{DynamicResource NotesStyle}"
/>
<Label Text="{Binding Date}"
Style="{DynamicResource DateStyle}"
/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
我希望能够在 ListView 的每一行中获取对名为 "ProductStackLayout" 的 StackLayout 的引用。我需要在页面出现时执行此操作,以动态操作它的内容(对于数据绑定无法实现的内容),因此我无法利用在源自 DataTemplate 中的元素的事件处理程序中传递的视图引用本身就像 ItemTapped 或类似的。
据我所知,在 WPF 或 UWP 中,借助 VisualTreeHelper class 可以实现类似的功能,但我不相信在 class Xamarin.Forms.
是的,可以在 run-time 中访问使用 DataTemplate
创建的视图。为来自 XAML 的 DataTemplate
内的视图挂钩 BindingContextChanged
事件。在事件回调中,可以使用 sender 参数访问从 DataTemplate
创建的视图。您需要对发件人进行类型转换才能访问视图,因为发件人已装箱为对象类型。
否则,您可以使用 DataTemplate 选择器根据您的对象创建视图。
你也可以这样投:
ITemplatedItemsView<Cell> templatedItemsView = listView as ITemplatedItemsView<Cell>;
ViewCell firstCell = templatedItemsView.TemplatedItems[0] as ViewCell;
StackLayout stackLayout = firstCell.View as StackLayout;
哪个会给你参考意见
但您可能希望根据绑定上下文的变化做出反应,否则您将不得不手动更改视图的内容。
我怀疑使用 BindingContextChanged
会让您渲染内容两次 - 首先,更改会导致像正常一样渲染 - 然后再渲染一次。因此,例如,如果字符串发生变化 - 标签将重新呈现 - 之后您将获得 BindingContextChanged 中的值并执行您真正想要的呈现。
您可以将 ListView 子类化,我认为这会阻止它:
public class CustomListView : ListView
{
protected override void SetupContent(Cell content, int index)
{
// render differently depending on content.BindingContext
base.SetupContent(content, index);
}
}
我想知道是否有办法在 Xamarin.Forms 的 ListView 中获取对 DataTemplate 内视图的引用。 假设我有这个 xaml:
<ListView x:Name="ProductList" ItemsSource="{Binding Products}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee" x:Name="ProductStackLayout"
Orientation="Vertical" Padding="5" Tapped="ListItemTapped">
<Label Text="{Binding Name}"
Style="{DynamicResource ProductPropertiesStyle}"/>
<Label Text="{Binding Notes}" IsVisible="{Binding HasNotes}"
Style="{DynamicResource NotesStyle}"
/>
<Label Text="{Binding Date}"
Style="{DynamicResource DateStyle}"
/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
我希望能够在 ListView 的每一行中获取对名为 "ProductStackLayout" 的 StackLayout 的引用。我需要在页面出现时执行此操作,以动态操作它的内容(对于数据绑定无法实现的内容),因此我无法利用在源自 DataTemplate 中的元素的事件处理程序中传递的视图引用本身就像 ItemTapped 或类似的。
据我所知,在 WPF 或 UWP 中,借助 VisualTreeHelper class 可以实现类似的功能,但我不相信在 class Xamarin.Forms.
是的,可以在 run-time 中访问使用 DataTemplate
创建的视图。为来自 XAML 的 DataTemplate
内的视图挂钩 BindingContextChanged
事件。在事件回调中,可以使用 sender 参数访问从 DataTemplate
创建的视图。您需要对发件人进行类型转换才能访问视图,因为发件人已装箱为对象类型。
否则,您可以使用 DataTemplate 选择器根据您的对象创建视图。
你也可以这样投:
ITemplatedItemsView<Cell> templatedItemsView = listView as ITemplatedItemsView<Cell>;
ViewCell firstCell = templatedItemsView.TemplatedItems[0] as ViewCell;
StackLayout stackLayout = firstCell.View as StackLayout;
哪个会给你参考意见
但您可能希望根据绑定上下文的变化做出反应,否则您将不得不手动更改视图的内容。
我怀疑使用 BindingContextChanged
会让您渲染内容两次 - 首先,更改会导致像正常一样渲染 - 然后再渲染一次。因此,例如,如果字符串发生变化 - 标签将重新呈现 - 之后您将获得 BindingContextChanged 中的值并执行您真正想要的呈现。
您可以将 ListView 子类化,我认为这会阻止它:
public class CustomListView : ListView
{
protected override void SetupContent(Cell content, int index)
{
// render differently depending on content.BindingContext
base.SetupContent(content, index);
}
}