在 C#/Silverlight 程序中自动生成列后重新排列列
本文关键字:新排列 排列 Silverlight 程序 自动生成 | 更新日期: 2023-09-27 18:32:26
我正在创建一个带有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, 总体完成百分比, TDO_ID, WBS_ID, baseLineSD, baseLineED, estimatedSD, estimatedED, IMS_Hours, ETC_Hours.
我想通过修改Column.DisplayIndex属性来正确设置它。但是,当此代码实际执行时,顺序为:taskNme, baseLineEd, TDO_ID, WBS_ID, totalallPercentComplete, baseLineSD, estimatedED, 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)
这在今天的Silverlight中似乎是不可能的。
在 WPF 中使用自动生成列事件生成工作解决方案后,我使用 Reflector 检查了 Silverlight DataGrid 源代码,首先,没有自动生成的列事件,其次,它们确实使用固定算法对GenerateColumns()
内的列(调用事件处理程序的位置)进行排序,而不管您的显示索引设置如何。
如果对此感兴趣,我可以使用 WPF 解决方案更新此占位符。
据我了解,WPF 在将数据网格列设置为True
AutoGenerateColumns
时呈现数据网格列的方式是: 如果结构是针对从类 B 继承的类 A 生成的,则生成顺序是 ClassA,然后是 ClassB,其声明顺序是 ClassA 和 ClassB 中包含数据的属性的声明顺序。
我设计类的方式是,属性将按功能重要性的顺序定义,我将使用自定义属性来控制顺序SortIndexAttribute
在属性上定义为[SortIndex(1)]
索引作为任何整数值。
所以,我也面临着克服这一点的很多挑战。
我的想法是,使用定义的排序索引,我可以相应地重新排列我的属性,然后在运行时DataGridColumn
AutoGeneratingColumn
事件中设置DisplayIndex
。
然而,我面临着新的挑战。如果属性和排序索引的声明顺序不匹配,并且 while 设置,如果排序索引大于列计数,则会引发错误。 DisplayIndex
,在设置时,可以为 0 或小于列计数(注意:列一次生成和填充一个;此外,如果未设置DisplayIndex
,它会存储无法手动分配的 -1)
我还没有实现以下逻辑,但它可能会起作用。1. 创建 ClassA 的所有属性(本机和继承属性)的排序列表2.在DataGridColumn
的AutoGeneratingColumn
事件中,将第一列的DisplayIndex
设置为03.现在,根据映射中的顺序,我将为新列w.r.t分配给第一列的0或1,依此类推。4.如果排序索引不可用,我将只将其设置为列计数或完全跳过并让WPF处理它 - 尚未实现
为了清楚地解释#3,属性和排序索引的生成顺序如下:员工: 姓名(1), ID(0), 地址(99), 邮政编码(50)
WPF 将按上述顺序生成列。因此,在AutoGeneratingColumn
事件中,我将为我的属性实现如下:
- 名称(1):设置
DisplayIndex = 0
(将首先插入) - ID(0):设置
DisplayIndex = 0
(应替换 0 处的现有值) - 地址(99):设置
DisplayIndex = 2
(用列计数标记或干脆跳过) - 邮编(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;
}
请尝试此操作并留下您的评论。
谢谢鲁帕克
看起来这是不可能的。 看这里: http://forums.silverlight.net/t/144247.aspx
好吧,我得到了这个工作。我能弄清楚这一点的唯一方法是不使用自动生成列,而只是在 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>
我很抱歉,这一切都乱七八糟。不太确定如何解决这个问题,因为线条太长了。保重一切。
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();
}
}