Answered Button-Command in einem DataGridTemplateColumn.Header

  • Donnerstag, 9. August 2012 05:48
     
      Enthält Code

    Hallo,

    Wie kann ich es hinbekomme in einem DataGrid (DataGridTemplateColumn.Header) ein Command Binding hinzubekommen. Bei einem Button außerhalb des DataGrid funktioniert es, wenn ich aber ein Button im Grid-Header habe geht es nicht. Es kommt der Hinweis das das Property nicht gefunden wird. Das muß doch aber gehen.


    Danke und Gruß
    Gerhard Ahrens

Alle Antworten

  • Donnerstag, 9. August 2012 07:28
     
     Beantwortet Enthält Code
    Hi Gerhard,
    da es bei mir problemlos funktioniert, wird bei Dir vermutlich eine falsche Bindung vorliegen. Hier meine Demo:
    <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
            xmlns:local="clr-namespace:WpfApplication1">
      <Window.Resources>
        <local:ViewModel x:Key="vm"/>
      </Window.Resources>
        <StackPanel DataContext="{Binding Source={StaticResource vm}}">
        <DataGrid Name="dg" ItemsSource="{Binding View}" AutoGenerateColumns="False">
          <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding col1}" SortMemberPath="">
              <DataGridTextColumn.HeaderTemplate>
                <DataTemplate>
                  <Button Content="Kopf" Command="{Binding Source={StaticResource vm}, Path=cmd}"/>
                </DataTemplate>
              </DataGridTextColumn.HeaderTemplate>
            </DataGridTextColumn>
          </DataGrid.Columns>
        </DataGrid>
        <Label Content="{Binding Prop2}"/>
      </StackPanel>
    </Window>
    
    Imports System.Data
    Imports System.ComponentModel
    
    Public Class ViewModel
      Implements INotifyPropertyChanged
    
      Dim cvs As New CollectionViewSource
      Public ReadOnly Property View As ICollectionView
        Get
          If cvs.View Is Nothing Then
            Dim dt As New DataTable
            With dt
              With .Columns
                With .Add("ID", GetType(Integer))
                  .AutoIncrement = True
                  .AutoIncrementSeed = 1
                  .AutoIncrementStep = 1
                End With
                .Add("col1", GetType(String))
              End With
              For i = 1 To 10
                Dim r = .NewRow
                r(1) = String.Format("Zeile {0:00}", i)
                .Rows.Add(r)
              Next
            End With
            cvs.Source = dt
          End If
          Return cvs.View
        End Get
      End Property
    
      Private cmd2 As New Action(Of Object)(AddressOf Cmd2Exec)
    
      Public ReadOnly Property cmd() As ICommand
        Get
          Return New RelayCommand(cmd2)
        End Get
      End Property
    
      Sub Cmd2Exec(ByVal obj As Object)
        Prop2 = String.Format("Button gedrückt: {0:HH:mm:ss.fff}", Now)
      End Sub
    
      Private _prop2 As String = "Button nicht gedrückt"
      Public Property Prop2() As String
        Get
          Return Me._prop2
        End Get
        Set(ByVal value As String)
          Me._prop2 = value
          RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Prop2"))
        End Set
      End Property
    
      Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    End Class
    
    
    Public Class RelayCommand
      Implements ICommand
      Private ReadOnly _execute As Action(Of Object)
      Private ReadOnly _canExecute As Predicate(Of Object)
      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
    
        Me._execute = execute
        Me._canExecute = canExecute
      End Sub
      <DebuggerStepThrough()> _
      Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute
        Return If(Me._canExecute Is Nothing, True, Me._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 System.Object, ByVal e As System.EventArgs)
        End RaiseEvent
      End Event
      Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
        Me._execute(parameter)
      End Sub
    End Class
    

    --
    Viele Gruesse
    Peter

    Ergänzung:

    Da nntp die Bilder nicht anzeigt, sehe ich erst jetzt das Bild in Deiner Frage. "btnSort" fehlt bei Dir in dem als ItemsSource gebundenen Objekt.

  • Freitag, 10. August 2012 05:15
     
     

    Hallo Peter,

    da muß ich nochmal schauen was ich falsch gemacht haben.

    Danke und Gruß

    Gerhard Ahrens

  • Freitag, 10. August 2012 05:37
     
      Enthält Code

    Hallo Peter,

    es funktioniert tatsächlich so. Nachdem das Grid einen DataContext bekommen hat, funktionierte der Button im Header sofort. Verstehen tue ich allerdings nicht, warum ich bei dem Grid den DataContext angeben muß,

                <Grid DataContext="{Binding Source={StaticResource vm}}" 
                      Visibility="{Binding Path=VokabelDataView.IsEmpty, 
                    UpdateSourceTrigger=PropertyChanged, Converter={StaticResource visibilityConverter}}">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*" />
                        <RowDefinition Height="35" />
                    </Grid.RowDefinitions>
                    <DataGrid Name="dataGrid1"
                              Margin="0"
                              HorizontalAlignment="Stretch"
                              VerticalAlignment="Stretch"
                              AlternatingRowBackground="Gainsboro"
                              AlternationCount="2"
                              AutoGenerateColumns="False"
                              CanUserAddRows="True"
                              CanUserDeleteRows="True"
                              commands:Behaviors.DoubleClick="{Binding EditVokabelCommand}"
                              IsReadOnly="True"
                              IsSynchronizedWithCurrentItem="True"
                              ItemsSource="{Binding Path=VokabelDataView,
                                                    Mode=OneWay}"
                              SelectionMode="Single"
                              SelectionUnit="FullRow">
    
                        <DataGrid.Columns>
                            <DataGridTemplateColumn Width="375"
                                                    CanUserSort="True"
                                                    IsReadOnly="True"
                                                    SortMemberPath="txtVokabelEn">
                                <DataGridTemplateColumn.Header>
                                    <Grid Width="Auto" Height="Auto">
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="*" />
                                            <ColumnDefinition Width="22" />
                                        </Grid.ColumnDefinitions>
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="20" />
                                            <RowDefinition Height="20" />
                                        </Grid.RowDefinitions>
    
                                        <TextBlock Grid.Row="0"
                                                   Grid.Column="0"
                                                   Width="350"
                                                   HorizontalAlignment="Left"
                                                   Text="Vokabel Englisch" />
                                        <Image Grid.Row="0"
                                               Grid.Column="1"
                                               Width="Auto"
                                               Height="Auto"
                                               HorizontalAlignment="Right"
                                               Source="{StaticResource imgEnGb}"
                                               Stretch="None" />
                                        <Button x:Name="btnZweite"
                                                Grid.Row="1"
                                                Grid.Column="0"
                                                Width="Auto"
                                                Command="{Binding Source={StaticResource vm},
                                                                  Path=RefreshCommand}"
                                                Content="Zweite Zeile" />
    
                                    </Grid>
                                </DataGridTemplateColumn.Header>
    

    und bei einem Botton in einem Dialog geht das auch ohne.

                <Button x:Name="cmbRefreshCommand"
                        Width="25"
                        Height="25"
                        Margin="5"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Center"
                        Command="{Binding Path=RefreshCommand}"
                        DockPanel.Dock="Right">
                    <Button.ToolTip>
                        <ToolTip Background="LightYellow">
                            <StackPanel>
                                <TextBlock FontWeight="Bold">Refresh</TextBlock>
                                <TextBlock>Liste der Vokabeln aktualisieren.</TextBlock>
                            </StackPanel>
                        </ToolTip>
                    </Button.ToolTip>
                    <Image Width="16"
                           Height="16"
                           Source="{StaticResource imgRefresh16}"
                           Stretch="None" />
                </Button>
    

    Gruß
    Gerhard Ahrens

  • Freitag, 10. August 2012 07:02
     
     
    Hallo Gerhard,
    das Grid braucht keinen DataContext. Der wird nur benötigt, wenn eingebettete Elemente den DataContext benötigen und ihnen selbst kein DataContext zugewiesen wurde. Wichtig in Deinem Beispiel bezüglich der Ausgangsfrage ist, dass als Source auch die richtige Instanz genutzt wird. Das hast Du mit der Source-Eigenschaft gemacht. Bei Deinem Button in einem Dialog fehlt die Source-Eigenschaft und er greift auf den DataContext zurück. Dieser muss aber im Baum irgendwo oberhalb auffindbar sein, bei Dir z.B. im Grid.
     
    --
    Viele Gruesse
    Peter