瀏覽代碼

Merge branch 'master' into feature/TabControlRework

Benedikt Schroeder 7 年之前
父節點
當前提交
4812dcb3ae

+ 1 - 1
packages.cake

@@ -303,7 +303,7 @@ public class Packages
                 {
                     new NuSpecContent { Source = "Avalonia.Android.dll", Target = "lib/MonoAndroid10" }
                 },
-                BasePath = context.Directory("./src/Android/Avalonia.Android/bin/" + parameters.DirSuffix + "/monoandroid44/"),
+                BasePath = context.Directory("./src/Android/Avalonia.Android/bin/" + parameters.DirSuffix + "/monoandroid44/MonoAndroid44/"),
                 OutputDirectory = parameters.NugetRoot
             },
             ///////////////////////////////////////////////////////////////////////////////

+ 3 - 0
readme.md

@@ -35,6 +35,9 @@ Install-Package Avalonia.Desktop
 Try out the latest build of Avalonia available for download here:
 https://ci.appveyor.com/project/AvaloniaUI/Avalonia/branch/master/artifacts
 
+or use nightly build feeds as described here:
+https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed
+
 ## Documentation
 
 As mentioned above, Avalonia is still in beta and as such there's not much documentation yet. You can take a look at the [getting started page](http://avaloniaui.net/docs/quickstart/) for an overview of how to get started but probably the best thing to do for now is to already know a little bit about WPF/Silverlight/UWP/XAML and ask questions in our [Gitter room](https://gitter.im/AvaloniaUI/Avalonia).

+ 7 - 0
src/Avalonia.Controls/Mixins/ContentControlMixin.cs

@@ -3,6 +3,7 @@
 
 using System;
 using System.Linq;
+using System.Reactive.Disposables;
 using System.Runtime.CompilerServices;
 using Avalonia.Collections;
 using Avalonia.Controls.Presenters;
@@ -75,6 +76,12 @@ namespace Avalonia.Controls.Mixins
                             null,
                             presenter.GetValue(ContentPresenter.ChildProperty));
 
+                        if (subscriptions.Value.TryGetValue(sender, out IDisposable previousSubscription))
+                        {
+                            subscription = new CompositeDisposable(previousSubscription, subscription);
+                            subscriptions.Value.Remove(sender);
+                        }
+
                         subscriptions.Value.Add(sender, subscription);
                     }
                 }

+ 106 - 0
tests/Avalonia.Controls.UnitTests/Mixins/ContentControlMixinTests.cs

@@ -0,0 +1,106 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Collections;
+using Avalonia.Controls.Mixins;
+using Avalonia.Controls.Presenters;
+using Avalonia.Controls.Primitives;
+using Avalonia.Controls.Templates;
+using Avalonia.LogicalTree;
+using Moq;
+using Xunit;
+
+namespace Avalonia.Controls.UnitTests.Mixins
+{
+    public class ContentControlMixinTests
+    {
+        [Fact]
+        public void Multiple_Mixin_Usages_Should_Not_Throw()
+        {
+            var target = new TestControl()
+            {
+                Template = new FuncControlTemplate(_ => new Panel
+                {
+                    Children =
+                    {
+                        new ContentPresenter { Name = "Content_1_Presenter" },
+                        new ContentPresenter { Name = "Content_2_Presenter" }
+                    }
+                })
+            };
+
+            var ex = Record.Exception(() => target.ApplyTemplate());
+
+            Assert.Null(ex);
+        }
+
+        [Fact]
+        public void Replacing_Template_Releases_Events()
+        {
+            var p1 = new ContentPresenter { Name = "Content_1_Presenter" };
+            var p2 = new ContentPresenter { Name = "Content_2_Presenter" };
+            var target = new TestControl
+            {
+                Template = new FuncControlTemplate(_ => new Panel
+                {
+                    Children =
+                    {
+                        p1,
+                        p2
+                    }
+                })
+            };
+            target.ApplyTemplate();
+
+            Control tc;
+
+            p1.Content = tc = new Control();
+            p1.UpdateChild();
+            Assert.Contains(tc, target.GetLogicalChildren());
+
+            p2.Content = tc = new Control();
+            p2.UpdateChild();
+            Assert.Contains(tc, target.GetLogicalChildren());
+
+            target.Template = null;
+
+            p1.Content = tc = new Control();
+            p1.UpdateChild();
+            Assert.DoesNotContain(tc, target.GetLogicalChildren());
+
+            p2.Content = tc = new Control();
+            p2.UpdateChild();
+            Assert.DoesNotContain(tc, target.GetLogicalChildren());
+
+        }
+
+        private class TestControl : TemplatedControl
+        {
+            public static readonly StyledProperty<object> Content1Property =
+                AvaloniaProperty.Register<TestControl, object>(nameof(Content1));
+
+            public static readonly StyledProperty<object> Content2Property =
+                AvaloniaProperty.Register<TestControl, object>(nameof(Content2));
+
+            static TestControl()
+            {
+                ContentControlMixin.Attach<TestControl>(Content1Property, x => x.LogicalChildren, "Content_1_Presenter");
+                ContentControlMixin.Attach<TestControl>(Content2Property, x => x.LogicalChildren, "Content_2_Presenter");
+            }
+
+            public object Content1
+            {
+                get { return GetValue(Content1Property); }
+                set { SetValue(Content1Property, value); }
+            }
+
+            public object Content2
+            {
+                get { return GetValue(Content2Property); }
+                set { SetValue(Content2Property, value); }
+            }
+        }
+    }
+}