将控件的ItemsSource作为值传递给依赖项属性

时间:2019-11-07 10:47:22

标签: c# wpf xaml

我有一个自定义ListView控件,该控件将ModelItems的列表作为其ItemsSource:

name

我还有一个依赖项属性def 'all events are published to subscribers'() { given: EventSubscriber subscriber = Mock() subscriber.shouldRegister() >> true subscriber.interests() >> new HashSet<Intent>(Arrays.asList(COUNTER, GAUGE)) publisher.subscribe(subscriber) when: def event = publisher.newEvent('test', COUNTER) event.start() event.newChild('child', GAUGE) event.finish() then: 1 * subscriber.onCreate({ it.name == 'test' }) 1 * subscriber.onCreate({ it.name == 'child' }) 1 * subscriber.onStart({ it.name == 'test' }, !null) 1 * subscriber.onEnd({ it.name == 'test' }, !null) 1 * subscriber.onChild({ it.name == 'test' }, { it.name == 'child' }) } ,其属性类型为 <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));

和在C#中:

ModelItems

但是,当我单击标题时似乎什么也没发生。我不确定是否是因为我在XAML中错误地绑定了它,或者是完全不同的东西。

编辑:抱歉,没有提供详细信息,我知道这有点混乱。

我的总体目标是通过单击GridViewColumn的标题来运行排序功能。 <GridView.ColumnHeaderContainerStyle> <Style BasedOn="{StaticResource {x:Type GridViewColumnHeader}}" TargetType="{x:Type GridViewColumnHeader}"> <Setter Property = "misc:GridViewColumnHeaderClick.HeaderClick" Value="{Binding ModelItems}"/> </Style> </GridView.ColumnHeaderContainerStyle> ICollectionView dataView = CollectionViewSource.GetDefaultView(HeaderClickProperty); 的子级。单击标题后,我希望将其绑定到GridView属性,并将值设置为ListViewEx的{​​{1}}(在本例中为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); } 进行排序的功能。

我的问题是我对依赖项/附加属性以及如何将其与视图绑定缺乏了解。正如评论中正确提到的那样,当我尝试调试setter时,不会在任何时候调用它,并且我不知道为什么会发生这种情况。

1 个答案:

答案 0 :(得分:1)

这是一个使用升序排序的简单排序示例。附加属性Sort.IsEnabled应该在GridViewColumnHeader上设置。 排序本身是通过设置列的父项SortDescription的默认CollectionView的{​​{1}}来完成的。

推荐阅读:
Attached Properties Overview
Dependency properties overview

数据模型: Person.cs

ListView.ItemsSource

ViewModel.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; }
}

附加属性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; } } Sort.cs

Sort

扩展助手方法来查找可视父对象: Extensions.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));
    }
  }
}

用法: MainWindow.xaml

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;
  }
}