2009-09-24 17 views
10

Używam DataGrid WPF z panelem RowDetails, w którym parametr RowDetailsVisibilityMode jest ustawiony na "VisibleWhenSelected" i SelectionMode = "Extended", tak aby można było wybrać wiele wierszy, a tym samym wyświetlić szczegóły wiersza, jako poniżej:WPF Datagrid RowDetailsWskazówkaTemplate związana z właściwością

<dg:DataGrid x:Name="MyGrid" 
      ItemsSource="{Binding Path=MyItems}" 
      AutoGenerateColumns="True" 
      SelectionMode="Extended" 
      RowDetailsVisibilityMode="VisibleWhenSelected"> 

    <dg:DataGrid.RowDetailsTemplate> 
    <DataTemplate> 
     <TextBlock Text="Further Details..."/> 
    </DataTemplate> 
    </dg:DataGrid.RowDetailsTemplate> 
    ... 
</dg:DataGrid> 

Niestety, dla tej aplikacji nie jest intuicyjny, aby wyświetlić szczegóły wiersz na „wybranych” wierszy, klient chciałby kliknij pole wyboru w wielu rzędach, aby wyświetlić panel RowDetails, ale również przewijaj siatkę, wybierając inne wiersze. Innymi słowy, naprawiaj wiersze wyświetlające dane RowDetails, bez względu na to, co dzieje się w DataGrid.

Tak obecnie przewijanie zamyka RowDetailsPanes, które otworzył. Chciałbym mieć pole wyboru w jednej z kolumn i powiązać widoczność panelu RowDetails z tą usługą, ale nie wiem, jak to zrobić. Problem polega na tym, że RowDetailsPane działa tylko w zaznaczeniu wiersza w datagrid - czy można go w jakiś sposób rozszerzyć, aby działał na wybranej przeze mnie własności?

Dzięki z góry, Will

Odpowiedz

14

Patrząc na kod źródłowy narzędzi WPF każdy DataGridRow ma właściwość DetailsVisibility.

Wstawiłem przycisk (tylko do testów) w pierwszej kolumnie.

<toolkit:DataGridTemplateColumn> 
    <toolkit:DataGridTemplateColumn.CellTemplate> 
     <DataTemplate> 
      <Button x:Name="buttonDetails" Content="Hello" ButtonBase.Click="Details_Click" /> 
     </DataTemplate> 
    </toolkit:DataGridTemplateColumn.CellTemplate> 
</toolkit:DataGridTemplateColumn> 

Po kliknięciu przycisku znajdź kliknięty wiersz i przełącz właściwość.

private void Details_Click(object sender, RoutedEventArgs e) 
    { 
     try 
     { 
     // the original source is what was clicked. For example 
     // a button. 
     DependencyObject dep = (DependencyObject)e.OriginalSource; 

     // iteratively traverse the visual tree upwards looking for 
     // the clicked row. 
     while ((dep != null) && !(dep is DataGridRow)) 
     { 
      dep = VisualTreeHelper.GetParent(dep); 
     } 

     // if we found the clicked row 
     if (dep != null && dep is DataGridRow) 
     { 
      // get the row 
      DataGridRow row = (DataGridRow)dep; 

      // change the details visibility 
      if (row.DetailsVisibility == Visibility.Collapsed) 
      { 
      row.DetailsVisibility = Visibility.Visible; 
      } 
      else 
      { 
      row.DetailsVisibility = Visibility.Collapsed; 
      } 
     } 
     } 
     catch (System.Exception) 
     { 
     } 
    } 

Nie zbadałem tego poprzez wiązanie danych.

+0

Dzięki Rory, ładne rozwiązanie. Dokładnie tego chciałem, myliłem się myśląc w kategoriach wiązania do właściwości w moim ViewModelu, ponieważ jest to funkcja czysto View, więc metoda działająca na zdarzeniu click tego pola wyboru jest idealna. – WillH

+2

To również działa dla Silverlight, jeśli ustawisz początkowy DataGrid.RowDetailsVisibilityMode = "Collapsed" –

9

Używając czystego XAML (+ konwerter):

XAML:

<DataGrid.RowHeaderTemplate> 
    <DataTemplate> 
     <ToggleButton 
      IsChecked="{Binding Path=DetailsVisibility, 
       RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, 
       Converter={StaticResource _VisibilityToNullableBooleanConverter}}" 
      /> 
    </DataTemplate> 
</DataGrid.RowHeaderTemplate> 

Przelicznik:

public class VisibilityToNullableBooleanConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value is Visibility) 
     { 
      return (((Visibility)value) == Visibility.Visible); 
     } 
     else 
     { 
      return Binding.DoNothing; 
     } 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value is bool?) 
     { 
      return (((bool?)value) == true ? Visibility.Visible : Visibility.Collapsed); 
     } 
     else if (value is bool) 
     { 
      return (((bool)value) == true ? Visibility.Visible : Visibility.Collapsed); 
     } 
     else 
     { 
      return Binding.DoNothing; 
     } 
    } 
} 
+3

+1 dla podejścia tylko Xaml, ponieważ łatwiej jest zastosować go w wielu miejscach i jest bardziej przenośny podczas przenoszenia DataGrid Xaml. –

+0

Działa to dobrze po ustawieniu RowDetailsVisibilityMode na Collapsed. – user3260977

0

Jeśli używasz (doskonała) biblioteki Lambda Konwertery można zaoszczędzić dodatkowe klasa. Ten konwerter wykorzystuje 2 wyrażeń lambda pierwszy dla Convert, drugi dla ConvertBack, np

public static readonly IValueConverter VisibilityToBoolean = 
     ValueConverter.Create<Visibility, bool>(
     (e => e.Value == Visibility.Visible), 
      (e => e.Value ? Visibility.Visible : Visibility.Collapsed)); 

Następnie XAML wygląda następująco (uwaga nie ma potrzeby StaticResources przy użyciu tej metody):

 <DataGrid.RowHeaderTemplate> 
      <DataTemplate> 
       <ToggleButton> 
        <ToggleButton.IsChecked> 
         <Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGridRow}}" Path="DetailsVisibility" 
           Converter="{x:Static lc40:Converters.VisibilityToBoolean}"/> 
        </ToggleButton.IsChecked> 
       </ToggleButton> 
      </DataTemplate> 
     </DataGrid.RowHeaderTemplate> 

lambda Konwertery dostępne są tutaj:

https://github.com/michael-damatov/lambda-converters

Powiązane problemy