此问题是以下问题的一个分支:本地化ObjectListView OLVColumn,由于Empty Name属性而不可能
为了简单起见,假设我的ObjectListView包含汽车信息。用户A希望只显示"生成"列和"模型"列。用户B只想显示"型号"one_answers"年份"列。这些首选项将保存到用户本地计算机上的.ini文件中/从该文件加载。
我无法循环遍历ObjectListView的列并执行if (col.Name == colNameFromIni) { col.Visible == true; }
,因为每列的.Name
属性都是空字符串("(,并且不会序列化到设计器代码绑定文件。任何其他Winforms控件(Label、Button等(都不会发生这种情况。它们总是将其.Name
写入设计器代码绑定。
从某种意义上说,这是Winforms本身的一个缺陷,因为OLVColumn继承自System.Windows.Forms.ColumnHeader
,而传统的ListView也有同样的问题。对于所有列,.Name
始终为空字符串。
我想修补ObjectListView.dll的本地版本,以强制填充.Name
属性,但我不知道Winforms是如何自动知道表单上每个控件的名称的。它不知何故(?(知道OLVColumn对象的名称,因为它可以在编辑列中显示它们对话框。我也有点不清楚最好的地方是在哪里插上这个。
(是的,根据顶部的链接问题,我知道作为最后的手段,我可以为源代码中的所有列硬编码colXX.Name = "colXX";
,但未来添加的列可能会被忽视,因此更倾向于使用编程解决方案。(
(另请参见:https://sourceforge.net/p/objectlistview/bugs/160/:ObjectListView的作者将其声明为wont-fix
,所以我想这取决于我(或我们(。(
正如您所指出的,这不是ObjectListView的错误,而是底层组件的错误。还有一个至少从2008年开始就存在的bug!因此,我怀疑它是否会被女士修复
实际上,这是设计器中自动生成代码的问题。
如果您查看按钮等其他组件,则自动生成的代码会添加这样的名称;
//
// button2
//
this.button2.Location = new System.Drawing.Point(458, 199);
this.button2.Name = "button2";
...
但对于ColumnHeader
(Listview(和OLVColumn
(ObjectListView(,则不会完成此操作,因此最终会出现此情况。
//
// olvColumn1
//
this.olvColumn1.AspectName = "Name";
this.olvColumn1.Text = "Name";
如果手动添加行
this.olvColumn1.Text = "olvColumn1";
然后;"问题";解决。
当然,您不能这样做,因为当您进行任何更改时,设计器将覆盖自动生成的代码,然后您将丢失这些手动添加的行。它也是不可持续的。
所以我担心你需要用某种丑陋的解决方案来解决这个问题。一些选项包括:
- 使用标签存储名称并与之进行比较
- 使用文本而不是名称(如果您有多个语言支持!(
- 在构造函数中手动对名称列进行编码
- 将文本设置为类似于";ColName;ColText";然后在你的代码将这些分开
我过去做过选项3,但只有我在维护代码,所以这很容易。
要确保没有差异,可以在构造函数中添加一个检查,将实际列数与期望的列数(硬编码(进行比较,如果不匹配,则抛出异常。此外,这不是最好的,而是另一种突出显示和减少错误的方法。
解决方法是通过反射获取OLV列,并在运行时设置其列的Name属性。每个OLV列都是一个表单级字段,所以只需从GetFields()
返回的列表中选择它们即可。
Dim allFieldInfos As FieldInfo() = GetType(FrmMain).GetFields(BindingFlags.NonPublic or BindingFlags.Instance)
For Each fi As FieldInfo In allFieldInfos
If fi.FieldType Is GetType(OLVColumn) Then
Dim instance As OLVColumn = fi.GetValue(Me)
For Each col As OLVColumn In fdlvMain.AllColumns
If ReferenceEquals(col, instance) Then
col.Name = fi.Name
End If
Next
End If
Next