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