I have a strange bug with WPF Interop and an Excel Addin. I'm using .Net 3.5 SP1.
I'm using Add-in Express to create a Custom Task Pane for Excel 2003. Within that taskpane I'm using ElementHost to host a WPF UserControl. The UserControl simply contains a Grid with a TextBox and ComboBox. My problem is that whilst everything displays properly, the ComboBox won't stay dropped-down unless I hold the mouse down over the down-arrow.
I don't believe this is necessarily related to Add-in Express because I've had a similar problem when I tried displaying a WPF window modelessly in Excel.
A second problem is that the ComboBox seems reluctant to give up focus. If I click it, the text area goes grey to indicate that it has focus, but I can't move focus anywhere else in the window. The only way to wrest focus away is to move the mousewheel.
Anybody else had a similar problem, and managed to fix it?
Add-in Express looked into this for me, and it turns out to have something to do with the Window style of the Task Pane that gets added to Excel. If you turn off the WS_CHILD flag in the Windows CreateParams then Combo Boxes and other popups work as expected.
They gave me this snippet of code to add to my ADXExcelTaskPane:
private const uint WS_CHILD = 0x40000000;
private const uint WS_CLIPCHILDREN = 0x02000000;
private const uint WS_CLIPSIBLINGS = 0x04000000;
private CreateParams _CreateParams = new CreateParams();
protected override CreateParams CreateParams
{
get
{
_CreateParams = base.CreateParams;
if (!DesignMode)
_CreateParams.Style = (int)(WS_CLIPCHILDREN | WS_CLIPSIBLINGS); //| WS_CHILD
return _CreateParams;
}
}
I had the same problem. I have a WPF user control hosted in a WinForm user control and the whole is an Excel AddIn. I work with Visual Studio 2010 and Excel 2007 and Excel 2010.
My problem was that when I clicked once in the Excel sheet, the AddIn never gains focus again.
I found a workaround.
In the constructor of my WinForm user control, I register on the event MouseEnter of my WPF user control.
In the MouseEnter event handler, I give the focus to myself (this.Focus())
public WpfContainerUserControl()
{
InitializeComponent();
GpecsBrowserTabUserControl gpecBrowser = elementHost1.Child as GpecsBrowserTabUserControl;
gpecBrowser.MouseEnter += new System.Windows.Input.MouseEventHandler(gpecBrowser_MouseEnter);
}
void gpecBrowser_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
this.Focus();
}
Related
I am using VS2012, C#, Winforms.
My application generates about 100 label controls at runtime. I want the user to right-click on a label control, bring up a context menu strip. I have this part working. But I am having trouble determining which control is being clicked on when I try to respond to a the context menu item click event. How can I pass on the control to the menu item click event?
I am using this code to determine the source control but it always causes a null exception:
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
Control sourceControl = new Control();
sourceControl = contextMenuStrip1.SourceControl;
MessageBox.Show(sourceControl.Text);
}
sourceControl always get a null from contextMenuStrip1.SourceControl;
The SourceControl property can be null, as this property is best used during the opening event. There are a couple of workarounds available. Check these two out on StackOverflow:
ContextMenuStrip.Owner Property null When Retrieving From Nested ToolStripMenuItem
Get the SourceControl of my ContextMenuStrip when I use the shortcut key
I have a wpf usercontrol that contains an activex control housed in a windowsformhost.
I'm using an MVVM pattern that says
ViewModel1 is mapped to a Pure WPF View and
ViewModel2 is mapped to wpf content and the above usercontrol
If ViewModel2 is "Hidden" and then becomes Visible then the Activex control inside it doesn't show (Specifically I'm talking about the VLC activex control).
I've tested in a non MVVM pattern with a button and the usercontrol. The usercontrol is hidden until you press the button and the same thing happens but if I create a method in the usercontrol to re attach the activex control to the windowsformhost then it reappears. If I call this method from a viewmodel then it still remains blank. Does anyone know how I can get this to show again?
EDIT - I've just discovered it's because I have transparency on in my wpf application. It seems it's not possable to do what I want with windowsformshost and transparency enabled.
As there are no obvious answers I'll share my experience. When transparency is turned on in the wpf window then the windows form host doesn't refresh when changing from Hidden to Visable. I have found no way to make this work unless it is hosted in a new window with "Allowstransparency=false".
How are you setting up your active x control? The following Typically works for me in WPF if you are just needing it to attach to a grid. No user control required.:
//Active X Control initializer
private Ax addAxObject<Ax>(Grid container)
where Ax : System.Windows.Forms.Control, new()
{
Ax ax = new Ax();
var hoster = new System.Windows.Forms.Integration.WindowsFormsHost();
hoster.Child = (System.Windows.Forms.Control)ax;
container.Children.Add(hoster);
return ax;
}
private MyActiveXControl myActiveXControl;
public Grid InitializeActiveX(Grid grid)
{
myActiveXControl = addAxObject<myActiveXControl>(grid);
return grid;
}
Then all you do is is add it to your grid in your main window like so:
public MainWindow()
{
InitializeComponent();
//initialize Active X control
gridMain = InitializeActiveX(gridMain);
}
It shows up just fine for me. (Obviously not in the designer since it is programatically created)
I'm working on an Outlook 2010 add-in that provides a dialog for user input. The code necessary for displaying the button in the ribbon is in its own Outlook 2010 Add-in project. That project has a reference to a WPF User Control Library that is responsible for the bulk of the work.
I use a static method in the WPF User Control Library project that is responsible for configuring Caliburn.Micro correctly and displaying the dialog. All of this works as expected except that I cannot figure out how to correctly position the dialog. I would like it to display centered over the Outlook window. I know I have access to the Microsoft.Office.Interop.Outlook.Application.ActiveWindow(), but I do not see how that helps me since I cannot translate it to a PlacementTarget as expected in the settings for Caliburn.Micro WindowManager's ShowDialog method.
WPF User Control Library
namespace WpfUserControlLibrary {
public static class Connector {
public static void ShowDialog() {
new AppBootstrapper();
var windowManager = IoC.Get<IWindowManager>();
windowManager.ShowDialog( new ShellViewModel() );
}
}
}
Outlook 2010 Add-in
WpfUserControlLibrary.Connector.ShowDialog();
I was able to track down a solution. Thanks to the help of this question, I was able to pass the appropriate parent window location and size parameters to the Connector. I checked the Caliburn.Micro source and noticed that I'm actually creating a ChildWindow--not a Popup. Therefore, I just needed to set the Top and Left values of the settings for the dialog.
WPF User Control Library
namespace WpfUserControlLibrary {
public static class Connector {
public static void ShowDialog(System.Windows.Rect parent) {
new AppBootstrapper();
var windowManager = IoC.Get<IWindowManager>();
// Popup is always 600 x 400
dynamic settings = new System.Dynamic.ExpandoObject();
settings.Left = (parent.Left + parent.Width / 2) - 300;
settings.Top = (parent.Top + parent.Height / 2) - 200;
windowManager.ShowDialog(new ShellViewModel(), settings: settings);
}
}
}
Outlook 2010 Add-in
var win = ThisAddIn.Application.ActiveWindow();
var parent = new System.Windows.Rect(win.Left, win.Top, win.Width, win.Height);
WpfUserControlLibrary.Connector.ShowDialog(parent);
I am making a Excel Addin in VS2010.
The following code work fines if I make a winforms usercontrol
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
var testControlView1 = new UserControl1();
var MyCustomPane = this.CustomTaskPanes.Add(testControlView, "Hello");
}
However I would like to make my UserControl1 be a WPF UserControl. Does anybody know how I would achieve similar functionality or an alternate approach?
As far as I can tell the CustomTaskPanes only allows Winforms Controls to be added to it.
Answer summary:
1. Add a .net winforms usercontrol
2. Add a SWF.Integration.ElementHost control to the user control.
3. Add a Wpf control to your project seperately (not to the user control).
3. Use the Hosted Content property (hostedcontentName) of the ElementHost control and set it to the wpf control.
I found this blog post that answered it great...
How can I go about hosting flash content inside a WPF form and still use transparency/alpha on my WPF window? Hosting a WinForms flash controls does not allow this.
Unless the control you use to display the Flash content is built in WPF, you will run in to these "airspace" issues. Every display technology from Win32 to WinForms used HWNDs "under the hood", but WPF uses DirectX. The Window Manager in Windows however, still only understands HWNDs, so WPF apps have one top-level HWND-based window, and everything under that is done in DirectX (actually things like context menus and tooltips also have top-level HWNDs as well). Adam Nathan has a very good description of WPF interop in this article.
Although I haven't done it, you can probably use the WebBrowser control found in WPF 3.5 sp1 to wrap your Flash content within WPF. I'm not sure how the transparency will be affected though.
Can you use Expression to convert the flash content to XAML? I believe that there are tools in there or off to the side that do this.
Just have been struggling with same problem of how to upload & Make WPF transparent with ability of displaying Flash, because if you enable on your MainWindow "Allow transparency" Flash will not show once the application will run.
1) I used WebBrowser Control to play Flash(.swf) files. They are on my PC, however it can play from internet or wherever you have hosted them. Don't forget to name your WebBrowser Control to get to it in C#.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
MyHelper.ExtendFrame(this, new Thickness(-1));
this.MyBrowser.Navigate(#"C:\Happy\Download\flash\PlayWithMEGame.swf");
}
2) Now for transparency. I have set in WPF 'false' to "Allow Transparency" and set "Window Style" to 'None'. After that I have used information from HERE and HERE and created a following code that produced desired effect of allowing transparency on MainWindow and running Flash at same time, here is my code:
public class MyHelper
{
public static bool ExtendFrame(Window window, Thickness margin)
{
IntPtr hwnd = new WindowInteropHelper(window).Handle;
window.Background = Brushes.Transparent;
HwndSource.FromHwnd(hwnd).CompositionTarget.BackgroundColor = Colors.Transparent;
MARGINS margins = new MARGINS(margin);
DwmExtendFrameIntoClientArea(hwnd, ref margins);
return true;
}
[DllImport("dwmapi.dll", PreserveSig = false)]
static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins);
}
struct MARGINS
{
public MARGINS(Thickness t)
{
Left = (int)t.Left;
Right = (int)t.Right;
Top = (int)t.Top;
Bottom = (int)t.Bottom;
}
public int Left;
public int Right;
public int Top;
public int Bottom;
}
And called it from Window_Loaded() + you need 'below' line for 'DllImport' to work.
using System.Runtime.InteropServices;
using System.Windows.Interop;