BindingOperations.cs 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Linq;
  5. using System.Reactive.Disposables;
  6. using System.Reactive.Linq;
  7. namespace Avalonia.Data
  8. {
  9. public static class BindingOperations
  10. {
  11. /// <summary>
  12. /// Applies an <see cref="InstancedBinding"/> a property on an <see cref="IAvaloniaObject"/>.
  13. /// </summary>
  14. /// <param name="target">The target object.</param>
  15. /// <param name="property">The property to bind.</param>
  16. /// <param name="binding">The instanced binding.</param>
  17. /// <param name="anchor">
  18. /// An optional anchor from which to locate required context. When binding to objects that
  19. /// are not in the logical tree, certain types of binding need an anchor into the tree in
  20. /// order to locate named controls or resources. The <paramref name="anchor"/> parameter
  21. /// can be used to provide this context.
  22. /// </param>
  23. /// <returns>An <see cref="IDisposable"/> which can be used to cancel the binding.</returns>
  24. public static IDisposable Apply(
  25. IAvaloniaObject target,
  26. AvaloniaProperty property,
  27. InstancedBinding binding,
  28. object anchor)
  29. {
  30. Contract.Requires<ArgumentNullException>(target != null);
  31. Contract.Requires<ArgumentNullException>(property != null);
  32. Contract.Requires<ArgumentNullException>(binding != null);
  33. var mode = binding.Mode;
  34. if (mode == BindingMode.Default)
  35. {
  36. mode = property.GetMetadata(target.GetType()).DefaultBindingMode;
  37. }
  38. switch (mode)
  39. {
  40. case BindingMode.Default:
  41. case BindingMode.OneWay:
  42. return target.Bind(property, binding.Observable ?? binding.Subject, binding.Priority);
  43. case BindingMode.TwoWay:
  44. return new CompositeDisposable(
  45. target.Bind(property, binding.Subject, binding.Priority),
  46. target.GetObservable(property).Subscribe(binding.Subject));
  47. case BindingMode.OneTime:
  48. var source = binding.Subject ?? binding.Observable;
  49. if (source != null)
  50. {
  51. return source
  52. .Where(x => BindingNotification.ExtractValue(x) != AvaloniaProperty.UnsetValue)
  53. .Take(1)
  54. .Subscribe(x => target.SetValue(property, x, binding.Priority));
  55. }
  56. else
  57. {
  58. target.SetValue(property, binding.Value, binding.Priority);
  59. return Disposable.Empty;
  60. }
  61. case BindingMode.OneWayToSource:
  62. return target.GetObservable(property).Subscribe(binding.Subject);
  63. default:
  64. throw new ArgumentException("Invalid binding mode.");
  65. }
  66. }
  67. }
  68. }