2011-11-30 11 views
22

मैं एक सूची दृश्य बनाना चाहता हूं जिसमें शेष चौड़ाई के साथ दो कॉलम हैं और शेष स्थान को भरने के लिए तीसरा कॉलम है। इस तरह तो कुछ:मैं अपने ग्रिड में शेष स्थान को भरने के लिए ListView GridViewColumn कैसे प्राप्त कर सकता हूं?

<ListView> 
    <ListView.View> 
     <GridView> 
      <GridViewColumn Header="Name" Width="*" /> 
      <GridViewColumn Header="Age" Width="50" /> 
      <GridViewColumn Header="Gender" Width="50" /> 
     </GridView> 
    </ListView.View> 
</ListView> 

समस्या मैं, शेष अंतरिक्ष में भरने के लिए * के लिए चौड़ाई काम नहीं करता है सेटिंग के रूप में Name स्तंभ जाने का कोई तरीका नहीं मिल सकती है। ऐसा लगता है कि value converter के साथ ऐसा करने का कोई तरीका है, लेकिन ऐसा लगता है कि एक आसान तरीका होना चाहिए। डेटाग्रिड नियंत्रण की तरह, आप * एस के साथ कॉलम की चौड़ाई निर्दिष्ट कर सकते हैं।

उत्तर

7

समस्या यह है कि ग्रिडलेव कॉलम की कॉलम चौड़ाई ग्रिडलेथेंथ ऑब्जेक्ट की बजाय डबल है, और * को संभालने के लिए कोई रूपांतरण नहीं है। सुनिश्चित नहीं है कि यह WPF टीम द्वारा निरीक्षण किया गया है या नहीं। आपको लगता है कि यह shoudl समर्थित होना चाहिए।

कनवर्टर के अलावा, मैंने इसे देखा है एकमात्र अन्य तरीका यहां है: http://www.ontheblog.net/CMS/Default.aspx?tabid=36&EntryID=37

दोनों अतिरिक्त काम हैं जिनकी आवश्यकता नहीं होनी चाहिए। मुझे ListView और GridView कॉम्बो के साथ अन्य "अजीब" चीजें मिली हैं, इसलिए मैंने उनका उपयोग छोड़ दिया। अगर मुझे डेटाग्रिड की ज़रूरत है तो मैं तीसरे पक्ष का उपयोग करता हूं जिसे हम लाइसेंस देते हैं, अगर मुझे एक जटिल सूची बॉक्स शैली मेनू की ज़रूरत है, तो मैं सिर्फ एक टेम्पलेटेड सूची बॉक्स का उपयोग करता हूं।

+0

आह, चौड़ाई एक डबल एक GridLength वस्तु के बजाय है । यह जानना दिलचस्प होगा कि यह वास्तव में सिर्फ एक निरीक्षण है या इसके पीछे कुछ तर्क है या नहीं। ओह ठीक है, ऐसा लगता है कि मेरे परिदृश्य के लिए सबसे सरल समाधान सिर्फ डेटाग्रिड का उपयोग करना है। – JChristian

+1

इसे आजमाएं http://stackoverflow.com/a/10526024/41211 – GONeale

31

मैं एक ही चीज़ को प्राप्त करने की कोशिश कर रहा था लेकिन फिर फैसला किया कि मैं सूची सूची के प्रतिशत का उपभोग करने के लिए अपने लिस्ट व्यू कॉलम को पसंद करूंगा, इसके परिणामस्वरूप सभी कॉलम अंतरिक्ष के एक हिस्से का उपभोग कर रहे हैं और सूची दृश्य में सभी जगहों का उपभोग किया जा रहा है । आप इसे अंतिम कॉलम पर अपने 'शेष स्थान को भरने' के लक्ष्य को सीधे प्राप्त करने के लिए अंतिम कॉलम पर जो भी प्रतिशत पसंद करते हैं, उसे सेट कर सकते हैं।

मुझे यह विधि काफी मजबूत और भरोसेमंद (आकार बदलने पर भी!) इसलिए सोचा कि मैं साझा कर सकता हूं।

मेरे पास इस सूची के लिए मेरी सूची दृश्य में चार कॉलम हैं। आप सभी की जरूरत नीचे ईवेंट हैंडलर के साथ अपने ListView में SizeChanged घटना रजिस्टर करने के लिए है:

private void ProductsListView_SizeChanged(object sender, SizeChangedEventArgs e) 
{ 
    ListView listView = sender as ListView; 
    GridView gView = listView.View as GridView; 

    var workingWidth = listView.ActualWidth - SystemParameters.VerticalScrollBarWidth; // take into account vertical scrollbar 
    var col1 = 0.50; 
    var col2 = 0.20; 
    var col3 = 0.15; 
    var col4 = 0.15; 

    gView.Columns[0].Width = workingWidth*col1; 
    gView.Columns[1].Width = workingWidth*col2; 
    gView.Columns[2].Width = workingWidth*col3; 
    gView.Columns[3].Width = workingWidth*col4; 
} 
+12

मैं हार्ड-कोडित '35' के बजाय 'SystemParameters.VerticalScrollBarWidth' का उपयोग करने का सुझाव देता हूं। कुछ उपयोगकर्ता (मेरे जैसे) उनकी स्क्रॉलबार चौड़ाई को अनुकूलित करते हैं। खान शायद 70 या उससे भी अधिक हैं :) किसी भी अच्छे जवाब के लिए +1 –

+0

धन्यवाद, अच्छा बिंदु @ कोनराडमोराव्स्की – GONeale

+1

यदि आप किसी प्रकार के बच्चे ग्रिड व्यू और कॉलम बनाते हैं तो आपको अतिरिक्त अंक मिलेंगे ताकि आप इसे सभी ग्रिड व्यू के बजाय लागू कर सकें प्रत्येक दृश्य के लिए कस्टम कार्यान्वयन। – JRadness

13

इस भर में आया जब एक ऐसी ही समस्या में देख, मेरा मुद्दा मैं होने के लिए सभी स्तंभों चाहते थे 'स्वचालित' उम्मीद पहले , जो केवल अतिरिक्त जगह भर जाएगा, इसलिए मैंने गोनेले के समाधान पर विस्तार किया।

private void ListView_SizeChanged(object sender, SizeChangedEventArgs e) 
{ 
    ListView _ListView = sender as ListView; 
    GridView _GridView = _ListView.View as GridView; 
    var _ActualWidth = _ListView.ActualWidth - SystemParameters.VerticalScrollBarWidth; 
    for (Int32 i = 1; i < _GridView.Columns.Count; i++) 
    { 
     _ActualWidth = _ActualWidth - _GridView.Columns[i].ActualWidth; 
    } 
    _GridView.Columns[0].Width = _ActualWidth; 
} 

फिर XAML बस है:

... 
<ListView.View> 
    <GridView> 
     <GridViewColumn Header="Title" /> 
     <GridViewColumn Header="Artist" Width="Auto" /> 
     <GridViewColumn Header="Album" Width="Auto" /> 
     <GridViewColumn Header="Genre" Width="Auto" /> 
    </GridView> 
</ListView.View> 
... 

इस कोड को भी पर इस्तेमाल किया जा सकता और अधिक सामान्य रूप से स्तंभों की संख्या नहीं हार्ड-कोडेड और एक छोटे से फेरबदल के साथ आप शायद कर सकता है के रूप में कुछ प्रकार के तर्क के माध्यम से 'कॉलम भरें' निश्चित करें।

आशा है कि यह मदद करता है किसी को :)

+0

ऐसा करने के बाद, मैंने अपने ग्रिड व्यू में कॉलम की संख्या बदलने के बाद और कॉलम की हार्ड-कोड संख्या को तोड़ दिया। मैंने इस दृष्टिकोण को पूरा करने के लिए संशोधित किया (मैंने पहले कॉलम की चौड़ाई तय की)। धन्यवाद। –

0

मेरे समस्या समान था, लेकिन मैं पहले कॉलम की चौड़ाई तय करने के लिए करना चाहता था और मैं भी इसे तोड़ने नहीं करना चाहता था अगर मैं जोड़े या निकाले कॉलम, यहां तक ​​कि रनटाइम पर। https://stackoverflow.com/a/14674830/492

private void ResultsListView_SizeChanged(object sender, SizeChangedEventArgs e) 
    { 
     double newWidthForColumnsExceptFirstColumn = ResultsListView.ActualWidth - SystemParameters.VerticalScrollBarWidth - ResultsGridView.Columns[0].Width; 
     int columnsCount = ResultsGridView.Columns.Count; 
     Double newColumnWidth = newWidthForColumnsExceptFirstColumn/(columnsCount -1); 

     for (int col = 1; col < columnsCount; col++) // skip column [0] 
     { 
     ResultsGridView.Columns[col].Width = newColumnWidth; 
     } 
    } 
0

पर टिप के लिए धन्यवाद @Gary यहाँ एक समाधान एक से अधिक listviews का लाभ उठाने के एक सामान्य "आकार" ईवेंट हैंडलर के लिए अनुमति देता है।

//Using dictionarys as trackers allows us to have multiple ListViews use the same code 
    private Dictionary<string, double> _fixedWidthTracker = new Dictionary<string, double>(); 
    private Dictionary<string, List<GridViewColumn>> _varWidthColTracker = new Dictionary<string, List<GridViewColumn>>(); 
    private void ListView_SizeChanged(object sender, SizeChangedEventArgs e) 
    { 
     ListView lv = sender as ListView; 
     if (lv != null) 
     { 
      //For validation during Debug 
      VerifyName(lv); 

      GridView gv = lv.View as GridView; 
      if (gv != null) 
      { 
       if (!_varWidthColTracker.ContainsKey(lv.Name)) 
       { 
        _varWidthColTracker[lv.Name] = new List<GridViewColumn>(); 
        _fixedWidthTracker[lv.Name] = 0; 
        foreach (GridViewColumn gvc in gv.Columns) 
        { 
         if (!double.IsNaN(gvc.Width)) _fixedWidthTracker[lv.Name] += gvc.Width; else _varWidthColTracker[lv.Name].Add(gvc); 
        } 
       } 
       double newWidthForColumns = e.NewSize.Width - SystemParameters.VerticalScrollBarWidth - _fixedWidthTracker[lv.Name]; 
       int columnsCount = gv.Columns.Count; 
       int numberOfFixedWithColumns = columnsCount - _varWidthColTracker[lv.Name].Count; 
       Double newColumnWidth = newWidthForColumns/(columnsCount - numberOfFixedWithColumns); 

       foreach (GridViewColumn gvc in _varWidthColTracker[lv.Name]) 
       { 
        gvc.Width = newColumnWidth; 
       } 
      } 
     } 
    } 

    /// <summary> 
    /// Warns the developer if this object does not have 
    /// a public property with the specified name. This 
    /// method does not exist in a Release build. 
    /// </summary> 
    [Conditional("DEBUG")] 
    [DebuggerStepThrough] 
    public void VerifyName(ListView listView) 
    { 
     if (String.IsNullOrEmpty(listView.Name)) 
     { 
      string msg = "The Name attribute is required to be set on the ListView in order to Bind to this method"; 
      Debug.Fail(msg); 
     } 
    } 
0

मैं ऊपर के उदाहरण लिया हो (इस महान है) और यह थोड़ा सुधार हुआ आकार बदलने पर क्रम अपवाद को रोकने के लिए:

private void tpList_SizeChanged(object sender, SizeChangedEventArgs e) 
     { 
      ListView listView = sender as ListView; 
      GridView gView = listView.View as GridView; 

      var workingWidth = listView.ActualWidth - (SystemParameters.VerticalScrollBarWidth + 20); // take into account vertical scrollbar 
      var col1 = 0.50; 
      var col2 = 0.50; 

      var t1 = workingWidth * col1; 
      var t2 = workingWidth * col2; 
      gView.Columns[0].Width = t1 > 0 ? t1 : 1; 
      gView.Columns[1].Width = t2 > 0 ? t2 : 1; 

     } 
    } 
0

मेरे जरूरत ही चौड़ाई के साथ सभी स्तंभों के लिए किया गया था। उपर्युक्त समाधान ठीक हैं, लेकिन मैं ऐसी चीज को एक संलग्न संपत्ति (एमवीवीएम, पुन: प्रयोज्यता, आदि) में लपेटना पसंद करता हूं। यहां मेरा कोड है, अगर यह मदद कर सकता है।

public class StarSizeHelper { 

    private static readonly List<FrameworkElement> s_knownElements = new List<FrameworkElement>(); 

    public static bool GetIsEnabled(DependencyObject d) { 
     return (bool) d.GetValue(IsEnabledProperty); 
    } 

    public static void SetIsEnabled(ListView d, bool value) { 
     d.SetValue(IsEnabledProperty, value); 
    } 

    public static readonly DependencyProperty IsEnabledProperty = 
     DependencyProperty.RegisterAttached("IsEnabled", 
              typeof(bool), 
              typeof(StarSizeHelper), 
              new FrameworkPropertyMetadata(IsEnabledChanged)); 

    public static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { 

     var ctl = d as ListView; 
     if (ctl == null) { 
      throw new Exception("IsEnabled attached property only works on a ListView type"); 
     } 

     RememberElement(ctl); 
    } 

    private static void RememberElement(ListView ctl) { 

     if (! s_knownElements.Contains(ctl)) { 
      s_knownElements.Add(ctl); 

      RegisterEvents(ctl); 
     } 
     // nothing to do if elt is known 
    } 

    private static void OnUnloaded(object sender, RoutedEventArgs e) { 

     FrameworkElement ctl = (FrameworkElement) sender; 
     ForgetControl(ctl); 
    } 

    private static void ForgetControl(FrameworkElement fe) { 

     s_knownElements.Remove(fe); 
     UnregisterEvents(fe); 
    } 

    private static void RegisterEvents(FrameworkElement fe) { 
     fe.Unloaded += OnUnloaded; 
     fe.SizeChanged += OnSizeChanged; 
    } 

    private static void UnregisterEvents(FrameworkElement fe) { 
     fe.Unloaded -= OnUnloaded; 
     fe.SizeChanged -= OnSizeChanged; 
    } 

    private static void OnSizeChanged(object sender, SizeChangedEventArgs e) { 

     ListView listView = sender as ListView; 
     if (listView == null) { 
      return; // should not happen 
     } 
     GridView gView = listView.View as GridView; 
     if (gView == null) { 
      return; // should not happen 
     } 

     var workingWidth = listView.ActualWidth - SystemParameters.VerticalScrollBarWidth -10; // take into account vertical scrollbar 
     var colWidth = workingWidth/gView.Columns.Count; 
     foreach (GridViewColumn column in gView.Columns) { 
      column.Width = colWidth; 
     } 
    } 
} 

आदेश में इसका इस्तेमाल करने की:

<ListView ... StarSizeHelper.IsEnabled="true" ... /> 

(आप अभी भी नाम स्थान घोषणा XAML में, निश्चित रूप से ठीक करने के लिए)

आप OnSizeChanged विधि में अपने आकार की जरूरत है अनुकूलित कर सकते हैं।

0

डेविड हैंनसन-ग्रीविले के OnTheBlog का समाधान पहले उत्तरों में से एक में उल्लिखित है, भले ही ब्लॉग अभी भी मौजूद है। मैं इसे वेबैक मशीन पर ढूंढने में सक्षम था और कुछ मॉडरेशन के साथ, यहां यह है:

चाल यह है कि आप अपनी सूची दृश्य पर Stretch = true सेट करते हैं और यह उन स्तंभों को फैलाएगा जिनकी चौड़ाई समान रूप से नहीं है।

using System; 
using System.Collections.Generic; 
using System.Windows; 
using System.Windows.Controls; 

namespace Demo.Extension.Properties 
{ 
    /// 
    /// ListViewColumnStretch 
    /// 
    public class ListViewColumns : DependencyObject 
    { 
     /// 
     /// IsStretched Dependancy property which can be attached to gridview columns. 
     /// 
     public static readonly DependencyProperty StretchProperty = 
      DependencyProperty.RegisterAttached("Stretch", 
      typeof(bool), 
      typeof(ListViewColumns), 
      new UIPropertyMetadata(true, null, OnCoerceStretch)); 

     /// 
     /// Gets the stretch. 
     /// 
     /// The obj. 
     /// 
     public static bool GetStretch(DependencyObject obj) 
     { 
      return (bool)obj.GetValue(StretchProperty); 
     } 

     /// 
     /// Sets the stretch. 
     /// 
     /// The obj. 
     /// if set to true [value]. 
     public static void SetStretch(DependencyObject obj, bool value) 
     { 
      obj.SetValue(StretchProperty, value); 
     } 

     /// 
     /// Called when [coerce stretch]. 
     /// 
     ///If this callback seems unfamilar then please read 
     /// the great blog post by Paul Jackson found here. 
     /// http://compilewith.net/2007/08/wpf-dependency-properties.html 
     /// The source. 
     /// The value. 
     /// 
     public static object OnCoerceStretch(DependencyObject source, object value) 
     { 
      ListView lv = (source as ListView); 

      //Ensure we dont have an invalid dependancy object of type ListView. 
      if (lv == null) 
      { 
       throw new ArgumentException("This property may only be used on ListViews"); 
      } 

      //Setup our event handlers for this list view. 
      lv.Loaded += new RoutedEventHandler(lv_Loaded); 
      lv.SizeChanged += new SizeChangedEventHandler(lv_SizeChanged); 
      return value; 
     } 

     /// 
     /// Handles the SizeChanged event of the lv control. 
     /// 
     /// The source of the event. 
     /// The instance containing the event data. 
     private static void lv_SizeChanged(object sender, SizeChangedEventArgs e) 
     { 
      ListView lv = (sender as ListView); 
      if (lv.IsLoaded) 
      { 
       //Set our initial widths. 
       SetColumnWidths(lv); 
      } 
     } 

     /// 
     /// Handles the Loaded event of the lv control. 
     /// 
     /// The source of the event. 
     /// The instance containing the event data. 
     private static void lv_Loaded(object sender, RoutedEventArgs e) 
     { 
      ListView lv = (sender as ListView); 
      //Set our initial widths. 
      SetColumnWidths(lv); 
     } 

     /// 
     /// Sets the column widths. 
     /// 
     private static void SetColumnWidths(ListView listView) 
     { 
      //Pull the stretch columns fromt the tag property. 
      List<GridViewColumn> columns = (listView.Tag as List<GridViewColumn>); 
      double specifiedWidth = 0; 
      GridView gridView = listView.View as GridView; 
      if (gridView != null) 
      { 
       if (columns == null) 
       { 
        //Instance if its our first run. 
        columns = new List<GridViewColumn>(); 
        // Get all columns with no width having been set. 
        foreach (GridViewColumn column in gridView.Columns) 
        { 
         if (!(column.Width >= 0)) 
         { 
          columns.Add(column); 
         } 
         else 
         { 
          specifiedWidth += column.ActualWidth; 
         } 
        } 
       } 
       else 
       { 
        // Get all columns with no width having been set. 
        foreach (GridViewColumn column in gridView.Columns) 
        { 
         if (!columns.Contains(column)) 
         { 
          specifiedWidth += column.ActualWidth; 
         } 
        } 
       } 

       // Allocate remaining space equally. 
       foreach (GridViewColumn column in columns) 
       { 
        double newWidth = (listView.ActualWidth - specifiedWidth)/columns.Count; 
        if (newWidth >= 10) 
        { 
         column.Width = newWidth - 10; 
        } 
       } 

       //Store the columns in the TAG property for later use. 
       listView.Tag = columns; 
      } 
     } 
    } 
} 

, जिसे आप सिर्फ XAML फाइल

xmlns:Extensions="clr-namespace:Demo.Extension.Properties" 

के नाम स्थान को जोड़ने और अपनी सूची दृश्य पर इसका इस्तेमाल:

<ListView ItemsSource="{Binding Path=Items}" DisplayMemberPath="Name" 
          ScrollViewer.VerticalScrollBarVisibility="Auto" 
          Grid.Column="0" Margin="8" Extensions:ListViewColumns.Stretch="true"> 
संबंधित मुद्दे