I came across a perculiar problem with StringBuilder and Listbox.
I made a Listbox on a WinForm and called it lbOut and a StringBuilder string named log.
The code:
public partial class formMain : Form
{
StringBuilder log = new StringBuilder();
public formMain()
{
InitializeComponent();
log.AppendLine("This is a test");
lbOut.Items.Add(log);
log.AppendLine("Second line");
}
}
If I execute this code, I should get:
This is a test
Instead I get:
This is a testSecond line
Why is that?
I mean, "Second line" isn't even add to lbOut.
I working with Visual Studio 2010, .Net 4.0 on a Vista.
Update: Thanks everyone for the answers. I've learned a bit more today.
I can't vote up (yet), but I was very pleased with the answers given.
I've forgat about the object references
That happens because you pass in the StringBuilder, and not the string.
Hence, when it is shown in the UI, it calls ToString on the StringBuilder, which in the meantime has changed it's value.
A possible solution is to pass in the string:
lbOut.Items.Add(log.ToString());
Or, even better, create a Log method that logs the string, and adds it to the ListBox.
Something like the method below. Note I use Invoke if required, so the Log method is thread safe:
private void Log(string text)
{
log.AppendLine(text);
if (lbOut.InvokeRequired)
{
lbOut.Invoke((MethodInvoker)delegate()
{
lbOut.Items.Add(text);
});
}
else
{
lbOut.Items.Add(text);
}
}
ListBox.ObjectCollection.Add documentation provides a hint:
If the DisplayMember property does not have a member specified, the ListBox then calls the ToString method of the object to obtain the text to display in the list.
The call of ToString is not happening right away, when you add the object. It happens only when ListBox needs to render the object that you have added. It is the object, not its string representation, that ListBox keeps. Therefore, every time that you change the object, the text in the ListBox is going to change.
If you do not want this to happen, you can add an immutable object, such as a string, to your ListBox.
But, you add log to your lbOut. Than you add something to log. It would be weird if it was not changed on your lbOut.
Your listbox has a reference to the StringBuilder and after you added it to the listbox you updated the StringBuilder. Just use a regular string for this.
when you add log to lbOut you are adding a pointer to the object log not the value of log.
you would want to print/log that out before the next append or add the value of log
lbOut.Items.Add(log.ToString());
You add the log object to the list. And it gets updated by the second text change. If you want add log.toString() to the list, then you should get what you want.
This is because you are doing it in the constructor. Internally the CLR sees the 2 log.AppendLine calls both a applied so the value of log is actually "This is a testSecond line".
If you do the exact same code in Form_Load you will get what you expect.
Related
I would love to remove all items from MemoryCache.
What I have tried already:
var listDBCalls = ((FixedSizedQueue<DalCacheDto>)MemoryCache.Default.Get($"DAL_CACHE_{HttpContext.Current?.User?.Identity?.Name}"))?.ToList();
listDBCalls.clear();
If I watch this code in debugger, it shows that listDBCalls is really empty. But, calling again:
((FixedSizedQueue<DalCacheDto>)MemoryCache.Default.Get($"DAL_CACHE_{HttpContext.Current?.User?.Identity?.Name}"))?.ToList()
is showing me that all items are still there. Why is that?
Avoid to use the default memory cache to have more control.
Create your own memory cache (by example as a static property of a static class) and when you need to erased it you can simply create a new one to replace the older one. Don't forget to call the dispose method.
It seems the way to go : How to clear MemoryCache?
Edit
When I read you code I'm not sure what you want to do.
If you want to remove a particular entry (which seems the case) you can use the remove method.
MemoryCache.Default.Remove($"DAL_CACHE_{HttpContext.Current?.User?.Identity?.Name}")
I have a bunch of messageboxes in an existing app, both simple informations to user and also questions.
I would like to "intercept" them (for sure not the correct IT wording), change automatically its content, and then normally display it to user.
The "OK" or other standard return should be returned/forwarded to the initial messagebox.
The modification function is a kind of translation, but for the purpose of demonstration, lets say that this special function does += " AAA" to the content and += " BBB" to the top header.
Note1: while searching, I have seen several custom message boxes, but
these are additional controls, mainly for changing the button captions
or style, not to "intercept". Please correct.
Note2: fully agree that a better & cleaner MVVM structure would have avoided the
trick needed above, but this big app started some time ago, with a
very small and different aim
As far as I know this isn't possible. You cannot have a reference to a MessageBox, so you cannot access it in any way once it is open.
According to the documentation:
You cannot create a new instance of the MessageBox class. To display a message box, call the static method MessageBox.Show.
This means that you cannot do like the following:
var box = new MessageBox([stuff]);
MS deliberately made the constructor or constructors of that class private (or protected), to make you use the factory method instead (MessageBox.Show();). Note that since they are explicitly defined, just not accessible, this means that no implicit constructor is generated either.
Doing this also won't work:
var box = MessageBox.Show([stuff]);
The Show method doesn't return a reference to the open box itself, but to the DialogResult object after it closes.
As for your situation, the only ways I can think of to solve your problem would be to either go through the program and change the strings, or create a new custom control and ditch the MessageBox entirely. You may be able to find another way, however "intercepting" the MessageBox instances isn't possible.
Assuming that the code uses System.Windows.MessageBox.Show calls using text and caption arguments, you can try defining a public static MessageBox class in a common namespace of your application providing a similar Show method that updates the arguments and calls the original MessageBox.Show method, e.g.:
public static class MessageBox
{
public static void Show(string text, string caption)
{
text += "AAA";
caption += "BBB";
System.Windows.MessageBox.Show(text, caption);
}
}
Note: this will only work if you are able to rebuild the solution from source code, as it requires adding a new source code file (the custom MessageBox class), and then rebuilding the solution.
I have inherited some code. I see that this code exists:
private List<int> Data { get; set; }
private CsClipboard()
{
Data = new List<int>();
}
public List<int> ComponentIDs
{
get
{
return Data;
}
set
{
Data.Clear();
Data = value;
}
}
I don't see any reason to call clear before setting Data to value. I'm wondering if there are scenarios in C# where I would want to call clear before setting the value aside from something like triggering an OnClear event. It's a fairly large code base with tech. debt, so just being overly cautious.
That code could have some nasty side affects.
What happens there is that the original list gets cleared. so every other place in the code that holds the original list will now hold an empty list.
Every new get request will hold the new list. But the the data isn't concurrent across the program.
In general, you should avoid public properties that return a mutable list. Once a consumer gets a reference to it, you no longer have a guarantee on the state of what should be an internal detail. Clearing the list in a setter only exacerbates the issue, because now you are clearing a list that a consumer might still have a reference to (even though it is no longer the correct list.)
You should consider changing the property so that it returns a copy (preferably read-only) of the current state of the list. The AsReadOnly() method can help here. If you can't do that, at least don't clear the list before setting the new value.
I would want to call clear before setting the value aside from
something like triggering an OnClear event.
The List class does not have events MSDN
So how about writing you own custom Clear method for the list
I mean extension method for the list class that will use your Clear method with your custom logic
I am trying to populate a combobox in C#, but for some reason, the items do not appear.
public List<string> items
{
set
{
combobox.Items.Clear();
foreach(string s in value)
{
combobox.Items.Add(s);
}
combobox.Update();
}
}
This seems like incredibly straightforward code. I simply cannot see what is wrong.
It is being called like this:
private void StoreNames(List<string> names)
{
if (selectionForm.InvokeRequired)
selectionForm.Invoke((MethodInvoker)delegate { selectionForm.items = names; });
else
selectionForm.items = names;
}
Interestingly, it seems to work when InvokeRequired returns true, but does not work when it returns false.
EDIT:
I discovered that selectionForm.IsHandleCreated is currently false. This is causing InvokeRequired to return false, but is also why calling the setter regularly isn't working. I don't have any idea why IsHandleCreated is set to false. The Form has been Show()n.
Not sure why your code isn't working - I tried it and it works just fine.
However, below is some more straightforward code which also works - you may find that doing it this way instead makes your problem go away. This does presume that there is not other reason why you need to go through that property - that is quite an unusual way of doing things.
public void StoreNames(List<string> input)
{
if (comboBox1.InvokeRequired)
comboBox1.Invoke((MethodInvoker)delegate {
StoreNames(input);
});
else
{
comboBox1.Items.Clear();
comboBox1.Items.AddRange(input.ToArray());
}
}
Here we just pass the list straight to the items.AddRange() method on the comboBox.
I suspect this won't work for you - something else is going on, but I have tried it both from a backgroundworker (where InvokeRequired is true) and from the main UI thread.
Is it a typo that you refer to both combobox and combobox1? Perhaps that is your error.
Do you mean "not appear" as in you can see them when the list displays, or as in you can't even scroll to them?
Combobox has a lot of properties that can affect what you see. Try a bigger value for combobox.MaxDropDownItems.
My other answer in this thread is really just showing the way to doing this if you can get at the code providing you with the list. Since it sounds like you cannot, I'm providing this answer.
It sounds like the key problem is that when the property is called the combobox has not yet been initialized. The best answer for that is that make sure that this does not happen within the calling code.
If you can't do that then you should wait for the property to be set before you use it to populate the combobox.
I would do this be having a private list which gets set in the property setter. Within the form load event i would then put some code (possibly within a background worker) that will wait until the private list is not null and then assign it to the combobox.
Have a look at this post by Jon Skeet here where he discusses how to correctly wait for a variable to be set by another thread. You will want to be careful when doing this - threading issues can be nasty.
In an earlier question about how to return a string from a dialog window, yapiskan suggested overloading the child form's ShowDialog() method to include an out parameter.
My question is whether or not this is a good approach in C#.
Here is some example code, based on yapiskan's suggestion. In the child form (in this example, it's a form with a textbox on it), you just need to add the ShowDialog overload and assign UI values to the out parameter:
public DialogResult ShowDialog(out string s)
{
DialogResult result = this.ShowDialog();
s = this.textBox1.Text;
return result;
}
And to show the form and retrieve the entered text, you do this:
using (CustomDialog frm = new CustomDialog())
{
string s;
if (frm.ShowDialog(out s) == DialogResult.OK)
{
// do something with s
}
}
One advantage I can think of is that this approach forces the user of the CustomDialog form to get the information it contains through the form's ShowDialog method (rather than from a who-knows-what-it's-called method like GetMyData() or something).
Better to have a Public property/method and get the information.
What would you do if you would need 3..4..5 informations, having 5 parameters out? More clean to have accessors to get your information from the Dialog.
It should not be OK since .net framework does not use this design. In the case of OpenFileDialog class, it has a parameterless ShowDialog() method returning a DialogResult. Once this method called, user is supposed to get the selected files by using the FileName, FileNames, SafeFileName and SafeFileNames methods.
Let's assume that this implented in the "out parameter" way. I would have to write code like this just to get the SafeFileName:
string dummyFileName;
string[] dummyFileNames;
string safeFileName;
string[] dummySafeFileNames;
myDialog.ShowDialog(out dummyFileName, out dummyFileNames, out safeFileName, out dummySafeFileNames);
Personally I try to avoid out parameters wherever possible, although I understand that like GoTo they are sometimes a necessary evil. I would say that it would be much better to use properties or methods to return the information.
In my experience, a custom modal dialog that collects only one piece of information is a pretty extreme outlier. Much more common are zero and many.
And a dialog that collects many pieces of data is almost certain to be modified at some point to collect just one more. I'd much rather fix only the code that uses that one new piece of data than every single piece of code that uses the modified dialog.
Also, think about how a developer uses IntelliSense to use your class. He's going to type this:
MyDialog d = new MyDialog();
d.ShowDialog(
...and at that last keystroke, IntelliSense will pop up telling him that he now has to declare three new string variables to hold the out parameters. So he moves the cursor up, and starts typing:
string foo;
string
...and, what was the name of the second parameter again? So it's back down to the open paren, hit CTRL+SPACE, oh yeah, it's bar, back up to the previous line, etc.
The problem with using properties on a custom dialog is that the Form class already has a million properties, and the three or four special ones that you're creating are going to get lost in the mix. To fix this, create a class for the dialog parameters and a Parameters property of that type on the custom dialog. That makes code like this easy to write:
MyDialog d = new MyDialog();
d.Parameters.Foo = "foo";
d.Parameters.Bar = "bar";
d.Parameters.Baz = "baz";
because the parameter names pop up in IntelliSense, and you don't need to declare any variables to hold their values.
My approach is typically to write a method that internally calls ShowDialog, then formats the output data appropriately. For (contrived) example:
public string GetFolderName(){
if(this.ShowDialog() == DialogResult.OK) {
return this.FolderName.Text;
}
return String.Empty;
}
In most cases I make this method static, and instantiate the dialog itself from within the body of the method - that way the caller doesn't have to deal with form references, or the notion of having to chose which 'show' method to call.
In the non-edge cases of having multiple output values, I typically construct a struct that holds these values, then have my 'Get' function return that struct.
public struct FolderData {
public static FolderData Empty = new FolderData();
public string FolderName {get; set;}
public int FilesInFolder {get; set;}
}
public FolderData GetFolderData(){
if(this.ShowDialog() == DialogResult.OK) {
return new FolderData {
FolderName = this.FolderName.Text;
FilesInFolder = int.Parse(this.FilesInFolder.Text);
}
}
return FolderData.Empty;
}
I prefer this one because I don't like the approach of getting result from a property or a method after you have done with the class. After dialog form was shown and closed I think the object should not be used any more because logically you have done with the dialog then why should I use its property or method to get the result?
#Musigenesis, you really don't want to force client code to break when you change your dialog, and using an out parameter that is only sometimes valid isn't a good design. As #Daok says, when you have more than 1 value returned this starts to get messy and ugly fast.
You also can't force client code to use the result any more than the .net framework ensures that you call properties on a file dialog. You're also not forcing the caller to do anything with the out parameter, all you've forced them to do is to accept a variable that they may not want to use.
If the dialog is very generic this may not be applicable, but instead of chucking all sorts of properties to the dialog itself, have a single method that you use consistently throughout your application, and have that return a specific class that holds the relevant data.
public sealed class MySaveDialogResult
{
public static MySaveDialogResult NonOkResult(); // Null Object pattern
public MySaveDialogResult( string filePath ) { ... }
// encapsulate the dialog result
public DialogResult DialogResult { get; private set; }
// some property that was set in the dialog
public string FilePath { get; private set; }
// another property set in the dialog
public bool AllowOVerwrite { get; private set; }
}
and your dialog is
public MySaveDialog ...
{
public MySaveDialogResult GetDialogResult() { .... }
}
The essence is a small immutable utility class that also implements null object pattern. The null object is returned whenever the dialog result wasn't OK. Obviously the above is a shot in the dark for your needs, so alter it at will, make inheritance hierarchies, etc.
The main point is to have GetDialogResult(), a single method on the dialog, to returned a class that encapsulates all the relevant dialog data.
edit:
#yapiskan wonders why not just 'out' the MyDialogResult versus calling GetDialogResult().
IMO - The points are simply:
That's not the convention
A method call is trivially easy, and made easier when you follow the 'convention' argument as made above.
out is awkward to use. GetDialogResult() is not forcing the caller to write awkward code, and it doesn't force the user to consume the dialog result at the point of invoking the dialog.
Normally the dialog isn't re-instantiated or re-shown to get the result, it's already there. Show() and Hide() do just that.
The reality is you're trading a method call for an awkward ShowDialog() syntax. Method calls are cheap, and you can't guarantee the caller will use your out parameter any more than you can guarantee they will call GetDialogResult(). So why bother. Make the thing easy to use, or don't overload ShowDialog in the first place.
Maybe whatever you're sub-classing is funky and acts differently and it's not applicable to your situation, but general design is forms don't go away when you click OK, they go away when they are Disposed() of.