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.
Related
I am using a RichTextBox which is in a Form that I am basically using as a log window whilst the program performs various functions - much like a debug window. Various methods write to the window as they perform tasks on various files. The simple class looks like this:
public partial class ValidationWindow : Form
{
public ValidationWindow()
{
InitializeComponent();
}
public void writeToWindow(string text)
{
if (richTextBoxValidationWindow.TextLength > 0)
{
richTextBoxValidationWindow.AppendText(Environment.NewLine + text);
}
else
{
richTextBoxValidationWindow.Text = text;
}
}
}
I have instantiated the Form containing the textbox from a class in the usual fashion i.e ValidationWindow valWindow = new ValidationWindow(), then call the show() method to display the window, and i can then write to it using the method in the above class called writeToWindow. All good.
I now need to be able to continue to write to the same window from other classes. I obviously don't want to create more instances of the same Validation Window. So what is the best way to do this please?
It sounds like you need access to this form from other forms and classes. In other words, you need this form to be globally accessible.
The simplest way to do this is add a global variable to your application, and save a reference to the logging window in that variable. Then, if any other class needs to log, it can access the logging window via the global variable.
However, this is perhaps not the best way to do this, as you are tying your logging to that window. What happens if you decide to log a different way? You'd have to change every reference to the window, which means changes all over the application. You would be better off looking at something like messages, which allow the calling code to send out a message requesting that something be logged, but not needing to know anything about the class that receives the message and does the actual logging. I know WOF supports this with MVVM, but am not sure how you would do it in WinForms (assuming that's what you're using). Maybe do a search on "winforms messages" and see what comes up.
Hope that helps
I grew up on VB.Net. From there, in a routine, I could instantiate a form, and access controls that I had put on that form, like a textbox. Further, after hiding the form, I could read public properties that got set on the form. I am trying to do this in C# and according to the intellisense, neither is accessible.
so, in Form 1, for example I say
Form f = new MyOtherForm();
from there, f only returns things like Text, or Tag.....I can't see any controls on f to set them.
Further, MyOtherForm has a public property called MyResult. After a show dialog, in VB.Net, I could, from the calling form, access
f.MyResult
In C#, I cannot.
Can someone help me understand how it works in C#?
If you want to see the properties of MyOtherForm, you should declare the form as MyOtherForm:
MyOtherForm f = new MyOtherForm();
Beside that, you should also check if the property you are looking for is set as public.
To make your life easier, learn and love the var keyword.
The implicit typing that this introduces allows for you to not have to worry about getting the correct type when declaring a variable. In your case, you know exactly what you're setting it to, so it isn't a huge deal. However, when you're getting results from methods, or LINQ calls, this provides a huge benefit.
Bear in mind, this isn't like the var keyword in JavaScript. Your variable still has the correct type, only you don't have to set it explicitly.
I have an application that can launch/new up a form(lets call it QuickNoteForm) from many different actions. It can launch the form from many different tabs and mostly are launched thru buttons all over my application.
I basically want to track where it was launched from, ie I need to track its Launch Path.
What would be a good approach to implement this. I was thinking to enclose this as a property that gets set via the constructor of the QuickNoteForm. I want to track from which action this form got launched from.
This is a windows forms application and not a asp.net app.
thanks.
Create an enum that would list all possible paths (or a static class with constants if you worry about maintainability, enums don't work well when compiled and then modified). Add a custom constructor to your form that would accept this enum as a parameter. When you instantiate a form, use that constructor. Basically replace all occurrences of New QuickNoteForm() with New QuickNoteForm(yourEnumValue). For compatibility, add an Unknown = 0 value to the enum, this way calling form's default constructor will work too, just not as useful.
If this approach is not practical (please provide more details on your application), you can also provide a context Control as parameter in your form's constructor. Then have code like If typeOf ctl Is Button AndAlso DirectCast(ctl, Button).Text = "Something" Then and all sorts of crazy stuff. This promotes separation of concerns, i.e. the calling code does not need to know how to call and only pass itself as a parameter, but also makes your code harder to maintain, because you may end up with one giant know-it-all method which would connect all pieces together.
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.
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.