[...]
None of this would be a problem if ListView didn't have this peculiarity
of
not functioning as expected when ShowGroups property is set to false.
When
it's set to false and I'm adding groups, everything goes haywire. When
it's
set to true, then everything works well.
Another weirdness is that if I programmatically set ShowGroups to true,
then add the reports and then then restore ShowGroups to previous value,
if
that value was previously false, it's all haywire again.
Anyone know of a simple workaround which doesn't involve creating a new
control?
Not unless you can be more specific than "goes haywire". At the very
least, you need to post a precise description of the problem, and ideally
you would post a concise-but-complete code example that demonstrates it.
Pete
Well, it's pretty much like I said it: it goes haywire. All the items I've
added to the list when ShowGroups was false are shown in the first line of
the ListView after I switch to ShowGroups = true. Also - and this is
obvious when many items get added - every time the control is refreshed,
all these items get drawn in the first line, and it can take quite a while.
Scrolling also makes all the items be redrawn and it makes the control
slow.
Scrolling in general makes the behavior of the control weird as items that
were drawn don't get removed so there's letters all over the place.
Need more?
As for code, here goes:
---------------------------------------------------------------------------
In GameLogForm.Designer.cs:
---------------------------------------------------------------------------
private void InitializeComponent()
{
this.lvLog = new System.Windows.Forms.ListView();
this.Entries = new System.Windows.Forms.ColumnHeader();
this.cbGroups = new System.Windows.Forms.CheckBox();
this.SuspendLayout();
//
// lvLog
//
this.lvLog.BackColor = System.Drawing.SystemColors.Control;
this.lvLog.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.lvLog.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.Entries});
this.lvLog.FullRowSelect = true;
this.lvLog.GridLines = true;
this.lvLog.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
this.lvLog.HideSelection = false;
this.lvLog.Location = new System.Drawing.Point(6, 19);
this.lvLog.MultiSelect = false;
this.lvLog.Name = "lvLog";
this.lvLog.ShowGroups = false; // IMPORTANT!!!
this.lvLog.Size = new System.Drawing.Size(496, 345);
this.lvLog.TabIndex = 0;
this.lvLog.UseCompatibleStateImageBehavior = false;
this.lvLog.View = System.Windows.Forms.View.Details;
//
// Entries
//
this.Entries.Text = "Entries";
this.Entries.Width = 476;
//
// cbGroups
//
this.cbGroups.AutoSize = true;
this.cbGroups.Location = new System.Drawing.Point(508, 155);
this.cbGroups.Name = "cbGroups";
this.cbGroups.Size = new System.Drawing.Size(102, 17);
this.cbGroups.TabIndex = 1;
this.cbGroups.Text = "Show as groups";
this.cbGroups.UseVisualStyleBackColor = true;
this.cbGroups.CheckedChanged += new System.EventHandler(this.cbGroups_CheckedChanged);
//
// GameLogForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(690, 394);
this.Controls.Add(this.cbGroups);
this.Controls.Add(this.lvLog);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Name = "GameLogForm";
this.MaximizeBox = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Load += new System.EventHandler(this.GameLogForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
private System.Windows.Forms.ListView lvLog;
private System.Windows.Forms.ColumnHeader Entries;
private System.Windows.Forms.CheckBox cbGroups;
---------------------------------------------------------------------------
In GameLogForm.cs:
---------------------------------------------------------------------------
public GameLogForm()
{
InitializeComponent();
}
private GameLogForm_Load(object sender, EventArgs e)
{
AddEntry("Group1", "Entry1_1");
AddEntry("Group1", "Entry1_2");
AddEntry("Group1", "Entry1_3");
AddEntry("Group2", "Entry2_1");
AddEntry("Group2", "Entry2_2");
AddEntry("Group2", "Entry2_3");
AddEntry("Group3", "Entry3_1");
AddEntry("Group3", "Entry3_2");
AddEntry("Group3", "Entry3_3");
}
private void AddEntry(string group, string entry)
{
ListViewItem lvi = new ListViewItem();
lvi.Group = new ListViewGroup(group);
ListViewGroupCollection lvgc = lvLog.Groups;
bool GroupFound = false;
foreach (ListViewGroup lvg in lvgc)
{
if (lvg.Header == group)
{
lvi.Group = lvg;
GroupFound = true;
break;
}
}
if (!GroupFound) lvLog.Groups.Add(lvi.Group);
lvi.Text = entry;
lvLog.Items.Add(lvi);
}
private void cbGroups_CheckedChanged(object sender, EventArgs e)
{
lvLog.ShowGroups = cbGroups.Checked;
}
---------------------------------------------------------------------------
End of code
---------------------------------------------------------------------------
When you run the program, click the checkbox to see what "haywire" means.
Of course, if you want things to be even more haywire, add more entries
(like 100 or 200), preferably each saying something meaningful, or of
random length.
If, on the other hand, you use (in GameLogForm.Designer.cs):
this.lvLog.ShowGroups = true;
then it will show fine.
It will also be fine if in designer I have the ShowGroups set to true, but
in the Load event I set it to false. This, however, is not good enough,
because I must be able to add things to the list *in real time*, and I
can't tell which mode (groups or no groups) the user is watching at the
moment when I need to put something on.
This particular example, for some reason, shows groups and entries well
when I set lvLog.ShowGroups to true at the beginning of GameLogForm_Load
and restore it at the end. I'm still trying to figure out why that is,
since the same trick doesn't work in the real application that I've built.
I'll try to see what makes the control behave oddly there and I'll
demonstrate the example.
Nikola