// 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 System;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
namespace Avalonia.Data
{
public static class BindingOperations
{
///
/// Applies an a property on an .
///
/// The target object.
/// The property to bind.
/// The instanced binding.
///
/// An optional anchor from which to locate required context. When binding to objects that
/// are not in the logical tree, certain types of binding need an anchor into the tree in
/// order to locate named controls or resources. The parameter
/// can be used to provide this context.
///
/// An which can be used to cancel the binding.
public static IDisposable Apply(
IAvaloniaObject target,
AvaloniaProperty property,
InstancedBinding binding,
object anchor)
{
Contract.Requires(target != null);
Contract.Requires(property != null);
Contract.Requires(binding != null);
var mode = binding.Mode;
if (mode == BindingMode.Default)
{
mode = property.GetMetadata(target.GetType()).DefaultBindingMode;
}
switch (mode)
{
case BindingMode.Default:
case BindingMode.OneWay:
return target.Bind(property, binding.Observable ?? binding.Subject, binding.Priority);
case BindingMode.TwoWay:
return new CompositeDisposable(
target.Bind(property, binding.Subject, binding.Priority),
target.GetObservable(property).Subscribe(binding.Subject));
case BindingMode.OneTime:
var source = binding.Subject ?? binding.Observable;
if (source != null)
{
return source
.Where(x => BindingNotification.ExtractValue(x) != AvaloniaProperty.UnsetValue)
.Take(1)
.Subscribe(x => target.SetValue(property, x, binding.Priority));
}
else
{
target.SetValue(property, binding.Value, binding.Priority);
return Disposable.Empty;
}
case BindingMode.OneWayToSource:
return target.GetObservable(property).Subscribe(binding.Subject);
default:
throw new ArgumentException("Invalid binding mode.");
}
}
}
}