2017-09-25 2 views
1

Ich habe eine DataGrid, in jedem DataGridRow Ich habe Zeilenangaben, die ein paar Steuerelemente enthalten.Wie Sie DataGridRow davon abhalten, auszuwählen, wenn Maus innerhalb RowDetails geklickt wird

Was Ich mag würde, ist, wenn überhaupt innerhalb der Zeile Details geklickt wird:
- Nicht die Zeile auswählen, oder genauer gesagt,
- ändern Sie die vorhandene DataGrid Auswahl.

Ich dachte an die Handhabung von PreviewMouseDown- und MouseDown-Ereignissen in einem Verhalten, wodurch das DataGrid irgendwie den Auswahlprozess überspringt, jedoch nicht sicher ist, wie es weitergehen soll.

Irgendwann werde ich ein TabControl in den Details mit mehr Informationen haben, so dass ich auch nicht möchte, dass ein TabItem-Klick die vorhandene Auswahl des DataGrid ändert.

Gäbe es eine Möglichkeit geben, das Tunneln von Preview bei der Grid „DetailsContainer“ Ebene zu starten und das Sprudeln von MouseDown- am Grid „DetailsContainer“ -Niveau

<DataGrid Name="dgAudit" 
      CanUserReorderColumns="False" 
      CanUserAddRows="False" 
      CanUserDeleteRows="False" 
      CanUserResizeColumns="False" 
      CanUserResizeRows="False" 
      CanUserSortColumns="False" 
      IsReadOnly="True" 
      ItemsSource="{Binding GEOM_ASSET_OC_LIST}" 
      VirtualizingPanel.ScrollUnit="Pixel" 
      RowDetailsVisibilityMode="Visible" 
      > 
    <i:Interaction.Behaviors> 
     <behaviors:DataGridBehaviors /> 
    </i:Interaction.Behaviors> 

    <DataGrid.Columns> 
     <DataGridTextColumn Header="Asset ID" Binding="{Binding ASSET_ID}" Width="200" /> 
     <DataGridTextColumn Header="Asset Type" Binding="{Binding ASSET_TYPE}" Width="200" /> 
     <DataGridTextColumn Header="Last Update By" Binding="{Binding LAST_UPDATE_BY}" Width="150" /> 
     <DataGridTextColumn Header="Last Update Date" Binding="{Binding LAST_UPDATE_DATETIME, StringFormat=\{0:dd.MM.yy HH:mm:ss tt\}}" Width="150" /> 
    </DataGrid.Columns> 
    <DataGrid.RowDetailsTemplate> 
     <DataTemplate> 
      <Grid Name="DetailsContainer"> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="*" /> 
        <ColumnDefinition Width="Auto" /> 
       </Grid.ColumnDefinitions> 
       <TextBlock Name Text="{Binding Notes}" Width="400" HorizontalAlignment="Left" TextWrapping="Wrap"/> 
       <Button Content="Button" Grid.Column="1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/> 
      </Grid> 
     </DataTemplate> 
    </DataGrid.RowDetailsTemplate> 
</DataGrid> 

Nur ein schneller Mock-up von einem leeren zu stoppen Verhalten

public class DataGridBehaviors : Behavior<DataGrid> 
{ 
    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     this.AssociatedObject.MouseDown += DataGrid_MouseDown; 
     this.AssociatedObject.PreviewMouseDown += DataGrid_PreviewMouseDown; 
    } 

    protected override void OnDetaching() 
    { 
     this.AssociatedObject.PreviewMouseDown -= DataGrid_PreviewMouseDown; 
     this.AssociatedObject.MouseDown -= DataGrid_MouseDown; 
     base.OnDetaching(); 
    } 

    private void DataGrid_MouseDown(object sender, MouseButtonEventArgs e) 
    { 
    } 

    private void DataGrid_PreviewMouseDown(object sender, MouseButtonEventArgs e) 
    { 
     DependencyObject obj = (DependencyObject)e.OriginalSource; 
     DataGridDetailsPresenter RowsDetails = FindParent<DataGridDetailsPresenter>(obj); 
     if (RowsDetails != null) 
     { 
      //Skip over selection, maybe temporarily removed native selection handler??? 
     } 
    } 

    public static T FindParent<T>(DependencyObject child) where T : DependencyObject 
    { 
     //get parent item 
     DependencyObject parentObject = VisualTreeHelper.GetParent(child); 

     //we've reached the end of the tree 
     if (parentObject == null) return null; 

     //check if the parent matches the type we're looking for 
     T parent = parentObject as T; 
     if (parent != null) 
      return parent; 
     else 
      return FindParent<T>(parentObject); 
    } 

    private static T GetVisualChild<T>(DependencyObject parent) where T : Visual 
    { 
     T child = default(T); 

     int numVisuals = VisualTreeHelper.GetChildrenCount(parent); 
     for (int i = 0; i < numVisuals; i++) 
     { 
      Visual v = (Visual)VisualTreeHelper.GetChild(parent, i); 
      child = v as T; 
      if (child == null) 
      { 
       child = GetVisualChild<T>(v); 
      } 
      if (child != null) 
      { 
       break; 
      } 
     } 
     return child; 
    } 
} 
+0

Darf nur Eigenschaft lesen macht auf „true“ –

Antwort

0

Ich fand eine andere mögliche Problemumgehung. Durch Erstellen einer kleinen Canvas innerhalb der DataGridRowHeader dann in der nächsten unter Container-Einstellung ClipsToBounds bis false. Es ist dann frei von der Kopfzeile, aber kann auch angeklickt werden, ohne die DataGrid s aktuelle Auswahl zu beeinflussen. Es ist an die IsExpanded der Zeilendetails gebunden und sieht das Teil aus.

Ein Wort der Warnung ist, dass, wenn die Zeile Details eine erhebliche Menge an Daten enthalten, mit dem Code, wie es unten ist, kann ziemlich ineffizient sein, Ladezeit und Scroll-Verzögerung. Abhängig davon, ob virtualization verwendet wird. Diese Daten werden zur gleichen Zeit wie die Zeile geladen und können ziemlich ineffizient sein, wenn die Steuerungen bei RowDetailsTemplate auf Anforderung geladen werden. Wahrscheinlich am besten, das Laden dieser Daten durch eine oder dynamisch zu kontrollieren.

Sie müssen wahrscheinlich auch auf das DataGridLayoutUpdated Ereignis hören, um die Breite des Detailsteuerelements anzupassen.

<DataGrid.RowHeaderTemplate> 
    <DataTemplate> 
     <Grid> 
      <Expander Template="{StaticResource StretchyExpanderTemp}" 
         OverridesDefaultStyle="True" 
         Header="" 
         HorizontalAlignment="Right" 
         VerticalAlignment="Top" 
         Expanded="Expander_Expanded" Collapsed="Expander_Collapsed" 
         IsExpanded="{Binding DataContext.IsExpanded, RelativeSource={RelativeSource AncestorType=DataGridRowHeader}}" /> 

      <Canvas Background="BlueViolet" 
        Width="5" 
        VerticalAlignment="Top" 
        HorizontalAlignment="Left" 
        Height="5"> 
       <TabControl Name="tcAA" 
          TabStripPlacement="Left" 
          Margin="20,18,0,0" 
          Height="185" 
          Width="500" 
          VerticalAlignment="Top" 
          HorizontalAlignment="Left" 
          ItemsSource="{Binding DataContext.AAUDIT, RelativeSource={RelativeSource AncestorType=DataGridRowHeader}}" 
          SelectedIndex="0" 
          ClipToBounds="False" 
          Visibility="{Binding DataContext.IsExpanded, RelativeSource={RelativeSource AncestorType=DataGridRowHeader}, Converter={StaticResource bool2VisibilityConverter}}" 
          > 
        ... 
        <TabControl.ItemTemplate> 
         <DataTemplate> 
          <Grid> 
           <TextBlock Text="{Binding DISPLAY_NAME}" /> 
          </Grid> 
         </DataTemplate> 
        </TabControl.ItemTemplate> 
        <TabControl.ContentTemplate> 
         <DataTemplate> 
          ... 
         </DataTemplate> 
        </TabControl.ContentTemplate> 
       </TabControl> 
      </Canvas> 
     </Grid> 
    </DataTemplate> 
</DataGrid.RowHeaderTemplate> 

<DataGrid.RowDetailsTemplate> 
    <DataTemplate> 
     <Grid Height="185" > 
     </Grid> 
    </DataTemplate> 
</DataGrid.RowDetailsTemplate> 

Wie es hier steht ein kurzes Beispiel von dem, was ich produziert habe: enter image description here

1

Leider mit dem aktuellen WPF DataGrid ‚s Implementierung ist es nicht möglich, zu erreichen, was Sie wollen.

Die DataGridDetailsPresenter Register ein class event handler für das MouseLeftButtonDownEvent gerouteten Ereignis mit dem EventManager API:

EventManager.RegisterClassHandler(
    typeof(DataGridDetailsPresenter), 
    MouseLeftButtonDownEvent, 
    new MouseButtonEventHandler(OnAnyMouseLeftButtonDownThunk), 
    true); 

Hinweis, dass letzten Parameter, der zu true eingestellt ist. Es ist ein Flag, das anzeigt, ob der Listener von Ereignissen hören möchte, die bereits behandelt wurden oder nicht. In diesem Fall wird der interne Event-Handler trotzdem auf true auf einer beliebigen Ebene gesetzt.

Dieser Event-Handler ist verantwortlich für die Fokussierung der DataRow Sie klicken auf die Detailansicht innerhalb. Und Sie wissen sicher, dass in WPF die Ereignisbehandlungsroutinen der Klasse vor den Ereignisbehandlungsroutinen für Instanzen aufgerufen werden. Das erste, was passieren wird, wenn man mit der linken Maustaste auf den Presenter einer Detailzeile klickt, ist die Fokussierung der umgebenden Zeile (eigentlich der ersten Zelle dieser Zeile).

Bitte beachten Sie auch, dass dieses Verhalten die Realisierung der virtuellen Objekte innerhalb der RowPresenter auch verwaltet, so dass es zu unerwünschten GUI-Nebenwirkungen führen kann.

Sie können die IsHitTestVisible Eigenschaft Ihres Containers Grid auf false setzen, dadurch wird das automatische Zeilenauswahlverhalten deaktiviert. Aber offensichtlich werden Sie in der Lage sein, irgendwelche Klicks innerhalb der Zeilendetails überhaupt zu handhaben.

+0

Große Antwort, schrecklichen Tatsachen, so kann ich mit der Überprüfung gelassen werden Wenn der Klick aus den Zeilendetails stammt, speichern Sie die vorhandenen ausgewählten Elemente/Indizes. Sobald die Steuerelemente ihr natürliches Verhalten wieder hergestellt haben, wenden Sie die Auswahl erneut an ... oder dort – Hank

Verwandte Themen