WPF:使用按钮作为DataTemplate,如何添加click事件

时间:2010-07-19 15:26:15

标签: wpf button eventsetter

我有一个带有对象集合的ItemsControl。我无法点击该对象,然后获得包含更多信息的面板。

所以我决定将ItemsControl中的项目的DataTemplate设置为按钮样式,这似乎工作正常。但是我不知道如何在样式中设置此按钮的click事件。它说我应该使用EventSetter,但我不能让它工作。

以下是代码:

  <Style TargetType="Expander" >
            <Style.Resources>
                <Style TargetType="ItemsControl" >
                    <Setter Property="Template" >
                        <Setter.Value>
                            <ControlTemplate TargetType="ItemsControl">
                                <Border BorderThickness="0,1,0,1" BorderBrush="{StaticResource DarkColorBrush}" >
                                    <ScrollViewer Margin="0" VerticalScrollBarVisibility="Auto"
                                                  Focusable="false">
                                        <StackPanel Margin="2" IsItemsHost="True" />
                                    </ScrollViewer>
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="ItemTemplate" >
                        <Setter.Value>
                            <DataTemplate DataType="{x:Type data:CompanyViewModel}" >
                                <Button>
                                    <Button.Resources>
                                        <Style TargetType="Button">
                                            <Setter Property="Template">
                                                <Setter.Value>
                                                    <ControlTemplate TargetType="Button">
                                                        <Border Name="Bd" BorderBrush="{StaticResource DarkColorBrush}"
                                                                BorderThickness="1"
                                                                Margin="5"
                                                                CornerRadius="8">

                                                            <Border.Background>
                                                                <!-- Removed for brevity -->
                                                            </Border.Background>

                                                            <StackPanel Orientation="Vertical">
                                                                <TextBlock Margin="5" Text="{Binding Path=Name}" Style="{StaticResource MenuText}" FontSize="16" HorizontalAlignment="Center" />
                                                                <TextBlock Margin="5,0,5,5" Text="{Binding Path=Code, StringFormat=Kt. {0}}" Style="{StaticResource MenuText}" HorizontalAlignment="Center" />
                                                            </StackPanel>
                                                        </Border>

                                                        <ControlTemplate.Triggers>
                                                            <Trigger Property="IsMouseOver" Value="true">
                                                                <Setter TargetName="Bd" Property="Background">
                                                                    <Setter.Value>
                                                                        <!-- Removed for brevity -->
                                                                    </Setter.Value>
                                                                </Setter>
                                                            </Trigger>
                                                            <Trigger Property="Button.IsPressed" Value="true">
                                                                <Setter TargetName="Bd" Property="Background">
                                                                    <Setter.Value>
                                                                        <!-- Removed for brevity -->
                                                                    </Setter.Value>
                                                                </Setter>
                                                            </Trigger>
                                                        </ControlTemplate.Triggers>
                                                    </ControlTemplate>
                                                </Setter.Value>
                                            </Setter>
                                        </Style>
                                    </Button.Resources>
                                </Button>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Style.Resources>
            <Setter Property="Template" >
                <Setter.Value>
                    <ControlTemplate TargetType="Expander">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="30" />
                            </Grid.ColumnDefinitions>
                            <ToggleButton Grid.Column="1"
                                          IsChecked="{Binding Path=IsExpanded,Mode=TwoWay,
                                          RelativeSource={RelativeSource TemplatedParent}}" />
                            <ContentPresenter Name="Content" Grid.Column="0" />
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsExpanded" Value="false">
                                <Setter TargetName="Content" Property="Visibility" Value="Collapsed" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

决定使用按钮点击添加我想要完成的内容:

<Button Click="CompanyClick" />

在后面的代码中定义了CompanyClick。

2 个答案:

答案 0 :(得分:4)

更改

<Button>

要...

<Button Command="{Binding OnClick}" />

在您用作此ItemsControl中的项的类上,实现一个只读属性,该属性返回要使用的按钮的ICommand。

编辑:

对于此示例,我使用了名为RelayCommand的ICommand实现,该实现可在http://msdn.microsoft.com/en-us/magazine/dd419663.aspx获得。有关C#中的完整RelayCommand类,请参阅该文章的图3。我把它转换为Visual Basic供我使用,代码如下。它只是通过WPF系统自动注册命令,并为您提供了方便的构造函数:

''' <summary>
''' Implements the ICommand interface
''' </summary>
''' <remarks>
''' Thanks to Josh Smith for this code: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
''' </remarks>
Public Class RelayCommand
    Implements ICommand
#Region "Fields"

    Private ReadOnly _execute As Action(Of Object)
    Private ReadOnly _canExecute As Predicate(Of Object)

#End Region ' Fields

#Region "Constructors"

    Public Sub New(ByVal execute As Action(Of Object))
        Me.New(execute, Nothing)
    End Sub

    Public Sub New(ByVal execute As Action(Of Object), ByVal canExecute As Predicate(Of Object))
        If execute Is Nothing Then
            Throw New ArgumentNullException("execute")
        End If

        _execute = execute
        _canExecute = canExecute
    End Sub
#End Region ' Constructors

#Region "ICommand Members"

    <DebuggerStepThrough()>
    Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute
        Return If(_canExecute Is Nothing, True, _canExecute(parameter))
    End Function

    Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
        AddHandler(ByVal value As EventHandler)
            AddHandler CommandManager.RequerySuggested, value
        End AddHandler
        RemoveHandler(ByVal value As EventHandler)
            RemoveHandler CommandManager.RequerySuggested, value
        End RemoveHandler
        RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
            CommandManager.InvalidateRequerySuggested()
        End RaiseEvent
    End Event

    Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
        _execute(parameter)
    End Sub

#End Region ' ICommand Members
End Class

使用该类,您可以在ViewModel上实现ICommand,方法是在该类中公开ICommand作为只读属性,以及存储RelayCommand的后备字段, ,别忘了,实现ICommand。这是一个截断的样本:

Public Class CompanyViewModel
    Implements INotifyPropertyChanged

    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Private _OnClick As RelayCommand
    Public ReadOnly Property OnClick As ICommand
        Get
            If _OnClick Is Nothing Then
                _OnClick = New RelayCommand(Sub()
                                                Me.OnClickExecute()
                                            End Sub,
                                            Function()
                                                Return Me.OnClickCanExecute()
                                            End Function)
            End If
            Return _OnClick
        End Get
    End Property
    Private Function OnClickCanExecute() As Boolean
        ' put a test here to tell the system whether conditions are right to execute your command.
        ' OR, just return True and it will always execute the command.
    End Function

    Private Sub OnClickExecute()
        ' put the processing for your command here; THIS IS YOUR EVENT HANDLER
    End Sub
    ' .... implement the rest of your ViewModel
End Class

“OnClick”名称​​不是必需的;命令可以采用任何名称,因为系统不是基于约定的VB6与其事件处理程序的方式。

有多种方法可以做到这一点。我对ICommand的“Caliburn.Micro”实现很感兴趣, 基于约定,可能会使事情更具可读性,具体取决于你的风格。但是,Caliburn是一个开发者的努力,虽然是一个非常称职和合格的发烧友。谷歌或Bing“Caliburn.Micro”获取更多相关信息。

答案 1 :(得分:2)

还有这个:

<ControlTemplate.Triggers>
    <EventTrigger RoutedEvent="Button.Click">
        <BeginStoryboard>
            <Storyboard>
<!-- Animations manipulating the button here -->
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
<!-- The rest of your triggers here -->
</ControlTemplate.Triggers>

模板中的这种机制可让您控制按钮的属性,以及可视树中其他部分的属性,具体取决于您放置定义的位置。

您可能还会考虑设计一些不同的东西。我不一定会以完全相同的方式将所有定义都包含在样式中。