Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / WinFormsIntegration / System / Windows / Integration / WindowsFormsHost.cs / 2 / WindowsFormsHost.cs
using MS.Win32; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Windows.Interop; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Automation.Provider; using System.Windows.Automation.Peers; using SD = System.Drawing; using SW = System.Windows; using SWC = System.Windows.Controls; using SWF = System.Windows.Forms; using SWM = System.Windows.Media; using SWI = System.Windows.Input; using System.Collections.Generic; using System.Windows.Input; namespace System.Windows.Forms.Integration { ////// An element that allows you to host a Windows Forms control on a /// Windows Presentation Foundation page. /// [System.ComponentModel.DesignerCategory("code")] [ContentProperty("Child")] [DefaultEvent("ChildChanged")] public class WindowsFormsHost : HwndHost, IKeyboardInputSink { private SWM.Brush _cachedBackbrush; private HandleRef _hwndParent; private WinFormsAdapter _hostContainerInternal; #region Constructors [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] static WindowsFormsHost() { //Keyboard tabbing support FocusableProperty.OverrideMetadata(typeof(WindowsFormsHost), new FrameworkPropertyMetadata(true)); SWC.Control.IsTabStopProperty.OverrideMetadata(typeof(WindowsFormsHost), new FrameworkPropertyMetadata(true)); } ////// Initializes a new instance of the WindowsFormsHost class. /// [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] public WindowsFormsHost() : base() { this._hostContainerInternal = new WinFormsAdapter(this); _propertyMap = new WindowsFormsHostPropertyMap(this); } #endregion #region Focus ////// Notifies Avalon that focus has moved within this WindowsFormsHost. /// void NotifyFocusWithinHost() { DependencyObject focusScope = GetFocusScopeForElement(this); if (null != focusScope) { System.Windows.Input.FocusManager.SetFocusedElement(focusScope, this); } } ////// Handles Child.GotFocus event. /// private void OnChildGotFocus(object sender, EventArgs e) { SyncChildImeEnabledContext(); } ////// Synchronizes the Winforms Child control ime context enble status. /// private void SyncChildImeEnabledContext() { if (SWF.ImeModeConversion.IsCurrentConversionTableSupported && this.Child != null && this.Child.IsHandleCreated) { Debug.WriteLineIf(HostUtils.ImeMode.Level >= TraceLevel.Info, "Inside SyncChildImeEnabledContext(), this = " + this); Debug.Indent(); // Note: Do not attempt to set Child.ImeMode directly, it will be updated properly from the context. if (InputMethod.GetIsInputMethodEnabled(this)) { if (this.Child.ImeMode == ImeMode.Disable) { SWF.ImeContext.Enable(this.Child.Handle); } } else { if (this.Child.ImeMode != ImeMode.Disable) { SWF.ImeContext.Disable(this.Child.Handle); } } Debug.Unindent(); } } ////// When implemented in a derived class, accesses the window process of the hosted child window. /// /// /// /// /// /// ///protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case NativeMethods.WM_CHILDACTIVATE: _hostContainerInternal.HandleChildActivate(); break; case NativeMethods.WM_SETFOCUS: case NativeMethods.WM_MOUSEACTIVATE: NotifyFocusWithinHost(); break; case NativeMethods.WM_GETOBJECT: handled = true; return OnWmGetObject(wParam, lParam); } return base.WndProc(hwnd, msg, wParam, lParam, ref handled); } /// /// Critical - Calls critical HwndHost.Handle. /// TreatAsSafe - This demands full trust, so it's safe /// [SecurityCritical, SecurityTreatAsSafe] [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] private IntPtr OnWmGetObject(IntPtr wparam, IntPtr lparam) { IntPtr result = IntPtr.Zero; WindowsFormsHostAutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(this) as WindowsFormsHostAutomationPeer; if (peer != null) { // get the element proxy IRawElementProviderSimple el = peer.GetProvider(); if (el != null) { //This requires FullTrust but we already have it. result = AutomationInteropProvider.ReturnRawElementProvider(Handle, wparam, lparam, el); } } return result; } private static DependencyObject GetFocusScopeForElement(DependencyObject element) { //Walk up the visual tree until we find an element that is a focus scope (or we run out of elements). //This will usually be the root Avalon Window. while (null != element && !FocusManager.GetIsFocusScope(element)) { element = VisualTreeHelper.GetParent(element); } return element; } #endregion #region Layout private Vector _currentScale = new Vector(1.0, 1.0); ////// Scales the hosted Windows Forms control, and tracks the scale factor. /// /// ///The new scale factor protected virtual Vector ScaleChild(Vector newScale) { if (newScale != _currentScale) { if (Child != null) { Child.Scale(new System.Drawing.SizeF((float)(newScale.X / _currentScale.X), (float)(newScale.Y / _currentScale.Y))); } } return newScale; } private void ScaleChild() { bool skewed; Vector newScale = HostUtils.GetScale(this, out skewed); if (skewed) { OnLayoutError(); } _currentScale = ScaleChild(newScale); } private event EventHandler_layoutError; /// /// Occurs when a layout error, such as a skew or rotation that WindowsFormsHost does not support, /// is encountered. /// public event EventHandlerLayoutError { add { _layoutError += value; } remove { _layoutError -= value; } } private void OnLayoutError() { InvalidOperationException exception = new InvalidOperationException(SR.Get(SRID.Host_CannotRotateWindowsFormsHost)); LayoutExceptionEventArgs args = new LayoutExceptionEventArgs(exception); if (_layoutError != null) { _layoutError(this, args); } if (args.ThrowException) { throw exception; } } /// /// Overrides the base class implementation of MeasureOverride to measure /// the size of a WindowsFormsHost object and return the proper size to the layout engine. /// protected override SW.Size MeasureOverride(SW.Size constraint) { if (this.Visibility == Visibility.Collapsed || Child == null) { //Child takes up no space return new Size(0, 0); } ScaleChild(); SD.Size constraintSize = Convert.ConstraintToSystemDrawingSize(constraint, _currentScale); SD.Size preferredSize = Child.GetPreferredSize(constraintSize); System.Windows.Size returnSize = Convert.ToSystemWindowsSize(preferredSize, _currentScale); // Apply constraints to the preferred size returnSize.Width = Math.Min(returnSize.Width, constraint.Width); returnSize.Height = Math.Min(returnSize.Height, constraint.Height); return returnSize; } // Note: the WPF layout engine may call ArrangeOverride multiple times in succession private Size _priorConstraint; ////// When implemented in a derived class, positions child elements and determines a /// size for a FrameworkElement-derived class. /// /// ///protected override Size ArrangeOverride(Size finalSize) { if (this.Visibility == Visibility.Collapsed || Child == null) { //Child takes up no space return new Size(0, 0); } Vector originalScale = _currentScale; ScaleChild(); bool scaled = (_currentScale != originalScale); SD.Size targetSize = Convert.ConstraintToSystemDrawingSize(finalSize, _currentScale); if ((Child.Size != targetSize) && ((finalSize != _priorConstraint) || scaled)) { _priorConstraint = finalSize; Child.Size = targetSize; } Size returnSize = Convert.ToSystemWindowsSize(Child.Size, _currentScale); returnSize.Width = Math.Min(returnSize.Width, finalSize.Width); returnSize.Height = Math.Min(returnSize.Height, finalSize.Height); if (HostContainerInternal.BackgroundImage != null) { _propertyMap.OnPropertyChanged(this, "Background", this.Background); } return returnSize; } #endregion Layout #region Containership /// /// Occurs when the Child property is set. /// public event EventHandlerChildChanged; /// /// Gets or sets the child control hosted by the WindowsFormsHost element. /// public Control Child { get { return _hostContainerInternal.Child; } set { #pragma warning disable 1634, 1691 #pragma warning disable 56526 Control oldChild = Child; SWF.Form form = value as SWF.Form; if (form != null) { if (form.TopLevel) { //WinOS #1030878 - Can't host top-level forms throw new ArgumentException(SR.Get(SRID.Host_ChildCantBeTopLevelForm)); } else { form.ControlBox = false; } } _hostContainerInternal.Child = value; if (Child != null) { _propertyMap.ApplyAll(); Child.Margin = SWF.Padding.Empty; Child.Dock = DockStyle.None; Child.AutoSize = false; Child.Location = SD.Point.Empty; // clear the cached size _priorConstraint = new Size(double.NaN, double.NaN); } OnChildChanged(oldChild); #pragma warning restore 1634, 1691, 56526 } } private void OnChildChanged(Control oldChild) { if (oldChild != null) { oldChild.GotFocus -= new EventHandler(this.OnChildGotFocus); } if (this.Child != null) { this.Child.GotFocus += new EventHandler(this.OnChildGotFocus); } if (ChildChanged != null) { ChildChanged(this, new ChildChangedEventArgs(oldChild)); } } internal WinFormsAdapter HostContainerInternal { get { return _hostContainerInternal; } } #endregion Containership #region Rendering static Brush defaultBrush = SystemColors.WindowBrush; ////// Manually searches up the parent tree to find the first FrameworkElement that /// has a non-null background, and returns that Brush. /// If no parent is found with a brush, then this returns WindowBrush. /// /// ///private static SWM.Brush FindBackgroundParent(SW.DependencyObject dependencyObject) { if (dependencyObject == null) { return defaultBrush; } Brush backgroundBrush = null; backgroundBrush = (Brush)dependencyObject.GetValue(SWC.Control.BackgroundProperty); if (backgroundBrush == null) { SW.FrameworkElement frameworkElement = dependencyObject as SW.FrameworkElement; if (frameworkElement != null) { DependencyObject parentElement = VisualTreeHelper.GetParent(frameworkElement); backgroundBrush = FindBackgroundParent(parentElement); } } return backgroundBrush ?? defaultBrush; } /// /// This is called by the OnPaintBackground method of the host container. /// internal void PaintBackground() { SWM.Brush parentBrush = FindBackgroundParent(this); if (parentBrush != null) { if (_cachedBackbrush != parentBrush) { _cachedBackbrush = parentBrush; _propertyMap.OnPropertyChanged(this, "Background", parentBrush); } } } #endregion Rendering #region Keyboarding ////// Enables Windows Forms forms to function correctly when opened modelessly from /// Windows Presentation Foundation. /// [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] public static void EnableWindowsFormsInterop() { ApplicationInterop.EnableWindowsFormsInterop(); } ////// Forwards focus from Windows Presentation Foundation to the hosted Windows Forms control. /// public virtual bool TabInto(SWI.TraversalRequest request) { return HostContainerInternal.FocusNext(request); } #endregion Keyboarding #region Activation private Control _focusedChild; private void RestoreFocusedChild() { _hostContainerInternal.Focus(); _hostContainerInternal.ActiveControl = _focusedChild; _focusedChild = null; } private void NotifyActivateApp(ref Message m) { if (m.WParam != IntPtr.Zero) { if (null != _focusedChild) { _hostContainerInternal.BeginInvoke(new MethodInvoker(RestoreFocusedChild)); } } else { IntPtr currentFocus = UnsafeNativeMethods.GetFocus(); if (currentFocus == Handle || UnsafeNativeMethods.IsChild(Handle, currentFocus)) { _focusedChild = _hostContainerInternal.ActiveControl; } } } private ActivateWindowListener _activateWindowListener; private class ActivateWindowListener : NativeWindow, IDisposable { WindowsFormsHost _host; public ActivateWindowListener(WindowsFormsHost host) { _host = host; } protected override void WndProc(ref Message m) { if (NativeMethods.WM_ACTIVATEAPP == m.Msg) { // This message is sent to every top child window in the app, if the focused top child // window contains a winforms host, we need to notify it so it activates or caches the // active control. IntPtr currentFocus = UnsafeNativeMethods.GetFocus(); if (UnsafeNativeMethods.IsChild(_host.Handle, currentFocus)) { _host.NotifyActivateApp(ref m); } } base.WndProc(ref m); } public void Dispose() { this.ReleaseHandle(); } } #endregion #region Window Handling & Misc ////// Overrides the base class implementation of BuildWindowCore to build the hosted /// Windows Forms control. /// protected override HandleRef BuildWindowCore(HandleRef hwndParent) { this.Loaded += new RoutedEventHandler(ApplyAllProperties); Debug.WriteLineIf(_traceHandle.TraceVerbose, String.Format(CultureInfo.CurrentCulture, "WindowsFormsHost({0}): BuildWindowCore (parent=0x{1:x8})", this.Name, hwndParent.Handle.ToInt32())); if (_activateWindowListener != null) { _activateWindowListener.Dispose(); } _activateWindowListener = new ActivateWindowListener(this); _activateWindowListener.AssignHandle(hwndParent.Handle); _hwndParent = hwndParent; //For Keyboard interop ApplicationInterop.ThreadWindowsFormsHostList.Add(this); //Keep track of this control, so it can get forwarded windows messages EnableWindowsFormsInterop(); //Start the forwarding of windows messages to all WFH controls on active windows UnsafeNativeMethods.SetParent(/* child = */ HostContainerInternal.Handle, /* parent = */ _hwndParent.Handle); return new HandleRef(HostContainerInternal, HostContainerInternal.Handle); } ////// Overrides the base class implementation of DestroyWindowCore to delete the /// window containing this object. /// protected override void DestroyWindowCore(HandleRef hwnd) { //For keyboard interop (remove this control from the list) //This line shouldn't be necessary since the list cleans itself, but it's good to be tidy. ApplicationInterop.ThreadWindowsFormsHostList.Remove(this); if (HostContainerInternal != null) { HostContainerInternal.Dispose(); } } void ApplyAllProperties(object sender, RoutedEventArgs e) { _propertyMap.ApplyAll(); } ////// Releases all resources used by the WindowsFormsHost element. /// protected override void Dispose(bool disposing) { try { base.Dispose(disposing); } finally { if (disposing) { if (_hostContainerInternal != null) { try { if (_activateWindowListener != null) { _activateWindowListener.Dispose(); } _hostContainerInternal.Dispose(); this.Loaded -= new RoutedEventHandler(ApplyAllProperties); } finally { if (Child != null) { Child.Dispose(); } } } } } } #endregion Window Handling & Misc #region Automation ////// Creates AutomationPeer ( protected override AutomationPeer OnCreateAutomationPeer() { return new WindowsFormsHostAutomationPeer(this); } #endregion Automation #region Property Mapping //Some of the properties that we would like to map don't exist on HwndHost, //so we add them here: TabIndex, Font (4x), Foreground, Background, Padding. ///) /// /// Identifies the Padding dependency property. /// public static readonly DependencyProperty PaddingProperty = SWC.Control.PaddingProperty.AddOwner(typeof(WindowsFormsHost)); ////// Specifies the size of the desired padding within the hosted Windows Forms control. /// [Bindable(true), Category("Behavior")] public Thickness Padding { get { return (Thickness)GetValue(PaddingProperty); } set { SetValue(PaddingProperty, value); } } ////// Identifies the TabIndex dependency property. /// public static readonly DependencyProperty TabIndexProperty = SWC.Control.TabIndexProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's tab index. /// [Bindable(true), Category("Behavior")] public int TabIndex { get { return (int)GetValue(TabIndexProperty); } set { SetValue(TabIndexProperty, value); } } ////// Identifies the FontFamily dependency property. /// public static readonly DependencyProperty FontFamilyProperty = SWC.Control.FontFamilyProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's font family as an ambient property. /// public SWM.FontFamily FontFamily { get { return (SWM.FontFamily)GetValue(FontFamilyProperty); } set { SetValue(FontFamilyProperty, value); } } ////// Identifies the FontSize dependency property. /// public static readonly DependencyProperty FontSizeProperty = SWC.Control.FontSizeProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's font size as an ambient property. /// public double FontSize { get { return (double)GetValue(FontSizeProperty); } set { SetValue(FontSizeProperty, value); } } ////// Identifies the FontStyle dependency property. /// public static readonly DependencyProperty FontStyleProperty = SWC.Control.FontStyleProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's font style as an ambient proeprty. /// public SW.FontStyle FontStyle { get { return (FontStyle)GetValue(FontStyleProperty); } set { SetValue(FontStyleProperty, value); } } ////// Identifies the FontWeight dependency property. /// public static readonly DependencyProperty FontWeightProperty = SWC.Control.FontWeightProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's font weight as an ambient property. /// public SW.FontWeight FontWeight { get { return (FontWeight)GetValue(FontWeightProperty); } set { SetValue(FontWeightProperty, value); } } ////// Identifies the Foreground dependency property. /// public static readonly DependencyProperty ForegroundProperty = SWC.Control.ForegroundProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's foreground color as an ambient property. /// public Brush Foreground { get { return (Brush)GetValue(ForegroundProperty); } set { SetValue(ForegroundProperty, value); } } ////// Identifies the Background dependency property. /// public static readonly DependencyProperty BackgroundProperty = SWC.Control.BackgroundProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's background as an ambient property. /// public Brush Background { get { return (Brush)GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } ////// Forces the translation of a mapped property. /// protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { base.OnPropertyChanged(e); // Invoke method currently set to handle this event if (_propertyMap != null) { _propertyMap.OnPropertyChanged(this, e.Property.Name, e.NewValue); } } ////// Gets the property map that determines how setting properties on the /// WindowsFormsHost element affects the hosted Windows Forms control. /// public PropertyMap PropertyMap { get { return _propertyMap; } } private PropertyMap _propertyMap; #endregion Property Mapping #region DEBUG #if DEBUG internal static readonly TraceSwitch _traceHandle = new TraceSwitch("WindowsFormsHostHandle", "Tracks WindowsFormsHost handle information."); internal static readonly TraceSwitch _traceLayout = new TraceSwitch("WindowsFormsHostLayout", "Tracks WindowsFormsHost layout information."); #else internal static readonly TraceSwitch _traceHandle = null; internal static readonly TraceSwitch _traceLayout = null; #endif #endregion DEBUG } #region WinFormsAdapter [System.ComponentModel.DesignerCategory("code")] internal class WinFormsAdapter : SWF.ContainerControl { private WindowsFormsHost _host; private FocusTargetControl _focusTarget; private IntPtr _prevFocusHwnd = IntPtr.Zero; private Control _child; public Control Child { get { return _child; } set { if (null != Child) { Controls.Remove(Child); } if (null != value) { Controls.Add(value); } _child = value; } } public void HandleChildActivate() { IntPtr focusHwnd = UnsafeNativeMethods.GetFocus(); try { if (IntPtr.Zero == _prevFocusHwnd ) { return; } //If focus is changing from a child of the WinFormsAdapter to something outside //we will activate the a temporary control to cause leave and validation events if ( _focusTarget.Handle != _prevFocusHwnd && UnsafeNativeMethods.IsChild(Handle, _prevFocusHwnd) && !UnsafeNativeMethods.IsChild(Handle, focusHwnd)) { this.ActiveControl = _focusTarget; } } finally { _prevFocusHwnd = focusHwnd; } } //Note: there's no notification when the ambient cursor changes, so we //can't do a normal mapping for this and have it work. We work around //this by overriding WinFormsAdapter.Cursor and walking the visual tree //to find the cursor IF the Cursor translator has not been changed. //host.PropertyMap["Cursor"] += delegate {MessageBox.Show("?");}; //will cause the mapping to no longer happen. public override Cursor Cursor { get { if (_host == null) { return base.Cursor; } if (!_host.PropertyMap.PropertyMappedToEmptyTranslator("Cursor")) { return base.Cursor; } bool forceCursorMapped = _host.PropertyMap.PropertyMappedToEmptyTranslator("ForceCursor"); FrameworkElement cursorSource = HostUtils.GetCursorSource(_host, forceCursorMapped); if (cursorSource == null) { return base.Cursor; } return Convert.ToSystemWindowsFormsCursor(cursorSource.Cursor); } set { base.Cursor = value; } } private class FocusTargetControl : Control { public FocusTargetControl() { this.Size = SD.Size.Empty; //Hide it as far away as possible this.Location = new SD.Point(short.MinValue, short.MinValue); this.TabStop = false; #if DEBUG this.Name = "Focus target"; #endif //DEBUG } } public WinFormsAdapter(WindowsFormsHost host) { _host = host; _focusTarget = new FocusTargetControl(); Controls.Add(_focusTarget); this.HandleCreated += WinFormsAdapter_HandleCreated; //Keyboard interop: We listen to this event to refresh the visual cues (workaround) SWI.InputManager.Current.PostProcessInput += InputManager_PostProcessInput; } protected override void Dispose(bool disposing) { try { if (disposing) { SWI.InputManager.Current.PostProcessInput -= InputManager_PostProcessInput; } } finally { base.Dispose(disposing); } } #region Keyboard Interop ////// Forwards focus from Avalon and into the WinForms "sink". /// The request is often First and Last, which isn't really mapped the /// same way, but it seems to work, probably because we only host one control. /// /// ///internal bool FocusNext(SWI.TraversalRequest request) { UpdateUIState(NativeMethods.UIS_INITIALIZE); bool forward = true; bool tabStopOnly = true; switch (request.FocusNavigationDirection) { case System.Windows.Input.FocusNavigationDirection.Down: case System.Windows.Input.FocusNavigationDirection.Right: forward = true; tabStopOnly = false; break; case System.Windows.Input.FocusNavigationDirection.Next: case System.Windows.Input.FocusNavigationDirection.First: forward = true; tabStopOnly = true; break; case System.Windows.Input.FocusNavigationDirection.Up: case System.Windows.Input.FocusNavigationDirection.Left: forward = false; tabStopOnly = false; break; case System.Windows.Input.FocusNavigationDirection.Previous: case System.Windows.Input.FocusNavigationDirection.Last: forward = false; tabStopOnly = true; break; default: Debug.Assert(false, "Unknown FocusNavigationDirection"); break; } _focusTarget.Enabled = false; try { if (this.SelectNextControl(null, forward, tabStopOnly, true, false)) { // find the inner most active control ContainerControl ret = this; while (ret.ActiveControl is ContainerControl) { ret = (ContainerControl)ret.ActiveControl; } if (!ret.ContainsFocus) { ret.Focus(); } return true; } return false; } finally { _focusTarget.Enabled = true; } } // CSS added for keyboard interop protected override bool ProcessDialogKey(Keys keyData) { _focusTarget.Enabled = false; try { if ((keyData & (Keys.Alt | Keys.Control)) == Keys.None) { Keys keyCode = (Keys)keyData & Keys.KeyCode; if (keyCode == Keys.Tab || keyCode == Keys.Left || keyCode == Keys.Right || keyCode == Keys.Up || keyCode == Keys.Down) { if (this.Focused || this.ContainsFocus) { // CSS: In WF apps, by default, arrow keys always wrap within a container // However, we don't want them to wrap in the Adapter, which always has only // one immediate child if ((keyCode == Keys.Left || keyCode == Keys.Right || keyCode == Keys.Down || keyCode == Keys.Up) && (this.ActiveControl != null && this.ActiveControl.Parent == this)) { SWF.Control c = this.ActiveControl.Parent; return c.SelectNextControl(this.ActiveControl, keyCode == Keys.Right || keyCode == Keys.Down, false, false, false); } else return base.ProcessDialogKey(keyData); } } } return false; } finally { _focusTarget.Enabled = true; } } // CSS added for keyboard interop internal bool PreProcessMessage(ref Message msg, bool hasFocus) { // Don't steal WM_CHAR messages from Avalon, Catch them later in InputManager_PostProcessInput if (!hasFocus && msg.Msg == NativeMethods.WM_CHAR) { return false; } return PreProcessMessage(ref msg); } /// /// For keyboard interop, when this handle is recreated, the current state of the /// visual shortcut key cues (AKA underlining the hotkey) is lost, so it needs /// to be refreshed. /// /// /// private void WinFormsAdapter_HandleCreated(object sender, EventArgs e) { //CSS - Workaround OS bug. The initial UI state was being set erratically // (sometimes cues were shown, sometimes not. This forces it to a known state. UpdateUIState(NativeMethods.UIS_SET); } ////// For keyboard interop /// Ensure the visual shortcut key cues on controls are in the same visual /// state that we expect. This is a workaround for odd Windows API. /// internal void UpdateUIState(int uiAction) { Debug.Assert(uiAction == NativeMethods.UIS_INITIALIZE || uiAction == NativeMethods.UIS_SET, "Unexpected uiAction"); int toSet = NativeMethods.UISF_HIDEACCEL | NativeMethods.UISF_HIDEFOCUS; if (UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.WM_UPDATEUISTATE, (IntPtr)(uiAction | (toSet << 16)), IntPtr.Zero) != IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } // CSS Added for keyboard interop // Catch WM_CHAR messages which weren't handled by Avalon // (including mnemonics which were typed without the "Alt" key) private void InputManager_PostProcessInput(object sender, SWI.ProcessInputEventArgs e) { // Should return immediately if this WFH is not in the active Window PresentationSource presentationSource = PresentationSource.FromVisual(this._host); if (presentationSource == null) { return; } Window presentationSourceWindow = presentationSource.RootVisual as Window; //CSS This active window check may not work for multiple levels of nesting... // RootVisual isn't top level window. Should we traverse upward through nested levels? if (presentationSourceWindow == null || !presentationSourceWindow.IsActive) return; // Now check for unhandled WM_CHAR messages and process them as mnemonics if (!e.StagingItem.Input.Handled && e.StagingItem.Input.RoutedEvent == SWI.TextCompositionManager.TextInputEvent) { SWI.TextCompositionEventArgs te = (SWI.TextCompositionEventArgs)e.StagingItem.Input; string text = te.Text; if (string.IsNullOrEmpty(text)) { text = te.SystemText; } if (!string.IsNullOrEmpty(text)) { e.StagingItem.Input.Handled = this.ProcessDialogChar(text[0]); } } } #endregion Keyboard Interop ////// Overridden to invalidate host layout when our layout changes. /// protected override void OnLayout(SWF.LayoutEventArgs e) { base.OnLayout(e); _host.InvalidateMeasure(); #if DEBUG string compName = ""; if (e.AffectedControl != null) { compName = e.AffectedControl.Name; } else if (e.AffectedComponent != null) { compName = e.AffectedComponent.ToString(); } Debug.WriteLineIf(WindowsFormsHost._traceLayout.TraceInfo, String.Format(CultureInfo.CurrentCulture, "WindowsFormsHost({0}): Layout invalidated (control='{1}',property='{2}')", _host.Name, compName, e.AffectedProperty)); #endif } ////// Forward the Host Containers paint events to the WFH, so that it can either /// use a bitmap to do "fake" transparency or set the BackColor correctly. /// protected override void OnPaintBackground(SWF.PaintEventArgs e) { _host.PaintBackground(); base.OnPaintBackground(e); } //Changing RightToLeft on the WinFormsAdapter recreates the handle. Since our //handle is being cached, this causes problems. The handle gets recreated when //RightToLeft changes. To avoid changing our handle, we can override the //RightToLeft property, and notify our child when the property changes. private RightToLeft _rightToLeft = RightToLeft.Inherit; ////// Gets or sets a value indicating whether control's elements are aligned /// to support locales using right-to-left fonts. /// public override RightToLeft RightToLeft { get { //Return the same default value as Control does (No) return _rightToLeft == RightToLeft.Inherit ? RightToLeft.No : _rightToLeft; } set { if (_rightToLeft != value) { //If RightToLeft is Inherit and we're setting to the "default" value, don't call OnRTLChanged. bool fireRightToLeftChanged = _rightToLeft != RightToLeft.Inherit || base.RightToLeft != value; _rightToLeft = value; if (fireRightToLeftChanged) { OnRightToLeftChanged(EventArgs.Empty); } } } } ////// Override OnRightToLeftChanged as noted above /// /// protected override void OnRightToLeftChanged(EventArgs e) { if (null != Child) { CallOnParentRightToLeftChanged(Child); } } //Use reflection to call protected OnParentRightToLeftChanged private void CallOnParentRightToLeftChanged(Control control) { MethodInfo methodInfo = typeof(SWF.Control).GetMethod("OnParentRightToLeftChanged", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(EventArgs) }, null); Debug.Assert(methodInfo != null, "Couldn't find OnParentRightToLeftChanged method!"); if (methodInfo != null) { methodInfo.Invoke(control, new object[] { EventArgs.Empty }); } } } #endregion WinFormsAdapter } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. using MS.Win32; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Windows.Interop; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Automation.Provider; using System.Windows.Automation.Peers; using SD = System.Drawing; using SW = System.Windows; using SWC = System.Windows.Controls; using SWF = System.Windows.Forms; using SWM = System.Windows.Media; using SWI = System.Windows.Input; using System.Collections.Generic; using System.Windows.Input; namespace System.Windows.Forms.Integration { ////// An element that allows you to host a Windows Forms control on a /// Windows Presentation Foundation page. /// [System.ComponentModel.DesignerCategory("code")] [ContentProperty("Child")] [DefaultEvent("ChildChanged")] public class WindowsFormsHost : HwndHost, IKeyboardInputSink { private SWM.Brush _cachedBackbrush; private HandleRef _hwndParent; private WinFormsAdapter _hostContainerInternal; #region Constructors [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] static WindowsFormsHost() { //Keyboard tabbing support FocusableProperty.OverrideMetadata(typeof(WindowsFormsHost), new FrameworkPropertyMetadata(true)); SWC.Control.IsTabStopProperty.OverrideMetadata(typeof(WindowsFormsHost), new FrameworkPropertyMetadata(true)); } ////// Initializes a new instance of the WindowsFormsHost class. /// [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] public WindowsFormsHost() : base() { this._hostContainerInternal = new WinFormsAdapter(this); _propertyMap = new WindowsFormsHostPropertyMap(this); } #endregion #region Focus ////// Notifies Avalon that focus has moved within this WindowsFormsHost. /// void NotifyFocusWithinHost() { DependencyObject focusScope = GetFocusScopeForElement(this); if (null != focusScope) { System.Windows.Input.FocusManager.SetFocusedElement(focusScope, this); } } ////// Handles Child.GotFocus event. /// private void OnChildGotFocus(object sender, EventArgs e) { SyncChildImeEnabledContext(); } ////// Synchronizes the Winforms Child control ime context enble status. /// private void SyncChildImeEnabledContext() { if (SWF.ImeModeConversion.IsCurrentConversionTableSupported && this.Child != null && this.Child.IsHandleCreated) { Debug.WriteLineIf(HostUtils.ImeMode.Level >= TraceLevel.Info, "Inside SyncChildImeEnabledContext(), this = " + this); Debug.Indent(); // Note: Do not attempt to set Child.ImeMode directly, it will be updated properly from the context. if (InputMethod.GetIsInputMethodEnabled(this)) { if (this.Child.ImeMode == ImeMode.Disable) { SWF.ImeContext.Enable(this.Child.Handle); } } else { if (this.Child.ImeMode != ImeMode.Disable) { SWF.ImeContext.Disable(this.Child.Handle); } } Debug.Unindent(); } } ////// When implemented in a derived class, accesses the window process of the hosted child window. /// /// /// /// /// /// ///protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case NativeMethods.WM_CHILDACTIVATE: _hostContainerInternal.HandleChildActivate(); break; case NativeMethods.WM_SETFOCUS: case NativeMethods.WM_MOUSEACTIVATE: NotifyFocusWithinHost(); break; case NativeMethods.WM_GETOBJECT: handled = true; return OnWmGetObject(wParam, lParam); } return base.WndProc(hwnd, msg, wParam, lParam, ref handled); } /// /// Critical - Calls critical HwndHost.Handle. /// TreatAsSafe - This demands full trust, so it's safe /// [SecurityCritical, SecurityTreatAsSafe] [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] private IntPtr OnWmGetObject(IntPtr wparam, IntPtr lparam) { IntPtr result = IntPtr.Zero; WindowsFormsHostAutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(this) as WindowsFormsHostAutomationPeer; if (peer != null) { // get the element proxy IRawElementProviderSimple el = peer.GetProvider(); if (el != null) { //This requires FullTrust but we already have it. result = AutomationInteropProvider.ReturnRawElementProvider(Handle, wparam, lparam, el); } } return result; } private static DependencyObject GetFocusScopeForElement(DependencyObject element) { //Walk up the visual tree until we find an element that is a focus scope (or we run out of elements). //This will usually be the root Avalon Window. while (null != element && !FocusManager.GetIsFocusScope(element)) { element = VisualTreeHelper.GetParent(element); } return element; } #endregion #region Layout private Vector _currentScale = new Vector(1.0, 1.0); ////// Scales the hosted Windows Forms control, and tracks the scale factor. /// /// ///The new scale factor protected virtual Vector ScaleChild(Vector newScale) { if (newScale != _currentScale) { if (Child != null) { Child.Scale(new System.Drawing.SizeF((float)(newScale.X / _currentScale.X), (float)(newScale.Y / _currentScale.Y))); } } return newScale; } private void ScaleChild() { bool skewed; Vector newScale = HostUtils.GetScale(this, out skewed); if (skewed) { OnLayoutError(); } _currentScale = ScaleChild(newScale); } private event EventHandler_layoutError; /// /// Occurs when a layout error, such as a skew or rotation that WindowsFormsHost does not support, /// is encountered. /// public event EventHandlerLayoutError { add { _layoutError += value; } remove { _layoutError -= value; } } private void OnLayoutError() { InvalidOperationException exception = new InvalidOperationException(SR.Get(SRID.Host_CannotRotateWindowsFormsHost)); LayoutExceptionEventArgs args = new LayoutExceptionEventArgs(exception); if (_layoutError != null) { _layoutError(this, args); } if (args.ThrowException) { throw exception; } } /// /// Overrides the base class implementation of MeasureOverride to measure /// the size of a WindowsFormsHost object and return the proper size to the layout engine. /// protected override SW.Size MeasureOverride(SW.Size constraint) { if (this.Visibility == Visibility.Collapsed || Child == null) { //Child takes up no space return new Size(0, 0); } ScaleChild(); SD.Size constraintSize = Convert.ConstraintToSystemDrawingSize(constraint, _currentScale); SD.Size preferredSize = Child.GetPreferredSize(constraintSize); System.Windows.Size returnSize = Convert.ToSystemWindowsSize(preferredSize, _currentScale); // Apply constraints to the preferred size returnSize.Width = Math.Min(returnSize.Width, constraint.Width); returnSize.Height = Math.Min(returnSize.Height, constraint.Height); return returnSize; } // Note: the WPF layout engine may call ArrangeOverride multiple times in succession private Size _priorConstraint; ////// When implemented in a derived class, positions child elements and determines a /// size for a FrameworkElement-derived class. /// /// ///protected override Size ArrangeOverride(Size finalSize) { if (this.Visibility == Visibility.Collapsed || Child == null) { //Child takes up no space return new Size(0, 0); } Vector originalScale = _currentScale; ScaleChild(); bool scaled = (_currentScale != originalScale); SD.Size targetSize = Convert.ConstraintToSystemDrawingSize(finalSize, _currentScale); if ((Child.Size != targetSize) && ((finalSize != _priorConstraint) || scaled)) { _priorConstraint = finalSize; Child.Size = targetSize; } Size returnSize = Convert.ToSystemWindowsSize(Child.Size, _currentScale); returnSize.Width = Math.Min(returnSize.Width, finalSize.Width); returnSize.Height = Math.Min(returnSize.Height, finalSize.Height); if (HostContainerInternal.BackgroundImage != null) { _propertyMap.OnPropertyChanged(this, "Background", this.Background); } return returnSize; } #endregion Layout #region Containership /// /// Occurs when the Child property is set. /// public event EventHandlerChildChanged; /// /// Gets or sets the child control hosted by the WindowsFormsHost element. /// public Control Child { get { return _hostContainerInternal.Child; } set { #pragma warning disable 1634, 1691 #pragma warning disable 56526 Control oldChild = Child; SWF.Form form = value as SWF.Form; if (form != null) { if (form.TopLevel) { //WinOS #1030878 - Can't host top-level forms throw new ArgumentException(SR.Get(SRID.Host_ChildCantBeTopLevelForm)); } else { form.ControlBox = false; } } _hostContainerInternal.Child = value; if (Child != null) { _propertyMap.ApplyAll(); Child.Margin = SWF.Padding.Empty; Child.Dock = DockStyle.None; Child.AutoSize = false; Child.Location = SD.Point.Empty; // clear the cached size _priorConstraint = new Size(double.NaN, double.NaN); } OnChildChanged(oldChild); #pragma warning restore 1634, 1691, 56526 } } private void OnChildChanged(Control oldChild) { if (oldChild != null) { oldChild.GotFocus -= new EventHandler(this.OnChildGotFocus); } if (this.Child != null) { this.Child.GotFocus += new EventHandler(this.OnChildGotFocus); } if (ChildChanged != null) { ChildChanged(this, new ChildChangedEventArgs(oldChild)); } } internal WinFormsAdapter HostContainerInternal { get { return _hostContainerInternal; } } #endregion Containership #region Rendering static Brush defaultBrush = SystemColors.WindowBrush; ////// Manually searches up the parent tree to find the first FrameworkElement that /// has a non-null background, and returns that Brush. /// If no parent is found with a brush, then this returns WindowBrush. /// /// ///private static SWM.Brush FindBackgroundParent(SW.DependencyObject dependencyObject) { if (dependencyObject == null) { return defaultBrush; } Brush backgroundBrush = null; backgroundBrush = (Brush)dependencyObject.GetValue(SWC.Control.BackgroundProperty); if (backgroundBrush == null) { SW.FrameworkElement frameworkElement = dependencyObject as SW.FrameworkElement; if (frameworkElement != null) { DependencyObject parentElement = VisualTreeHelper.GetParent(frameworkElement); backgroundBrush = FindBackgroundParent(parentElement); } } return backgroundBrush ?? defaultBrush; } /// /// This is called by the OnPaintBackground method of the host container. /// internal void PaintBackground() { SWM.Brush parentBrush = FindBackgroundParent(this); if (parentBrush != null) { if (_cachedBackbrush != parentBrush) { _cachedBackbrush = parentBrush; _propertyMap.OnPropertyChanged(this, "Background", parentBrush); } } } #endregion Rendering #region Keyboarding ////// Enables Windows Forms forms to function correctly when opened modelessly from /// Windows Presentation Foundation. /// [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] public static void EnableWindowsFormsInterop() { ApplicationInterop.EnableWindowsFormsInterop(); } ////// Forwards focus from Windows Presentation Foundation to the hosted Windows Forms control. /// public virtual bool TabInto(SWI.TraversalRequest request) { return HostContainerInternal.FocusNext(request); } #endregion Keyboarding #region Activation private Control _focusedChild; private void RestoreFocusedChild() { _hostContainerInternal.Focus(); _hostContainerInternal.ActiveControl = _focusedChild; _focusedChild = null; } private void NotifyActivateApp(ref Message m) { if (m.WParam != IntPtr.Zero) { if (null != _focusedChild) { _hostContainerInternal.BeginInvoke(new MethodInvoker(RestoreFocusedChild)); } } else { IntPtr currentFocus = UnsafeNativeMethods.GetFocus(); if (currentFocus == Handle || UnsafeNativeMethods.IsChild(Handle, currentFocus)) { _focusedChild = _hostContainerInternal.ActiveControl; } } } private ActivateWindowListener _activateWindowListener; private class ActivateWindowListener : NativeWindow, IDisposable { WindowsFormsHost _host; public ActivateWindowListener(WindowsFormsHost host) { _host = host; } protected override void WndProc(ref Message m) { if (NativeMethods.WM_ACTIVATEAPP == m.Msg) { // This message is sent to every top child window in the app, if the focused top child // window contains a winforms host, we need to notify it so it activates or caches the // active control. IntPtr currentFocus = UnsafeNativeMethods.GetFocus(); if (UnsafeNativeMethods.IsChild(_host.Handle, currentFocus)) { _host.NotifyActivateApp(ref m); } } base.WndProc(ref m); } public void Dispose() { this.ReleaseHandle(); } } #endregion #region Window Handling & Misc ////// Overrides the base class implementation of BuildWindowCore to build the hosted /// Windows Forms control. /// protected override HandleRef BuildWindowCore(HandleRef hwndParent) { this.Loaded += new RoutedEventHandler(ApplyAllProperties); Debug.WriteLineIf(_traceHandle.TraceVerbose, String.Format(CultureInfo.CurrentCulture, "WindowsFormsHost({0}): BuildWindowCore (parent=0x{1:x8})", this.Name, hwndParent.Handle.ToInt32())); if (_activateWindowListener != null) { _activateWindowListener.Dispose(); } _activateWindowListener = new ActivateWindowListener(this); _activateWindowListener.AssignHandle(hwndParent.Handle); _hwndParent = hwndParent; //For Keyboard interop ApplicationInterop.ThreadWindowsFormsHostList.Add(this); //Keep track of this control, so it can get forwarded windows messages EnableWindowsFormsInterop(); //Start the forwarding of windows messages to all WFH controls on active windows UnsafeNativeMethods.SetParent(/* child = */ HostContainerInternal.Handle, /* parent = */ _hwndParent.Handle); return new HandleRef(HostContainerInternal, HostContainerInternal.Handle); } ////// Overrides the base class implementation of DestroyWindowCore to delete the /// window containing this object. /// protected override void DestroyWindowCore(HandleRef hwnd) { //For keyboard interop (remove this control from the list) //This line shouldn't be necessary since the list cleans itself, but it's good to be tidy. ApplicationInterop.ThreadWindowsFormsHostList.Remove(this); if (HostContainerInternal != null) { HostContainerInternal.Dispose(); } } void ApplyAllProperties(object sender, RoutedEventArgs e) { _propertyMap.ApplyAll(); } ////// Releases all resources used by the WindowsFormsHost element. /// protected override void Dispose(bool disposing) { try { base.Dispose(disposing); } finally { if (disposing) { if (_hostContainerInternal != null) { try { if (_activateWindowListener != null) { _activateWindowListener.Dispose(); } _hostContainerInternal.Dispose(); this.Loaded -= new RoutedEventHandler(ApplyAllProperties); } finally { if (Child != null) { Child.Dispose(); } } } } } } #endregion Window Handling & Misc #region Automation ////// Creates AutomationPeer ( protected override AutomationPeer OnCreateAutomationPeer() { return new WindowsFormsHostAutomationPeer(this); } #endregion Automation #region Property Mapping //Some of the properties that we would like to map don't exist on HwndHost, //so we add them here: TabIndex, Font (4x), Foreground, Background, Padding. ///) /// /// Identifies the Padding dependency property. /// public static readonly DependencyProperty PaddingProperty = SWC.Control.PaddingProperty.AddOwner(typeof(WindowsFormsHost)); ////// Specifies the size of the desired padding within the hosted Windows Forms control. /// [Bindable(true), Category("Behavior")] public Thickness Padding { get { return (Thickness)GetValue(PaddingProperty); } set { SetValue(PaddingProperty, value); } } ////// Identifies the TabIndex dependency property. /// public static readonly DependencyProperty TabIndexProperty = SWC.Control.TabIndexProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's tab index. /// [Bindable(true), Category("Behavior")] public int TabIndex { get { return (int)GetValue(TabIndexProperty); } set { SetValue(TabIndexProperty, value); } } ////// Identifies the FontFamily dependency property. /// public static readonly DependencyProperty FontFamilyProperty = SWC.Control.FontFamilyProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's font family as an ambient property. /// public SWM.FontFamily FontFamily { get { return (SWM.FontFamily)GetValue(FontFamilyProperty); } set { SetValue(FontFamilyProperty, value); } } ////// Identifies the FontSize dependency property. /// public static readonly DependencyProperty FontSizeProperty = SWC.Control.FontSizeProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's font size as an ambient property. /// public double FontSize { get { return (double)GetValue(FontSizeProperty); } set { SetValue(FontSizeProperty, value); } } ////// Identifies the FontStyle dependency property. /// public static readonly DependencyProperty FontStyleProperty = SWC.Control.FontStyleProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's font style as an ambient proeprty. /// public SW.FontStyle FontStyle { get { return (FontStyle)GetValue(FontStyleProperty); } set { SetValue(FontStyleProperty, value); } } ////// Identifies the FontWeight dependency property. /// public static readonly DependencyProperty FontWeightProperty = SWC.Control.FontWeightProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's font weight as an ambient property. /// public SW.FontWeight FontWeight { get { return (FontWeight)GetValue(FontWeightProperty); } set { SetValue(FontWeightProperty, value); } } ////// Identifies the Foreground dependency property. /// public static readonly DependencyProperty ForegroundProperty = SWC.Control.ForegroundProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's foreground color as an ambient property. /// public Brush Foreground { get { return (Brush)GetValue(ForegroundProperty); } set { SetValue(ForegroundProperty, value); } } ////// Identifies the Background dependency property. /// public static readonly DependencyProperty BackgroundProperty = SWC.Control.BackgroundProperty.AddOwner(typeof(WindowsFormsHost)); ////// Gets or sets the hosted control's background as an ambient property. /// public Brush Background { get { return (Brush)GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } ////// Forces the translation of a mapped property. /// protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { base.OnPropertyChanged(e); // Invoke method currently set to handle this event if (_propertyMap != null) { _propertyMap.OnPropertyChanged(this, e.Property.Name, e.NewValue); } } ////// Gets the property map that determines how setting properties on the /// WindowsFormsHost element affects the hosted Windows Forms control. /// public PropertyMap PropertyMap { get { return _propertyMap; } } private PropertyMap _propertyMap; #endregion Property Mapping #region DEBUG #if DEBUG internal static readonly TraceSwitch _traceHandle = new TraceSwitch("WindowsFormsHostHandle", "Tracks WindowsFormsHost handle information."); internal static readonly TraceSwitch _traceLayout = new TraceSwitch("WindowsFormsHostLayout", "Tracks WindowsFormsHost layout information."); #else internal static readonly TraceSwitch _traceHandle = null; internal static readonly TraceSwitch _traceLayout = null; #endif #endregion DEBUG } #region WinFormsAdapter [System.ComponentModel.DesignerCategory("code")] internal class WinFormsAdapter : SWF.ContainerControl { private WindowsFormsHost _host; private FocusTargetControl _focusTarget; private IntPtr _prevFocusHwnd = IntPtr.Zero; private Control _child; public Control Child { get { return _child; } set { if (null != Child) { Controls.Remove(Child); } if (null != value) { Controls.Add(value); } _child = value; } } public void HandleChildActivate() { IntPtr focusHwnd = UnsafeNativeMethods.GetFocus(); try { if (IntPtr.Zero == _prevFocusHwnd ) { return; } //If focus is changing from a child of the WinFormsAdapter to something outside //we will activate the a temporary control to cause leave and validation events if ( _focusTarget.Handle != _prevFocusHwnd && UnsafeNativeMethods.IsChild(Handle, _prevFocusHwnd) && !UnsafeNativeMethods.IsChild(Handle, focusHwnd)) { this.ActiveControl = _focusTarget; } } finally { _prevFocusHwnd = focusHwnd; } } //Note: there's no notification when the ambient cursor changes, so we //can't do a normal mapping for this and have it work. We work around //this by overriding WinFormsAdapter.Cursor and walking the visual tree //to find the cursor IF the Cursor translator has not been changed. //host.PropertyMap["Cursor"] += delegate {MessageBox.Show("?");}; //will cause the mapping to no longer happen. public override Cursor Cursor { get { if (_host == null) { return base.Cursor; } if (!_host.PropertyMap.PropertyMappedToEmptyTranslator("Cursor")) { return base.Cursor; } bool forceCursorMapped = _host.PropertyMap.PropertyMappedToEmptyTranslator("ForceCursor"); FrameworkElement cursorSource = HostUtils.GetCursorSource(_host, forceCursorMapped); if (cursorSource == null) { return base.Cursor; } return Convert.ToSystemWindowsFormsCursor(cursorSource.Cursor); } set { base.Cursor = value; } } private class FocusTargetControl : Control { public FocusTargetControl() { this.Size = SD.Size.Empty; //Hide it as far away as possible this.Location = new SD.Point(short.MinValue, short.MinValue); this.TabStop = false; #if DEBUG this.Name = "Focus target"; #endif //DEBUG } } public WinFormsAdapter(WindowsFormsHost host) { _host = host; _focusTarget = new FocusTargetControl(); Controls.Add(_focusTarget); this.HandleCreated += WinFormsAdapter_HandleCreated; //Keyboard interop: We listen to this event to refresh the visual cues (workaround) SWI.InputManager.Current.PostProcessInput += InputManager_PostProcessInput; } protected override void Dispose(bool disposing) { try { if (disposing) { SWI.InputManager.Current.PostProcessInput -= InputManager_PostProcessInput; } } finally { base.Dispose(disposing); } } #region Keyboard Interop ////// Forwards focus from Avalon and into the WinForms "sink". /// The request is often First and Last, which isn't really mapped the /// same way, but it seems to work, probably because we only host one control. /// /// ///internal bool FocusNext(SWI.TraversalRequest request) { UpdateUIState(NativeMethods.UIS_INITIALIZE); bool forward = true; bool tabStopOnly = true; switch (request.FocusNavigationDirection) { case System.Windows.Input.FocusNavigationDirection.Down: case System.Windows.Input.FocusNavigationDirection.Right: forward = true; tabStopOnly = false; break; case System.Windows.Input.FocusNavigationDirection.Next: case System.Windows.Input.FocusNavigationDirection.First: forward = true; tabStopOnly = true; break; case System.Windows.Input.FocusNavigationDirection.Up: case System.Windows.Input.FocusNavigationDirection.Left: forward = false; tabStopOnly = false; break; case System.Windows.Input.FocusNavigationDirection.Previous: case System.Windows.Input.FocusNavigationDirection.Last: forward = false; tabStopOnly = true; break; default: Debug.Assert(false, "Unknown FocusNavigationDirection"); break; } _focusTarget.Enabled = false; try { if (this.SelectNextControl(null, forward, tabStopOnly, true, false)) { // find the inner most active control ContainerControl ret = this; while (ret.ActiveControl is ContainerControl) { ret = (ContainerControl)ret.ActiveControl; } if (!ret.ContainsFocus) { ret.Focus(); } return true; } return false; } finally { _focusTarget.Enabled = true; } } // CSS added for keyboard interop protected override bool ProcessDialogKey(Keys keyData) { _focusTarget.Enabled = false; try { if ((keyData & (Keys.Alt | Keys.Control)) == Keys.None) { Keys keyCode = (Keys)keyData & Keys.KeyCode; if (keyCode == Keys.Tab || keyCode == Keys.Left || keyCode == Keys.Right || keyCode == Keys.Up || keyCode == Keys.Down) { if (this.Focused || this.ContainsFocus) { // CSS: In WF apps, by default, arrow keys always wrap within a container // However, we don't want them to wrap in the Adapter, which always has only // one immediate child if ((keyCode == Keys.Left || keyCode == Keys.Right || keyCode == Keys.Down || keyCode == Keys.Up) && (this.ActiveControl != null && this.ActiveControl.Parent == this)) { SWF.Control c = this.ActiveControl.Parent; return c.SelectNextControl(this.ActiveControl, keyCode == Keys.Right || keyCode == Keys.Down, false, false, false); } else return base.ProcessDialogKey(keyData); } } } return false; } finally { _focusTarget.Enabled = true; } } // CSS added for keyboard interop internal bool PreProcessMessage(ref Message msg, bool hasFocus) { // Don't steal WM_CHAR messages from Avalon, Catch them later in InputManager_PostProcessInput if (!hasFocus && msg.Msg == NativeMethods.WM_CHAR) { return false; } return PreProcessMessage(ref msg); } /// /// For keyboard interop, when this handle is recreated, the current state of the /// visual shortcut key cues (AKA underlining the hotkey) is lost, so it needs /// to be refreshed. /// /// /// private void WinFormsAdapter_HandleCreated(object sender, EventArgs e) { //CSS - Workaround OS bug. The initial UI state was being set erratically // (sometimes cues were shown, sometimes not. This forces it to a known state. UpdateUIState(NativeMethods.UIS_SET); } ////// For keyboard interop /// Ensure the visual shortcut key cues on controls are in the same visual /// state that we expect. This is a workaround for odd Windows API. /// internal void UpdateUIState(int uiAction) { Debug.Assert(uiAction == NativeMethods.UIS_INITIALIZE || uiAction == NativeMethods.UIS_SET, "Unexpected uiAction"); int toSet = NativeMethods.UISF_HIDEACCEL | NativeMethods.UISF_HIDEFOCUS; if (UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.WM_UPDATEUISTATE, (IntPtr)(uiAction | (toSet << 16)), IntPtr.Zero) != IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } // CSS Added for keyboard interop // Catch WM_CHAR messages which weren't handled by Avalon // (including mnemonics which were typed without the "Alt" key) private void InputManager_PostProcessInput(object sender, SWI.ProcessInputEventArgs e) { // Should return immediately if this WFH is not in the active Window PresentationSource presentationSource = PresentationSource.FromVisual(this._host); if (presentationSource == null) { return; } Window presentationSourceWindow = presentationSource.RootVisual as Window; //CSS This active window check may not work for multiple levels of nesting... // RootVisual isn't top level window. Should we traverse upward through nested levels? if (presentationSourceWindow == null || !presentationSourceWindow.IsActive) return; // Now check for unhandled WM_CHAR messages and process them as mnemonics if (!e.StagingItem.Input.Handled && e.StagingItem.Input.RoutedEvent == SWI.TextCompositionManager.TextInputEvent) { SWI.TextCompositionEventArgs te = (SWI.TextCompositionEventArgs)e.StagingItem.Input; string text = te.Text; if (string.IsNullOrEmpty(text)) { text = te.SystemText; } if (!string.IsNullOrEmpty(text)) { e.StagingItem.Input.Handled = this.ProcessDialogChar(text[0]); } } } #endregion Keyboard Interop ////// Overridden to invalidate host layout when our layout changes. /// protected override void OnLayout(SWF.LayoutEventArgs e) { base.OnLayout(e); _host.InvalidateMeasure(); #if DEBUG string compName = ""; if (e.AffectedControl != null) { compName = e.AffectedControl.Name; } else if (e.AffectedComponent != null) { compName = e.AffectedComponent.ToString(); } Debug.WriteLineIf(WindowsFormsHost._traceLayout.TraceInfo, String.Format(CultureInfo.CurrentCulture, "WindowsFormsHost({0}): Layout invalidated (control='{1}',property='{2}')", _host.Name, compName, e.AffectedProperty)); #endif } ////// Forward the Host Containers paint events to the WFH, so that it can either /// use a bitmap to do "fake" transparency or set the BackColor correctly. /// protected override void OnPaintBackground(SWF.PaintEventArgs e) { _host.PaintBackground(); base.OnPaintBackground(e); } //Changing RightToLeft on the WinFormsAdapter recreates the handle. Since our //handle is being cached, this causes problems. The handle gets recreated when //RightToLeft changes. To avoid changing our handle, we can override the //RightToLeft property, and notify our child when the property changes. private RightToLeft _rightToLeft = RightToLeft.Inherit; ////// Gets or sets a value indicating whether control's elements are aligned /// to support locales using right-to-left fonts. /// public override RightToLeft RightToLeft { get { //Return the same default value as Control does (No) return _rightToLeft == RightToLeft.Inherit ? RightToLeft.No : _rightToLeft; } set { if (_rightToLeft != value) { //If RightToLeft is Inherit and we're setting to the "default" value, don't call OnRTLChanged. bool fireRightToLeftChanged = _rightToLeft != RightToLeft.Inherit || base.RightToLeft != value; _rightToLeft = value; if (fireRightToLeftChanged) { OnRightToLeftChanged(EventArgs.Empty); } } } } ////// Override OnRightToLeftChanged as noted above /// /// protected override void OnRightToLeftChanged(EventArgs e) { if (null != Child) { CallOnParentRightToLeftChanged(Child); } } //Use reflection to call protected OnParentRightToLeftChanged private void CallOnParentRightToLeftChanged(Control control) { MethodInfo methodInfo = typeof(SWF.Control).GetMethod("OnParentRightToLeftChanged", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(EventArgs) }, null); Debug.Assert(methodInfo != null, "Couldn't find OnParentRightToLeftChanged method!"); if (methodInfo != null) { methodInfo.Invoke(control, new object[] { EventArgs.Empty }); } } } #endregion WinFormsAdapter } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Simplifier.cs
- Content.cs
- InvalidFilterCriteriaException.cs
- Operand.cs
- CodeSubDirectoriesCollection.cs
- DataGridViewCellLinkedList.cs
- GenericPrincipal.cs
- Compiler.cs
- HybridObjectCache.cs
- ExternalException.cs
- CookieParameter.cs
- MulticastIPAddressInformationCollection.cs
- MulticastOption.cs
- GradientSpreadMethodValidation.cs
- XPathQilFactory.cs
- ImageListImage.cs
- SystemIcmpV6Statistics.cs
- ServiceManager.cs
- CommonGetThemePartSize.cs
- RadioButtonFlatAdapter.cs
- Decoder.cs
- UnsafeNativeMethodsCLR.cs
- __ConsoleStream.cs
- CounterSet.cs
- HyperLink.cs
- Image.cs
- PtsContext.cs
- SqlDelegatedTransaction.cs
- InvalidateEvent.cs
- UTF32Encoding.cs
- Double.cs
- DefinitionBase.cs
- MenuRenderer.cs
- GeometryGroup.cs
- Confirm.cs
- CompilationSection.cs
- XmlWriterSettings.cs
- AsyncCodeActivity.cs
- SystemTcpStatistics.cs
- Window.cs
- SqlDataSourceCommandEventArgs.cs
- HttpModulesInstallComponent.cs
- VBCodeProvider.cs
- BindingObserver.cs
- EventHandlersStore.cs
- ViewSimplifier.cs
- Types.cs
- CodeCatchClauseCollection.cs
- NotImplementedException.cs
- FontStyleConverter.cs
- String.cs
- UnsafeNativeMethods.cs
- DbSourceCommand.cs
- IgnoreFlushAndCloseStream.cs
- PhonemeEventArgs.cs
- SortedDictionary.cs
- SHA1CryptoServiceProvider.cs
- TemplateAction.cs
- CompilationLock.cs
- ProviderManager.cs
- DirectoryInfo.cs
- ButtonField.cs
- ItemsControl.cs
- ArraySet.cs
- SigningCredentials.cs
- Buffer.cs
- XmlSchemaAll.cs
- MaskPropertyEditor.cs
- SettingsProperty.cs
- SqlCacheDependency.cs
- XmlILStorageConverter.cs
- NodeInfo.cs
- HttpCachePolicy.cs
- LocalIdKeyIdentifierClause.cs
- DllNotFoundException.cs
- AffineTransform3D.cs
- IgnoreFlushAndCloseStream.cs
- UriSection.cs
- InternalBufferOverflowException.cs
- DoubleCollectionValueSerializer.cs
- GreenMethods.cs
- SystemTcpConnection.cs
- CheckBoxPopupAdapter.cs
- RectKeyFrameCollection.cs
- WebBodyFormatMessageProperty.cs
- PathGeometry.cs
- RewritingPass.cs
- ObjectQuery.cs
- ItemsChangedEventArgs.cs
- StorageScalarPropertyMapping.cs
- ValidationErrorCollection.cs
- BrowserTree.cs
- WindowProviderWrapper.cs
- MetadataArtifactLoaderComposite.cs
- AccessedThroughPropertyAttribute.cs
- SignedXml.cs
- DBNull.cs
- Viewport3DAutomationPeer.cs
- DataRecordObjectView.cs
- ContainerSelectorGlyph.cs