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.
Related
I need to convert existing plugin for CAD systems from WinForm based UI to WPF. The plugin is a basic dll library with Main method used by main application as an entry point to call this plugin. Also it includes a couple of mandatory methods to load/unload the library with plugin.
Long story short. How it looks today (WinForm based):
public class MyPluginClass : System.Windows.Forms.Form
{
private static MyPluginClass thePlugin;
public MyPluginClass()
{
InitializeComponent();
// Make the displayed window a child of the main application window
Reparent(this);
}
private void InitializeComponent()
{
//UI initialization logic
}
// The main entry point. Called when this library is loaded
public static void Main()
{
thePlugin = new MyPluginClass();
thePlugin.Show();
}
}
Once I load this dll, the parent app executes the Main methods and I get the plugin form loaded and displayed.
Now I'm trying to use WPF instead of WinForm (and I have zero experience in WPF, so apologize for silly questions if any).
First thing I tried is to apply the same logic I used with WinForms - just extend Window class:
public class MyPluginClass : Window
{
private static MyPluginClass thePlugin;
.....
public static void Main()
{
thePlugin = new MyPluginClass();
thePlugin.Show();
}
}
...and I didn't find the way to load required XAML file with my window layout. While trying to find solution, I read several posts saying that maybe it's not a good approach to create derived class based on Window. Though, examples I found so far, describe the standalone application (.exe), while in my case I'm trying to invoke WPF UI while being inside the dll file called by parent application.
Is there a way to specify the required XAML file in this case (when I derive my class from Window class) or I'm going completely wrong way?
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...
I'm working on a project that is based on an old project someone started and didn't finish. I was trying to use as much of their code as I could, so in doing so I ran into some tweaking issues.
Namely, when I put some of the old xaml in the new project there were some errors that were thrown regarding the "x:static" property and "Dynamic property."
here are the error messages themselves:
Error 1: The type 'DynamicResource' was not
found. Verify that you are not missing
an assembly reference and that all
referenced assemblies have been built.
Error 2: The type 'x:Static' was not found.
Verify that you are not missing an
assembly reference and that all
referenced assemblies have been built.
Some notable points that I think is causing the errors: the old project was programmed in VS2008, WPF, v3.5 .Net framework; whereas I am programming in VS2010, Silverlight 4, .Net framework v4.0.
I realize there are differences from WPF to Silverlight as far as xaml goes and there are plenty of differences from the different .Net framework versions and editions of Visual Studio. But I just can't seem to find a fix for this anywhere so I didn't know if there was just a library I was missing or just something I'm simply overlooking or what.
I can recreate this if need be, but like I said, I'd rather use as much of the old code as I can as long as the tweaking doesn't cause more trouble than what it's worth.
Unfortunately, you can't directly use the DynamicResource and Static keywords in a Silverlight's subset of XAML, but you can mimic their behavior. Here is the article on the topic:
{x:Type} and {x:Static} in Silverlight
In general, there is no easy way to migrate a project from WPF to Silverlight. They have very much in common, but strictly speaking are a different technologies.
Another way to achieve binding to static properties - to bind in code. Below is an example.
Main application class:
public partial class App : Application
{
public static MyViewModel MyViewModel { get; private set; }
// ...
}
Main window markup:
<TextBlock Loaded="MyTextBlockLoaded" />
Main window back-code:
public partial class MainPage : PhoneApplicationPage
{
// ...
private void MyTextBlockLoaded(object sender, RoutedEventArgs e)
{
TextBlock textBlock = ((TextBlock)sender);
if (textBlock.Tag == null)
{
textBlock.Tag = true;
Binding bind = new Binding("MyInfo");
bind.Source = App.MyViewModel;
bind.Mode = BindingMode.OneWay;
textBlock.SetBinding(TextBlock.TextProperty, bind);
}
}
}
Maybe the TextBlock.Tag approach of checking, was Binding already set or not, isn't the most elegant one, but it works.
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
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.