How to call a method from WindowsForms in Monogame? - winforms

Hi im currently working on a project. My main form is a form and whenever i click on a button the monogame program starts. This works.
Now i made a method in the main form and i want to pass the bool to the monogame form.
Main Form method: (if checkbox is checked monogame should draw a skyline)
public bool skyCheck()
{
if (checkBox1.Checked == true)
{
sky = true;
}
else
{
sky = false;
}
return sky;
Monogame check:
if (skyCheck() == true)
{
DrawSky();
}
This gives me the name 'skyCheck' does not exist in the current context.

I made a Control that embeds a monogame into a form so that a seperate program doesn't have to be run. It isn't the normal embedded monogame you see that only gives you a graphics device and no update or game methods. it's an actual monogame embeded.
This is not the source of your problem but it could help fix it along with make your program better.
Here is the source and some brief documentation is contained in the Readme on how to use it

Pass a reference of the form to the constructor of Game1:
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
//Change the Form1 to the name of the form class.
Form1 form;
//...
public Game1(Form1 form)
{
this.form = form;
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
//...
// I will assume the DrawSky() should be called in Draw.
protected override void Draw(GameTime gameTime)
{
//...
if (form.skyCheck()) // the "== true" is redundant.
{
DrawSky();
}
//...
}
}
The following code would normally be in Program.cs, but as a Window Forms application, this code would be in the form that launches the game:
game = new Game1(this); // where "this" refers to the current form
game.Run();
Please note the caveats to mixing Windows forms and MonoGame:
The form's message pump and the Game run in the same thread. Any stall on the form will cause the game to lag.
There will be a performance penalty.
Make sure the game shuts down properly before the form is unloaded to ensure the resources are cleaned up properly.
It is is possible to start another thread for the game to run in(thus bypassing the first two caveats), but, all communication between the two threads must be thread safe. Thread safety is guaranteed for a Boolean assignments, as well as Integer assignments (=< 32 bits for 32 bit processes, and =< 64 for 64-bit processes).
Exit coordination in both threads is required.

Related

How to stop User Control execution process until the User responds to the user control

Hi we have a WPF Application which we have developed using MVVM pattern. We have such kind of architecture where we have some DLLs which contain some POP UPs (WPF Windows) which are no where realeted to our Main Application.
Using some internal layer we are doing some analysis and dynamically picking the required dlls based on some conditions and we are showing those pop ups on main application by joining the thread of that dll with the WPF main application thread.
But now we want to remove those pop ups and instead of pop ups we want to show usercontrols in main window by replacing all these windows with usercontrol.
So now also we faced some issue with thread in dlls , and from dlls again we are sending the usercontrol object to main application and able to load in main application.
But earlier while showing pop ups we used the window.ShowDialog which will stop the further processing in that dll untill user responds.
But as now we changed those windows to usercontrols and we dont have any such mechanism in usercontrol which will stop further processing untill user responds to it, so before user responds the execution in dll is goinng to next level which we dont want.
Can any one help how to get the Window.ShowDialog() equivalent functionality while displaying or loading a User Control as well?
We tried setting up some flags in an infinite loop in usercontrol untill user responds , but we are getting again wpf thread issues even there.
Hi this is the code snippet and details as well:
We have one DLL called some XYZTest.dll which is of type user library where we have some wpf window which will be invoked from the same DLL from some other class Package.cs as follows earlier:
Initial Pop Up Approach where we are showing WPF window from dynamically invoked dll as pop up on the main application :
If(somecount>0)
{
MessagePanel messagePanel=new MessagePanel(request.ClientInfo.IPAddress);
messagePanel.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
messagePanel.ShowDialog();
}
Return obj;
In this above code untill user responds to the above window the execution process does not go further…
And this XYZTest.dll is dynamically invoked by a business layer and there using the following code we are attaching this thread to main application or thread which is our ui…
Dynamic Invocation of that DLL and joining thread to main window:::
Thread thread = new Thread((ThreadStart)delegate { retrunObject = invoke(requestObject); });
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start();
thread.Join();
return retrunObject;
But now we don’t want to display pop ups and so I wanted to change all the windows to user controls and wanted to display the respected user control in the main application dynamically.
So now we changed code something like this...
1st approach::
PangaeaServerApplication.App.Current.Dispatcher.Invoke((Action)(() =>
{
MessagePanelUserControl userControl = new MessagePanelUserControl();
MainApplication.ViewModel.MainWindowViewModel.ADDClientUUTPopUP( userControl);
while (true)
{
if (isRunning == false)
{
break;
}
else
{
userControl.trigger.WaitOne(2000);
}
}
}));
2nd Approach::
Thread newWindowThread = new Thread(new ThreadStart(() =>
{
// Create our context, and install it:
SynchronizationContext.SetSynchronizationContext(
new DispatcherSynchronizationContext(
Dispatcher.CurrentDispatcher));
MessagePanelUserControl userControl = new MessagePanelUserControl ();
MainApplication.ViewModel.MainWindowViewModel.ADDClientUUTPopUP(userControl);
while (true)
{
if (isRunning == false)
{
break;
}
else
{
userControl.trigger.WaitOne(2000);
}
}
System.Windows.Threading.Dispatcher.Run();
}));
newWindowThread.SetApartmentState(ApartmentState.STA);
// Make the thread a background thread
newWindowThread.IsBackground = true;
// Start the thread
newWindowThread.Start();
Here my intention is to achieve a behaviour similar to messagePanel.ShowDialog(); where the execution will not proceed further ...but while using autoresentevent I am getting complete ui hanged and if I am not using any timers and all then not able to stop execution untill user responds...

await Task.Delay(...) freezes if there exists a System.Windows.Forms.Form instance

The following program hangs on the DoTheStuff().Wait(); line, if running as a Console application:
namespace Test
{
using System.Threading.Tasks;
using System.Windows.Forms;
class Program
{
static void Main(string[] args)
{
new Form();
DoTheStuff().Wait();
}
private static async Task DoTheStuff()
{
await Task.Delay(1000);
}
}
}
It works just as expected though, if you comment out the new Form(); line. (Runs for 1sec, then quits).
How can I keep the expected behaviour and still have a Form instance?
Now, some background if you are interested:
I have an application which is hosted as a windows service (as console when testing locally).
It requires to have access to the SystemEvents.TimeChanged event.
However, as per the documentation, this only works when having a windows Form (thus not in a service or console app). A workaround is presented in the linked documentation, and consists of creating a hidden form.
Unfortunately, the program now completely freezes instead, which is caused by the combination of await and having a Form instance.
So how on earth can I still have the expected async/await behaviour while accessing the SystemEvents.TimeChanged event?
Thanks to help below, here comes modified code which works without freeze:
namespace Test
{
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
class Program
{
static void Main(string[] args)
{
new Thread(() => Application.Run(new Form())).Start();
// SynchronizationContext.SetSynchronizationContext(null);
DoTheStuff().Wait();
}
private static async Task DoTheStuff()
{
await Task.Delay(1000);
}
}
}
In my program, I need to use "SynchronizationContext.SetSynchronizationContext(null);", since the threadpool should be used for awaiting tasks. I don't think that is a good practice, since Form obviously initialized it for a reason. But running the form hidden without user input (it is a service!), and can't see any harm right now.
The documentation feels a bit incomplete, with MS not even mentioning the issue that may arise using the example 2 (await/async implicitly changes behaviour when instantiating a Form).
This is by design. Creating a new Form object get the Winforms plumbing to install a new SynchronizationContext. Something you can see in the debugger by looking at the SynchronizationContext.Current property.
That property is big deal whenever you do anything asynchronously. If it is null, the default, then using await gets code to run on threadpool threads. If it is not then the await plumbing will implement the await by calling the SynchronizationContext.Post() method. Which ensures that your code runs on the main thread.
But that doesn't work in your program because you broke the contract. You didn't call Application.Run(). Required.
The SystemEvents class will create its own hidden notification window and pumps a message loop if you don't provide one. No need to create a form. The consequence is that its events will fire on an arbitrary thread, not your main thread. So do watch out for locking requirements.
The call to Wait causes a deadlock, as I explain on my blog and in a recent MSDN article.
In your case, you could use a simple MainAsync as such:
static void Main(string[] args)
{
MainAsync().Wait();
}
static async Task MainAsync()
{
new Form();
await DoTheStuff();
}
private static async Task DoTheStuff()
{
await Task.Delay(1000);
}
However, there are a couple of problems here. First, when you create a form (even a hidden form), you are expected to run an STA event loop, e.g., Application.Run. Second, as a Win32 service, you are expected to give your main thread back to the SCM, e.g., ServiceBase.Run.
So I would recommend a solution where you create a form and run an event loop on a secondary thread.

Closing (Exiting) and Application before Application.Run() is called?

I'm having trouble understanding how to close an C# .NET winforms application. What I'm trying to do is:
Display a form to allow the user to set-up the environment how they want
If the user presses the "OK" button, perform some logic for setting up the application environment (instantiate objects, etc)
If the user presses "Cancel" or closes the window, close the application.
The problem is, I'm calling the environment set-up form before the main (1st) form. It's a recent requirement change, and I didn't fancy re-writing the code that I have from the very beginning.
The code I have (which should make more sense than my little preamble) is:
public MainForm()
{
InitializeComponent();
//Get the user to set-up the environment (load specific config files, etc)
environmentSetupForm newEnvrionmenSetupForm = new environmentSetupForm ();
if (newEnvrionmenSetupForm .ShowDialog() == DialogResult.OK)
{
newEnvrionmenSetupForm .Close();
//some logic based on what the user selected on the set-up form
}
else
{
//Since the user didn't set-up the environment correctly (there
//was a message box, informing them and giving them another
//shot at it), exit out of the application.
Application.Exit();
}
}
My only problem is that after Application.Exit(), the stack jumps back to Program.cs and performs
Application.Run(new MainForm());
So the Main form (and app) runs regardless. Is there a better way to do what I'm trying to do?
Edit: for clarity my program.cs code reads:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace myNamespace
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
Neither the form's constructor nor its OnLoad or Load event are good places to put this code. The constructor runs due to the new MainForm() statement in the Main() method, before the Application.Run() call. The Load event is fired because the Application class calls the Show() method, hidden inside the framework code just before Application.Run() enters the message loop. Application.Exit() cannot do anything until that message loop starts running.
The workaround is to move this code to the Main() method in Program.cs. Make it look similar to this:
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainForm main;
using (var dlg = new environmentSetupForm()) {
if (dlg.ShowDialog() != DialogResult.OK) return;
// Use dlg values
//...
main = new MainForm();
// Make main form show up at the same location
main.StartPosition = FormStartPosition.Manual;
main.Location = dlg.Location;
}
Application.Run(main);
}
Move the logic from the constructor to the main method.
Since it's related to the start up of the application and not the form it makes sense to have it as part of the start up logic.
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var newEnvrionmenSetupForm = new environmentSetupForm ();
if (newEnvrionmenSetupForm .ShowDialog() == DialogResult.OK) {
newEnvrionmenSetupForm .Close();
//some logic based on what the user selected on the set-up form
var mainform = new MainForm();
Application.Run(mainform);
}
}
Having that kind of logic, especially because it's modal and halts the execution, in a constructor is not a good idea. You want your constructors to be simple initialization of the object and to be repeatable. E.g. if you at some point needed to construct the main form again you wouldn't want the popup at that point in time I guess
Move your code below "InitializeComponent();" to MainForm_Load Event
at Mainform_Load Event instead to do an Application.Exit() just Close() the Form, this should close the app as well.

How Do I Add Background Thread To Silverlight Custom Control?

I'm building a custom control for Windows Phone 7+ that can do augmented reality image processing. The control works wonderfully in practice (when I run the app), but because I have the image processing running on a separate thread, it breaks when I try to open the page in Blend or the Visual Studio designer.
Here's an example of the thread I'm trying to run (basically taken from http://msdn.microsoft.com/en-us/library/hh202982(v=vs.92).aspx) :
public override void OnApplyTemplate()
{
// assigning template stuff, initializing my camera
_myManualResetEvent = new ManualResetEvent(true);
_myCameraProcessingThread = new System.Threading.Thread(ProcessingMethod);
_myCameraProcessingThread.Start();
}
void ProcessingMethod()
{
int[] myBuffer = new int[640 * 480];
while(_someCondition)
{
_myManualResetEvent.WaitOne();
_myCamera.GetPreviewBufferArgb32(myBuffer);
// do my processing stuff
_myManualResetEvent.Set();
}
}
This breaks the ever-loving heck out of Blend. Would love to know why.
It looks like you are doing a lot of run-time stuff in the OnApplyTemplate method.
This will get called when Blend or Visual Studio instantiates the design view of your control.
You should either check to see if you are in design mode using the DesignMode:
if (!DesignMode)
{
_myManualResetEvent = new ManualResetEvent(true);
_myCameraProcessingThread = new System.Threading.Thread(ProcessingMethod);
_myCameraProcessingThread.Start();
}
or move this code into a method/event handler that only gets called when the application actually runs.

Control.IsAccessible

I need to check if a c# WinForm Window (FORM Class) has been initialized and waiting for user events. But I could not find out how to manage that.
Therefore I had the idea to set the Control.IsAccessible Flag of the Form to true, within the OnLoad Event of the Windows Form.
My question is now, what is the Control.IsAccessible Flag origin intended for? Or is there an other solution to check if the Winform is initialized.
Thanks for your help
I do not know what IsAccessible is intended for but for the check you are doing you want Created
if(myForm.Created)
{
//Do stuff
}
I had a whole bunch of problems with it, here is one of my old question on SO that helped me out a lot with it.
Control.IsAccessible just means the control is visible to accessibility applications.
You can check myForm.Created to see if the window exists.
You can also register an event handler for the Application.Idle event, which occurs when the application has finished initializing and is ready to begin processing windows messages.
Here is a common usage:
public int Main(string[] args)
{
Application.Idle += WaitUntilInitialized;
}
private void WaitUntilInitialized(object source, EventArgs e)
{
// Avoid processing this method twice
Application.Idle -= WaitUntilInitialized;
// At this point, the UI is visible and waiting for user input.
// Begin work here.
}

Resources