Perplexing Listbox behavior.

S

Sean Wolfe

I have a winform that is used for setting configuration parameters for
an application, and stores the settings to a file so it can be read when
the application starts. You starndard properties window.

One of the settings is for Logging and the level of logging that wishes
to be captured. In our application, the logging levels is provided by
BitFlag Enum. So I wished to display the selected bitflags inside a
Multi-select listbox, which people could click on the levels that they
want available. I got this working fine for saving and loading. But
there is a particularly peculiar problem i ran into with the ListBox
control.

Our enum has 6 levels of severity, and has 3 helper levels (All,
Default, None). Here is the code example of the Enum.

[Flags]
public enum LogMessageSeverity
{
None = 0,
Debug = 1,
Notification = 2,
Warning = 4,
Error = 8,
Critical = 16,
Fatal = 32,
Default = (Warning | Error | Critical | Fatal ),
All = (Debug | Notification | Default)
}

In the listbox, to avoid confusion with users, I only have the 6
severity levels. Each one can be selected individually. But what happens
is when the user selects Fatal + Critical + Error + Warning, the enum ==
Default. And if the user selects all 6 then the enum == All. This is
fine so I account for that in the code.

The problem occurs that when I load up the settings form, it will try to
select the appropriate values in the select box that have been saved in
the settings file. When it loads items that are selected individually,
it works. But for an item that has an enumeration == All, I tried to use
a for loop that uses the SetSelected() method, and when I do, the items
don't show up selected on the form. The thing that is bizzare about
this, is that if I run it in the debugger and step through it, it will
display it successfully, but when it runs without stepping through it
won't. I've tied calling the Update() method and DoEvents, and these
don't seem to help. I ended up having to select each item explicitly.

Here is an excerpt from the code showing this behavior.
-------------------------------------------------------------
// early in the code
ListBox logfileSeverity;
this.logfileSeverity = new System.Windows.Forms.ListBox();
this.logfileSeverity.Items.AddRange(new object[] {
"Fatal",
"Critical",
"Error",
"Warning",
"Notification",
"Debug"});
this.logfileSeverity.Location = new System.Drawing.Point(160, 48);
this.logfileSeverity.Name = "logfileSeverity";
this.logfileSeverity.SelectionMode =
System.Windows.Forms.SelectionMode.MultiSimple;
this.logfileSeverity.Size = new System.Drawing.Size(104, 82);
this.logfileSeverity.TabIndex = 32;


// where the code has the problems.
// TrayParameters.LogfileSeverity is a
// LogMessageSeverity enum.
string logSeverityFlags = TrayParameters.LogfileSeverity.ToString("g");
// if the enum is individual flags it works.
// if the enum is "All" or "Default" the selections do not work.
foreach(string sev in logSeverityFlags.Split(new char[] {','}))
{
if(sev == "All")
{
for(int itemIndex = 0; itemIndex < 6; itemIndex++)
{
// this doesn't seem to actually set the list items.
this.logfileSeverity.SetSelected(itemIndex, true);
}
break;
}
else if(sev == "Default")
{
for(int itemIndex = 0; itemIndex < 4; itemIndex++)
{
// this doesn't seem to actually set the list items.
this.logfileSeverity.SetSelected(itemIndex, true);
}
}
else
this.logfileSeverity.SelectedItem = sev.Trim();
}

// I had to change the code block above to as follows.
foreach(string sev in logSeverityFlags.Split(new char[] {','}))
{
if(sev == "All")
{
this.messageSeverity.SelectedItem = "Fatal";
this.messageSeverity.SelectedItem = "Critical";
this.messageSeverity.SelectedItem = "Error";
this.messageSeverity.SelectedItem = "Warning";
this.messageSeverity.SelectedItem = "Notification";
this.messageSeverity.SelectedItem = "Debug";
break;
}
else if(sev == "Default")
{
this.messageSeverity.SelectedItem = "Fatal";
this.messageSeverity.SelectedItem = "Critical";
this.messageSeverity.SelectedItem = "Error";
this.messageSeverity.SelectedItem = "Warning";
}
else
this.logfileSeverity.SelectedItem = sev.Trim();
}

---------------------------------------------------------


Does anyone have any ideas as to why this happens?

sean
 
J

Jeff Gaines

On Fri, 09 Apr 2004 18:01:30 -0500, Sean Wolfe


[code snipped]

Sean

Before starting the detective work you use 'logfileSeverity' in
the functions that don't work and 'messageSeverity' in the one
that does. Is this relevant?

I pasted the code that doesn't work into my testbed and it works
fine assuming the ListBox is multi select and it's called with
the right name.
 
S

Sean Wolfe

Jeff said:
On Fri, 09 Apr 2004 18:01:30 -0500, Sean Wolfe
Sean

Before starting the detective work you use 'logfileSeverity' in
the functions that don't work and 'messageSeverity' in the one
that does. Is this relevant?

I pasted the code that doesn't work into my testbed and it works
fine assuming the ListBox is multi select and it's called with
the right name.

Sorry for the late reply, i was out sick.

and sorry for the code issues. but yes, that was actually some typoes.
Or some mispasting actually. In my app i actually have two listboxes
that work the same way, one called messageSeverity and one called
logfileSeverity. This is to set up logging in two different locations
(screen and file).

here is a repaste of the prototype code with the correct naming.
Also please keep in mind that the area where noted is a portion of the
code rewritten to allow it to work. The section before it where noted
doesn't work.
-------------------------------------------------------------------------

[Flags]
public enum LogMessageSeverity
{
None = 0,
Debug = 1,
Notification = 2,
Warning = 4,
Error = 8,
Critical = 16,
Fatal = 32,
Default = (Warning | Error | Critical | Fatal ),
All = (Debug | Notification | Default)
}

// early in the code
ListBox logfileSeverity;
this.logfileSeverity = new System.Windows.Forms.ListBox();
this.logfileSeverity.Items.AddRange(new object[] {
"Fatal",
"Critical",
"Error",
"Warning",
"Notification",
"Debug"});
this.logfileSeverity.Location = new System.Drawing.Point(160, 48);
this.logfileSeverity.Name = "logfileSeverity";
this.logfileSeverity.SelectionMode =
System.Windows.Forms.SelectionMode.MultiSimple;
this.logfileSeverity.Size = new System.Drawing.Size(104, 82);
this.logfileSeverity.TabIndex = 32;


// **************** PLEASE NOTE ******************
// where the code has the problems.
// TrayParameters.LogfileSeverity is a
// LogMessageSeverity enum.
string logSeverityFlags = TrayParameters.LogfileSeverity.ToString("g");
// if the enum is individual flags it works.
// if the enum is "All" or "Default" the selections do not work.
foreach(string sev in logSeverityFlags.Split(new char[] {','}))
{
if(sev == "All")
{
for(int itemIndex = 0; itemIndex < 6; itemIndex++)
{
// this doesn't seem to actually set the list items.
this.logfileSeverity.SetSelected(itemIndex, true);
}
break;
}
else if(sev == "Default")
{
for(int itemIndex = 0; itemIndex < 4; itemIndex++)
{
// this doesn't seem to actually set the list items.
this.logfileSeverity.SetSelected(itemIndex, true);
}
}
else
this.logfileSeverity.SelectedItem = sev.Trim();
}


// ***********PLEASE NOTE************
// I had to change the code block above to as follows.
foreach(string sev in logSeverityFlags.Split(new char[] {','}))
{
if(sev == "All")
{
this.logfileSeverity.SelectedItem = "Fatal";
this.logfileSeverity.SelectedItem = "Critical";
this.logfileSeverity.SelectedItem = "Error";
this.logfileSeverity.SelectedItem = "Warning";
this.logfileSeverity.SelectedItem = "Notification";
this.logfileSeverity.SelectedItem = "Debug";
break;
}
else if(sev == "Default")
{
this.logfileSeverity.SelectedItem = "Fatal";
this.logfileSeverity.SelectedItem = "Critical";
this.logfileSeverity.SelectedItem = "Error";
this.logfileSeverity.SelectedItem = "Warning";
}
else
this.logfileSeverity.SelectedItem = sev.Trim();
}
 
J

Jeff Gaines

Sorry for the late reply, i was out sick.

here is a repaste of the prototype code with the correct naming.
Also please keep in mind that the area where noted is a portion of the
code rewritten to allow it to work. The section before it where noted
doesn't work.
-------------------------------------------------------------------------

Hi Sean

I have pasted you revised code into a test app and it works
fine.

I am not sure what the following line returns:
string logSeverityFlags = TrayParameters.LogfileSeverity.ToString("g");

So I set the strings up manually.

The only time it didn't select anything was when I typed 'all'
instead of 'All', because of case sensitivity, and when I tested
it with a string that doesn't appear in the ListBox.

Are you sure the above line of code sets the string up properly
and in the correct case?

I used the following test strings:

//string logSeverityFlags = "Default,";
//string logSeverityFlags = "all,"; ** Didn't select anything
//string logSeverityFlags = "All,";
//string logSeverityFlags = "Critical,Warning,Debug";
//string logSeverityFlags = "NotThere"; ** Didn't select
anything
//string logSeverityFlags = "Fatal, Critical, Error, Warning,
Notification, Debug";

I also used the same strings where it is just one word but
without the comma at the end.

And the following code from you message:
// **************** PLEASE NOTE ******************
// where the code has the problems.
// TrayParameters.LogfileSeverity is a
// LogMessageSeverity enum.
string logSeverityFlags = TrayParameters.LogfileSeverity.ToString("g");
// if the enum is individual flags it works.
// if the enum is "All" or "Default" the selections do not work.
foreach(string sev in logSeverityFlags.Split(new char[] {','}))
{
if(sev == "All")
{
for(int itemIndex = 0; itemIndex < 6; itemIndex++)
{
// this doesn't seem to actually set the list items.
this.logfileSeverity.SetSelected(itemIndex, true);
}
break;
}
else if(sev == "Default")
{
for(int itemIndex = 0; itemIndex < 4; itemIndex++)
{
// this doesn't seem to actually set the list items.
this.logfileSeverity.SetSelected(itemIndex, true);
}
}
else
this.logfileSeverity.SelectedItem = sev.Trim();
}

It might be worth checking the format of the string you are
passing in?
 
S

Sean Wolfe

Jeff said:
I am not sure what the following line returns:

This parses the Enum to a strun, and forces it to not output as a
number. if there are more than one flags set, it delimits each one with
a comma
"Critical, Warning, Debug"

if you do just a stright ToString operation on the enum that has
multiple flags, it will just output a string representation of the
number value.
So I set the strings up manually.

The only time it didn't select anything was when I typed 'all'
instead of 'All', because of case sensitivity, and when I tested
it with a string that doesn't appear in the ListBox.

Are you sure the above line of code sets the string up properly
and in the correct case?

Yes, I have had it output to the debug window, and I have had it step
through the code. Every time the "All" was parsed and detected properly.
Also i do see it actually call the SetSelected() method. Same for
"Default". The odd thing is though, is that if i step through it in the
debugger, it does select them correctly. But if i run it outside the
debugger , it doesn't select them correctly.
I used the following test strings:

//string logSeverityFlags = "Default,";
//string logSeverityFlags = "all,"; ** Didn't select anything
//string logSeverityFlags = "All,";
//string logSeverityFlags = "Critical,Warning,Debug";
//string logSeverityFlags = "NotThere"; ** Didn't select
anything
//string logSeverityFlags = "Fatal, Critical, Error, Warning,
Notification, Debug";

I also used the same strings where it is just one word but
without the comma at the end.

And the following code from you message:

// **************** PLEASE NOTE ******************
// where the code has the problems.
// TrayParameters.LogfileSeverity is a
// LogMessageSeverity enum.
string logSeverityFlags = TrayParameters.LogfileSeverity.ToString("g");
// if the enum is individual flags it works.
// if the enum is "All" or "Default" the selections do not work.
foreach(string sev in logSeverityFlags.Split(new char[] {','}))
{
if(sev == "All")
{
for(int itemIndex = 0; itemIndex < 6; itemIndex++)
{
// this doesn't seem to actually set the list items.
this.logfileSeverity.SetSelected(itemIndex, true);
}
break;
}
else if(sev == "Default")
{
for(int itemIndex = 0; itemIndex < 4; itemIndex++)
{
// this doesn't seem to actually set the list items.
this.logfileSeverity.SetSelected(itemIndex, true);
}
}
else
this.logfileSeverity.SelectedItem = sev.Trim();
}


It might be worth checking the format of the string you are
passing in?

The stirng format is fine, because the second set of code runs just
fine, I jsut replaced the loop and the SetSelected methods with direct
explicit calls to the SelectedItem property.

Sean
 
Y

Ying-Shen Yu[MSFT]

Hi Sean,

After a quick look at this problem it seems this issue is related to the
lazy initialization of the ListBox, the window handle of the listbox hasn't
been created when you call SetSelected to the listbox.(check it using
messageSeverigy.IsHandleCreated property). The reason why the SelectedItem
will work is it will force creating the handle before set selection on it.

We have a simple workaround for this problem. just reading the Handle will
force creating the handle, here is the modified code snippet.
<code>
if(sev == "All")
{
IntPtr p =messageSeverity.Handle;// add this line , force creating the
window handle
for(int itemIndex = 0; itemIndex < messageSeverity.Items.Count;
itemIndex++)
{
// this doesn't seem to actually set the list items.
this.messageSeverity.SetSelected(itemIndex, true);
}
break;
}
</code>

Does it resolve your problem?

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top