【问题标题】:How do I attach an eventHandler for GridViewColumnHeader.Click with Caliburn Micro?如何使用 Caliburn Micro 为 GridViewColumnHeader.Click 附加事件处理程序?
【发布时间】:2015-05-21 09:13:52
【问题描述】:

我有一个带有 GridView 的 ListView 作为视图,它按照约定绑定到我的 ViewModel 的 Instances 属性:

<ListView Name="Instances">
  <ListView.View>
    <GridView>
      <GridViewColumn DisplayMemberBinding="{Binding Property}"
                      Header="Property"/>
    </GridView>
  </ListView.View>
</ListView>

现在我需要在单击 GridViewColumnHeader 时触发 ViewModel 上的一些方法。

我尝试过这样增强 GridViewColumn

<ListView Name="Instances"
          cal:Message.Attach="[Event GridViewColumnHeader.Click] = [Action Foo()]">
  <!-- the rest stays unchanged -->
</ListView>

我什至试着像这样玩弄 ColumnHeaderContainerStyle

<GridView>
  <GridView.ColumnHeaderContainerStyle>
    <Style TargetType="GridViewColumnHeader">
      <EventSetter Event="Click">
        <cal:ActionMessage MethodName="Foo"/>
        <!-- does not compile -->
      </EventSetter>
    </Style>
  </GridView.ColumnHeaderContainerStyle>
</GridView>

这显然不起作用。

如何使用 Caliburn Micro 将 ViewModel 中的方法(而不是具有绑定的命令)连接到附加事件(以更一般的方式询问)?

【问题讨论】:

  • 如果可以的话,你真的必须通过VM 来做吗?我正在使用GridView 为我的ListView 创建排序,并且只使用代码隐藏进行排序。它节省了很多时间和麻烦。这仅适用于您需要进行排序的情况。您的示例看起来像是在排序完成后显示了一些信息。这只是一个建议 HTH
  • @XAMlMAX 绝对,...因为我需要应用 propertyInfo(从绑定中获取)对数据库进行新查询(具有正确的排序),因为我们只显示完整的摘录数据集。否则排序将是错误的......
  • 好的,那么在这种情况下你怎么能不使用简单的DrillDownCommand 来使用呢?您可以使用绑定并将数据传递给您的命令方法,并执行您需要执行的操作。除非我在这里遗漏了一些关键约束? BTW DrillDownCommand 基本上会调用你的 Foo() 方法。
  • @XAMlMAX 您能否提供一个示例作为答案?我想尽可能减少混乱,以尽可能严格地坚持 Caliburn Micro 实践。
  • @XAMlMAX 时间目前不在我这边 - 我稍后会检查 :)

标签: wpf events caliburn.micro attached-properties


【解决方案1】:

我已经按照@XAMIMAX 的建议解决了这个问题:

<GridView.ColumnHeaderTemplate>
  <DataTemplate>
    <Button Content="{Binding}"
            BorderBrush="Transparent"
            Background="Transparent"
            cal:Message.Attach="[Event Click] = [Action Foo($this)]">
      <Button.Template>
        <ControlTemplate TargetType="Button">
          <ContentPresenter />
        </ControlTemplate>
      </Button.Template>
    </Button>
  </DataTemplate>
</GridView.ColumnHeaderTemplate>

这会在 ViewModel 上触发 Foo 并将 {Binding}(在我的例子中:属性名称)传递给它。

【讨论】:

  • 你知道我还想到了什么吗,我认为你最初的方法不起作用的原因是因为默认情况下用于GridViewColumnHeader 的模板是TextBlock,但要让它工作您需要包含 Blend SDK 中的 interaction 以连接事件和命令。 HTH
  • @XAMlMAX 更进一步地思考:GridViewColumnHeader.Click 的实际发件人是什么?我相信那是实际的GridViewColumnHeader,因此应该有一种方法可以附加到它的点击事件...
  • 当我找到一些时间时,我会创建一个包含所有详细信息的答案。工作有点忙。
  • 这种方式的问题是,只有直接点击文本才会触发点击。您需要通过创建这样的 ColumnHeaderContainerStyle 将按钮拉伸到标题上:&lt;GridView.ColumnHeaderContainerStyle&gt; &lt;Style TargetType="GridViewColumnHeader"&gt; &lt;Setter Property="HorizontalContentAlignment" Value="Stretch"/&gt; &lt;Setter Property="VerticalContentAlignment" Value="Stretch"/&gt; &lt;/Style&gt; &lt;/GridView.ColumnHeaderContainerStyle&gt;
【解决方案2】:

我找到了this 解释校准的文章,我以前从未使用过校准,所以我不得不做一些研究。
这就是本文以另一种方式呈现Binding 的方式。

<TextBox x:Name="Name" />
<Button Content="Save"> 
    <i:Interaction.Triggers> 
        <i:EventTrigger EventName="Click"> 
            <cal:ActionMessage MethodName="Save"> 
               <cal:Parameter Value="{Binding ElementName=Name, Path=Text}" /> 
            </cal:ActionMessage> 
        </i:EventTrigger> 
    </i:Interaction.Triggers> 
</Button> 

地点:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
xmlns:cal="http://www.caliburnproject.org"

为了让您在应用程序中继续使用TextBlock,您必须像这样创建GridViewColumnHeader 的显式定义:

<DataTemplate>
<!-- Without the Calibrum micro -->
    <TextBlock Text="Test">
       <TextBlock.InputBindings>
          <MouseBinding MouseAction="LeftClick" Command="{Binding TestCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=TextBlock}, Path=Text}"/>
       </TextBlock.InputBindings>
    </TextBlock>
<!-- With Calibrum Micro -->
    <TextBlock>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="LeftClick">
                <cal:ActionMessage MethodName="Save">
                    <cal:Parameter Value="{Binding ElementName=Name, Path=Text}" /> 
                </cal:ActionMessage> 
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBlock>
</DataTemplate>

现在这只是基于我从互联网上收集的材料,我无法在工作时对其进行测试。
但是,如果这不起作用,应该让您了解如何克服开发中的一些困难。
编辑:
并回答您的问题:
GridViewColumnHeader Template 替换为DataTemplate 的显式定义并使用一个按钮,以便您可以附加到Click 事件,或者您可以像示例中一样使用TextBlock,以避免不必要的开销使用Button
编辑
经过一些研究后,我可以得出结论,在您的视图模型上使用这些方法既简单又有趣 :-)。
看看我的工作 ListView:

<ListView>
<ListView.View>
    <GridView>
        <GridView.ColumnHeaderTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="MouseDown">
                            <ei:CallMethodAction MethodName="TestPublicMethod" TargetObject="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext}"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </TextBlock>
            </DataTemplate>
        </GridView.ColumnHeaderTemplate>
        <GridViewColumn Header="Example Header"/>
    </GridView>
</ListView.View>
<ListViewItem>
    <StackPanel Orientation="Horizontal">
        <TextBlock>
            normal text with a lot of characters
        </TextBlock>
        <Rectangle Width="20" Height="20" Fill="Red"/>
    </StackPanel>
</ListViewItem>

以及视图模型(消息是 INPC 的一个属性):

#region Public Methods

public void TestPublicMethod() { Message = "You have just invoked a public method !!!."; }

#endregion
其中:

xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"  

抱歉格式不佳,但编辑不想在星期一早上工作:-p。
因为TextBlock 将只使用所需的最小空间,你可以使用这个肮脏的技巧让它伸展到列标题的宽度:

Width="{Binding RelativeSource={RelativeSource AncestorType=GridViewColumnHeader}, Path=ActualWidth}"

【讨论】:

  • 不幸的是:EventTrigger 类型不支持直接内容。另外:您是否故意忘记了Text="{Binding}"?并且TextBlock 不会在整个列中拉伸,因此单击它可能会有点挑战:)
猜你喜欢
  • 1970-01-01
  • 2019-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-19
  • 1970-01-01
相关资源
最近更新 更多