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()); } }
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); } }
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()); }
/// <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()); }
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."); }
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()); }
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); } }
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); }
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); } }
/// <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)); }
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); } }
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); }
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); }
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()); }
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(); } } }