在子元素更改时更改 ListView.ItemTemplate

发布于 2024-12-27 18:00:48 字数 1235 浏览 1 评论 0原文

假设我们有一个简单的数据类:

public class Ex {
    public string Prop1 {...} // notify property
    public string Prop2 {...} // notify property
}

以及该类对象的 ObservableCollection。我希望将此集合显示在具有单独 DataTemplated 的 ListView 中,该 DataTemplated 由 Ex.Prop2 区分(如果为 null 或空,则使用 template01,否则使用 template02)。此属性可以在运行时更改,因此使用 ListView.ItemTemplateSelector 的简单“技巧”不起作用:(

如何实现此功能? 除了在集合的每个对象上侦听 NotifyPropertyChanged 并手动更改之外,是否可以通过任何其他方式来实现它模板?

谢谢你的帮助,

我已经有了下面的代码:

<ListView x:Name="lstTerms"
    ItemsSource="{Binding Game.Words}"
    HorizontalContentAlignment="Stretch"
    Grid.IsSharedSizeScope="True">
    <ListView.ItemContainerStyle>
        <Style>
            <Setter Property="Control.Padding" Value="0" />
        </Style>
    </ListView.ItemContainerStyle>

    <!-- checks if element is null or its Prop2 is null or empty. If so, uses NullTemplate -->
    <ListView.ItemTemplateSelector>
        <local:MySelectTemplate
            NormalTemplate="{StaticResource NormalItemTemplate}"
            NullTemplate="{StaticResource NullItemTemplate}" />
    </ListView.ItemTemplateSelector>
</ListView>

let's say we have simple data class:

public class Ex {
    public string Prop1 {...} // notify property
    public string Prop2 {...} // notify property
}

and an ObservableCollection of objects of this class. I want to have this collection displayed in a ListView with seperated DataTemplated which is distinguished by Ex.Prop2 (if it is null or empty then template01 is used, otherwise template02). This property can be changed in runtime so simple "trick" with ListView.ItemTemplateSelector does not work :(

How to achieve this functionality? Is it possible to achieve it any other way than listening to NotifyPropertyChanged on each object of the collection and than changing manually the template?

Thanks for your help.

Below piece of code which I already have:

<ListView x:Name="lstTerms"
    ItemsSource="{Binding Game.Words}"
    HorizontalContentAlignment="Stretch"
    Grid.IsSharedSizeScope="True">
    <ListView.ItemContainerStyle>
        <Style>
            <Setter Property="Control.Padding" Value="0" />
        </Style>
    </ListView.ItemContainerStyle>

    <!-- checks if element is null or its Prop2 is null or empty. If so, uses NullTemplate -->
    <ListView.ItemTemplateSelector>
        <local:MySelectTemplate
            NormalTemplate="{StaticResource NormalItemTemplate}"
            NullTemplate="{StaticResource NullItemTemplate}" />
    </ListView.ItemTemplateSelector>
</ListView>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

岁月蹉跎了容颜 2025-01-03 18:00:49

您可以使用包含两个网格的单个 DataTemplate,而不是使用 TemplateSelector,这两个网格根据属性值切换可见性。

这是一个示例:

<ListView.ItemTemplate>
    <DataTemplate>
        <Grid>
            <Grid Background="LightBlue" Name="normalGrid">
                <Grid.Style>
                    <Style>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Path=Prop1}" Value="{x:Null}">
                                <Setter Property="Grid.Visibility" Value="Hidden"></Setter>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Grid.Style>
                <TextBlock Text="{Binding Prop1}"></TextBlock>
            </Grid>
            <Grid Background="Green" Name="nullGrid">
                <Grid.Style>
                    <Style>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ElementName=normalGrid, Path=Visibility}" Value="Visible">
                                <Setter Property="Grid.Visibility" Value="Hidden"></Setter>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Grid.Style>
                <TextBlock Text="{Binding Prop2}"></TextBlock>
            </Grid>
        </Grid>
    </DataTemplate>
</ListView.ItemTemplate>

显然,您可以将 TextBlock 元素替换为代表两个 DataTemplate 的 UserControls。

如果需要,您还可以通过将 Grid.Visibility 绑定到 ViewModel 上的属性(例如,命名为 IsVisible)并使用 VisibilityConverter 来消除对庞大样式的需求。

Instead of using a TemplateSelector, you can have a single DataTemplate containing two Grids, which switch visibility dependent on the property values.

Here is an example:

<ListView.ItemTemplate>
    <DataTemplate>
        <Grid>
            <Grid Background="LightBlue" Name="normalGrid">
                <Grid.Style>
                    <Style>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Path=Prop1}" Value="{x:Null}">
                                <Setter Property="Grid.Visibility" Value="Hidden"></Setter>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Grid.Style>
                <TextBlock Text="{Binding Prop1}"></TextBlock>
            </Grid>
            <Grid Background="Green" Name="nullGrid">
                <Grid.Style>
                    <Style>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ElementName=normalGrid, Path=Visibility}" Value="Visible">
                                <Setter Property="Grid.Visibility" Value="Hidden"></Setter>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Grid.Style>
                <TextBlock Text="{Binding Prop2}"></TextBlock>
            </Grid>
        </Grid>
    </DataTemplate>
</ListView.ItemTemplate>

Obviously you could replace the TextBlock elements with UserControls representing your two DataTemplates.

If you want, you can also remove the need for the bulky Styles by binding Grid.Visibility to a property (named, for example, IsVisible) on your ViewModel and using a VisibilityConverter.

孤城病女 2025-01-03 18:00:49

我通常只使用 ContentControl,它根据 DataTrigger 更改其 ContentTemplate。 DataTriggers 响应值的更改,而 DataTemplateSelectors 则不响应。

<Style x:Key="SomeStyleKey" TargetType="{x:Type ContentControl}">
    <Setter Property="ContentTemplate" Value="{StaticResource DefaultTemplate}" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding Prop2}" Value="{x:Null}">
            <Setter Property="ContentTemplate" Value="{StaticResource NullTemplate}" />
        </DataTrigger>
        <DataTrigger Binding="{Binding Prop2}" Value="">
            <Setter Property="ContentTemplate" Value="{StaticResource NullTemplate}" />
        </DataTrigger>
    </Style.Triggers>
</Style>

...

<ListView.ItemTemplate>
    <DataTemplate>
        <ContentControl Style="{StaticResource SomeStyleKey}" />
    </DataTemplate>
</ListView.ItemTemplate>

如果需要,您还可以使用返回 String.IsNullOrEmpty(value)Converter单个DataTrigger

I usually just use a ContentControl which changes its ContentTemplate based on a DataTrigger. DataTriggers respond to the value getting changed, while DataTemplateSelectors do not

<Style x:Key="SomeStyleKey" TargetType="{x:Type ContentControl}">
    <Setter Property="ContentTemplate" Value="{StaticResource DefaultTemplate}" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding Prop2}" Value="{x:Null}">
            <Setter Property="ContentTemplate" Value="{StaticResource NullTemplate}" />
        </DataTrigger>
        <DataTrigger Binding="{Binding Prop2}" Value="">
            <Setter Property="ContentTemplate" Value="{StaticResource NullTemplate}" />
        </DataTrigger>
    </Style.Triggers>
</Style>

...

<ListView.ItemTemplate>
    <DataTemplate>
        <ContentControl Style="{StaticResource SomeStyleKey}" />
    </DataTemplate>
</ListView.ItemTemplate>

You could also use a Converter that returns String.IsNullOrEmpty(value) if you wanted a single DataTrigger

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文