2 changed files with 116 additions and 0 deletions
@ -0,0 +1,60 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using Avalonia.Markup.Xaml.Templates; |
|||
using ReactiveUI; |
|||
|
|||
namespace Avalonia.ReactiveUI |
|||
{ |
|||
/// <summary>
|
|||
/// AutoDataTemplateBindingHook is a binding hook that checks ItemsControls
|
|||
/// that don't have DataTemplates, and assigns a default DataTemplate that
|
|||
/// loads the View associated with each ViewModel.
|
|||
/// </summary>
|
|||
public class AutoDataTemplateBindingHook : IPropertyBindingHook |
|||
{ |
|||
private static Lazy<DataTemplate> DefaultItemTemplate { get; } = new Lazy<DataTemplate>(() => |
|||
{ |
|||
var template = @"
|
|||
<DataTemplate xmlns='https://github.com/avaloniaui'
|
|||
xmlns:reactiveUi='http://reactiveui.net'>
|
|||
<reactiveUi:ViewModelViewHost |
|||
ViewModel='{Binding Mode=OneWay}' |
|||
VerticalContentAlignment='Stretch' |
|||
HorizontalContentAlignment='Stretch' /> |
|||
</DataTemplate>";
|
|||
|
|||
var loader = new AvaloniaXamlLoader(); |
|||
return (DataTemplate)loader.Load(template); |
|||
}); |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool ExecuteHook( |
|||
object source, object target, |
|||
Func<IObservedChange<object, object>[]> getCurrentViewModelProperties, |
|||
Func<IObservedChange<object, object>[]> getCurrentViewProperties, |
|||
BindingDirection direction) |
|||
{ |
|||
var viewProperties = getCurrentViewProperties(); |
|||
var lastViewProperty = viewProperties.LastOrDefault(); |
|||
if (lastViewProperty == null) |
|||
return true; |
|||
|
|||
var itemsControl = lastViewProperty.Sender as ItemsControl; |
|||
if (itemsControl == null) |
|||
return true; |
|||
|
|||
var propertyName = viewProperties.Last().GetPropertyName(); |
|||
if (propertyName != "Items" && |
|||
propertyName != "ItemsSource") |
|||
return true; |
|||
|
|||
if (itemsControl.ItemTemplate != null) |
|||
return true; |
|||
|
|||
itemsControl.ItemTemplate = DefaultItemTemplate.Value; |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
// 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 Xunit; |
|||
using ReactiveUI; |
|||
using Avalonia.ReactiveUI; |
|||
using Avalonia.UnitTests; |
|||
using Avalonia.Controls; |
|||
using System.Collections.Generic; |
|||
using System.Collections.ObjectModel; |
|||
using System.Linq; |
|||
using Splat; |
|||
|
|||
namespace Avalonia.ReactiveUI.UnitTests |
|||
{ |
|||
public class AutoDataTemplateBindingHookTest |
|||
{ |
|||
public class NestedViewModel : ReactiveObject { } |
|||
|
|||
public class NestedView : ReactiveUserControl<NestedViewModel> { } |
|||
|
|||
public class ExampleViewModel : ReactiveObject |
|||
{ |
|||
public ObservableCollection<NestedViewModel> Items { get; } = new ObservableCollection<NestedViewModel>(); |
|||
} |
|||
|
|||
public class ExampleView : ReactiveUserControl<ExampleViewModel> |
|||
{ |
|||
public ListBox List { get; } = new ListBox(); |
|||
|
|||
public ExampleView() |
|||
{ |
|||
Content = List; |
|||
ViewModel = new ExampleViewModel(); |
|||
this.OneWayBind(ViewModel, x => x.Items, x => x.List.Items); |
|||
} |
|||
} |
|||
|
|||
public AutoDataTemplateBindingHookTest() |
|||
{ |
|||
Locator.CurrentMutable.RegisterConstant(new AutoDataTemplateBindingHook(), typeof(IPropertyBindingHook)); |
|||
Locator.CurrentMutable.Register(() => new ExampleView(), typeof(IViewFor<ExampleViewModel>)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Apply_Data_Template_Binding_When_No_Template_Is_Set() |
|||
{ |
|||
var view = new ExampleView(); |
|||
var root = new TestRoot |
|||
{ |
|||
Child = view |
|||
}; |
|||
Assert.NotNull(view.List.ItemTemplate); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue