|
ms
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Weird behavior of ListView.ShowGroups propertyI'm using a ListView to show a list of reports, all coming in from different parts of my application (like a log only less detailed), so I figured it would be useful to be able to see these reports both in the order as they arrived, as well as grouped, depending on which part of the application they came from. This list must be shown and updated in real time. 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? Thanks, Nikola On Tue, 09 Jun 2009 09:28:30 -0700, Nikola Novak
<enlorkMA***@ovogmail.com> wrote: Show quoteHide quote > [...] Not unless you can be more specific than "goes haywire". At the very > 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? 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 On Tue, 09 Jun 2009 10:21:36 -0700, Peter Duniho wrote:
Show quoteHide quote > On Tue, 09 Jun 2009 09:28:30 -0700, Nikola Novak Well, it's pretty much like I said it: it goes haywire. All the items I've> <enlorkMA***@ovogmail.com> wrote: > >> [...] >> 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 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 On Tue, 09 Jun 2009 11:49:22 -0700, Nikola Novak
<enlorkMA***@ovogmail.com> wrote: > Well, it's pretty much like I said it: it goes haywire. You did say that. And it still means nothing. :(That said, you provided the most crucial piece of information: a code example. It wasn't complete, but it was concise and was close enough to complete that it was fairly easy to get working. I wasn't able to reproduce the exact behavior you described, but it didn't work very well either, so at least there was a problem to be seen. :) The docs aren't really very clear, but there's enough caveats about making sure your groups are set up before display that it's not hard to believe that ShowGroups _must_ be set to "true" any time you want to do anything to the ListView that involves grouping. And in fact, I found that as a work-around, setting ShowGroups to "true" before adding an item to the ListView works very well. Here is a new version of the AddEntry() method from the code you posted that causes the ListView to display properly, at least on my computer: private Dictionary<string, ListViewGroup> _dictGroups = new Dictionary<string, ListViewGroup>(); private void AddEntry(string group, string entry) { bool fGroupsSave = lvLog.ShowGroups; lvLog.ShowGroups = true; try { ListViewItem lvi = new ListViewItem(); ListViewGroup lvg; if (!_dictGroups.TryGetValue(group, out lvg)) { lvg = new ListViewGroup(group); _dictGroups.Add(group, lvg); lvLog.Groups.Add(lvg); } lvi.Group = lvg; lvi.Text = entry; lvLog.Items.Add(lvi); } finally { lvLog.ShowGroups = fGroupsSave; } } Note that I also changed the way groups are cached. Instead of a linear search through the ListView's actual Groups collection (and the awkward "always create a group even if we're not going to use it"), I store the ListViewGroup instances in a dictionary, indexed by their name. Whether this is actually the expected use of the ListView control, or it would actually be considered a bug that it only handles grouping correctly when ShowGroups is set to "true", I don't know. I mean, it seems like a bug to me, but Microsoft has their own rules. In any case, my experience has been that fixing bugs in the ListView control is fairly low priority for them. There are a number of other bugs on the Connect web site (http://connect.microsoft.com/) for the control that have basically been postponed indefinitely and probably will never be fixed. If this particular issue is important to you, you should file a bug report on Connect. At best, it will probably be postponed. But at least you can get the problem on record, and maybe even get a response from Microsoft indicating their take on it. In the meantime, hopefully the above work-around is helpful to you. Pete On Wed, 10 Jun 2009 21:21:22 -0700, Peter Duniho wrote:
> Here is a new version of the AddEntry() method from the code you posted A quote from my previous post:> that causes the ListView to display properly, at least on my computer: "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.e. I knew of your workaround before. However, for some reason this doesn't work in my real-life example which is just too big to post here. I'm still searching for the reason and trying to make the simplest example that demonstrates the bug although that's not my priority at this point. I had earlier just made the log without the grouping functionality and for now that's fine enough. In any case, thanks for the trouble, the code, and the link. I hadn't used the dictionary for the groups because I never expected the group list to go beyond the size of 10-15 groups which would work fine with linear search. But you're right, this is better. Thanks again, Nikola |
|||||||||||||||||||||||