Передайте ItemsSource элемента управления в качестве значения свойству зависимости - PullRequest
0 голосов
/ 07 ноября 2019

У меня есть собственный элемент управления ListView, который принимает список ModelItems в качестве его ItemsSource:

          <customControls:ListViewEx Name="DocumentListView"
                ItemsSource="{Binding ModelItems, Mode=OneWay}">

У меня также есть свойство зависимости GridViewColumnHeaderClick.HeaderClick, тип свойства которого object:

        public static readonly DependencyProperty HeaderClickProperty = DependencyProperty.RegisterAttached(
        "HeaderClick", 
        typeof(object), 
        typeof(GridViewColumnHeaderClick), 
        new UIPropertyMetadata(null, OnHeaderClickChanged));

Я бы хотел, чтобы значение ModelItems было передано в качестве значения этого свойства зависимости, и я попытался сделать это так:

            <GridView.ColumnHeaderContainerStyle>
              <Style BasedOn="{StaticResource {x:Type GridViewColumnHeader}}" TargetType="{x:Type GridViewColumnHeader}">
                <Setter Property = "misc:GridViewColumnHeaderClick.HeaderClick" 
                        Value="{Binding ModelItems}"/>
              </Style>
            </GridView.ColumnHeaderContainerStyle>

и в C #:

            ICollectionView dataView =
            CollectionViewSource.GetDefaultView(HeaderClickProperty);

Однако, кажется, ничего не происходит, когда я нажимаю на заголовок. Я не уверен, что это потому, что я неправильно связываю его в XAML, или что-то совершенно другое.

РЕДАКТИРОВАТЬ: извинения за отсутствие деталей, я понимаю, что это немного грязно.

Моя общая цель - запустить функцию сортировки, щелкнув заголовок GridViewColumn. GridView - это ребенок ListViewEx. При щелчке по заголовку я хочу привязать его к свойству HeaderClick и установить значение как ItemsSource из ListView (в данном случае ItemsSource=ModelItems), чтобы я мог его отсортировать.

При нажатии запускается функция OnHeaderClickChanged:

        private static void OnHeaderClickChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var headerClicked = sender as GridViewColumnHeader;
        headerClicked.MouseUp += (s, me) => HeaderClickedOnMouseUp(s, me, e.NewValue);
    }

Это добавляет функцию HeaderClickedOnMouseUp к событию MouseUp. Эта функция выполняет сортировку с ModelItems.

Моя проблема в том, что я не понимаю, когда речь идет о зависимостях / вложенных свойствах и о том, как связать их с представлением. Как правильно упомянуто в комментариях, сеттер не вызывается в любой момент, когда я пытаюсь отладить его, и я теряюсь в том, почему это так.

1 Ответ

1 голос
/ 07 ноября 2019

Это простой пример сортировки, который использует сортировку по возрастанию. Присоединенное свойство Sort.IsEnabled должно быть установлено на GridViewColumnHeader. Сама сортировка выполняется путем установки SortDescription значения по умолчанию CollectionView родительского столбца ListView.ItemsSource.

Рекомендуемое чтение:
Обзор прикрепленных свойств
Обзор свойств зависимостей

Модель данных: Person.cs

class Person
{
  public Person(string firstName, string lastName)
  {
    this.FirstName = firstName;
    this.LastName = lastName;
  }

  public string FirstName { get; set; }
  public string LastName { get; set; }
}

ViewModel.cs

class ViewModel : INotifyPropertyChanged
{
  public ViewModel()
  {
    this.Persons = new ObservableCollection<Person>()
    {
      new Person("Derek", "Zoolander"),
      new Person("Tony", "Montana"),
      new Person("The", "Dude")
    };
  }

  public ObservableCollection<Person> Persons { get; set; }
}   

Свойство Attached Sort: Sort.cs

class Sort : DependencyObject
{
  #region IsEnabled attached property

  public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached(
    "IsEnabled", typeof(bool), typeof(Sort), new PropertyMetadata(false, Sort.OnIsEnabled));

  public static void SetIsEnabled([NotNull] DependencyObject attachingElement, bool value) => attachingElement.SetValue(Sort.IsEnabledProperty, value);

  public static bool GetIsEnabled([NotNull] DependencyObject attachingElement) => (bool) attachingElement.GetValue(Sort.IsEnabledProperty);

  #endregion

  private static void OnIsEnabled(DependencyObject attachingElement, DependencyPropertyChangedEventArgs e)
  {
    bool isSortingEnabled = (bool) e.NewValue;
    if (isSortingEnabled == (bool) e.OldValue)
    {
      return;
    }

    if (attachingElement is GridViewColumnHeader columnHeader)
    {
      if (isSortingEnabled)
      {
        columnHeader.Click += Sort.SortByColumn;
      }
      else
      {
        columnHeader.Click -= Sort.SortByColumn;
      }  
    }
  }

  private static void SortByColumn(object sender, RoutedEventArgs e)
  {
    var columnHeader = sender as GridViewColumnHeader;
    PropertyPath columnSourceProperty = (columnHeader.Column.DisplayMemberBinding as Binding).Path;

    // Use an extension method to find the parent ListView 
    // by traversing the visual tree
    if (columnHeader.TryFindVisualParentElement(out ListView parentListView))
    {
      var collectionView = (CollectionView)CollectionViewSource.GetDefaultView(parentListView.ItemsSource);
      collectionView.SortDescriptions.Clear();

      // Apply sorting
      collectionView.SortDescriptions.Add(new SortDescription(columnSourceProperty.Path, ListSortDirection.Ascending));
    }
  }
}

Вспомогательный метод расширения для поиска визуального родителя: Extensions.cs

public static class Extensions
{
  /// <summary>
  /// Traverses the visual tree towards the root until an element with a matching element name is found.
  /// </summary>
  /// <typeparam name="TParent">The type the visual parent must match.</typeparam>
  /// <param name="child"></param>
  /// <param name="resultElement"></param>
  /// <returns><c>true</c> when the parent visual was found otherwise <c>false</c></returns>
  public static bool TryFindVisualParentElement<TParent>(this DependencyObject child, out TParent resultElement)
    where TParent : DependencyObject
  {
    resultElement = null;

    DependencyObject parentElement = VisualTreeHelper.GetParent(child);

    if (parentElement is TParent parent)
    {
      resultElement = parent;
      return true;
    }

    return parentElement?.TryFindVisualParentElement(out resultElement) ?? false;
  }
}

Использование: MainWindow.xaml

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>

  <ListView ItemsSource="{Binding Persons}">
    <ListView.View>
      <GridView>
        <GridViewColumn DisplayMemberBinding="{Binding FirstName}">
          <GridViewColumnHeader Sort.IsEnabled="True" Content="First Name" />
        </GridViewColumn>
        <GridViewColumn DisplayMemberBinding="{Binding LastName}">
          <GridViewColumnHeader Sort.IsEnabled="True" Content="Last Name" />
        </GridViewColumn>
      </GridView>
    </ListView.View>
  </ListView>
</Window>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...