I am having a problem that is strange to me but hopefully is not so strange to someone else. : ) Some background: I am working on a simple IM client that allows the user to broadcast messages to multiple recipients. The goal is to create a chat form for each of the recipients containing the text of the broadcast message, then show that form only if the recipient responds to the broadcast-er. However, when the application receives a response then attempts to locate the form for that particular chat session (using Application.OpenForms) it cannot find it UNLESS I .Show at the time it is created. I would like to avoid having to show this form when it is created because this means that the user will see a flash on the screen. The form doesn't seem to really be created until I show it, but it would seem there has to be a way to do this without showing first. Can anyone assist?
I can provide code snippets if needed, I didn't in this post because this feels more like a conceptual misunderstanding on my part than a bug in the code. Thanks in advance!
Instead of using the form as a base class, do it the other way, create a class that can reference a form. That way, you'll keep the class informed of the content, and reflect it on the form (if it's initialized), not the other way around.
You shouldn't rely on Forms as a basis of your objects. Using Application.OpenForms should be unnecessary.
public class Contact
{
string displayname = String.Empty;
List<Message> history = new List<Message>();
MessageForm theform = new MessageForm(this);
public void OnEvent(Message msg)
{
if(msg.Sender != me && !theform.Visible)
theform.Show();
}
public void Tell(string message)
{
}
}
etc
Keep your contacts in some sort of list, and things should be relatively simple.
(Be aware that windows forms aren't thread-safe, and will throw an exception if you try to alter any properties of any of the controls from a different thread than main)
windows form has methods like Hide(),Show() and Activate(). use these method for your problem.
Why not store a reference to the form with the chat session and use that to call .Show() when you need to display the form:
session.form.Show();
You can then create the form without showing it and you don't have the overhead of calling Application.OpenForms each time you want to reference it.
I know this is stating the obvious but OpenForms won't find a form that hasn't been shown because it's not open.
As the form handle does not get created until the form is shown you can assign it manually like so:
mf = new MainForm();
/* Need to assign a handle to MainForm instance manually
as handle does not get created until form is shown */
IntPtr handle = mf.Handle;
Related
I have a Windows Desktop App with an auto-update method implemented. I want to show a custom Form (because I need to change the button texts) asking the user if he or she wants to download the new version or not when a new update is detected and I want to "block" all input actions in the Desktop App until the user has made his selection.
After reading Form.ShowDialog() documentation and several topics here saying "ShowDialog() is not making my windows modal" and several answers replying "You need to properly set the owner" I still don't understand how to set this owner. Of course if I make two forms and the first one shows the second, I can "block" the first one doing:
secondForm.ShowDialog(firstForm);
But I don't know how to make that the firstForm blocks all the application to prevent the user using a deprecated version of it.
I tried several approaches like getting the current id process (or trying to get it) and convert it to IWin32Window. But nothing seemed to work.
If you need it, I add here the code I'm using:
FormAsk formAsk = new FormAsk (param1, param2);
formAsk.StartPosition = FormStartPosition.CenterParent;
formAsk.TopLevel = true;
formAsk.TopMost = true;
formAsk.DialogResult = formAsk .ShowDialog();
if(formAsk.DialogResult.Equals(DialogResult.OK))
{
// do stuff
}
else
{
// do other stuff
}
I've also seen lots of solution implementing:
myForm.ShowDialog(this);
But VS start's crying because the types are not compatible. I'm using a MVVM pattern so I can't just set a Form as an owner because I don't have a main form. Just views in .xaml and views controllers in c#.
Edit: I would like to add few comments I learned after facing this issue that may help to understand better my situation.
The main method of the program executes the following:
[STAThread]
static void Main()
{
//stuff
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try
{
//stuff
STAApplicationContext context = new STAApplicationContext();
Application.Run(context);
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, Localization.Strings.error_popup_title);
Application.Exit();
}
}
}
And this context is the one that generates the service layer and views manager of the application. If I display the Forms in the service layer, showDialog() method can not "block" the input in the views but if I display them from the views (generated and handled by the view manager) i can. There's a communication between views and service, because actions triggered in the views have as consequence a service method call, but in this case the communication I want is the opposite: the service calling the methods in the view controllers to display the Forms by showDialog().
You need to pass an instance of the IWin32Window interface to the ShowDialog method.
IntPtr myWindowHandle = IntPtr(parent.Handle);
IWin32Window w = Control.FromHandle(myWindowHandle);
Do your Stuff in your first Form and whatever button you press to create your second Form just go like this. (Pseudo Code)
button1_click()
{
Form2 = new Form()
Form2.Owner = this;
}
and now from your Form2 you can talk to your Owner with this.Owner.Visible = false for example.
Thats how you make the Owner if thats what you asked for.
Thanks those who tried to help with your replies. However, although your answers probably will work in other circumstances, mine where a bit different.
Finally I achieved to solve it, I needed to do the handle with Forms in a higher level of abstraction. The information managed was retrieved from an asynchronous task so I couldn't use there a showDialog method and block the MainWindow of the application. Instead I did several threads, wait them and eventually show dialogs when I needed. It's not the best approach, but given the context is the only thing I could do.
I'm having a bit of an issue that I'm stumped on and I was hoping someone could shed some light on it. I have a Form called form2 and I'm running some code to add some items to the Listview(s) of that form using a MethodInvoker so that the UI thread stays responsive while I do so.
Everything runs fine with it the first time around but then when I close that form (the one with the Listview on it) and run my code again I get a InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
So I looked into this and Googled it a bit more as well as looked on StackOverflow and I saw the issue was being caused by the form not having a handle created for it since it's being disposed when it's closed the first time.
So my solution was to have it force the form to set a handle for itself via CreateControl(). Even after using this, my form still isn't setting the handle when I inspect it in the break from the exception. It has 00x0000000 or something like that, and I'm still getting my InvalidOperationException. I have also tried to checked .isDisposed() and tried to use CreateControl() after that with no luck. Have any of you guys heard of this before? The other threads on SO have yield no solutions for me.
My Code:
if (!form2.IsHandleCreated)
{
form2.CreateControl();
}
form2.Invoke((MethodInvoker) delegate
{
//Do Stuff Here.
}
So since nobody responded to this I'll answer my own question in case anybody comes across this and it helps them. I actually ended up putting this outside the scope of my new thread that was created and creating the form in a button click event. I then checked to see if my form was Disposed or still open and created new instances of the Form based on that.
This is my code:
var checkDMS = CheckIfNull(dealtxt.Text);
if (checkDMS)
{
//If DMS Deal is valid -> If Form is Closed ->
if (form2.IsDisposed)
{
// If Form not open -> Create new instance
form2 = new Form2();
form2.Show();
form2.SendToBack();
}
else
{
// If Form still open -> Close and make new instance.
form2.Close();
form2 = new Form2();
form2.Show();
form2.SendToBack();
}
runDMSQueryFromNewThread(materialCheckBox1.Checked);
}
else
{
MessageBox.Show("Cannot Pull Deal From DMS.");
}
I have one application built with WinForms with a big number of forms on it (approximately 90 forms) and now there is a requirement that when any form is opened the first input should get focused, so that it is ready for being typed into.
I imagine how to do that for a single form. We could run the following:
var firstInput = this.Controls.OfType<TextBox>().FirstOrDefault();
if (firstInput != null)
firstInput.Focus();
That's fine, but replacing this on every form is not just a huge task, but also it is a tremendous amount of code duplication.
I wanted to do that for all forms at once. In that case I created a base class:
public class BaseForm : Form
{
public void SetFoucsOnFirstInput()
{
var firstInput = this.Controls.OfType<TextBox>().FirstOrDefault();
if (firstInput != null)
firstInput.Focus();
}
}
And made all forms inherit from it instead of Form. The only problem is how do I call this method on all the forms after initializing the form. Is searched for some Form intialization event that I could subscribe to on the base class but found none.
How can I accomplish this in Windows Forms? Is there any way I can use my base class approach without needing to modify all 90 forms? Is there any better way? Or simply there isn't any way of doing it without modifying each form itself?
You can override OnShown(...) in your base form:
public class BaseForm : Form
{
public void override OnShown()
{
base.OnShown();
SetFoucsOnFirstInput();
}
public void SetFoucsOnFirstInput()
{
var firstInput = this.Controls.OfType<TextBox>().FirstOrDefault();
if (firstInput != null)
firstInput.Focus();
}
}
This methos will get called once every time a new form is shown.
But the more important thing is - that you dont have to call i yourself - the framework will do it for you.
You can use form Load event for setting focus.
help in msdn
I have an application that I am deploying using ClickOnce. I am using the default InstallUpdateUpdateSyncWithInfo() method provided here. I made two changes though; I made the method public and static as I am calling it from a static class. I know bad practices. This is some lazy code just to try out ClickOnce.
Everytime the application updates it loads two instances, the old one and the new one.
Other than that though I am calling the method in my app.xaml.cs like this:
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
MainWindow window = new MainWindow();
CheckForUpdates.InstallUpdateSyncWithInfo();
window.Show();
}
}
I thought if I call Window.Show() after checking for an Update it would call the Application.Restart() method in InstallUpdateUpdateSyncWithInfo() before the old version could load, but this is not the case.
Does anyone know how I can prevent two instances of my application from loading after the application is updated?
There was another post on Stack Overflow which from the title, I thought would directly address this question, but I did not see how the poster modified his code to prevent two instances from loading.
There's no need to write the auto-update code yourself. First, I would remove your update code.
Next right-click on your C# project and select Properties. Then go to Publish and click Updates.... Tick the checkbox so your application checks for updates and ClickOnce will handle the rest.
How can i trap a Windows system message (like WM_SETTEXT) that was sent by some window (VLC player window in my case)? I've tried to inherit NativeWindow class and override WndProc like this:
class VLCFilter : NativeWindow
{
System.IntPtr iHandle;
const int WM_SETTEXT = 0x000C;
public VLCFilter()
{
Process p = Process.GetProcessesByName("vlc")[0];
iHandle = p.MainWindowHandle;
}
protected override void WndProc(ref Message aMessage)
{
base.WndProc(ref aMessage);
if (aMessage.HWnd != iHandle)
return false;
if (aMessage.Msg == WM_SETTEXT)
{
MessageBox.Show("VLC window text changed!");
}
}
}
I have checked with Microsoft Spy++ that WM_SETTEXT message is sent by VLC player but my code doesn't seem to get the work done. I've refered mainly to:
http://www.codeproject.com/kb/dotnet/devicevolumemonitor.aspx
I'm trying to make this work for some time with no success. What am I doing wrong? What I am not doing? Maybe there is easier way to do this?
My initial goal is to catch when VLC player (that could be playing somewhere in the background and is not emmbed in my application) repeats its playback (have noticed that WM_SETTEXT message is sent then and I'm trying to find it out like this).
Is your code even being reached? I'm guessing you've inherited from NativeWindow but haven't made your actual windows inherit from your VLCFilter class. Which is in fact going to be a really difficult thing because you'll probably have to rewrite System.Windows.Forms.Form... (I'm guessing there's inheritance in there, but honestly not sure the internal structure in the framework.)
Perhaps you should inherit from Form instead and then have your forms inherit from your new class instead of Form?
I suppose, you could use hook techniques. It's designed for such cases.
Also, this links could be useful, despite they are easiely googled.
http://www.codeproject.com/KB/cs/netwin32hooks.aspx
http://www.codeproject.com/KB/system/WilsonSystemGlobalHooks.aspx
Hello and thanks for Your answers. ;)
Following the: http://www.codeproject.com/KB/system/WilsonSystemGlobalHooks.aspx did the trick and now I'm hooked up to event i wanted. Everything works fine, there's just one glitch: when ovverriding WndProc it starts recieving messages as soon as form is created. Is there a way to temporarily disable WndProc from recieving those messages and enable only when i want to get them?
Do your stuff before the call to the base implementation, else values in Message could have changed.
Somewhere in your code, you should be making a call to NativeWindow.AssignHandle. If you aren't (or if you're passing the wrong handle), then your overridden WndProc won't be called.
Edit: However, because VLC is running in a separate process, this technique won't work. The documentation for the NativeWindow.AssignHandle method states:
Note:
The handle to assign cannot be in a different application process.