WinForms Application in MonoDevelop - winforms

I just installed the new MonoDevelop Windows beta, but when trying to create a C# windows application the only option was GTK#. Since Mono supports WinForms, why is this not an option in MonoDevelop. I would like to not have the GTK# dependency in my applications.

Althought Winforms is supported in mono since version 2.0, the WinForms designer is not usable yet in MonoDevelop, which could be the reason for the lack of a WinForms project in MonoDevelop
http://www.mono-project.com/WinForms_Designer
AFAIK, you should think of mono's support for winforms as a way to port existing winforms aplication to linux. If you want to make a cross-platform app from the ground up, you should use GTK#

Although there is no WinForms project template, you can write WinForms apps in MD on any of the platforms MD runs on.
Just create a new empty C# project and add a reference to System.Windows.Forms, then write your code, and build & run. Although there's no Winforms designer in MD, you'll have code completion for the Winforms types.

Sorry for raising the dead, but I tried to do this recently. While MonoDevelop doesn't provide the GUI designer, you can indeed write Winforms by hand, as mhutch pointed out. It goes like this:
Create a new, empty C# project.
Add a reference to System.Windows.Forms
Create a new, empty C# file:
The contents of the file:
using System;
using System.Windows.Forms;
namespace HelloForms
{
public class MainForm: Form
{
Label label1 = new Label();
public MainForm ()
{
this.SuspendLayout();
// Initialize your components here
this.label1.Text = "Hello, World!";
this.Controls.Add(label1);
this.ResumeLayout();
this.Name = "MainForm Name.";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "MainForm Title!";
}
}
public class Program
{
public static void Main(string[] args) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm ());
}
}
}
Expand your Form by adding components to MainForm's constructor.

Related

Applying a Theme to a WPF UserControl When Hosted in WinForms

I am hosting a WPF UserControl (several, actually) in a WinForms application.
Because of visual differences between the default themes for Win7 (Aero), Win8 (Aero2) and (I assume) Win10, I am trying to specify the lowest common denominator theme (Aero) and tailor my UI from there, thereby hopefully avoiding any OS theme issues.
The problem as I understand it is two fold: 1) there is no System.Windows.Application object since it is hosted in a WinForms project, so I have to create one and 2) I have to specify the theme I want to use.
Point one, thanks to this Dr. Wpf blog post, is simple enough to address with the EnsureWpfApplicationResources() method (strings are split where it helps readability):
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
EnsureWpfApplicationResources();
AssignWin7Theme();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new myWinForm());
}
static void EnsureWpfApplicationResources()
{
if (Wpf.Application.Current == null)
{
// create the wpf application object
new Wpf.Application(); // autoassigns to Wpf.Application.Current
}
}
static void AssignWin7Theme()
{
Uri uri = new Uri(
"PresentationFramework.Aero;V4.0.0.0;" +
"31bf3856ad364e35;component\\themes/aero.normalcolor.xaml",
UriKind.Relative);
Wpf.Application.Current.Resources.MergedDictionaries.Add(
Wpf.Application.LoadComponent(uri) as Wpf.ResourceDictionary);
}
}
The AssignWin7Theme(), which I derived from this blog post by Eli Arbel, is giving me trouble. The code runs fine (doesn't throw an exception) but the look of my controls isn't changing on Win8 to match what I see on Win7. I thought it was supposed to pick this setting up automagically; is there an attribute I need to set in the XAML on each control? What else am I doing wrong here?
You should be using UriKind.Relative and not absolute. It's weird that it doesn't throw.
Also note the version. If you're on .NET 4.x, it should be V4.0.0.0.

Caliburn Launch without App.xaml, but with bootstrapper

I have a WinForms project from which I want to open a WPF window from a WPF user control project.
But when I create an instance of the WPF window and call Show(), the bootstrapper isn't loaded. In an Windows Application, it's located in the App.xaml, but an user control project doesn't have this.
What can I do?
Thanks!
The only thing accomplished by having the bootstrapper in App.xaml's resources is instantiation of the bootstrapper and keeping a reference so it isn't garbage-collected. You could try making it instantiate like this:
public class SomeClass {
static Bootstrapper _bs = new Bootstrapper();
...
}
That will make sure it's initialized as part of static construction, which happens sometime before you can create an instance of SomeClass. You may have to experiment to see whether that should happen in your UserControl or in your Window.
I have a console application which presents a WPF gui that I made with Caliburn.Micro. I present the GUI like this:
_App = new App();
_App.Run();
Where App.xaml contains the bootstrapper and the main thread is STA like this:
[STAThread]
static int Main(string[] args)
{ ... }
I know your situation is different but maybe this will give you an idea.
Console application test:
Add MaterialDesignColors pakage
[System.STAThreadAttribute()]
static void Main(string[] args)
{
var _app = new App();
_app.InitializeComponent();
_app.Run();
_app.Shutdown();
}

Cannot show up WPF application when setting MainWindow manually and composing application (MEF)

I got my hands om MEF for a week now and I am trying to build up a WPF application that loads imported controls from MEF.
I created a WPF application project and removed the default window and application start up URI. Then I handled the application startup event to compose the application:
public partial class App : Application, IPartImportsSatisfiedNotification
{
{...}
private void App_Startup(object sender, StartupEventArgs e)
{
this.Compose();
}
public void Compose()
{
try
{
globalCatalog.Catalogs.Add(new DirectoryCatalog(extensionsDirectoryPath));
CompositionContainer container = new CompositionContainer(globalCatalog);
container.ComposeParts(this);
}
catch (Exception ex)
{
// Do something
}
}
{...}
}
Actually, when debugging and watching objects after imports are satisfied, everything has hierarchically composed fine like I wanted. But when I try to show up the MainWindow of the application an exception is thrown on MainWindow.Show() call:
"Specified element is already the logical child of another element. Disconnect it first."
Though my code in OnImportsSatisfied method seems fine as it is working when not using MEF mecanism:
public void OnImportsSatisfied()
{
Window mainWindow = new Window();
mainWindow.Content = this.importedControl;
this.MainWindow = mainWindow;
this.MainWindow.Show();
}
I insist on the fact that this works perfectly when not importing controls with MEF. What is surprising is that this code does not work too:
Window mainWindow = new Window();
//mainWindow.Content = this.importedControl;
this.MainWindow = mainWindow;
this.MainWindow.Show();
So I suspect that ComposeParts is doing a bit more than what it says as it is the only member acting on my actual application instance.
Hope someone can help me (Glenn?).
Thanks.
Edit:
I discovered that when I remove the IPartImportsSatisfiedNotification interface from my parts, no exception is thrown and the window shows up. But of course the window is empty as I need this OnImportsSatisfied method to set the DataContext of the window to its associated imported view model.
The sample applications of the WPF Application Framework (WAF) show how to use MEF within a WPF application.
I finally discovered that I was importing my WPF user controls by using the default ImportAttribute constructor, which in fact will make a shared instance of the class if the creation policy is not specified during export. And as many of my controls were implementing the same interface and I was binding them in my views, I was actually trying to add this shared user control instance to different visual elements, which is not permited by WPF (and so the exception).
I marked my imports using the RequiredCreationPolicy set to NonShared and everything got back in order! That was all about learning MEF...

WPF & WinForms Integration and Application Class

I am planning to create a WPF application with a main window which would launch various WinForms. Some of the WinForms use the System.Windows.Forms.Application class (DoEvents, Application.Path, etc). Do you think that there will be a problem in doing this?
Can I still use System.Windows.Forms.Application.DoEvents() from a WinForm that is launched from a WPF application?
The main problem will the ability to instantiate the Windows Forms window and set it's owner to that of the WPF window. The Winforms will want a IWin32Window which a WPF window isn't. To get around this, you need to make a custom class.
I found this code on Mark Rendle's blog (I've copied it here as I had to use the Google Cache to access the page).
LINK - WARNING: May not work
class Shim : IWin32Window
{
public Shim(System.Windows.Window owner)
{
// Create a WindowInteropHelper for the WPF Window
interopHelper = new WindowInteropHelper(owner);
}
private WindowInteropHelper interopHelper;
#region IWin32Window Members
public IntPtr Handle
{
get
{
// Return the surrogate handle
return interopHelper.Handle;
}
}
#endregion
}
and it's method of use:
namespace System.Windows.Forms
{
public static class WPFInteropExtensions
{
public static DialogResult ShowDialog(
this System.Windows.Forms.Form form,
System.Windows.Window owner)
{
Shim shim = new Shim(owner);
return form.ShowDialog(shim);
}
}
}
I haven't tested this code, but reading around the internet, it appears that you can host Winforms windows inside of a WPF app.
I just found this link on MSDN that has a very detailed description of how to interop a Win32 control/window in a WPF application.
Hope these help you out.
I've been doing this sometimes and didn't encounter any problem.
However i don't really recommend it, you should prefer WPF when you are in a WPF Application.
for exemple if you want application path use this :
System.Reflection.Assembly.GetExecutingAssembly().Location

Problems with Prism hosted in a WinForm ElementHost

I am having problems with hosting a WPF prism app in an ElementHost control and am desparate for help.
The PRISM app runs fine in silverlight and in a standalone WPF.
The main Shell seems to setup fine in the elementHost on a WinForm however other views only load with the “RegisterViewWithRegion” and not the “Add,Activate” procedure. I need “Add,Activate” for scoping. However I beleive the problem is that I am loading my shell twice … not on purpose. I cannot find a way to call the bootsrapper and set the elementHot without calling “Resolve” twice.
Here is the code for my WinForm and my bootstrapper. Again everything works when using "RegisterViewWithRegion".
Here is the Winform Constructor:
public Form1()
{
InitializeComponent();
if (System.Windows.Application.Current == null)
{
new MyApp();
}
Bootstrapper bootStrapper = new Bootstrapper();
bootStrapper.Run();
var shellElement = bootStrapper.Container.Resolve<ShellContainer>();
//Attach the WPF control to the host
elementHost.Child = shellElement;
}
Here is the bootstrapper:
public class Bootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
{
return Container.Resolve<ShellContainer>();
}
protected override void InitializeModules()
{
IModule moduleSurvey = Container.Resolve<SurveyModule>();
moduleSurvey.Initialize();
}
}
The Bootstrapper automatically sets Application.Current.MainForm to whatever you returned in the CreateShell method. Hopefully you are setting up an Application (I think that's what you are doing in the first If block). If so, you can just change this:
var shellElement = bootStrapper.Container.Resolve<ShellContainer>();
To this:
var shellElement = Application.Current.MainForm;
That ought to work, but there are definitely some weirdnesses with the ElementHost. We ended up with a lot of strange rendering bugs, especially in a Citrix environment. I don't know if this is a limitation of your setup, but I thought I would mention it.
Good luck!
I had the same GCE (Gross Conceptual Error). I was seeing the same behavior of my views being instantiated twice when using Add or Activate. I was deep into debugging the behaviors when it hit me.
The following is returning a new instance of the ShellContainer.
var shellElement = bootStrapper.Container.Resolve<ShellContainer>();
Either register your ShellContainer type in the container with a ContainerControlledLifetimeManager or put a prublic property on your bootstrapper to access the ShellContainer instance to set into your ElementHost.

Resources