【问题标题】:Reording columns after column autogeneration in C#/Silverlight Program在 C#/Silverlight 程序中自动生成列后重新排序列
【发布时间】:2012-04-25 19:25:32
【问题描述】:

我正在使用 C# Silverlight 创建一个应用程序。我试图弄清楚如何在我的数据网格中的列自动生成后重新排序。

我试着做这样的事情:

    private void dataGrid1_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        switch (e.PropertyName)
        {
            case "taskName":
                {
                    e.Column.DisplayIndex = 0;
                    break;
                }
            case "overallPercentComplete":
                {
                    e.Column.DisplayIndex = 1;
                    break;
                }
            case "TDO_ID":
                {
                    e.Column.DisplayIndex = 2;
                    break;
                }
            case "WBS_ID":
                {
                    e.Column.DisplayIndex = 3;
                    break;
                }
            case "baseLineSD":
                {
                    e.Column.DisplayIndex = 4;
                    break;
                }
            case "baseLineEd":
                {
                    e.Column.DisplayIndex = 5;
                    break;
                }
            case "estimatedSD":
                {
                    e.Column.DisplayIndex = 6;
                    break;
                }
            case "estimatedED":
                {
                    e.Column.DisplayIndex = 7;
                    break;
                }
            case "IMS_Hours":
                {
                    e.Column.DisplayIndex = 8;
                    break;
                }
            case "ETC_Hours":
                {
                    e.Column.DisplayIndex = 9;
                    break;
                }
        }
    }   

这并不完全正确。对于这个数据网格,顺序应该是: taskName、overallPercentComplete、TDO_ID、WBS_ID、baseLineSD、baseLineED、estimateSD、estimateED、IMS_Hours、ETC_Hours。

我想通过修改 Column.DisplayIndex 属性来正确设置它。 但是,当这段代码实际执行时,顺序是: taskNme、baseLineEd、TDO_ID、WBS_ID、overallPercentComplete、baseLineSD、estimateedED、estimatedSD、ETC_Hours、IMS_Hours。

有什么想法吗?任何帮助将不胜感激。提前致谢。

* 编辑 *

  void dataGrid1_Loaded(object sender, RoutedEventArgs e)
    {
        dataGrid1.Columns[0].DisplayIndex = 6;
        dataGrid1.Columns[1].DisplayIndex = 7;
        dataGrid1.Columns[2].DisplayIndex = 8;
        dataGrid1.Columns[3].DisplayIndex = 9;
        dataGrid1.Columns[4].DisplayIndex = 4;
        dataGrid1.Columns[5].DisplayIndex = 5;
        dataGrid1.Columns[6].DisplayIndex = 3;
        dataGrid1.Columns[7].DisplayIndex = 2;
        dataGrid1.Columns[8].DisplayIndex = 0;
        dataGrid1.Columns[9].DisplayIndex = 1;
    }

仍然没有,但是使用 Loaded 事件处理程序时,我得到一个错误:

Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

Error Details:
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List`1.get_Item(Int32 index)
at System.Collections.ObjectModel.Collection`1.get_Item(Int32 index)
at camDashboard.Views.Details.dataGrid1_Loaded(Object sender, RoutedEventArgs e)
at MS.Internal.CoreInvokeHandler.InvokeEventHandler(UInt32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName, UInt32 flags)

【问题讨论】:

  • 我不知道,也许不可能。我还尝试了 Loaded 事件。依然没有。上面发布代码...

标签: c# .net sql silverlight


【解决方案1】:

不幸的是,这在今天的 Silverlight 中似乎确实是不可能的。

在 WPF 中使用 AutoGeneratedColumns 事件生成了一个可行的解决方案后,我使用 Reflector 检查了 Silverlight DataGrid 源代码,首先,没有 AutoGeneratedColumns 事件,其次,它们确实对 GenerateColumns() 内的列进行了排序(无论您的显示索引设置如何,都使用固定算法调用您的事件处理程序的位置。

如果有任何兴趣,我可以使用 WPF 解决方案更新这个占位符。

【讨论】:

    【解决方案2】:

    据我了解,当AutoGenerateColumns 设置为True 时,WPF 呈现数据网格列的方式是:如果针对继承自 ClassB 的 ClassA 生成结构,则生成顺序是 ClassA,然后是 ClassB包含数据的 ClassA 和 ClassB 中的属性的声明顺序。

    我设计我的类的方式是按功能意义的顺序定义属性,我将使用在属性上定义为[SortIndex(1)] 的自定义属性SortIndexAttribute 来控制顺序,索引为任何整数值.

    所以,我也面临着克服这一点的许多挑战。

    我的想法是,通过定义的排序索引,我可以相应地重新排列我的属性,然后在运行时在DataGridColumnAutoGeneratingColumn 事件中设置DisplayIndex

    但是,我面临着新的挑战。如果属性的声明顺序和排序索引不匹配,并且在设置时,如果排序索引大于列数,则会引发错误。 DisplayIndex,在设置时,可以为0或小于列数(注意:列是一次生成并填充一个;另外,当DisplayIndex未设置时,它存储-1,不能手动分配)

    我还没有实现以下逻辑,但它可能会起作用。 1.创建一个ClassA所有属性的排序列表(包括原生的和继承的) 2.在DataGridColumnAutoGeneratingColumn事件中,将第一列的DisplayIndex设置为0 3. 现在,根据我的映射顺序,我将为新列 w.r.t 分配 0 或 1,以此类推.. 4. 如果排序索引不可用,我将其设置为列数或完全跳过并让 WPF 处理它 - 尚未实现

    为了清楚地解释#3,属性和排序索引的生成顺序如下: 员工:姓名(1)、ID(0)、地址(99)、邮政编码(50)

    WPF 将按上述顺序生成列。所以在AutoGeneratingColumn 事件中,我将为我的属性实现如下:

    1. Name(1):设置DisplayIndex = 0(将插入第一个位置)
    2. ID(0):设置DisplayIndex = 0(应该取代现有的0)
    3. 地址(99):设置DisplayIndex = 2(用列数标记或直接跳过)
    4. ZIPCODE(50):设置DisplayIndex = 2(应该取代现有的 0)

    下面是我的最终代码:

      private int SetDisplayIndex(string propName)
      {
        int result = -1;
        int curr = dictPropertySortIndexMap.GetValueFromKey[propName];
        int last = dictPropertySortIndexMap[nameSortLast];
    
        // For the first property in order, always set 0
        if (nameSortLast.IsBlank())
          result = 0;
    
        // For the property with lower index than sorted at first position
        else if (curr > dictColumnsSorted.Values.Max())
          result = dgrdUniversal.Columns.Count;
    
        // For the property with higher index than sorted at last position
        else if (curr < dictColumnsSorted.Values.Min())
          result = 0;
    
        else // For the property to be inserted between
          result = dictColumnsSorted[dictPropertySortIndexMap[
              dictPropertySortIndexMap._Where(
                p => dictColumnsSorted.Keys.Contains(p.Key) && p.Value > curr)                 ._Select(p => p.Value)._Min()]];
    
        dictColumnsSorted.Add(propName, result);
        nameSortLast = propName;
    
        return result;
      }
    




    请试试这个,然后离开你的 cmets。

    谢谢, 鲁帕克

    【讨论】:

      【解决方案3】:

      看起来不太可能。见这里:http://forums.silverlight.net/t/144247.aspx

      【讨论】:

      • 我读过同一个论坛。虽然,我很难相信这是不可能的。程序更改表格的顺序,支持字母顺序,并且不允许您重新排列它们并以某种体面的顺序放置它们,这似乎有点荒谬。
      • 如果您事先知道所有列,为什么不自己设置它们而不是使用 AutoGenerateColumns?
      • 看来我必须这样做。这意味着创建一些解决方法,但看起来我没有太多选择。谢谢大家。
      【解决方案4】:

      好吧,我得到了这个工作。几乎我能弄清楚这一点的唯一方法是不使用自动生成列,而只是自己在 XAML 中定义列。如果有人感兴趣,这就是我的做法。

          <sdk:DataGrid AutoGenerateColumns="False" Height="392" Margin="32,360,36,0" Name="dataGrid3" VerticalAlignment="Top" ItemsSource="{Binding}" IsReadOnly="True" >
              <sdk:DataGrid.Columns>
                  <sdk:DataGridTextColumn x:Name="TDO1" Binding="{Binding Path=TDO_ID, Mode=OneWay}" Header="TDO_ID" IsReadOnly="True" Width="100" />
                  <sdk:DataGridTextColumn x:Name="taskName1" Binding="{Binding Path=taskName, Mode=OneWay}" Header="taskName" IsReadOnly="True" Width="304" />
                  <sdk:DataGridTextColumn x:Name="weekName" Binding="{Binding Path=weekName, Mode=OneWay}" Header="weekName" IsReadOnly="True" Width="200" />
                  <sdk:DataGridTextColumn x:Name="scheduleVariance" Binding="{Binding Path=scheduleVariance, Mode=OneWay}" Header="SV (Days)" IsReadOnly="True" Width="100" />
                  <sdk:DataGridTextColumn x:Name="schedulePerformanceIndex" Binding="{Binding Path=schedulePerformanceIndex, Mode=OneWay}" Header="SPI" IsReadOnly="True" Width="100" />
                  <sdk:DataGridTextColumn x:Name="ECD" Binding="{Binding Path=ECD, Mode=OneWay}" Header="ECD" IsReadOnly="True" Width="100" />
                  <sdk:DataGridTextColumn x:Name="percentComplete" Binding="{Binding Path=percentComplete, Mode=OneWay}" Header="% Complete" IsReadOnly="True" Width="100" />
                  <sdk:DataGridTextColumn x:Name="percentExpected" Binding="{Binding Path=percentExpected, Mode=OneWay}" Header="% Expected" IsReadOnly="True" Width="100" />
                  <sdk:DataGridTextColumn x:Name="WBS1" Binding="{Binding Path=WBS_ID, Mode=OneWay}" Header="WBS_ID" IsReadOnly="True" Width="100" />
              </sdk:DataGrid.Columns>
          </sdk:DataGrid>
      

      我很抱歉,这一切都混乱了。不太确定如何解决这个问题,因为线路太长了。照顾好一切。

      【讨论】:

        【解决方案5】:
        void autogen()
        {
            cmd = new SqlCommand("select count(*) from Employee", con);
            dr = cmd.ExecuteReader();
            while (dr.Read())
            {
                i = int.Parse(dr[0].ToString()) + 1;
        
            }
            dr.Close();
            cmd.Dispose();
            if (i <= 9)
            {
                TextBox1.Text = "EID0" + i.ToString();
            }
            else if (i <= 99)
            {
                TextBox1.Text = "EID" + i.ToString();
            }
        
        }
        

        【讨论】:

          猜你喜欢
          • 2019-04-30
          • 2019-10-23
          • 2015-09-16
          • 2012-08-11
          • 2011-06-04
          • 1970-01-01
          • 2016-01-26
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多