WPF:当某个值更改时重新应用DataTemplateSelector

Nic*_*ick 27 c# wpf binding datatemplateselector

所以这是我拥有的XAML:

<ItemsControl ItemsSource="{Binding Path=Groups}" ItemTemplateSelector="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=ListTemplateSelector}"/>
Run Code Online (Sandbox Code Playgroud)

这是我的ListTemplateSelector类:

public class ListTemplateSelector : DataTemplateSelector {
public DataTemplate GroupTemplate { get; set; }
public DataTemplate ItemTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container) {
    GroupList<Person> list = item as GroupList<Person>;
    if (list != null && !list.IsLeaf)
        return GroupTemplate;
    return ItemTemplate;
}
}
Run Code Online (Sandbox Code Playgroud)

GroupTemplate数据模板本身引用了ListTemplateSelector,所以这就是我设置的原因.这是我可以放在一起的唯一递归黑客.但这不是我遇到的问题.

我的问题是,我想在IsLeaf属性更改时从ItemTemplate更改为GroupTemplate.这是第一次读取房产以来的第一次.但是一旦此属性更改,模板选择器就不会重新应用.现在,我可以使用触发器绑定到值并适当地设置项目模板,但我需要能够为每个项目设置不同的模板,因为它们可能处于不同的状态.

例如,假设我有一个像这样的组列表:

第1组:IsLeaf = false,因此template = GroupTemplate

第2组:IsLeaf = true,因此template = ItemTemplate

第3组:IsLeaf = false,因此template = GroupTemplate

一旦组1的IsLeaf属性更改为true,模板就需要自动更改为ItemTemplate.

编辑:

这是我的临时解决方案.有更好的方法吗?

<ItemsControl ItemsSource="{Binding Path=Groups}">
<ItemsControl.ItemTemplate>
    <DataTemplate>
        <ContentControl Content="{Binding}">
            <ContentControl.Style>
                <Style TargetType="{x:Type ContentControl}">
                    <Setter Property="ContentTemplate" Value="{DynamicResource ItemTemplate}"/>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=IsLeaf}" Value="False">
                            <Setter Property="ContentTemplate" Value="{DynamicResource GroupTemplate}"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ContentControl.Style>
        </ContentControl>
    </DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Run Code Online (Sandbox Code Playgroud)

ASa*_*nch 22

关于你的编辑,DataTemplate Trigger不是足够而不是使用Style?那是:

<ItemsControl ItemsSource="{Binding Path=Groups}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentControl x:Name="cc" Content="{Binding}" ContentTemplate="{DynamicResource ItemTemplate}"/>

            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=IsLeaf}" Value="False">
                    <Setter TargetName="cc" Property="ContentTemplate" Value="{DynamicResource GroupTemplate}"/>
                </DataTrigger>
            </DataTemplate.Triggers>

        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
Run Code Online (Sandbox Code Playgroud)

  • DataTemplateSelectors需要进行改进,以便它们允许这种情况,因为这个解决方案虽然是必要的,但却是一种更加丑陋的语法.希望WPF团队能够解决这个问题 (9认同)

Jas*_*ran 21

我发现这种解决方法对我来说似乎更容易.从TemplateSelector中听取您关心的属性,然后重新应用模板选择器以强制刷新.

public class DataSourceTemplateSelector : DataTemplateSelector
{

    public DataTemplate IA { get; set; }
    public DataTemplate Dispatcher { get; set; }
    public DataTemplate Sql { get; set; }

    public override DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
    {
        var ds = item as DataLocationViewModel;
        if (ds == null)
        {
            return base.SelectTemplate(item, container);
        }
      PropertyChangedEventHandler lambda = null;
        lambda = (o, args) =>
            {
                if (args.PropertyName == "SelectedDataSourceType")
                {
                    ds.PropertyChanged -= lambda;
                    var cp = (ContentPresenter)container;
                    cp.ContentTemplateSelector = null;
                    cp.ContentTemplateSelector = this;                        
                }
            };
        ds.PropertyChanged += lambda;

        switch (ds.SelectedDataSourceType.Value)
        {
            case DataSourceType.Dispatcher:
                return Dispatcher;
            case DataSourceType.IA:
                return IA;
            case DataSourceType.Sql:
                return Sql;
            default:
                throw new NotImplementedException(ds.SelectedDataSourceType.Value.ToString());
        }
    }


}
Run Code Online (Sandbox Code Playgroud)

  • 小心这段代码 - 在实现这个作为我自己的模板切换情况的解决方案并注意到性能下降后发现由于切换时涉及的DataTemplate的大小导致大量内存泄漏的调查 - 更好的想法使用DataTriggers方法似乎根本没有泄漏. (2认同)
  • @toadflakz Mem泄漏可能是由于(或者增加)这个lambda被分配给ItemsSource中每个项目的属性一次,因此将重复运行 - 每次强制刷新.也许只是应用它一次会有更好的表现? (2认同)