【问题标题】:Datatrigger on contentpresenter.content not workingcontentpresenter.content 上的数据触发器不起作用
【发布时间】:2012-03-10 16:32:44
【问题描述】:

我正在尝试基于 datatrigger 切换 contentpresenter 的内容。我想在 contentpresenter.content 中显示一个用户控件,如果我设置了值,否则我需要显示错误消息。但是绑定我的数据触发器失败,说明找不到该属性。我无法让数据上下文继承以进行数据触发器检查。我可以使用注释掉的代码使其工作。但我很困惑为什么它不能正常工作。

  <ContentPresenter.Style>
            <Style TargetType="{x:Type ContentPresenter}">
                  <Setter Property="Content" Value="{Binding UC}"/>
                <Style.Triggers>
                    <!--<DataTrigger Binding="{Binding DataContext.HasValue,RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}" Value="false">
                        <Setter Property="Content" Value="No preview"/>
                    </DataTrigger>-->
                    <DataTrigger Binding="{Binding HasValue}" Value="false">
                        <Setter Property="Content" Value="No value"/>
                    </DataTrigger> 

                </Style.Triggers> 

            </Style>
        </ContentPresenter.Style>
    </ContentPresenter>

【问题讨论】:

    标签: wpf datatrigger


    【解决方案1】:

    我一般都是这样用触发器的……

                            <UserControl>
                                <UserControl.Resources>
                                    <DataTemplate x:Key="normalTemplate" >
                                         <!-Fav UserControl->
                                    </DataTemplate >
                                    <DataTemplate x:Key="overWriteTempalte">
                                        <!-Fav UserControl->                                    </DataTemplate>
                                </UserControl.Resources>
                                <ContentPresenter x:Name="ContentField"
                                                  Content="{Binding}"
                                                  ContentTemplate="{StaticResource ResourceKey=normalTemplate}" />
                                <UserControl.Triggers>
                                    <DataTrigger Binding="{Binding Path=MyProperty}" Value="True">
                                        <Setter TargetName="ContentField" Property="ContentTemplate" Value="{StaticResource ResourceKey=overWriteTempalte}" />
                                    </DataTrigger>
                                </UserControl.Triggers>
                            </UserControl>
    

    如果绑定有问题,请使用 Snoop 检测绑定错误

    【讨论】:

    • 这是错误的。 UserControl 上的触发器必须是 EventTrigger 类型。
    • @IAbstract 无法通过提供类型来完成用户控件的绑定...需要在用户控件实例中声明静态资源,然后将其绑定为内容将起作用。 Joe - 由于此用户控件基于视图模型绑定显示为内容演示者的内容,因此将使用数据触发器....当您希望基于 UserControl 属性显示时使用事件触发器
    【解决方案2】:

    如果你想使用触发器来显示 UserControl,你应该使用 ContentControl 而不是 ContentPresenter。 我更喜欢将 ContentPresenter 用于 CustomControls,当我使用 UserControl 来查看系统中的自定义数据类型并允许提供动态行为时。

    示例:要为 ContentPresenter 切换模板,您需要像这样设置 ContentTemplateSelector

    <ContentPresenter Content="{Binding MyContent}"
                              ContentTemplate="{Binding MyContentTemplate}"
                              ContentTemplateSelector="{Binding MyContentTemplateSelector}"/>
    

    MyContent、MyContentTemplate 和 MyContentTemplateSelector 是依赖属性,可以在任何使用它的实例的地方绑定。

    阅读

    Usage of ContentPresenter

    What is the difference between ContentControl and ContentPresenter

    问题中提到的绑定不起作用

    ContentPresenter 的 DataContext 自动设置为 它的 Content 属性,而 ContentControl 的 DataContext 不是。

    绑定相对于 DataContext 属性的值进行解析。如果您在 ContentPresenter 上声明绑定,则在设置其内容的那一刻,绑定将被重新评估。

    ContentControl.Content 属性可以根据您的要求在任何触发器上更改。如果您想使用它来更改 ViewModel 的属性的 PropertyChanged 事件,可以通过将 DataTrigger 与其中带有 UserControl 实例的 DataTemplate 绑定或使用该 UserControl 的静态资源来使用 DataTrigger。

    <ContentControl>
        <ContentControl.Style>
            <Style TargetType="{x:Type ContentControl}">
                <Setter Value="{StaticResource UnSelectedDataTemplate}" Property="ContentTemplate" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=IsSelected}" Value="True">
                        <Setter Value="{StaticResource SelectedDataTemplate}" Property="ContentTemplate" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ContentContro.Style>
    </ContentControl>
    

    阅读How to use triggers for content template,更多详情here

    DataTemplate 和 StaticResource 范围的区别在于,DataTemplate 每次应用模板时都会创建一个新的模板实例。 然而,StaticResource 再次使用 UserControl 的相同实例(静态实例)。 您还可以使用 EventTriggers 来更改内容库,例如 MouseOver 等控制事件。

    替代方法
    与上述非常相似,略有不同。在资源中定义为数据模板。内容更改的触发本质上是相同的。

    ...在&lt;x.Resources /&gt; 标签中:

    <DataTemplate x:Key="DesignerTemplate" DataType="{x:Type vm:SolutionViewModel}">
        <vw:SolutionDesignerView />
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:SolutionViewModel}">
        <ContentControl Content="{Binding }">
            <ContentControl.Style>
                <Style TargetType="{x:Type ContentControl}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsLoaded}" Value="True">
                            <Setter Property="ContentTemplate" Value="{StaticResource DesignerTemplate}" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ContentControl.Style>
        </ContentControl>
    </DataTemplate>
    

    ...然后:

    <ContentControl Content="{Binding Solution}" />  
    

    【讨论】:

    • 我想出了编码解决方案。你在这里提供了一些很好的信息。我可以将示例粘贴到您的答案中,您可以进行编辑和修改。这将奖励你赏金和可能的一些赞成票。
    • 当然,你可以添加它..我也在添加一些信息..谢谢你的赏金
    • 赏金奖励窗口在 24 小时内不会打开。
    • @IAbstract 没问题 :)
    • 直接解决 OP 的问题 - {Binding HasValue} 触发器不起作用,因为 ContentPresenter.DataContext 设置为 ContentPresenter.Content 的任何值。因此,一旦将内容设置为ViewModel.UC 值,它就会尝试寻找UC.HasValue 而不是ViewModel.HasValue,并且可以理解地失败了。出于同样的原因,相对源方法有效。可以在您提供的第一个链接下找到此信息,但我认为在您的回答中明确指出它会很有用。
    猜你喜欢
    • 2011-01-26
    • 2013-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-05
    • 2020-08-10
    • 1970-01-01
    相关资源
    最近更新 更多