My setup is kinda unorthodox - The CLR is hosted in a native Win32 application. Application loads and invokes a managed assembly (written in C++/CLI). Assembly creates a Windows Forms form with a WPF ElementHost. ElementHost gets populated with a stack panel that includes an image control and label control.
The managed assembly contains embedded image resources. The name of the resource file (in the project) is 'Images' and that of the particular resource in question is 'ISIconDB'.
How do I use the aforementioned resource as the image control's source?
Figured it out.
[DllImport("gdi32.dll")] int DeleteObject(IntPtr hObject);
//Drawing::Bitmap^ OrgResource;
Windows::Media::Imaging::BitmapSource^ Marshalled = nullptr;
try {
Marshalled = System::Windows::Interop::Imaging::CreateBitmapSourceFromHBitmap(OrgResource->GetHbitmap(),
IntPtr::Zero, Windows::Int32Rect::Empty, Windows::Media::Imaging::BitmapSizeOptions::FromEmptyOptions());
}
catch (...) {
Marshalled = nullptr;
}
finally {
DeleteObject(OrgResource->GetHbitmap());
}
Related
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.
One of our customers hosts our WinForms .NET grid control iGrid.NET (http://www.10tec.com/) inside a WPF ElementHost container together with other WPF controls. It may look strange as it's a WinForms control inside a WPF host inside a WinForms form, but they have no choice because of the other WPF stuff they use (it's the AvalonDock http://avalondock.codeplex.com/ docking container).
The problem is that our .NET datagrid control's infrastructure requires to know the parent WinForms form, but the following construction we use for that always return null in this situation:
Form myTopLevelOwnerForm = fCurrentGrid.TopLevelControl as Form;
I.e. the standard Control.TopLevelControl property intended for this purpose returns null - though most likely it should be so in the case of WPF host.
The question is: are there other ways to know the parent form from the current control's code? Say, using WinAPI handles or better other native .NET memebrs?
The following code works. At least, in our project :)
// API declaration
[System.Runtime.InteropServices.DllImport("user32.dll", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr GetParent(IntPtr hWnd);
// Main code snippet
Control myTopLevelControl = fOwner.TopLevelControl;
if (myTopLevelControl == null)
{
IntPtr handle = fOwner.Handle;
while (true)
{
IntPtr parentHandle = GetParent(handle);
if (parentHandle == IntPtr.Zero)
{
myTopLevelControl = Control.FromHandle(handle) as Form;
break;
}
handle = parentHandle;
}
}
I have an ActiveX control (written in Delphi) which I want to host in a WPF application. When I try to load it into the toolbox to add it to the XAML at design time, it is not shown in the list of available controls. Does anyone know what filters this list and why I can't see the control to add it?
Edit
This is where I get to - the host.Child = (ax); statement gets an error (Cannot implicitly convert type 'DemoFrameControl.DemoFrameCtrl' to 'System.Windows.Forms.Control'), hope this helps clarify my problem
private void WindowLoaded(object sender, RoutedEventArgs e)
{
// Create the interop host control.
System.Windows.Forms.Integration.WindowsFormsHost host =
new System.Windows.Forms.Integration.WindowsFormsHost();
// Create the ActiveX control.
DemoFrameControl.DemoFrameCtrl ax = new DemoFrameControl.DemoFrameCtrl();
// Assign the ActiveX control as the host control's child.
host.Child = (ax);
// Add the interop host control to the Grid
// control's collection of child controls.
this.grid1.Children.Add(host);
// Play a .wav file with the ActiveX control.
//axWmp.URL = #"C:\WINDOWS\Media\Windows XP Startup.wav";
}
Thanks
Check out Walkthrough: Hosting an ActiveX Control in WPF.
Update:
How is DemoFrameCtrl defined? Like the error says, it needs to be a subclass of System.Windows.Forms.Control to use WindowsFormsHost. An ActiveX control wrapper will inherit from AxHost which inherits from Control. I think Visual Studio will generate the wrapper if you add a reference to the ActiveX library. If not, you can try using Aximp.exe (Windows Forms ActiveX Control Importer).
Wondering how to accomplish setting the Style xaml with the code in F#. The code is simple enough:
this.DefaultStyleKey <- typeof<MyControl>
In a C# project the build options allow you to mark the XAML as a resource custom build command of: MSBuild:Compile
I don't see it in the properties panel, so I tried to add it by hand to the project file myself...
Any ideas? The application loads - the custom control has no output (but the code executes).
Thanks
UPDATE:
I checked the manifests and the resource was included as expected between my project and the project I am porting... Looking for a next step.
UPDATE 2:
Well it may be included in the manifest OK - but it is not being "compiled" as the C# version of the project throws an error in the build process when I malform the XML while the F# version allows the malformed XML to be brought into the application.
UPDATE 3:
Loading the XAML is fine now (i guess) however I am having some issues with the properties of the control:
static member ItemsProperty : DependencyProperty =
DependencyProperty.Register(
"Items",
typeof<MyMenuItemCollection>,
typeof<MyMenu>,
null);
member this.Items
with get () : MyMenuItemCollection = this.GetValue(MyMenu.ItemsProperty) :?> MyMenuItemCollection
and set (value: MyMenuItemCollection) = this.SetValue(MyMenu.ItemsProperty, value);
The problem occurs on access:
for menuItem in this.Items do
let contentElement: FrameworkElement = menuItem.Content
where I get a null pointer exception on this.Items; however I have it initialized in the constructor:
do
this.Items <- new CoolMenuItemCollection()
The C# style of compilation of XAML files is not supported by the F# tools for Visual Studio, so there is no way to get the same behavior as in C#. I think you have two options:
Create a C# project with XAML files and reference F# library which implements the core functionality (or reference C# library from F# and load user interface from the C# library in your F# application)
Use XamlReader object (see MSDN) and load the XAML file (embedded in resources in the simple way) programmatically. You won't get any of the C#-compiler generated features (e.g. named properties for all objects with x:Name), but otherwise, it should work in the usual way.
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