Creating a message box in C# with custom buttons - c#

Would like to know if it is possible to create a MessageBox with custom buttons similar to what one would achieve with showOptionDialog in java?
String[]colors = {"Red", "Green", "Blue"};
int color = JOptionPane.showOptionDialog(null, "Please choose color", "Color please", 0, JOptionPane.INFORMATION_MESSAGE,null, colors, colors[0]);
if(color == 0)
{
JOptionPane.showMessageDialog(null, "Red it is");
}
What would the equivalent for this be in C#?

I'm afraid that the answer is: you can't.
There is no way to alter the MessageBox as far as I know. You will need to code your own dialog (is not that hard).
Probably the MessageBox class is making a WinApi call at the end and that could be the main reason.

I think this does what you want:
http://snipplr.com/view/14245/custom-messagebox-buttons/
Here is similar approach, in C++, but with more explanation:
http://www.codeproject.com/Articles/10037/How-to-change-the-MessageBox-window-Add-controls-a
NOTE: Just be aware that the WinApi messagebox is optimized to be able to display even under very low memory conditions. So the OS can display messages in a crash or low memory condition.
If you mess with it, like above, you may lose some of that robustness.

I don't think you can. The messagebox class has only private constructor so you can't derive from it. However, as SoMoS already wrote, you could make your own custom message box by using a windows form and its showdialog() method. Hope it helped

Related

how "intercept" messagebox & modify its content, and back to normal flow?

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.

is using while for this ok?

while(player.CloseMenu(menuType))
{
}
player.CloseMenu(menuType) will close one menu of the chosen type, or return false if there are none left of that type.
is it ok to use an empty loop like this to close all the menus of a given type?
Be careful when coming up with clever ways of doing things in code. It may save a few keystrokes in the short run, but someday someone else may look at this code and wonder:
What is this even doing?
Ok, I see what it's doing, but why was it done this way?
Is there a compelling reason for this, and should I avoid it so as to not break something else?
Keep in mind, that someone else may very well be you in several months after you've forgotten the details of this code.
Saving a few lines of code isn't really a big deal. Anything that has to be written only once is a finite amount of work. Anything that sows confusion in support going forward produces an unknown and less finite amount of work.
I'd go with more self documentation in case other people need to read it.
The problem is that you have to infer from the fact that the invocation is inferred as a bool to understand.
Maybe if you named it player.IsMoreAfterClose().
or
while(true)
{
bool b = player.CloseMenu(menuType);
if(!b) break;
}
or
bool b = true;
while(b)
{
b = player.CloseMenu(menuType);
}
I would expand on all of these answers and create a method called CloseAllMenus(MenuType menuType). Then you can put whatever kind of ugly implementation in there, and it will be obvious what it is doing when you call it. Your current code doesn't explain what exactly is happening unless you already know that there can be multiple menus of a particular type open, and that this call will only close one of them.
It'll work, obviously, but it makes the code a little hard to read/maintain. You might be better of with the loop condition being a check for any open menus, with the body of the loop closing one.
It's ok to do that as it means do something until certain condition is met. But it's better to incorporate that in the CloseMenu function so that you don't have to repeat this instruction many times and in fact it's a variation of closing menu where you want to close all menus. You can add a boolean argument to the function to indicate if you want to close all menus.
bool CloseMenu(type, closeAll){
if(closeAll)
while(exists(type))
{ close...
else
if(exists(type)
{ close...
}
Maybe the "right" thing to do is invert from While/Close with no body to For/Open with the body doing the Close operation.
foreach(var menu in player.OpenMenus)
menu.Close();
or:
player.OpenMenus.ForEach(c => c.Close());

Is it possible to disable c++ assert from .net app

I have the following problem:
I use c++ library from my WPF app, the library throws an assertion in some very rare cases. It shows a nice dialog with c++ filename, the line number and assert expression. So the question is: can I disable asserts in the c++ library assuming that I don't have source code. What I really need is to "catch" this assertion and log it.
Thanks.
One way is to create a thread that performs EnumWindows every so often and detects if an assert window pops up, it can then capture the message and click the ignore button. This will still cause the window to show up for a short while (depending on your interval between EnumWindows but I assume you customers aren't going to be getting the debug DLL so it shouldn't matter.
Another option is calling _CrtSetReportMode(_CRT_ASSERT, 0) to disable asserts from being shown altogether.
If you want to PInvoke this from .NET note that _CRT_ASSERT is equal to 2.
Depending on your assembler skills and whether steps have been taken deliberately to block this type of stuff, it's usually possible to modify binary code to prevent this sort of message being displayed.
However, an assertion firing is often a precursor to some more spectacular crash or other misbehaviour, so just stopping the message box might not get you much further. Of course, some assertions are buggy, so this might be all you need.
If I had to modify this DLL, I would disassemble it with IDA and work out a patch. Hiding the assertion would probably be fairly easy, logging it quite a lot harder.
I recently had to fix some old code which relied on a DLL which sometimes popped up an assert message. I tried all the above suggestions, and the only one which I got working was to click on the Ignore button. The user above suggested running EnumWindows on a separate thread - I used FindWindow instead.
This is the function which finds the Assert popup message, finds the Ignore button within there, and then clicks it. It goes on a loop which checks a global variable each time (ugly but quick):
void CloseAssertBox (void *param) {
HWND window, button;
Sleep (200); //wait 200 milliseconds
while (!finishThread) { //see if we can stop checking
if ((window = FindWindow (NULL, L"Microsoft Visual C++ Runtime Library"))
&& (button = FindWindowEx (window, NULL, L"Button", L"&Ignore")))
SendMessage (button, BM_CLICK, 0, 0); //click the button
Sleep (50); //then check every 50 milliseconds
}
}
The title of your Assert box might be different. If your Ignore button is referenced differently, you can use EnumChildWindows to get the name of each child control including buttons.
Before the bit of code which pops up the assert, I start a new thread which calls the function above.
finishThread = 0; //this is set to 1 when the thread should finish
_beginthread (CloseAssertBox, 0, NULL); //begin the thread
After making it through the dangerous assert-prone code, I set:
finishThread = 1; //done threaded stuff
That way the thread will close next time round its loop. There's probably better ways of doing that.
I had to include these libraries to make it work:
#include <process.h> //for multithreading
#include <WinBase.h> //for Sleep function
int finishThread; //to tell the thread when encoding has finished
This was all done in Visual Studio 2010 using a library from 2006.

Programatically finding a message box and generating a click on a button

I am trying to automate testing of a winform application. I am running it in the same process as the test code, so it is fairly easy to find the .Net controls and simulate user action on them. I got however stuck a bit with a message box (created using the standard MessageBox.Show method). How can I get hold of it and simulate that a button is pressed?
I'd advise treating the underlying disease rather than the symptom.
Take a few minutes to read these
the Humble Dialog box by Michael Feathers
User Interrogator by Tim Haughton
In short, use an interface to separate out all modal dialog pop-ups - which are a pain in the neck for UI test automation. You can then substitute a mock implementation of the interface that does nothing or returns predetermined test values. The real implementation of course pops up the actual dialog modally... something like this (from the 2nd link)
public class UserInterrogator : IUserInterrogator
{
private Form owner;
public UserInterrogator(Form owner)
{ this.owner = owner; }
public Font GetFontFromUser() // member of the IUserInterrogator interface
{
FontDialog fd = new FontDialog();
fd.ShowDialog( owner );
return fd.Font;
}
}
The easier approach is of course to write some code that finds the dialog and closes/kills it. I've seen some people have some success with Win32 APIs and NUnitForms ...
codeplex.com/white - Free
testautomationfx.com - Commercial but very good
You probably will have to use WinAPI calls (FindWindowEx, ect) and send a messages of LMB down and up to a button handle.
If you know the caption (and it is unique) you can loop through Application.OpenForms to find it.
One of the best free tools is AutoHotKey.
You can use autoit script system.
But i am suggest to separate the GUI and implementation, because basic principle of unit testing is "unit", where unit is class that separated from other classes or real world.
This principle give you good class design and help to avoid software eruption and lot of other good stuff..

How to create IDLE -like functionality to WinForms application

I'd like to add "IDLE-like functionality" to C# WinForms application, but I don't quite have an idea how to do that and couldn't find anything useful with Google.
So basically I want interactive command line interface, where user could enter some Python code and execute it (not just expressions, should be possible to define new functions).
So, where to start? Are there any good tutorials or samples available?
If my memory serves me correctly there's a chapter on embedding Python in the book Python in a Nutshell. Perhaps you can find some useful information there, but since the book is not Windows specific, you may have to adapt it yourself.
I would setyp my WinForm like this: add 2 textboxes.
1: for output. Set the multiline property of the first to true, and make it read only.
2: for input. Use KeyUp Or KeyPress Event for e.g. the return key and use the text to do what you want: add command to output textbox, launch code against the engine and capture output of interpreter
This link (http://groups.google.com/group/ironpy/browse_thread/thread/5e61a944c7c94d4b/0cbf29ec0f5fbb64?pli=1) might give some answers about launching commands agains a python engine.
IronRuby comes with a command line interpreter. Doesn't IronPython also have one? If so, the source code would be a good start :)
Oh, and if it doesn't, be sure to look at the IronRuby interpreter, because both languages are based on the DLR and are therefore similar enough to learn from both.
Thru IronPython mailing list I found IronTextBox2, which is good example how things are done. It needs a little tweaking, to get it running, but otherwise is good solution.
Here go my most generic solution:
Point cursorPoint;
int minutesIdle=0;
private bool isIdle(int minutes)
{
return minutesIdle >= minutes;
}
private void idleTimer_Tick(object sender, EventArgs e)
{
if (Cursor.Position != cursorPoint)
{
// The mouse moved since last check
minutesIdle = 0;
}
else
{
// Mouse still stoped
minutesIdle++;
}
// Save current position
cursorPoint = Cursor.Position;
}
You can setup a timer running on 60000 interval. By this way you will just know how many minutes the user don't move the mice. You can also call "isIdle" on the Tick event itself to check on each interval.

Categories

Resources