C# 传递一个控件';s ItemsSource作为依赖项属性的值
我有一个自定义ListView控件,它将ModelItems列表作为其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
<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
事件中。我对这个问题补充了一些细节。谢谢