列ヘッダーのクリックでWPFListView / GridViewを並べ替える最良の方法は?


84

この一見非常に基本的なWPFからの省略を埋めようとするソリューションは、インターネット上にたくさんあります。私は「最良の」方法が何であるかについて本当に混乱しています。たとえば...並べ替えの方向を示すために、列ヘッダーに小さな上向き/下向き矢印が必要です。これを行うには、コードを使用する方法、マークアップを使用する方法、マークアップとコードを使用する方法の3つの方法があり、すべてハックのように見えます。

誰かが以前にこの問題に遭遇し、彼らが完全に満足している解決策を見つけたことがありますか?このような基本的なWinFormsの機能がWPFにないため、ハッキングする必要があるのは奇妙に思えます。


utilを認識させる方法についての上記の質問への回答。XAMLドキュメントの一番上に名前空間に:「Wpf.UtilをCLR名前空間」= UTIL:のxmlnsを追加
meldo

可能であれば、DataGridを使用してください。
Abhijeet Nagre

回答:



111

を自動的に並べ替えるための添付プロパティのセットを作成GridViewましたこちらで確認できます。上/下矢印は処理しませんが、簡単に追加できます。

<ListView ItemsSource="{Binding Persons}"
          IsSynchronizedWithCurrentItem="True"
          util:GridViewSort.AutoSort="True">
    <ListView.View>
        <GridView>
            <GridView.Columns>
                <GridViewColumn Header="Name"
                                DisplayMemberBinding="{Binding Name}"
                                util:GridViewSort.PropertyName="Name"/>
                <GridViewColumn Header="First name"
                                DisplayMemberBinding="{Binding FirstName}"
                                util:GridViewSort.PropertyName="FirstName"/>
                <GridViewColumn Header="Date of birth"
                                DisplayMemberBinding="{Binding DateOfBirth}"
                                util:GridViewSort.PropertyName="DateOfBirth"/>
            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>

8
トーマスに感謝します。ソートの問題に対するソリューションは、エレガントで使いやすく、非常に柔軟です。言い換えれば、完璧です!他の人へのヒント:1)Thomasの記事にリンクされている更新バージョンを使用し、2)コメントでAlexのよりきれいなグリフバージョンを使用します。
Helge Klein

優れた実用性Lさん!
メトロスマーフ2011年

私はWPFを初めて使用し、この「util」ビットを完全には理解していません。その参照は何ですか?編集:nm ...「ソースの表示」と呼ばれるこの小さなリンクがありましたが、すぐには飛び出しませんでした。これにより、クラスのソースコードが拡張されます
oscilatingcretin 2011

私はそれがとても好きです!アイテムを動的に追加/削除していますが、これは順序を変更しなくてもうまく機能します。しかし、どうすればソートの初期状態を設定できますか?CollectionViewSource.GetDefaultView(MyList.ItemsSource).SortDescriptions.Add(new SortDescription("Number", ListSortDirection.Ascending));動作しません。
zee 2011

@zee、動作するはずですが、ソートグリフが表示されません...初期順序を設定する方法を実装していませんが、いつでもコードを変更してみることができます;)
Thomas Levesque 2011

23

MSDNには、上/下のグリフを持つ並べ替えを実行する簡単な方法があります。ただし、この例は完全ではありません。グリフのデータテンプレートの使用方法については説明されていません。以下は、ListViewを使用して作業するために取得したものです。これは.Net4で機能します。

ListViewで、GridViewColumnHeaderをクリックしたときに起動するイベントハンドラーを指定する必要があります。私のListViewは次のようになります。

<ListView Name="results" GridViewColumnHeader.Click="results_Click">
    <ListView.View>
        <GridView>
            <GridViewColumn DisplayMemberBinding="{Binding Path=ContactName}">
                <GridViewColumn.Header>
                    <GridViewColumnHeader Content="Contact Name" Padding="5,0,0,0" HorizontalContentAlignment="Left" MinWidth="150" Name="ContactName" />
                </GridViewColumn.Header>
            </GridViewColumn>
            <GridViewColumn DisplayMemberBinding="{Binding Path=PrimaryPhone}">
                <GridViewColumn.Header>
                    <GridViewColumnHeader Content="Contact Number" Padding="5,0,0,0" HorizontalContentAlignment="Left" MinWidth="150" Name="PrimaryPhone"/>
                </GridViewColumn.Header>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

コードビハインドで、並べ替えを処理するコードを設定します。

// Global objects
BindingListCollectionView blcv;
GridViewColumnHeader _lastHeaderClicked = null;
ListSortDirection _lastDirection = ListSortDirection.Ascending;

// Header click event
void results_Click(object sender, RoutedEventArgs e)
{
    GridViewColumnHeader headerClicked =
    e.OriginalSource as GridViewColumnHeader;
    ListSortDirection direction;

    if (headerClicked != null)
    {
    if (headerClicked.Role != GridViewColumnHeaderRole.Padding)
    {
        if (headerClicked != _lastHeaderClicked)
        {
            direction = ListSortDirection.Ascending;
        }
        else
        {
            if (_lastDirection == ListSortDirection.Ascending)
            {
                direction = ListSortDirection.Descending;
            }
            else
            {
                direction = ListSortDirection.Ascending;
            }
        }

        string header = headerClicked.Column.Header as string;
        Sort(header, direction);

        if (direction == ListSortDirection.Ascending)
        {
            headerClicked.Column.HeaderTemplate =
              Resources["HeaderTemplateArrowUp"] as DataTemplate;
        }
        else
        {
            headerClicked.Column.HeaderTemplate =
              Resources["HeaderTemplateArrowDown"] as DataTemplate;
        }

        // Remove arrow from previously sorted header
        if (_lastHeaderClicked != null && _lastHeaderClicked != headerClicked)
        {
            _lastHeaderClicked.Column.HeaderTemplate = null;
        }

        _lastHeaderClicked = headerClicked;
        _lastDirection = direction;
    }
}

// Sort code
private void Sort(string sortBy, ListSortDirection direction)
{
    blcv.SortDescriptions.Clear();
    SortDescription sd = new SortDescription(sortBy, direction);
    blcv.SortDescriptions.Add(sd);
    blcv.Refresh();
}

次に、XAMLで、並べ替え方法で指定した2つのDataTemplatesを追加する必要があります。

<DataTemplate x:Key="HeaderTemplateArrowUp">
    <DockPanel LastChildFill="True" Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type GridViewColumnHeader}}}">
        <Path x:Name="arrowUp" StrokeThickness="1" Fill="Gray" Data="M 5,10 L 15,10 L 10,5 L 5,10" DockPanel.Dock="Right" Width="20" HorizontalAlignment="Right" Margin="5,0,5,0" SnapsToDevicePixels="True"/>
        <TextBlock Text="{Binding }" />
    </DockPanel>
</DataTemplate>

<DataTemplate x:Key="HeaderTemplateArrowDown">
    <DockPanel LastChildFill="True" Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type GridViewColumnHeader}}}">
        <Path x:Name="arrowDown" StrokeThickness="1" Fill="Gray"  Data="M 5,5 L 10,10 L 15,5 L 5,5" DockPanel.Dock="Right" Width="20" HorizontalAlignment="Right" Margin="5,0,5,0" SnapsToDevicePixels="True"/>
        <TextBlock Text="{Binding }" />
    </DockPanel>
</DataTemplate>

使用DockPanelしてLastChildFilltrueに設定すると、ヘッダーの右にグリフを維持し、ラベルはスペースの残りの部分を埋めるようになります。私はバインドDockPanelに幅をActualWidthするGridViewColumnHeader私の列がそれらをコンテンツに自動調整することができます何の幅を持っていないので。MinWidthただし、グリフが列のタイトルを隠さないように、列にsを設定しました。TextBlock Textヘッダで指定された列名を表示する結合空に設定されています。


1
これは、XAMLのどこにDataTemplates Grid.Resourcesを配置するかを指定していませんか?

4
@Markこれはおそらく手遅れですが、テンプレートはルート要素のリソース(通常は<Window.Resources>または)に配置する必要があり<UserControl.Resources>ます。HTHS;)
CptRobby 2013

1
@CptRobbyこんにちは..私にとって、blcvは初期化されていないため、null参照例外が発生します...では、このコードは誰にとってもどのように機能するでしょうか?
Jay Nirgudkar 2015年

@JayNirgudkar私はこれの作者ではありません、JaredHarleyはそうです。しかし、blcvは、彼がListViewのItemsSourceとして使用していたものであると言えます。同じことをする必要はありません。ItemsSourceを処理する別の方法については、彼が提供したMSDNリンクをクリックしてください。
cptRobby 2015年

2
MSDNの例では、headerClicked.Column.Header(ヘッダーテキスト)が(headerClicked.Column.DisplayMemberBinding as Binding).Path.Path(バインディングパス)と同等であると想定しています。ヘッダーテキストの並べ替えは機能しません。とても奇妙です。
クリス

5

私はMVVMを使用しているので、Thomasを参照して、独自の添付プロパティをいくつか作成しました。ヘッダーをクリックすると、一度に1つの列で並べ替えが行われ、昇順と降順が切り替わります。最初の列を使用して最初から並べ替えます。そしてそれはWin7 / 8スタイルのグリフを示しています。

通常、必要なのはmainプロパティをtrueに設定することだけです(ただし、GridViewColumnHeadersを明示的に宣言する必要があります)。

<Window xmlns:local="clr-namespace:MyProjectNamespace">
  <Grid>
    <ListView local:App.EnableGridViewSort="True" ItemsSource="{Binding LVItems}">
      <ListView.View>
        <GridView>
          <GridViewColumn DisplayMemberBinding="{Binding Property1}">
            <GridViewColumnHeader Content="Prop 1" />
          </GridViewColumn>
          <GridViewColumn DisplayMemberBinding="{Binding Property2}">
            <GridViewColumnHeader Content="Prop 2" />
          </GridViewColumn>
        </GridView>
      </ListView.View>
    </ListView>
  </Grid>
<Window>

表示とは異なるプロパティで並べ替える場合は、次のように宣言する必要があります。

<GridViewColumn DisplayMemberBinding="{Binding Property3}"
                local:App.GridViewSortPropertyName="Property4">
    <GridViewColumnHeader Content="Prop 3" />
</GridViewColumn>

添付されたプロパティのコードは次のとおりです。怠惰になり、提供されたApp.xaml.csに配置するのが好きです。

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data.
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace MyProjectNamespace
{
  public partial class App : Application
  {
      #region GridViewSort
      public static DependencyProperty GridViewSortPropertyNameProperty =
          DependencyProperty.RegisterAttached(
              "GridViewSortPropertyName", 
              typeof(string), 
              typeof(App), 
              new UIPropertyMetadata(null)
          );

      public static string GetGridViewSortPropertyName(GridViewColumn gvc)
      {
          return (string)gvc.GetValue(GridViewSortPropertyNameProperty);
      }

      public static void SetGridViewSortPropertyName(GridViewColumn gvc, string n)
      {
          gvc.SetValue(GridViewSortPropertyNameProperty, n);
      }

      public static DependencyProperty CurrentSortColumnProperty =
          DependencyProperty.RegisterAttached(
              "CurrentSortColumn", 
              typeof(GridViewColumn), 
              typeof(App), 
              new UIPropertyMetadata(
                  null, 
                  new PropertyChangedCallback(CurrentSortColumnChanged)
              )
          );

      public static GridViewColumn GetCurrentSortColumn(GridView gv)
      {
          return (GridViewColumn)gv.GetValue(CurrentSortColumnProperty);
      }

      public static void SetCurrentSortColumn(GridView gv, GridViewColumn value)
      {
          gv.SetValue(CurrentSortColumnProperty, value);
      }

      public static void CurrentSortColumnChanged(
          object sender, DependencyPropertyChangedEventArgs e)
      {
          GridViewColumn gvcOld = e.OldValue as GridViewColumn;
          if (gvcOld != null)
          {
              CurrentSortColumnSetGlyph(gvcOld, null);
          }
      }

      public static void CurrentSortColumnSetGlyph(GridViewColumn gvc, ListView lv)
      {
          ListSortDirection lsd;
          Brush brush;
          if (lv == null)
          {
              lsd = ListSortDirection.Ascending;
              brush = Brushes.Transparent;
          }
          else
          {
              SortDescriptionCollection sdc = lv.Items.SortDescriptions;
              if (sdc == null || sdc.Count < 1) return;
              lsd = sdc[0].Direction;
              brush = Brushes.Gray;
          }

          FrameworkElementFactory fefGlyph = 
              new FrameworkElementFactory(typeof(Path));
          fefGlyph.Name = "arrow";
          fefGlyph.SetValue(Path.StrokeThicknessProperty, 1.0);
          fefGlyph.SetValue(Path.FillProperty, brush);
          fefGlyph.SetValue(StackPanel.HorizontalAlignmentProperty, 
              HorizontalAlignment.Center);

          int s = 4;
          if (lsd == ListSortDirection.Ascending)
          {
              PathFigure pf = new PathFigure();
              pf.IsClosed = true;
              pf.StartPoint = new Point(0, s);
              pf.Segments.Add(new LineSegment(new Point(s * 2, s), false));
              pf.Segments.Add(new LineSegment(new Point(s, 0), false));

              PathGeometry pg = new PathGeometry();
              pg.Figures.Add(pf);

              fefGlyph.SetValue(Path.DataProperty, pg);
          }
          else
          {
              PathFigure pf = new PathFigure();
              pf.IsClosed = true;
              pf.StartPoint = new Point(0, 0);
              pf.Segments.Add(new LineSegment(new Point(s, s), false));
              pf.Segments.Add(new LineSegment(new Point(s * 2, 0), false));

              PathGeometry pg = new PathGeometry();
              pg.Figures.Add(pf);

              fefGlyph.SetValue(Path.DataProperty, pg);
          }

          FrameworkElementFactory fefTextBlock = 
              new FrameworkElementFactory(typeof(TextBlock));
          fefTextBlock.SetValue(TextBlock.HorizontalAlignmentProperty,
              HorizontalAlignment.Center);
          fefTextBlock.SetValue(TextBlock.TextProperty, new Binding());

          FrameworkElementFactory fefDockPanel = 
              new FrameworkElementFactory(typeof(StackPanel));
          fefDockPanel.SetValue(StackPanel.OrientationProperty,
              Orientation.Vertical);
          fefDockPanel.AppendChild(fefGlyph);
          fefDockPanel.AppendChild(fefTextBlock);

          DataTemplate dt = new DataTemplate(typeof(GridViewColumn));
          dt.VisualTree = fefDockPanel;

          gvc.HeaderTemplate = dt;
      }

      public static DependencyProperty EnableGridViewSortProperty =
          DependencyProperty.RegisterAttached(
              "EnableGridViewSort", 
              typeof(bool), 
              typeof(App), 
              new UIPropertyMetadata(
                  false, 
                  new PropertyChangedCallback(EnableGridViewSortChanged)
              )
          );

      public static bool GetEnableGridViewSort(ListView lv)
      {
          return (bool)lv.GetValue(EnableGridViewSortProperty);
      }

      public static void SetEnableGridViewSort(ListView lv, bool value)
      {
          lv.SetValue(EnableGridViewSortProperty, value);
      }

      public static void EnableGridViewSortChanged(
          object sender, DependencyPropertyChangedEventArgs e)
      {
          ListView lv = sender as ListView;
          if (lv == null) return;

          if (!(e.NewValue is bool)) return;
          bool enableGridViewSort = (bool)e.NewValue;

          if (enableGridViewSort)
          {
              lv.AddHandler(
                  GridViewColumnHeader.ClickEvent,
                  new RoutedEventHandler(EnableGridViewSortGVHClicked)
              );
              if (lv.View == null)
              {
                  lv.Loaded += new RoutedEventHandler(EnableGridViewSortLVLoaded);
              }
              else
              {
                  EnableGridViewSortLVInitialize(lv);
              }
          }
          else
          {
              lv.RemoveHandler(
                  GridViewColumnHeader.ClickEvent,
                  new RoutedEventHandler(EnableGridViewSortGVHClicked)
              );
          }
      }

      public static void EnableGridViewSortLVLoaded(object sender, RoutedEventArgs e)
      {
          ListView lv = e.Source as ListView;
          EnableGridViewSortLVInitialize(lv);
          lv.Loaded -= new RoutedEventHandler(EnableGridViewSortLVLoaded);
      }

      public static void EnableGridViewSortLVInitialize(ListView lv)
      {
          GridView gv = lv.View as GridView;
          if (gv == null) return;

          bool first = true;
          foreach (GridViewColumn gvc in gv.Columns)
          {
              if (first)
              {
                  EnableGridViewSortApplySort(lv, gv, gvc);
                  first = false;
              }
              else
              {
                  CurrentSortColumnSetGlyph(gvc, null);
              }
          }
      }

      public static void EnableGridViewSortGVHClicked(
          object sender, RoutedEventArgs e)
      {
          GridViewColumnHeader gvch = e.OriginalSource as GridViewColumnHeader;
          if (gvch == null) return;
          GridViewColumn gvc = gvch.Column;
          if(gvc == null) return;            
          ListView lv = VisualUpwardSearch<ListView>(gvch);
          if (lv == null) return;
          GridView gv = lv.View as GridView;
          if (gv == null) return;

          EnableGridViewSortApplySort(lv, gv, gvc);
      }

      public static void EnableGridViewSortApplySort(
          ListView lv, GridView gv, GridViewColumn gvc)
      {
          bool isEnabled = GetEnableGridViewSort(lv);
          if (!isEnabled) return;

          string propertyName = GetGridViewSortPropertyName(gvc);
          if (string.IsNullOrEmpty(propertyName))
          {
              Binding b = gvc.DisplayMemberBinding as Binding;
              if (b != null && b.Path != null)
              {
                  propertyName = b.Path.Path;
              }

              if (string.IsNullOrEmpty(propertyName)) return;
          }

          ApplySort(lv.Items, propertyName);
          SetCurrentSortColumn(gv, gvc);
          CurrentSortColumnSetGlyph(gvc, lv);
      }

      public static void ApplySort(ICollectionView view, string propertyName)
      {
          if (string.IsNullOrEmpty(propertyName)) return;

          ListSortDirection lsd = ListSortDirection.Ascending;
          if (view.SortDescriptions.Count > 0)
          {
              SortDescription sd = view.SortDescriptions[0];
              if (sd.PropertyName.Equals(propertyName))
              {
                  if (sd.Direction == ListSortDirection.Ascending)
                  {
                      lsd = ListSortDirection.Descending;
                  }
                  else
                  {
                      lsd = ListSortDirection.Ascending;
                  }
              }
              view.SortDescriptions.Clear();
          }

          view.SortDescriptions.Add(new SortDescription(propertyName, lsd));
      }
      #endregion

      public static T VisualUpwardSearch<T>(DependencyObject source) 
          where T : DependencyObject
      {
          return VisualUpwardSearch(source, x => x is T) as T;
      }

      public static DependencyObject VisualUpwardSearch(
                          DependencyObject source, Predicate<DependencyObject> match)
      {
          DependencyObject returnVal = source;

          while (returnVal != null && !match(returnVal))
          {
              DependencyObject tempReturnVal = null;
              if (returnVal is Visual || returnVal is Visual3D)
              {
                  tempReturnVal = VisualTreeHelper.GetParent(returnVal);
              }
              if (tempReturnVal == null)
              {
                  returnVal = LogicalTreeHelper.GetParent(returnVal);
              }
              else
              {
                  returnVal = tempReturnVal;
              }
          }

          return returnVal;
      }
  }
}

3

私はMicrosoftの方法を採用し、ListViewコントロールをオーバーライドしてSortableListView:を作成しました。

public partial class SortableListView : ListView
    {        
        private GridViewColumnHeader lastHeaderClicked = null;
        private ListSortDirection lastDirection = ListSortDirection.Ascending;       

        public void GridViewColumnHeaderClicked(GridViewColumnHeader clickedHeader)
        {
            ListSortDirection direction;

            if (clickedHeader != null)
            {
                if (clickedHeader.Role != GridViewColumnHeaderRole.Padding)
                {
                    if (clickedHeader != lastHeaderClicked)
                    {
                        direction = ListSortDirection.Ascending;
                    }
                    else
                    {
                        if (lastDirection == ListSortDirection.Ascending)
                        {
                            direction = ListSortDirection.Descending;
                        }
                        else
                        {
                            direction = ListSortDirection.Ascending;
                        }
                    }

                    string sortString = ((Binding)clickedHeader.Column.DisplayMemberBinding).Path.Path;

                    Sort(sortString, direction);

                    lastHeaderClicked = clickedHeader;
                    lastDirection = direction;
                }
            }
        }

        private void Sort(string sortBy, ListSortDirection direction)
        {
            ICollectionView dataView = CollectionViewSource.GetDefaultView(this.ItemsSource != null ? this.ItemsSource : this.Items);

            dataView.SortDescriptions.Clear();
            SortDescription sD = new SortDescription(sortBy, direction);
            dataView.SortDescriptions.Add(sD);
            dataView.Refresh();
        }
    }

((Binding)clickedHeader.Column.DisplayMemberBinding).Path.Pathビットは、列名がバインドパスと同じでない場合を処理しますが、Microsoftの方法では処理されません。

GridViewColumnHeader.Clickもう考えなくてもいいように、イベントを傍受したかったのですが、どうすればいいのかわかりませんでした。その結果、XAMLに次のものをすべて追加しますSortableListView

GridViewColumnHeader.Click="SortableListViewColumnHeaderClicked"

そして、Window任意の数のを含むものSortableListViewに、次のコードを追加するだけです。

private void SortableListViewColumnHeaderClicked(object sender, RoutedEventArgs e)
        {
            ((Controls.SortableListView)sender).GridViewColumnHeaderClicked(e.OriginalSource as GridViewColumnHeader);
        }

コントロールControlsを作成した名前空間のXAMLIDはどこにありますかSortableListView

したがって、これにより、並べ替え側でのコードの重複が防止されます。上記のようにイベントを処理することを忘れないでください。


1
私はあなたのソリューションからインスピレーションを得て、同じ道を進み、GridViewColumnHeader.Clickイベントにアクセスし、コンストラクターにハンドラーを追加できます。this.AddHandler(GridViewColumnHeader.ClickEvent、new RoutedEventHandler(GridViewColumnHeaderClicked));
デリックモラー2015

3

リストビューがあり、それをグリッドビューに変換する場合は、これを行うことで、グリッドビューの列ヘッダーをクリック可能にすることができます。

        <Style TargetType="GridViewColumnHeader">
            <Setter Property="Command" Value="{Binding CommandOrderBy}"/>
            <Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Self},Path=Content}"/>
        </Style>

次に、コードにデリゲートコマンドを設定するだけです。

    public DelegateCommand CommandOrderBy { get { return new DelegateCommand(Delegated_CommandOrderBy); } }

    private void Delegated_CommandOrderBy(object obj)
    {
        throw new NotImplementedException();
    }

ここでICommandDelegateCommandを作成する方法を皆さんが知っていると仮定します。これにより、ViewModelですべてのビューをクリックし続けることができました。

同じことを達成するための複数の方法があるように、これを追加しただけです。ヘッダーに矢印ボタンを追加するためのコードは作成しませんでしたが、XAMLスタイルで作成されるため、JanDotNetのコードに含まれるヘッダー全体を再設計する必要があります。


0

列ヘッダーテンプレートを含む、既存の回答とコメントのすべての作業部分を要約するソリューション:

見る:

<ListView x:Class="MyNamspace.MyListView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             ItemsSource="{Binding Items}"
             GridViewColumnHeader.Click="ListViewColumnHeaderClick">
    <ListView.Resources>

        <Style TargetType="Grid" x:Key="HeaderGridStyle">
            <Setter Property="Height" Value="20" />
        </Style>

        <Style TargetType="TextBlock" x:Key="HeaderTextBlockStyle">
            <Setter Property="Margin" Value="5,0,0,0" />
            <Setter Property="VerticalAlignment" Value="Center" />
        </Style>

        <Style TargetType="Path" x:Key="HeaderPathStyle">
            <Setter Property="StrokeThickness" Value="1" />
            <Setter Property="Fill" Value="Gray" />
            <Setter Property="Width" Value="20" />
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="Margin" Value="5,0,5,0" />
            <Setter Property="SnapsToDevicePixels" Value="True" />
        </Style>

        <DataTemplate x:Key="HeaderTemplateDefault">
            <Grid Style="{StaticResource HeaderGridStyle}">
                <TextBlock Text="{Binding }" Style="{StaticResource HeaderTextBlockStyle}" />
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="HeaderTemplateArrowUp">
            <Grid Style="{StaticResource HeaderGridStyle}">
                <Path Data="M 7,3 L 13,3 L 10,0 L 7,3" Style="{StaticResource HeaderPathStyle}" />
                <TextBlock Text="{Binding }" Style="{StaticResource HeaderTextBlockStyle}" />
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="HeaderTemplateArrowDown">
            <Grid Style="{StaticResource HeaderGridStyle}">
                <Path Data="M 7,0 L 10,3 L 13,0 L 7,0"  Style="{StaticResource HeaderPathStyle}" />
                <TextBlock Text="{Binding }" Style="{StaticResource HeaderTextBlockStyle}" />
            </Grid>
        </DataTemplate>

    </ListView.Resources>

    <ListView.View>
        <GridView ColumnHeaderTemplate="{StaticResource HeaderTemplateDefault}">

            <GridViewColumn Header="Name" DisplayMemberBinding="{Binding NameProperty}" />
            <GridViewColumn Header="Type" Width="45" DisplayMemberBinding="{Binding TypeProperty}"/>

            <!-- ... -->

        </GridView>
    </ListView.View>
</ListView>

コードビハインド:

public partial class MyListView : ListView
{
    GridViewColumnHeader _lastHeaderClicked = null;

    public MyListView()
    {
        InitializeComponent();
    }

    private void ListViewColumnHeaderClick(object sender, RoutedEventArgs e)
    {
        GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;

        if (headerClicked == null)
            return;

        if (headerClicked.Role == GridViewColumnHeaderRole.Padding)
            return;

        var sortingColumn = (headerClicked.Column.DisplayMemberBinding as Binding)?.Path?.Path;
        if (sortingColumn == null)
            return;

        var direction = ApplySort(Items, sortingColumn);

        if (direction == ListSortDirection.Ascending)
        {
            headerClicked.Column.HeaderTemplate =
                Resources["HeaderTemplateArrowUp"] as DataTemplate;
        }
        else
        {
            headerClicked.Column.HeaderTemplate =
                Resources["HeaderTemplateArrowDown"] as DataTemplate;
        }

        // Remove arrow from previously sorted header
        if (_lastHeaderClicked != null && _lastHeaderClicked != headerClicked)
        {
            _lastHeaderClicked.Column.HeaderTemplate =
                Resources["HeaderTemplateDefault"] as DataTemplate;
        }

        _lastHeaderClicked = headerClicked;
    }


    public static ListSortDirection ApplySort(ICollectionView view, string propertyName)
    {
        ListSortDirection direction = ListSortDirection.Ascending;
        if (view.SortDescriptions.Count > 0)
        {
            SortDescription currentSort = view.SortDescriptions[0];
            if (currentSort.PropertyName == propertyName)
            {
                if (currentSort.Direction == ListSortDirection.Ascending)
                    direction = ListSortDirection.Descending;
                else
                    direction = ListSortDirection.Ascending;
            }
            view.SortDescriptions.Clear();
        }
        if (!string.IsNullOrEmpty(propertyName))
        {
            view.SortDescriptions.Add(new SortDescription(propertyName, direction));
        }
        return direction;
    }
}

1
何百行ものコードを捨てても、彼らが何をしているのかを説明しなければ意味がありません
schizoid 0418

0

誰かがWPFListViewを並べ替えることができる別の簡単な方法を追加したかっただけです

void SortListView(ListView listView)
{
    IEnumerable listView_items = listView.Items.SourceCollection;
    List<MY_ITEM_CLASS> listView_items_to_list = listView_items.Cast<MY_ITEM_CLASS>().ToList();

    Comparer<MY_ITEM_CLASS> scoreComparer = Comparer<MY_ITEM_CLASS>.Create((first, second) => first.COLUMN_NAME.CompareTo(second.COLUMN_NAME));

    listView_items_to_list.Sort(scoreComparer);
    listView.ItemsSource = null;
    listView.Items.Clear();
    listView.ItemsSource = listView_items_to_list;
}

0

たくさん検索した後、最終的に私はここで簡単に見つけましたhttps://www.wpf-tutorial.com/listview-control/listview-how-to-column-sorting/

private GridViewColumnHeader listViewSortCol = null;
private SortAdorner listViewSortAdorner = null;
private void GridViewColumnHeader_Click(object sender, RoutedEventArgs e)
{
  GridViewColumnHeader column = (sender as GridViewColumnHeader);
  string sortBy = column.Tag.ToString();
  if (listViewSortCol != null)
  {
    AdornerLayer.GetAdornerLayer(listViewSortCol).Remove(listViewSortAdorner);
    yourListView.Items.SortDescriptions.Clear();
  }

  ListSortDirection newDir = ListSortDirection.Ascending;
  if (listViewSortCol == column && listViewSortAdorner.Direction == newDir)
    newDir = ListSortDirection.Descending;

  listViewSortCol = column;
  listViewSortAdorner = new SortAdorner(listViewSortCol, newDir);
  AdornerLayer.GetAdornerLayer(listViewSortCol).Add(listViewSortAdorner);
  yourListView.Items.SortDescriptions.Add(new SortDescription(sortBy, newDir));
}

クラス:

public class SortAdorner : Adorner
{
    private static Geometry ascGeometry =
        Geometry.Parse("M 0 4 L 3.5 0 L 7 4 Z");

    private static Geometry descGeometry =
        Geometry.Parse("M 0 0 L 3.5 4 L 7 0 Z");

    public ListSortDirection Direction { get; private set; }

    public SortAdorner(UIElement element, ListSortDirection dir)
        : base(element)
    {
        this.Direction = dir;
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        base.OnRender(drawingContext);

        if(AdornedElement.RenderSize.Width < 20)
            return;

        TranslateTransform transform = new TranslateTransform
            (
                AdornedElement.RenderSize.Width - 15,
                (AdornedElement.RenderSize.Height - 5) / 2
            );
        drawingContext.PushTransform(transform);

        Geometry geometry = ascGeometry;
        if(this.Direction == ListSortDirection.Descending)
            geometry = descGeometry;
        drawingContext.DrawGeometry(Brushes.Black, null, geometry);

        drawingContext.Pop();
    }
}

Xaml

<GridViewColumn Width="250">
  <GridViewColumn.Header>
    <GridViewColumnHeader Tag="Name" Click="GridViewColumnHeader_Click">Name</GridViewColumnHeader>
  </GridViewColumn.Header>
  <GridViewColumn.CellTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding Name}" ToolTip="{Binding Name}"/>
    </DataTemplate>
  </GridViewColumn.CellTemplate>
</GridViewColumn>

1
ありがとう。追加のポイントとして、説明の要約も追加できますか?これは現在、リンクとコードのみです(これはすでにリンクのみよりも優れています...)。
ユンノッシュ

-2

これを試して:

using System.ComponentModel;
youtItemsControl.Items.SortDescriptions.Add(new SortDescription("yourFavoritePropertyFromItem",ListSortDirection.Ascending);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.