कॉलम-हेडर क्लिक पर WPF ListView / GridView सॉर्ट करने के लिए सबसे अच्छा तरीका है?


84

कर रहे हैं बहुत सारे इंटरनेट WPF से मालूम होता है बहुत-बुनियादी चूक को भरने के लिए प्रयास करने पर समाधान के। मैं वास्तव में उलझन में हूं कि "सबसे अच्छा" तरीका क्या होगा। उदाहरण के लिए ... मैं चाहता हूं कि सॉर्ट दिशा को इंगित करने के लिए कॉलम हेडर में थोड़ा ऊपर / नीचे तीर हो। जाहिरा तौर पर ऐसा करने के 3 अलग-अलग तरीके हैं, कुछ कोड का उपयोग कर, कुछ मार्कअप का उपयोग कर रहे हैं, कुछ मार्कअप-प्लस-कोड का उपयोग कर रहे हैं, और सभी एक हैक की तरह लग रहे हैं।

क्या किसी ने पहले इस समस्या में भाग लिया, और एक समाधान पाया कि वे पूरी तरह से खुश हैं? यह विचित्र लगता है कि कार्यक्षमता का ऐसा बुनियादी WinForms WPF से गायब है और इसे हैक करने की आवश्यकता है।


मान्यता प्राप्त करने के लिए उपयोग कैसे करें के बारे में उपरोक्त प्रश्न के उत्तर में। Xmlns जोड़ें: उपयोग = "clr-namespace: Wpf.Util" xaml डॉक्यूमेंट में सबसे ऊपर नामस्थान पर
meldo

यदि संभव हो तो .. DataGrid का उपयोग करें।
अभिजीत नागरे

जवाबों:


22

यह सब वास्तव में निर्भर करता है, यदि आप WPF टूलकिट से डेटाग्रिड का उपयोग कर रहे हैं तो एक बिल्ट इन सॉर्ट, यहां तक ​​कि एक मल्टी-कॉलम सॉर्ट भी है जो बहुत उपयोगी है। यहां और देखें:

विंसेंट सिबल्स ब्लॉग

वैकल्पिक रूप से, यदि आप एक अलग नियंत्रण का उपयोग कर रहे हैं जो छँटाई का समर्थन नहीं करता है, तो मैं निम्नलिखित विधियों की सिफारिश करूँगा:

ली गाओ की कस्टम छँटाई

के बाद:

ली गाओ की तेज़ छँटाई


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) थॉमस के लेख में लिंक किए गए अद्यतन संस्करण का उपयोग करें, और 2) टिप्पणियों में एलेक्स के प्रीटियर ग्लिफ़ संस्करण का उपयोग करें।
हेलिज क्लेन

उत्कृष्ट उपयोगिता श्री एल!
मेट्रो स्मर्फ

मैं WPF के लिए नया हूँ और इस "उपयोग" बिट को काफी नहीं समझता। वह संदर्भ क्या है? संपादित करें: nm ... "व्यू सोर्स" नाम की यह छोटी सी कड़ी थी जो अभी मेरे ऊपर से नहीं निकली थी। यह कक्षा के लिए स्रोत कोड का विस्तार करता है
oscilatingcretin

मुझे वह बेहद पसंद है! मैं गतिशील रूप से आइटम जोड़ / निकाल रहा हूं और यह बिना ऑर्डर बदले बहुत अच्छा काम करता है। लेकिन मैं छंटाई के लिए प्रारंभिक स्थिति कैसे निर्धारित कर सकता हूं? CollectionViewSource.GetDefaultView(MyList.ItemsSource).SortDescriptions.Add(new SortDescription("Number", ListSortDirection.Ascending));काम नहीं करता है।
ज़ी

@ ज़ी, यह काम करना चाहिए, लेकिन यह सॉर्ट ग्लिफ़ को प्रदर्शित नहीं करेगा ... मैंने एक प्रारंभिक आदेश सेट करने का तरीका लागू नहीं किया है, लेकिन आप हमेशा मेरे कोड को संशोधित करने का प्रयास कर सकते हैं;)
थॉमस लेवेस्क

23

MSDN स्तंभों पर सॉर्ट करने का एक आसान तरीका है अप / डाउन ग्लिफ़ वाले । उदाहरण पूर्ण नहीं है, हालांकि - वे यह नहीं समझाते कि ग्लिफ़ के लिए डेटा टेम्प्लेट का उपयोग कैसे करें। नीचे मुझे अपने ListView के साथ काम करने का मौका मिला। यह .Net 4 पर काम करता है।

अपने ListView में, आपको GridViewColumnHeader पर एक क्लिक के लिए आग लगाने के लिए एक इवेंट हैंडलर निर्दिष्ट करना होगा। मेरी सूची दृश्य इस तरह दिखता है:

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

और फिर अपने एक्सएएमएल में, आपको दो डेटाटेम्पलेट्स जोड़ने की जरूरत है जिन्हें आपने छँटाई विधि में निर्दिष्ट किया है:

<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के साथ LastChildFillसही पर सेट हैडर के दाईं तरफ ग्लिफ़ रखने के लिए और लेबल अंतरिक्ष के बाकी भरने देगा। मैं की DockPanelचौड़ाई के लिए बाध्य ActualWidthहैGridViewColumnHeader क्योंकि मेरी वाले कॉलम चौड़ाई है, जो सामग्री के लिए उन्हें autofit की सुविधा देता है है। MinWidthहालांकि, मैंने स्तंभों पर सेट किया , ताकि ग्लिफ़ कॉलम शीर्षक को कवर न करे। यह TextBlock Textएक खाली बाइंडिंग पर सेट है जो हैडर में निर्दिष्ट कॉलम नाम को प्रदर्शित करता है।


1
यह निर्दिष्ट नहीं करता है कि XAML में DataTemplates Grid.Resource को कहां रखा जाए?

4
@ मार्क यह शायद आपकी मदद करने के लिए बहुत देर हो चुकी है, लेकिन टेम्प्लेट को मूल तत्व के संसाधन में रखा जाना चाहिए, आमतौर पर <Window.Resources>या <UserControl.Resources>। HTHS;)
CptRobby

1
@ CptRobby हाय .. मेरे लिए, जैसा कि blcv को इनिशियलाइज़ नहीं किया गया है, यह एक शून्य संदर्भ अपवाद देता है ... तो यह कोड किसी के लिए कैसे काम करेगा?
जय निर्गुडकर

@JayNirgudkar मैं इसका लेखक नहीं हूं, जेरेड हार्ले है। लेकिन मैं आपको बता सकता हूं कि blcv वह है जो वह अपने ListView के आइटम स्रोत के रूप में उपयोग कर रहा था। आपको एक ही काम नहीं करना है। आइटम के स्रोत से निपटने के वैकल्पिक तरीके के लिए MSDN लिंक पर क्लिक करें।
CptRobby

2
MSDN उदाहरण मानता है headerClicked.Column.Header(जो हेडर टेक्स्ट है) (headerClicked.Column.DisplayMemberBinding as Binding).Path.Path(जो बाध्यकारी पथ है) के बराबर है । हेडर टेक्स्ट पर सॉर्ट करने से काम नहीं चलता है। बहुत अजीब।
क्रिस

5

मैं MVVM का उपयोग करता हूं, इसलिए मैंने थॉमस के संदर्भ के रूप में उपयोग करते हुए, अपने स्वयं के कुछ संलग्न गुण बनाए। यह एक समय में एक कॉलम पर छंटनी करता है जब आप हेडर पर क्लिक करते हैं, आरोही और अवरोही के बीच टॉगल करते हैं। यह पहले कॉलम का उपयोग करके शुरुआत से ही सॉर्ट करता है। और यह Win7 / 8 शैली के ग्लिफ़ को दर्शाता है।

आम तौर पर, आपको बस इतना करना है कि मुख्य संपत्ति को सही पर सेट करें (लेकिन आपको स्पष्ट रूप से ग्रिड व्यूऑनलाइनहेडर्स घोषित करना होगा):

<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"

और फिर किसी भी s पर किसी Windowभी संख्या में SortableListView, बस निम्नलिखित कोड जोड़ें:

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

Controlsउस नामस्थान के लिए सिर्फ XAML ID कहां है जिसमें आपने SortableListViewनियंत्रण बनाया था ।

तो, यह कोड को डुप्लिकेट करने के लिए छँटाई को रोकता है, आपको बस ऊपर दिए गए ईवेंट को संभालने के लिए याद रखने की आवश्यकता है।


1
मैंने आपके समाधान से प्रेरणा ली और उसी सड़क के नीचे चला गया, जिससे ग्रिड व्यूक्लुमहेडर का उपयोग किया जा सके। क्लिक करें घटना आप कंस्ट्रक्टर में एक हैंडलर जोड़ सकते हैं। इस। एडलर
डेरिक म्यूलर

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

Im आप सभी को लगता है कि यहाँ पर ICommand DelegateCommand बनाना जानते हैं। इससे मुझे ViewModel में अपने सभी View पर क्लिक करने की अनुमति मिली।

मैंने केवल इसे जोड़ा ताकि एक ही चीज़ को पूरा करने के कई तरीके हों। मैंने हेडर में एरो बटन जोड़ने के लिए कोड नहीं लिखा था, लेकिन यह एक्सएएमएल शैली में किया जाएगा, आपको पूरे हेडर को फिर से डिज़ाइन करना होगा जो कि उनके कोड में 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
कोड की सैकड़ों पंक्तियों को फेंकने का मतलब कुछ भी नहीं है अगर आप यह नहीं समझाते कि वे क्या कर रहे हैं
schizoid04

0

बस एक और सरल तरीका जोड़ना चाहता था कोई WPF ListView को सॉर्ट कर सकता है

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);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.