C# 传递一个控件';s ItemsSource作为依赖项属性的值

C# 传递一个控件';s ItemsSource作为依赖项属性的值,c#,wpf,xaml,C#,Wpf,Xaml,我有一个自定义ListView控件,它将ModelItems列表作为其ItemsSource: <customControls:ListViewEx Name="DocumentListView" ItemsSource="{Binding ModelItems, Mode=OneWay}"> 我希望将ModelItems作为值传递给此依赖项属性,我已尝试这样做: <GridView.ColumnHe

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

          <customControls:ListViewEx Name="DocumentListView"
                ItemsSource="{Binding ModelItems, Mode=OneWay}">
我希望将
ModelItems
作为值传递给此依赖项属性,我已尝试这样做:

            <GridView.ColumnHeaderContainerStyle>
              <Style BasedOn="{StaticResource {x:Type GridViewColumnHeader}}" TargetType="{x:Type GridViewColumnHeader}">
                <Setter Property = "misc:GridViewColumnHeaderClick.HeaderClick" 
                        Value="{Binding ModelItems}"/>
              </Style>
            </GridView.ColumnHeaderContainerStyle>
但是,当我单击标题时,似乎什么也没有发生。我不确定这是因为我在XAML中错误地绑定了它,还是因为完全不同的原因

编辑:为缺乏细节道歉,我理解这有点混乱

我的总体目标是通过单击GridViewColumn的标题来运行排序函数。
GridView
ListViewEx
的子项。单击标题时,我希望将其绑定到
HeaderClick
属性,并将该值设置为
ListView
ItemsSource
(在本例中为
ItemsSource=modelsitems
),以便对其进行排序

单击后,将运行函数
OnHeaderClickChanged

        private static void OnHeaderClickChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var headerClicked = sender as GridViewColumnHeader;
        headerClicked.MouseUp += (s, me) => HeaderClickedOnMouseUp(s, me, e.NewValue);
    }
这会将函数
headerclickednomouseup
添加到
MouseUp
事件中。此函数是使用
ModelItems
执行排序的函数


我的问题是,当涉及到依赖/附加属性以及如何将其与视图绑定时,我缺乏理解。正如在注释中正确提到的,在调试setter时,在任何时候都不会调用它,我不明白为什么会这样

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

推荐阅读:

数据模型: 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; }
}
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; }
}   
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));
    }
  }
}
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;
  }
}
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; }
}   
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));
    }
  }
}
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;
  }
}
用于查找可视父对象的扩展助手方法: Extensions.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; }
}   
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));
    }
  }
}
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;
  }
}
公共静态类扩展
{
/// 
///向根遍历可视树,直到找到具有匹配元素名称的元素。
/// 
///视觉父级必须匹配的类型。
/// 
/// 
///当发现父视觉对象时为true,否则为false
public static bool TryFindVisualParentElement(此DependencyObject子对象,out tParentResultElement)
其中TParent:DependencyObject
{
resultElement=null;
DependencyObject parentElement=VisualTreeHelper.GetParent(子级);
if(parentElement是TParent父元素)
{
结果成分=父母;
返回true;
}
返回parentElement?.TryFindVisualParentElement(OutResultElement)?false;
}
}
用法: main window.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>


GridViewColumnHeaderClick。HeaderClick
在类型
GridViewColumnHeader
上不存在,并且不是附加属性。因此,
Setter
将永远不会执行。对不起,您能稍微扩展一下吗?这是否意味着我不应该将目标类型指定为
GridViewColumnHeader
。我对依赖属性的概念还不太熟悉,所以我不确定它不是附加属性是什么意思。您使用该属性的方式使它看起来像是附加属性,但它不是。它是类型
GridViewColumnHeaderClick
上的一个简单依赖属性,没有人知道它的作用。当我读到你的问题时,我最初的想法也是“对不起,你能稍微扩展一下吗?”。我无法提供解决方案,因为我不知道您在做什么。您只提供了随机代码片段,没有上下文和解释。我所能看到的是,您正在为
GridView
GridViewColumnHeader
设置样式。您的setter正在设置一个在
GridViewColumnHeader
@monadoboi的上下文中不存在的属性:为什么在单击标题时会设置附加属性?您是否在某处处理单击?@mm8是的,我需要的功能已添加到
MouseUp
事件中。我对这个问题补充了一些细节。谢谢