Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 如何按显示的、转换的值而不是绑定的源属性值对DataGridTextColumn进行排序?_Wpf_Mvvm_Data Binding_Datagrid_Wpfdatagrid - Fatal编程技术网

Wpf 如何按显示的、转换的值而不是绑定的源属性值对DataGridTextColumn进行排序?

Wpf 如何按显示的、转换的值而不是绑定的源属性值对DataGridTextColumn进行排序?,wpf,mvvm,data-binding,datagrid,wpfdatagrid,Wpf,Mvvm,Data Binding,Datagrid,Wpfdatagrid,如何按显示的、转换的值、未绑定的源属性值对WPF DataGridTextColumn进行排序?现在它是按行viewmodel中的整数值排序的,而不是由转换器返回的显示文本。我使用MVVM 下面是一个请求示例。然而,这是一个普遍的问题。我可以将MmsClass.Name放入表示行的类中。但我需要在任何地方进行适当的分类,而不仅仅是在这里 一行的类: public class MaintenanceDataItem { public MaintenanceDataItem(int clas

如何按显示的、转换的值、未绑定的源属性值对WPF DataGridTextColumn进行排序?现在它是按行viewmodel中的整数值排序的,而不是由转换器返回的显示文本。我使用MVVM

下面是一个请求示例。然而,这是一个普遍的问题。我可以将MmsClass.Name放入表示行的类中。但我需要在任何地方进行适当的分类,而不仅仅是在这里

一行的类:

public class MaintenanceDataItem
{
    public MaintenanceDataItem(int classId, Type objectType, object value, IEnumerable<MmsData> rows)
    {
        ClassId = classId;
        TypeOfObject = objectType;
        Value = value;
        ObjectIds = new List<int>();
        MmsDataRows = rows;
    }

    public int ClassId { get; private set; }
    // rest of the properrties omitted
}
xaml中的列:

            <DataGridTextColumn Header="{StaticResource ResourceKey=MmsStrCondClass}" Binding="{Binding ClassId, Converter={StaticResource mmsclasstonameconverter}}" Width="*">
                <DataGridTextColumn.ElementStyle>
                    <Style TargetType="{x:Type TextBlock}"
                        BasedOn="{StaticResource {x:Type TextBlock}}">
                        <Setter Property="TextWrapping" Value="NoWrap" />
                        <Setter Property="TextTrimming" Value="CharacterEllipsis"/>
                    </Style>
                </DataGridTextColumn.ElementStyle>
            </DataGridTextColumn>


我真的认为默认排序将显示为值。如果这个问题不容易解决,那么对datagridcolumn来说,使用转换器就没有多大意义。

听起来您可能想查看CollectionViewSource.SortDescriptions

下面是一个可能的示例:

XAML

其中MainWindowViewModel.Fruits简单定义为:
public静态字符串[]Fruits{get;}={“苹果”、“香蕉”、“葡萄”、“橙子”、“猕猴桃”}

结果 这将自动生成:

不幸的是,这种方法只适用于viewmodel值,如果您使用的是转换器,您反而希望将这些值公开为viewmodel属性,然后将它们提供给SortDescriptions。据我所知,DataGrid即使在用户排序模式下也不支持这种情况


如果您想讨论这个问题,请随时来我们的房间找任何一位房主,如果我不在那里,他们将能够提供帮助。

不幸的是,这不是一项微不足道的任务。正如@Maverik正确指出的那样,
DataGrid
对底层数据进行排序,而不是对转换器输出的数据进行排序。为此,您需要自己进行排序。首先创建一个类,该类具有一个属性以使用自定义排序器,另一个属性定义要在给定列上使用的排序器:

    public static ICustomSorter GetCustomSorter(DependencyObject obj)
    {
        return (ICustomSorter)obj.GetValue(CustomSorterProperty);
    }

    public static void SetCustomSorter(DependencyObject obj, ICustomSorter value)
    {
        obj.SetValue(CustomSorterProperty, value);
    }

    // Using a DependencyProperty as the backing store for CustomSorter.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CustomSorterProperty =
        DependencyProperty.RegisterAttached("CustomSorter", typeof(ICustomSorter), typeof(CustomSortBehavior), new PropertyMetadata(null));

    public static bool GetAllowCustomSort(DependencyObject obj)
    {
        return (bool)obj.GetValue(AllowCustomSortProperty);
    }

    public static void SetAllowCustomSort(DependencyObject obj, bool value)
    {
        obj.SetValue(AllowCustomSortProperty, value);
    }

    // Using a DependencyProperty as the backing store for AllowCustomSort.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty AllowCustomSortProperty =
        DependencyProperty.RegisterAttached("AllowCustomSort", typeof(bool), typeof(CustomSortBehavior), new PropertyMetadata(false, AllowCustomSortChanged));
icCustomSorter
是一个非常简单的界面:

public interface ICustomSorter : IComparer
{
    ListSortDirection SortDirection { get; set; }

    string SortMemberPath { get; set; }
}
现在需要从“AllowCustomSort”实现自定义排序:

这只是连接
排序
事件,然后通过调用提供的
iccustomsorter
对集合进行排序来处理它

在XAML中,您可以创建一个已实现的
icCustomSorter
的实例,并使用以下附加属性:

            <DataGridTextColumn Header="Column1" Binding="{Binding Column1, Converter={StaticResource Column1Converter}}" IsReadOnly="True"
                                util:CustomSortBehavior.CustomSorter="{StaticResource Column1Comparer}"/>


这很痛苦,您必须对所有转换的值进行自定义排序,但它确实允许您在
DataGrid
超级简单的工作解决方案中执行此操作:

  • 侦听DataGrid的排序事件
  • 激发事件时,请验证列
  • 按你喜欢的方式对列表排序
  • 将已排序的新集合放回DataGrid的ItemsSource
  • 已处理标记事件,因此不会应用基本排序
  • 例如:

    cs

    //
    ///捕获DataGrid的排序事件和
    ///按员工而不是按计划顺序对所有行进行排序
    /// 
    私有void MainDataGrid_排序(对象发送方、DataGridSortingEventArgs e)
    {
    if(e.Column.Header是字符串Header&&Header.Equals(Properties.Resources.EmployeeName))
    {
    //AllRows是绑定到我的DataGrid的ItemsSource的属性
    AllRows=programaItems.ToList().OrderBy(item=>item.SelectedWorkOrder.WorkOrderResource.EmployeeName),然后By(item=>item.SelectedWorkOrder.WorkOrderResource.PlanitSetupOrder);
    //已处理的标志事件
    e、 已处理=正确;
    }
    }
    
    xaml

    
    
    分享一些代码以更好地理解您的问题…感谢您的关注。我的问题是一般性的。这就是为什么我省略了代码。尽管如此,我还是添加了一段代码。您是否尝试将
    SortMemberPath
    设置为列的
    Text
    属性?我不确定是否可以设置像
    这样的绑定。也许你需要设置一个RelativeSource(只是随便玩一下)。DataGridTextColumn没有文本。必须以其他方式找到它。查找文本块和文本的孩子。我尝试了这个,但没有成功:谢谢你的回答,但我不明白这些和我的问题有什么关系。这将使用属性,而不是转换的显示值,对吗?这还将在打开窗口时设置长度的升序排序。我只是想定义排序的工作方式(按显示值),而不是设置排序。重点是向您显示CollectionViewSource+SortDescriptions。并不是说你们像我在示例中展示的那个样硬编码。Re:你关于转换价值的问题,我已经回答了。简而言之,这是不可能的。我们的WPF会议室中提到了另一种方法。你很快就会看到另一个答案。如果没有,你可能想到我们的房间来推布拉德利(或者只是读一下我和他之间的文字记录)。。。至于为什么在SetMemberPath上使用SortDescriptions:我个人使用collectionviewsource作为一站式控件进行分组和排序,而不管显示控件是否支持SortMemberPath(您可能知道,它们通常不支持)。另外,SortDescriptions允许我执行我不知道您可以使用SortMemberPath执行的多重排序。@matti My viewmodel不需要知道显示的值。我不同意,因为模型包含我们的抽象,viewmodel需要实现它们并跟踪状态。而视图应尽可能保持沉默,仅表示viewmodel状态。这就是为什么可以从视图中进行排序,它只是表示。但是用于排序的值应该来自viewmodel。至于XAML转换器,我认为它们是boolToVis的意思,而不是从字典中获取数据
    public interface ICustomSorter : IComparer
    {
        ListSortDirection SortDirection { get; set; }
    
        string SortMemberPath { get; set; }
    }
    
        private static void AllowCustomSortChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataGrid control = d as DataGrid;
            {
                var oldAllow = (bool)e.OldValue;
                var newAllow = (bool)e.NewValue;
    
                if (!oldAllow && newAllow)
                {
                    control.Sorting += HandleCustomSorting;
                }
                else
                {
                    control.Sorting -= HandleCustomSorting;
                }
            }
        }
    
        private static void HandleCustomSorting(object sender, DataGridSortingEventArgs e)
        {
            //Check if we should even be using custom sorting
            DataGrid dataGrid = sender as DataGrid;
            if (dataGrid != null && GetAllowCustomSort(dataGrid))
            {
                //Make sure we have a source we can sort
                ListCollectionView itemsSource = dataGrid.ItemsSource as ListCollectionView;
                if (itemsSource != null)
                {
                    ICustomSorter columnSorter = GetCustomSorter(e.Column);
    
                    //Only do our own sort if a sorter was defined
                    if (columnSorter != null)
                    {
                        ListSortDirection nextSortDirection = e.Column.SortDirection == ListSortDirection.Ascending ?
                                                              ListSortDirection.Descending :
                                                              ListSortDirection.Ascending;
                        e.Column.SortDirection = columnSorter.SortDirection = nextSortDirection;
                        columnSorter.SortMemberPath = e.Column.SortMemberPath;
                        itemsSource.CustomSort = columnSorter;
    
                        //We've handled the sort, don't let the DataGrid mess with us
                        e.Handled = true;
                    }
                }
            }
        }
    
                <DataGridTextColumn Header="Column1" Binding="{Binding Column1, Converter={StaticResource Column1Converter}}" IsReadOnly="True"
                                    util:CustomSortBehavior.CustomSorter="{StaticResource Column1Comparer}"/>
    
            /// <summary>
            /// catch DataGrid's sorting event and 
            /// sort AllRows by employee, than by planit order
            /// </summary>
            private void MainDataGrid_Sorting(object sender, DataGridSortingEventArgs e)
            {
                if (e.Column.Header is string header && header.Equals(Properties.Resources.EmployeeName))
                {
                    // AllRows is a property binded to my DataGrid's ItemsSource
                    AllRows = programaItems.ToList().OrderBy(item => item.SelectedWorkOrder.WorkOrderResource.EmployeeName).ThenBy(item => item.SelectedWorkOrder.WorkOrderResource.PlanitSetupOrder);
                    // flag event handled
                    e.Handled = true;
                }
            }
    
    <DataGrid ... Sorting="MainDataGrid_Sorting">
        <DataGrid.Columns...