Browse Source

Add initial AutoDataTemplateBindingHook implementation

pull/2560/head
artyom 7 years ago
parent
commit
fe7e7054fb
  1. 60
      src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs
  2. 56
      tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs

60
src/Avalonia.ReactiveUI/AutoDataTemplateBindingHook.cs

@ -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;
}
}
}

56
tests/Avalonia.ReactiveUI.UnitTests/AutoDataTemplateBindingHookTest.cs

@ -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…
Cancel
Save