Browse Source

Embeddable control window lifecycle should be tied to native host control

Nikita Tsukanov 9 years ago
parent
commit
528e891e55

+ 1 - 1
samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs

@@ -85,7 +85,7 @@ namespace WindowsInteropTest
             this.avaloniaHost.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
             | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
-            this.avaloniaHost.Child = null;
+            this.avaloniaHost.Content = null;
             this.avaloniaHost.Location = new System.Drawing.Point(6, 19);
             this.avaloniaHost.Name = "avaloniaHost";
             this.avaloniaHost.Size = new System.Drawing.Size(489, 393);

+ 1 - 4
samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs

@@ -17,10 +17,7 @@ namespace WindowsInteropTest
         public EmbedToWinFormsDemo()
         {
             InitializeComponent();
-            var ctrl = new EmbeddableControl();
-            ctrl.Content = new ControlCatalogControl();
-            ctrl.ApplyTemplate();
-            avaloniaHost.Child = ctrl;
+            avaloniaHost.Content = new ControlCatalogControl();
         }
     }
 }

+ 1 - 1
samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs

@@ -25,7 +25,7 @@ namespace WindowsInteropTest
         public EmbedToWpfDemo()
         {
             InitializeComponent();
-            Host.Child = new EmbeddableControl {Content = new ControlCatalogControl()};
+            Host.Content =  new ControlCatalogControl();
         }
     }
 }

+ 1 - 1
src/Avalonia.Controls/Avalonia.Controls.csproj

@@ -56,7 +56,7 @@
     <Compile Include="HotkeyManager.cs" />
     <Compile Include="IApplicationLifecycle.cs" />
     <Compile Include="IScrollable.cs" />
-    <Compile Include="EmbeddableControl.cs" />
+    <Compile Include="EmbeddableControlRoot.cs" />
     <Compile Include="Platform\IEmbeddableWindowImpl.cs" />
     <Compile Include="WindowIcon.cs" />
     <Compile Include="IPseudoClasses.cs" />

+ 7 - 3
src/Avalonia.Controls/EmbeddableControl.cs → src/Avalonia.Controls/EmbeddableControlRoot.cs

@@ -11,9 +11,9 @@ using Avalonia.Styling;
 
 namespace Avalonia.Controls
 {
-    public class EmbeddableControl : TopLevel, IStyleable, IFocusScope, INameScope
+    public class EmbeddableControlRoot : TopLevel, IStyleable, IFocusScope, INameScope, IDisposable
     {
-        public EmbeddableControl() : base(PlatformManager.CreateEmbeddableWindow())
+        public EmbeddableControlRoot() : base(PlatformManager.CreateEmbeddableWindow())
         {
             PlatformImpl.Show();
         }
@@ -63,6 +63,10 @@ namespace Avalonia.Controls
 
         public void Unregister(string name) => _nameScope.Unregister(name);
 
-        Type IStyleable.StyleKey => typeof(EmbeddableControl);
+        Type IStyleable.StyleKey => typeof(EmbeddableControlRoot);
+        public void Dispose()
+        {
+            PlatformImpl.Dispose();
+        }
     }
 }

+ 1 - 1
src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj

@@ -209,7 +209,7 @@
     </Reference>
   </ItemGroup>
   <ItemGroup>
-    <EmbeddedResource Include="EmbeddableControl.xaml">
+    <EmbeddedResource Include="EmbeddableControlRoot.xaml">
       <SubType>Designer</SubType>
     </EmbeddedResource>
   </ItemGroup>

+ 1 - 1
src/Avalonia.Themes.Default/DefaultTheme.xaml

@@ -32,5 +32,5 @@
   <StyleInclude Source="resm:Avalonia.Themes.Default.TreeView.xaml?assembly=Avalonia.Themes.Default"/>
   <StyleInclude Source="resm:Avalonia.Themes.Default.TreeViewItem.xaml?assembly=Avalonia.Themes.Default"/>
   <StyleInclude Source="resm:Avalonia.Themes.Default.Window.xaml?assembly=Avalonia.Themes.Default"/>
-  <StyleInclude Source="resm:Avalonia.Themes.Default.EmbeddableControl.xaml?assembly=Avalonia.Themes.Default"/>
+  <StyleInclude Source="resm:Avalonia.Themes.Default.EmbeddableControlRoot.xaml?assembly=Avalonia.Themes.Default"/>
 </Styles>

+ 1 - 1
src/Avalonia.Themes.Default/EmbeddableControl.xaml → src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml

@@ -1,4 +1,4 @@
-<Style xmlns="https://github.com/avaloniaui" Selector="EmbeddableControl">
+<Style xmlns="https://github.com/avaloniaui" Selector="EmbeddableControlRoot">
   <Setter Property="Background" Value="{StyleResource ThemeBackgroundBrush}"/>
   <Setter Property="FontFamily" Value="Segoe UI"/>
   <Setter Property="FontSize" Value="{StyleResource FontSizeNormal}"/>

+ 29 - 46
src/Windows/Avalonia.Win32/Embedding/WinFormsAvaloniaControlHost.cs

@@ -5,45 +5,31 @@ using Avalonia.Controls;
 using Avalonia.Input;
 using Avalonia.VisualTree;
 using Avalonia.Win32.Interop;
-using Control = System.Windows.Forms.Control;
+using WinFormsControl = System.Windows.Forms.Control;
 
 namespace Avalonia.Win32.Embedding
 {
     [ToolboxItem(true)]
-    public class WinFormsAvaloniaControlHost : Control
+    public class WinFormsAvaloniaControlHost : WinFormsControl
     {
-        private EmbeddableControl _child;
+        private readonly EmbeddableControlRoot _root = new EmbeddableControlRoot();
 
-        public EmbeddableControl Child
+        public WinFormsAvaloniaControlHost()
+        {
+            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
+            UnmanagedMethods.SetParent(_root.PlatformImpl.Handle.Handle, Handle);
+            _root.Prepare();
+            if (_root.IsFocused)
+                FocusManager.Instance.Focus(null);
+            _root.GotFocus += RootGotFocus;
+            _root.PlatformImpl.LostFocus += PlatformImpl_LostFocus;
+            FixPosition();
+        }
+
+        public Avalonia.Controls.Control Content
         {
-            get { return _child; }
-            set
-            {
-                if (value !=null && value.PlatformImpl.Handle.HandleDescriptor != PlatformConstants.WindowHandleType)
-                    throw new ArgumentException("Invalid widget for embedding, don't know what to do with " +
-                                                value.PlatformImpl.Handle.HandleDescriptor);
-                if (_child != null)
-                {
-                    _child.GotFocus -= _child_GotFocus;
-                    _child.PlatformImpl.LostFocus -= PlatformImpl_LostFocus;
-                    _child.PlatformImpl.Hide();
-                    Unfocus();
-                    UnmanagedMethods.SetParent(_child.PlatformImpl.Handle.Handle, EmbeddedWindowImpl.DefaultParentWindow);
-                }
-                _child = value;
-                if (_child != null)
-                {
-                    UnmanagedMethods.SetParent(_child.PlatformImpl.Handle.Handle, Handle);
-                    _child.Prepare();
-                    if (_child.IsFocused)
-                        FocusManager.Instance.Focus(null);
-                    _child.GotFocus += _child_GotFocus;
-                    _child.PlatformImpl.LostFocus += PlatformImpl_LostFocus;
-                    FixPosition();
-                    if(Focused)
-                        UnmanagedMethods.SetFocus(_child.PlatformImpl.Handle.Handle);
-                }
-            }
+            get { return (Avalonia.Controls.Control)_root.Content; }
+            set { _root.Content = value; }
         }
 
         void Unfocus()
@@ -54,7 +40,7 @@ namespace Avalonia.Win32.Embedding
             while (focused.VisualParent != null)
                 focused = focused.VisualParent;
 
-            if (focused == _child)
+            if (focused == _root)
                 KeyboardDevice.Instance.SetFocusedElement(null, NavigationMethod.Unspecified, InputModifiers.None);
         }
 
@@ -65,32 +51,30 @@ namespace Avalonia.Win32.Embedding
 
         protected override void Dispose(bool disposing)
         {
-            Child = null;
+            if (disposing)
+                _root.Dispose();
             base.Dispose(disposing);
         }
 
-        private void _child_GotFocus(object sender, Interactivity.RoutedEventArgs e)
+        private void RootGotFocus(object sender, Interactivity.RoutedEventArgs e)
         {
-            UnmanagedMethods.SetFocus(_child.PlatformImpl.Handle.Handle);
+            UnmanagedMethods.SetFocus(_root.PlatformImpl.Handle.Handle);
         }
 
         protected override void OnGotFocus(EventArgs e)
         {
-            if (_child != null)
-                UnmanagedMethods.SetFocus(_child.PlatformImpl.Handle.Handle);
+            if (_root != null)
+                UnmanagedMethods.SetFocus(_root.PlatformImpl.Handle.Handle);
         }
 
 
         void FixPosition()
         {
-            if (_child != null && Width > 0 && Height > 0)
-                UnmanagedMethods.MoveWindow(_child.PlatformImpl.Handle.Handle, 0, 0, Width, Height, true);
+            if (_root != null && Width > 0 && Height > 0)
+                UnmanagedMethods.MoveWindow(_root.PlatformImpl.Handle.Handle, 0, 0, Width, Height, true);
         }
 
-        public WinFormsAvaloniaControlHost()
-        {
-            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
-        }
+
 
         protected override void OnResize(EventArgs e)
         {
@@ -100,8 +84,7 @@ namespace Avalonia.Win32.Embedding
 
         protected override void OnPaint(PaintEventArgs e)
         {
-            if (Child == null)
-                base.OnPaint(e);
+
         }
     }
 }

+ 6 - 6
src/Windows/Avalonia.Win32/Embedding/WpfAvaloniaControlHost.cs

@@ -16,16 +16,16 @@ namespace Avalonia.Win32.Embedding
     public class WpfAvaloniaControlHost : HwndHost
     {
         private WinFormsAvaloniaControlHost _host;
-        private EmbeddableControl _child;
+        private Avalonia.Controls.Control _content;
 
-        public EmbeddableControl Child
+        public Avalonia.Controls.Control Content
         {
-            get { return _child; }
+            get { return _content; }
             set
             {
                 if (_host != null)
-                    _host.Child = value;
-                _child = value;
+                    _host.Content = value;
+                _content = value;
                 
             }
         }
@@ -39,7 +39,7 @@ namespace Avalonia.Win32.Embedding
         protected override HandleRef BuildWindowCore(HandleRef hwndParent)
         {
             DestroyHost();
-            _host = new WinFormsAvaloniaControlHost {Child = _child};
+            _host = new WinFormsAvaloniaControlHost {Content = _content};
             UnmanagedMethods.SetParent(_host.Handle, hwndParent.Handle);
             return new HandleRef(this, _host.Handle);
         }