Пример #1
0
        public void StyleResource_Can_Be_Assigned_To_StyleResource_Property()
        {
            using (UnitTestApplication.Start(TestServices.StyledWindow))
            {
                var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
        xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
    <Window.Styles>
        <Style>
            <Style.Resources>
                <Color x:Key='color'>#ff506070</Color>
                <SolidColorBrush x:Key='brush' Color='{StyleResource color}'/>
            </Style.Resources>
        </Style>
    </Window.Styles>
    <Button Name='button' Background='{StyleResource brush}'/>
</Window>";

                var loader = new AvaloniaXamlLoader();
                var window = (Window)loader.Load(xaml);
                var brush  = (ISolidColorBrush)window.FindStyleResource("brush");
                var button = window.FindControl <Button>("button");

                DelayedBinding.ApplyBindings(button);

                var buttonBrush = (ISolidColorBrush)button.Background;

                Assert.Equal(0xff506070, brush.Color.ToUint32());
                Assert.Equal(0xff506070, buttonBrush.Color.ToUint32());
            }
        }
Пример #2
0
        public void Xaml_Binding_Is_Delayed()
        {
            if (!AvaloniaXamlLoader.UseLegacyXamlLoader)
            {
                return;
            }

            using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
            {
                var xaml =
                    @"<ContentControl xmlns='https://github.com/avaloniaui' Content='{Binding}'/>";

                var target = AvaloniaXamlLoader.Parse <ContentControl>(xaml);

                Assert.Null(target.Content);

                target.DataContext = "Foo";

                Assert.Null(target.Content);

                DelayedBinding.ApplyBindings(target);

                Assert.Equal("Foo", target.Content);
            }
        }
Пример #3
0
        public void Control_Property_Is_Updated_When_Parent_Is_Changed()
        {
            var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
    <UserControl.Resources>
        <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
    </UserControl.Resources>

    <Border Name='border' Background='{DynamicResource brush}'/>
</UserControl>";

            var loader      = new AvaloniaXamlLoader();
            var userControl = (UserControl)loader.Load(xaml);
            var border      = userControl.FindControl <Border>("border");

            DelayedBinding.ApplyBindings(border);

            var brush = (SolidColorBrush)border.Background;

            Assert.Equal(0xff506070, brush.Color.ToUint32());

            userControl.Content = null;

            Assert.Null(border.Background);

            userControl.Content = border;

            brush = (SolidColorBrush)border.Background;
            Assert.Equal(0xff506070, brush.Color.ToUint32());
        }
        public void DynamicResource_Tracks_Added_Style_MergedResource_Dictionary()
        {
            var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
    <UserControl.Styles>
        <Style>
        </Style>
    </UserControl.Styles>
    <Border Name='border' Background='{DynamicResource brush}'/>
</UserControl>";

            var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
            var border      = userControl.FindControl <Border>("border");

            DelayedBinding.ApplyBindings(border);

            Assert.Null(border.Background);

            var dictionary = new ResourceDictionary
            {
                { "brush", new SolidColorBrush(0xff506070) },
            };

            ((Style)userControl.Styles[0]).Resources.MergedDictionaries.Add(dictionary);

            var brush = (SolidColorBrush)border.Background;

            Assert.NotNull(brush);
            Assert.Equal(0xff506070, brush.Color.ToUint32());
        }
Пример #5
0
        /// <summary>
        /// Loads XAML from a stream.
        /// </summary>
        /// <param name="stream">The stream containing the XAML.</param>
        /// <param name="localAssembly">Default assembly for clr-namespace</param>
        /// <param name="rootInstance">
        /// The optional instance into which the XAML should be loaded.
        /// </param>
        /// <param name="uri">The URI of the XAML</param>
        /// <returns>The loaded object.</returns>
        public object Load(Stream stream, Assembly localAssembly, object rootInstance = null, Uri uri = null)
        {
            var readerSettings = new XamlXmlReaderSettings()
            {
                BaseUri         = uri,
                LocalAssembly   = localAssembly,
                ProvideLineInfo = true,
            };

            var context = IsDesignMode ? AvaloniaXamlSchemaContext.DesignInstance : AvaloniaXamlSchemaContext.Instance;
            var reader  = new XamlXmlReader(stream, context, readerSettings);

            object result = LoadFromReader(
                reader,
                AvaloniaXamlContext.For(readerSettings, rootInstance));

            var topLevel = result as TopLevel;

            if (topLevel != null)
            {
                DelayedBinding.ApplyBindings(topLevel);
            }

            return(result);
        }
        public void Control_Property_Is_Updated_When_Parent_Is_Changed()
        {
            using (StyledWindow())
            {
                var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
    <Window.Resources>
        <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
    </Window.Resources>

    <Border Name='border' Background='{DynamicResource brush}'/>
</Window>";

                var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
                var border = window.FindControl <Border>("border");

                DelayedBinding.ApplyBindings(border);

                var brush = (ISolidColorBrush)border.Background;
                Assert.Equal(0xff506070, brush.Color.ToUint32());

                window.Content = null;

                Assert.Null(border.Background);

                window.Content = border;

                brush = (ISolidColorBrush)border.Background;
                Assert.Equal(0xff506070, brush.Color.ToUint32());
            }
        }
        public void ResolvesStreamObservableBindingCorrectly()
        {
            using (UnitTestApplication.Start(TestServices.StyledWindow))
            {
                var xaml      = @"
<Window xmlns='https://github.com/avaloniaui'
        xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
        xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
        x:DataType='local:TestDataContext'>
    <TextBlock Text='{CompiledBinding ObservableProperty^}' Name='textBlock' />
</Window>";
                var window    = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
                var textBlock = window.FindControl <TextBlock>("textBlock");

                DelayedBinding.ApplyBindings(textBlock);

                var subject     = new Subject <string>();
                var dataContext = new TestDataContext
                {
                    ObservableProperty = subject
                };

                window.DataContext = dataContext;

                subject.OnNext("foobar");

                Assert.Equal("foobar", textBlock.Text);
            }
        }
        public void DynamicResource_From_MergedDictionary_Can_Be_Assigned_To_Property()
        {
            var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>

    <Border Name='border' Background='{DynamicResource brush}'/>
</UserControl>";

            var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
            var border      = userControl.FindControl <Border>("border");

            DelayedBinding.ApplyBindings(border);

            var brush = (ISolidColorBrush)border.Background;

            Assert.Equal(0xff506070, brush.Color.ToUint32());
        }
Пример #9
0
        public void StyleResource_Can_Be_Assigned_To_Property()
        {
            var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
    <UserControl.Styles>
        <Style>
            <Style.Resources>
                <SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush>
            </Style.Resources>
        </Style>
    </UserControl.Styles>

    <Border Name='border' Background='{StyleResource brush}'/>
</UserControl>";

            var loader      = new AvaloniaXamlLoader();
            var userControl = (UserControl)loader.Load(xaml);
            var border      = userControl.FindControl <Border>("border");

            DelayedBinding.ApplyBindings(border);

            var brush = (SolidColorBrush)border.Background;

            Assert.Equal(0xff506070, brush.Color.ToUint32());
        }
        public object ProvideValue(IServiceProvider serviceProvider)
        {
            var stack         = serviceProvider.GetService <IAvaloniaXamlIlParentStackProvider>();
            var provideTarget = serviceProvider.GetService <IProvideValueTarget>();

            var targetType = provideTarget.TargetProperty switch
            {
                AvaloniaProperty ap => ap.PropertyType,
                PropertyInfo pi => pi.PropertyType,
                _ => null,
            };

            if (provideTarget.TargetObject is Setter setter)
            {
                targetType = setter.Property.PropertyType;
            }

            var previousWasControlTheme = false;

            // Look upwards though the ambient context for IResourceNodes
            // which might be able to give us the resource.
            foreach (var parent in stack.Parents)
            {
                if (parent is IResourceNode node && node.TryGetResource(ResourceKey, out var value))
                {
                    return(ColorToBrushConverter.Convert(value, targetType));
                }

                // HACK: Temporary fix for #8678. Hard-coded to only work for the DevTools main
                // window as we don't want 3rd parties to start relying on this hack.
                //
                // We need to implement compile-time merging of resource dictionaries and this
                // hack can be removed.
                if (previousWasControlTheme &&
                    parent is ResourceDictionary hack &&
                    hack.Owner?.GetType().FullName == "Avalonia.Diagnostics.Views.MainWindow" &&
                    hack.Owner.TryGetResource(ResourceKey, out value))
                {
                    return(ColorToBrushConverter.Convert(value, targetType));
                }

                previousWasControlTheme = parent is ControlTheme;
            }

            if (provideTarget.TargetObject is IControl target &&
                provideTarget.TargetProperty is PropertyInfo property)
            {
                // This is stored locally to avoid allocating closure in the outer scope.
                var localTargetType = targetType;
                var localInstance   = this;

                DelayedBinding.Add(target, property, x => localInstance.GetValue(x, localTargetType));
                return(AvaloniaProperty.UnsetValue);
            }

            throw new KeyNotFoundException($"Static resource '{ResourceKey}' not found.");
        }
Пример #11
0
        public void Binding_ContentTemplate_After_Content_Does_Not_Leave_Orpaned_TextBlock()
        {
            // Test for #1271.
            var children  = new List <IControl>();
            var presenter = new ContentPresenter();

            // The content and then the content template property need to be bound with delayed bindings
            // as they are in Avalonia.Markup.Xaml.
            DelayedBinding.Add(presenter, ContentPresenter.ContentProperty, new Binding("Content")
            {
                Priority       = BindingPriority.TemplatedParent,
                RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
            });

            DelayedBinding.Add(presenter, ContentPresenter.ContentTemplateProperty, new Binding("ContentTemplate")
            {
                Priority       = BindingPriority.TemplatedParent,
                RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
            });

            presenter.GetObservable(ContentPresenter.ChildProperty).Subscribe(children.Add);

            var target = new ContentControl
            {
                Template        = new FuncControlTemplate <ContentControl>(_ => presenter),
                ContentTemplate = new FuncDataTemplate <string>(x => new Canvas()),
                Content         = "foo",
            };

            // The control must be rooted.
            var root = new TestRoot
            {
                Child = target,
            };

            target.ApplyTemplate();

            // When the template is applied, the Content property is bound before the ContentTemplate
            // property, causing a TextBlock to be created by the default template before ContentTemplate
            // is bound.
            Assert.Collection(
                children,
                x => Assert.Null(x),
                x => Assert.IsType <TextBlock>(x),
                x => Assert.IsType <Canvas>(x));

            var textBlock = (TextBlock)children[1];

            // The leak in #1271 was caused by the TextBlock's logical parent not being cleared when
            // it is replaced by the Canvas.
            Assert.Null(textBlock.GetLogicalParent());
        }
Пример #12
0
            private void ApplyBinding(IAvaloniaObject obj, IBinding binding)
            {
                var control  = obj as IControl;
                var property = Property;

                if (control != null && property != Control.DataContextProperty)
                {
                    DelayedBinding.Add(control, property, binding);
                }
                else
                {
                    obj.Bind(property, binding);
                }
            }
Пример #13
0
        private static bool ApplyBinding(
            object instance,
            AvaloniaProperty property,
            IValueContext context,
            IBinding binding)
        {
            if (property == null)
            {
                return(false);
            }

            var control = instance as IControl;

            if (control != null)
            {
                if (property != Control.DataContextProperty)
                {
                    DelayedBinding.Add(control, property, binding);
                }
                else
                {
                    control.Bind(property, binding);
                }
            }
            else
            {
                // The target is not a control, so we need to find an anchor that will let us look
                // up named controls and style resources. First look for the closest IControl in
                // the TopDownValueContext.
                object anchor = context.TopDownValueContext.StoredInstances
                                .Select(x => x.Instance)
                                .OfType <IControl>()
                                .LastOrDefault();

                // If a control was not found, then try to find the highest-level style as the XAML
                // file could be a XAML file containing only styles.
                if (anchor == null)
                {
                    anchor = context.TopDownValueContext.StoredInstances
                             .Select(x => x.Instance)
                             .OfType <IStyle>()
                             .FirstOrDefault();
                }

                ((IAvaloniaObject)instance).Bind(property, binding, anchor);
            }

            return(true);
        }
Пример #14
0
        public void MergedDictionary_Resource_With_DynamicResource_Is_Updated_When_Added_To_Parent()
        {
            var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <SolidColorBrush x:Key='brush' Color='{DynamicResource color}'/>
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>

    <Border Name='border' Background='{DynamicResource brush}'/>
</UserControl>";

            var loader      = new AvaloniaXamlLoader();
            var userControl = (UserControl)loader.Load(xaml);
            var border      = userControl.FindControl <Border>("border");

            DelayedBinding.ApplyBindings(border);

            var brush = (SolidColorBrush)border.Background;

            Assert.Equal(0u, brush.Color.ToUint32());

            brush.GetObservable(SolidColorBrush.ColorProperty).Subscribe(_ => { });

            using (UnitTestApplication.Start(TestServices.StyledWindow))
            {
                var window = new Window
                {
                    Resources =
                    {
                        { "color", Colors.Red }
                    },
                    Content = userControl,
                };

                window.Show();

                Assert.Equal(Colors.Red, brush.Color);
            }
        }
Пример #15
0
        /// <summary>
        /// Loads XAML from a stream.
        /// </summary>
        /// <param name="stream">The stream containing the XAML.</param>
        /// <param name="rootInstance">
        /// The optional instance into which the XAML should be loaded.
        /// </param>
        /// <returns>The loaded object.</returns>
        public object Load(Stream stream, object rootInstance = null)
        {
            var result = base.Load(stream, new Settings
            {
                RootInstance = rootInstance,
                InstanceLifeCycleListener = s_lifeCycleListener,
            });

            var topLevel = result as TopLevel;

            if (topLevel != null)
            {
                DelayedBinding.ApplyBindings(topLevel);
            }

            return(result);
        }
        public void DynamicResource_Can_Be_Assigned_To_Attached_Property()
        {
            var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
    <UserControl.Resources>
        <x:Int32 x:Key='col'>5</x:Int32>
    </UserControl.Resources>

    <Border Name='border' Grid.Column='{DynamicResource col}'/>
</UserControl>";

            var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
            var border      = userControl.FindControl <Border>("border");

            DelayedBinding.ApplyBindings(border);

            Assert.Equal(5, Grid.GetColumn(border));
        }
Пример #17
0
            private void ApplyBinding(IAvaloniaObject obj, IBinding binding)
            {
                var control     = obj as IControl;
                var property    = Property;
                var xamlBinding = binding as XamlBinding;

                if (control != null && property != Control.DataContextProperty)
                {
                    DelayedBinding.Add(control, property, binding);
                }
                else if (xamlBinding != null)
                {
                    obj.Bind(property, xamlBinding.Value, xamlBinding.Anchor?.Target);
                }
                else
                {
                    obj.Bind(property, binding);
                }
            }
Пример #18
0
        public void Binding_With_DelayedBinding_And_Initialization_Where_DataContext_Is_Root_Works()
        {
            // Test for #1932.
            var root = new RootWithItems();

            root.BeginInit();
            root.DataContext = root;

            var target = new ListBox();

            target.BeginInit();
            root.Child = target;

            DelayedBinding.Add(target, ItemsControl.ItemsProperty, new Binding(nameof(RootWithItems.Items)));
            DelayedBinding.Add(target, ListBox.SelectedItemProperty, new Binding(nameof(RootWithItems.Selected)));
            target.EndInit();
            root.EndInit();

            Assert.Equal("b", target.SelectedItem);
        }
        public void DynamicResource_Can_Be_Assigned_To_ItemTemplate_Property()
        {
            var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
    <UserControl.Resources>
        <DataTemplate x:Key='PurpleData'>
          <TextBlock Text='{Binding Name}' Background='Purple'/>
        </DataTemplate>
    </UserControl.Resources>

    <ListBox Name='listBox' ItemTemplate='{DynamicResource PurpleData}'/>
</UserControl>";

            var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
            var listBox     = userControl.FindControl <ListBox>("listBox");

            DelayedBinding.ApplyBindings(listBox);

            Assert.NotNull(listBox.ItemTemplate);
        }
Пример #20
0
        public object ProvideValue(IServiceProvider serviceProvider)
        {
            var stack         = serviceProvider.GetService <IAvaloniaXamlIlParentStackProvider>();
            var provideTarget = serviceProvider.GetService <IProvideValueTarget>();

            var targetType = provideTarget.TargetProperty switch
            {
                AvaloniaProperty ap => ap.PropertyType,
                PropertyInfo pi => pi.PropertyType,
                _ => null,
            };

            if (provideTarget.TargetObject is Setter setter)
            {
                targetType = setter.Property.PropertyType;
            }

            // Look upwards though the ambient context for IResourceNodes
            // which might be able to give us the resource.
            foreach (var parent in stack.Parents)
            {
                if (parent is IResourceNode node && node.TryGetResource(ResourceKey, out var value))
                {
                    return(ColorToBrushConverter.Convert(value, targetType));
                }
            }

            if (provideTarget.TargetObject is IControl target &&
                provideTarget.TargetProperty is PropertyInfo property)
            {
                // This is stored locally to avoid allocating closure in the outer scope.
                var localTargetType = targetType;
                var localInstance   = this;

                DelayedBinding.Add(target, property, x => localInstance.GetValue(x, localTargetType));
                return(AvaloniaProperty.UnsetValue);
            }

            throw new KeyNotFoundException($"Static resource '{ResourceKey}' not found.");
        }
        /// <summary>
        /// Loads XAML from a stream.
        /// </summary>
        /// <param name="stream">The stream containing the XAML.</param>
        /// <param name="rootInstance">
        /// The optional instance into which the XAML should be loaded.
        /// </param>
        /// <param name="uri">The URI of the XAML</param>
        /// <returns>The loaded object.</returns>
        public object Load(Stream stream, object rootInstance = null, Uri uri = null)
        {
            var readerSettings = new XamlXmlReaderSettings()
            {
                BaseUri       = uri,
                LocalAssembly = rootInstance?.GetType().GetTypeInfo().Assembly
            };

            var reader = new XamlXmlReader(stream, _context, readerSettings);

            object result = LoadFromReader(
                reader,
                AvaloniaXamlContext.For(readerSettings, rootInstance));

            var topLevel = result as TopLevel;

            if (topLevel != null)
            {
                DelayedBinding.ApplyBindings(topLevel);
            }

            return(result);
        }
Пример #22
0
        public void DynamicResource_Tracks_Added_Style_Resource()
        {
            var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
             xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
    <Border Name='border' Background='{DynamicResource brush}'/>
</UserControl>";

            var loader      = new AvaloniaXamlLoader();
            var userControl = (UserControl)loader.Load(xaml);
            var border      = userControl.FindControl <Border>("border");

            DelayedBinding.ApplyBindings(border);

            Assert.Null(border.Background);

            userControl.Styles.Resources.Add("brush", new SolidColorBrush(0xff506070));

            var brush = (SolidColorBrush)border.Background;

            Assert.NotNull(brush);
            Assert.Equal(0xff506070, brush.Color.ToUint32());
        }
Пример #23
0
        public object ProvideValue(IServiceProvider serviceProvider)
        {
            // Look upwards though the ambient context for IResourceProviders which might be able
            // to give us the resource.
            foreach (var resourceProvider in serviceProvider.GetParents <IResourceNode>())
            {
                if (resourceProvider.TryGetResource(ResourceKey, out var value))
                {
                    return(value);
                }
            }

            // The resource still hasn't been found, so add a delayed one-time binding.
            var provideTarget = serviceProvider.GetService <IProvideValueTarget>();

            if (provideTarget.TargetObject is IControl target &&
                provideTarget.TargetProperty is PropertyInfo property)
            {
                DelayedBinding.Add(target, property, GetValue);
                return(AvaloniaProperty.UnsetValue);
            }

            throw new KeyNotFoundException($"Static resource '{ResourceKey}' not found.");
        }
        /// <summary>
        /// Loads XAML from a stream.
        /// </summary>
        /// <param name="stream">The stream containing the XAML.</param>
        /// <param name="rootInstance">
        /// The optional instance into which the XAML should be loaded.
        /// </param>
        /// <param name="uri">The URI of the XAML</param>
        /// <returns>The loaded object.</returns>
        public object Load(Stream stream, object rootInstance = null, Uri uri = null)
        {
            try
            {
                if (uri != null)
                {
                    s_uriStack.Push(uri);
                }

                var result = base.Load(stream, new Settings
                {
                    RootInstance = rootInstance,
                    InstanceLifeCycleListener = s_lifeCycleListener,
                    ParsingContext            = new Dictionary <string, object>
                    {
                        { "Uri", uri }
                    }
                });

                var topLevel = result as TopLevel;

                if (topLevel != null)
                {
                    DelayedBinding.ApplyBindings(topLevel);
                }

                return(result);
            }
            finally
            {
                if (uri != null)
                {
                    s_uriStack.Pop();
                }
            }
        }