【问题标题】:Can not change template of ContentControl from style's datatrigger - datatrigger not firing无法从样式的数据触发器更改 ContentControl 的模板 - 数据触发器未触发
【发布时间】:2014-05-19 06:07:51
【问题描述】:

您好 WPF 爱好者,

我在用户控件中有一个内容控件,它将数据上下文设置为同一用户控件中列表视图的选定项。视图模型上的选定项属性称为 Selection

这是内容控件的声明:

<ContentControl DataContext="{Binding Selection}">
    <ContentControl.Style>
        <Style TargetType="ContentControl">
            <Setter Property="Template"  Value="{StaticResource JobSnapShotProgDetail}"/>                            
            <Style.Triggers>
                <DataTrigger Binding="{Binding bTandM}" Value="1">
                    <Setter Property="Template" Value="{StaticResource JobSnapShotProgDetail}"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding bTandM}" Value="0">
                    <Setter Property="Template" Value="{StaticResource JobSnapShotTM_Detail}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>                        
    </ContentControl.Style>
</ContentControl> 

模板在另一个资源文件中定义为 ControlTemplates,例如:

 <ControlTemplate x:Key="JobSnapShotProgDetail" >
     ...
 </ControlTemplate >
 <ControlTemplate x:Key="JobSnapShotTM_Detail" >
     ...
 </ControlTemplate >

绑定很有效,意味着模板的字段都显示来自 Selection 对象的正确数据。

我的问题:

我希望内容控件根据选择的 bTandM 属性的值使用两个不同的控件模板之一。

现在发生了什么:

当我更改列表视图的选择时,会更改 Selection 对象,模板不会根据 Selection 的 bTandM 属性的值(一个 sql服务器位数据类型)。是的,Selection 对象实现了 iNotifyPropertyChanged,并且绑定到 Selection 的 属性的 ControlTemplate 字段都在输出窗口中显示正确的数据而没有任何绑定错误。

我尝试了什么:

数据触发器似乎没有被代码“命中”。我试图通过添加 foo 而不是应该无法转换的数字来破坏数据触发器,但不会产生错误。即:

 <DataTrigger Binding="{Binding bTandM}" Value="foo">

这让我相信触发器由于某种原因没有触发。

问题:

谁能帮我弄清楚为什么这个数据触发器没有效果。

提前致谢

JK


编辑 1:

我尝试使用HERE 发现的技术,但它也不起作用。数据触发器没有被触发。

将 DataTemplate 与针对内容控件模板属性的 DataTrigger 一起使用的新尝试:

<ItemsControl ItemsSource="{Binding SelectionCollection}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentControl x:Name="DetailControl" Template="{DynamicResource JobSnapShotProgDetail}" />
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding bTandM}" Value="False">
                    <Setter TargetName="DetailControl" Property="Template" Value="{DynamicResource JobSnapShotProgDetail}" />
                </DataTrigger>
                <DataTrigger Binding="{Binding bTandM}" Value="1">
                    <Setter TargetName="DetailControl" Property="Template" Value="{DynamicResource JobSnapShotTM_Detail}" />
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

同样,模板加载正常,并且在样式设置器中设置的初始模板的属性正确显示,但模板不会根据对象的 bTandM 布尔属性更改。

【问题讨论】:

  • 这似乎是正确的...只是一个愚蠢的问题..您是否正确地从您的 VM 中为 Selection 属性提高 PropertyChanged?
  • 您可以尝试使用 ContentTemplate 而不是 Template 吗?
  • @nit 是的 PropertyChanged 已使用并正在工作,因为依赖于此的其他 UI 更新正在工作
  • @GazTheDestroyer,我无法使用 contentTemplate,因为在样式设置器中出现转换错误:“System.Windows.Controls.ControlTemplate”不是“System.Windows.Controls”的有效值。 Setter 上的 ContentControl.ContentTemplate' 属性。
  • @JKing,您需要使用 DataTemplate 而不是 ControlTemplate

标签: wpf xaml mvvm


【解决方案1】:

好的,结果证明这是 NotifyPropertyChanged 的​​问题。

我的视图模型的选择属性确实实现了 INPC,但问题是底层类类型 (vw_Job_Snapshot 这是一个来自 sql server 视图的映射实体) 的选择没有。

我必须在底层类中实现 iNPC,然后在我的视图模型中使用选择属性的属性设置器来通知特定的 bTandM 属性更改,如下所示:

    Public Property Selection As vw_Job_Snapshot
        Get
            Return Me._Selection
        End Get
        Set(ByVal value As vw_Job_Snapshot)
            Me._Selection = value

            ''Notify of specific property changed
            value.OnPropertyChanged("bTandM")

            _Selection = value
            RaisePropertyChanged(JobSnapshotSelectedPropertyName)
        End Set
    End Property

在此之后,我认为以下代码运行良好:

<ContentControl DataContext="{Binding Selection}">
    <ContentControl.Style>
        <Style TargetType="ContentControl">
            <Setter Property="Template"  Value="{DynamicResource JobSnapShotTM_Detail}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding bTandM}" Value="False">
                    <Setter Property="Template" Value="{DynamicResource JobSnapShotProgDetail}"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding bTandM}" Value="True">
                    <Setter Property="Template" Value="{DynamicResource JobSnapShotTM_Detail}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ContentControl.Style>
</ContentControl>

感谢所有帮助过的人

【讨论】:

    【解决方案2】:

    尝试改用DataTemplateSelector

    你的选择器看起来像这样(我假设你的类叫做 JobSnapShot):

    public class JobSnapShotDataTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            FrameworkElement element = container as FrameworkElement;
    
            if (element != null && item != null && item is JobSnapShot)
            {
                JobSnapShot jobSnapShot = item as JobSnapShot;
    
                if (jobSnapShot.bTandM == 1)
                    return
                        element.FindResource("JobSnapShotProgDetail") as DataTemplate;
                else
                    return
                        element.FindResource("JobSnapShotTM_Detail") as DataTemplate;
            }
    
            return null;
        }
    }
    

    XAML:

    <Window.Resources>
        <local:JobSnapShotDataTemplateSelector x:Key="myDataTemplateSelector"/>
    </Window.Resources>
    
    
    
    <ContentControl ItemTemplateSelector="{StaticResource myDataTemplateSelector}" .... />
    

    【讨论】:

    • 感谢 Eirik,我希望在使用 MVVM 时避免使用 DataTemplateSelector,它会使视图视图模型关系复杂化。我知道这很有效,可能最终不得不使用它,但我希望有一个“纯”的 xaml 解决方案。
    猜你喜欢
    • 1970-01-01
    • 2011-09-20
    • 2016-02-06
    • 2018-08-06
    • 1970-01-01
    • 1970-01-01
    • 2010-11-14
    • 2013-06-14
    • 2016-06-18
    相关资源
    最近更新 更多