Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update BindableObject API docs #17099

Merged
merged 2 commits into from
Aug 31, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 128 additions & 22 deletions src/Controls/src/Core/BindableObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,24 @@

namespace Microsoft.Maui.Controls
{
/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="Type[@FullName='Microsoft.Maui.Controls.BindableObject']/Docs/*" />
/// <summary>
/// Provides a mechanism by which application developers can propagate changes that are made to data in one object to another, by enabling validation, type coercion, and an event system.
jfversluis marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
/// <remarks>The <see cref="BindableObject" /> class provides a data storage mechanism that enables the application developer to synchronize data between objects in response to changes, for example, between the View and View Model in the MVVM design pattern. All of the visual elements in the <c>Microsoft.Maui.Controls</c> namespace inherit from <see cref="BindableObject" /> class, so they can all be used to bind the data behind their user interface elements to View Models that are supplied by the application developer.</remarks>
jfversluis marked this conversation as resolved.
Show resolved Hide resolved
public abstract class BindableObject : INotifyPropertyChanged, IDynamicResourceHandler
{
IDispatcher _dispatcher;

// return the dispatcher that was available when this was created,
// otherwise try to find the nearest dispatcher (probably the window/app)
/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='Dispatcher']/Docs/*" />
/// <summary>
/// Gets the dispatcher that was available when this was created,
/// otherwise tries to find the nearest available dispatcher (probably the Window/App one).
jfversluis marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
public IDispatcher Dispatcher =>
_dispatcher ??= this.FindDispatcher();

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='.ctor']/Docs/*" />
/// <summary>
/// Initializes a new instance of the <see cref="BindableObject"/> class.
/// </summary>
public BindableObject()
{
// try use the current thread's dispatcher
Expand All @@ -38,18 +44,37 @@ public BindableObject()
BindableProperty.Create(nameof(BindingContext), typeof(object), typeof(BindableObject), default(object),
BindingMode.OneWay, null, BindingContextPropertyChanged, null, null, BindingContextPropertyBindingChanging);

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='BindingContext']/Docs/*" />
/// <summary>
/// Gets or sets an object that contains the properties that will be targeted by the bound properties that belong to this <see cref="BindableObject" />.
/// This is a bindable property.
/// </summary>
public object BindingContext
{
get => _inheritedContext?.Target ?? GetValue(BindingContextProperty);
set => SetValue(BindingContextProperty, value);
}

/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;

/// <summary>
/// Occurs when a property value is changing.
/// </summary>
public event PropertyChangingEventHandler PropertyChanging;

/// <summary>
/// Occurs when the value of the <see cref="BindingContext"/> property changes.
/// </summary>
public event EventHandler BindingContextChanged;

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='ClearValue'][1]/Docs/*" />
/// <summary>
/// Clears any value that is previously set for a bindable property.
/// </summary>
/// <param name="property">The <see cref="BindableProperty"/> to clear the value for.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="property"/> is <see langword="null"/>.</exception>
/// <remarks>When <paramref name="property"/> is read-only, nothing will happen.</remarks>
public void ClearValue(BindableProperty property)
{
if (property == null)
Expand Down Expand Up @@ -78,7 +103,12 @@ internal void ClearValue(BindableProperty property, SetterSpecificity specificit
ClearValueCore(property, specificity);
}

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='ClearValue'][2]/Docs/*" />
/// <summary>
/// Clears any value that is previously set for a bindable property, identified by its key.
/// </summary>
/// <param name="propertyKey">The key that identifies the bindable property to clear the value for.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="propertyKey"/> is <see langword="null"/>.</exception>
/// <exception cref="InvalidOperationException">Thrown when <paramref name="propertyKey"/> is a read-only property.</exception>
public void ClearValue(BindablePropertyKey propertyKey)
{
if (propertyKey == null)
Expand Down Expand Up @@ -108,11 +138,19 @@ void ClearValueCore(BindableProperty property, SetterSpecificity specificity)
OnPropertyChanged(property.PropertyName);
property.PropertyChanged?.Invoke(this, original, newValue);
}


}

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='GetValue']/Docs/*" />
/// <summary>
/// Returns the value that is contained in the given bindable property.
/// </summary>
/// <param name="property">The bindable property for which to get the value.</param>
/// <returns>The value that is contained in the <see cref="BindableProperty" />.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="property"/> is <see langword="null"/>.</exception>
/// <remarks>
/// <see cref="GetValue(BindableProperty)" /> and <see cref="SetValue(BindableProperty, object)" /> are used to access the values of properties that are implemented by a <see cref="BindableProperty" />.
/// That is, application developers typically provide an interface for a bound property by defining a <see langword="public" /> property whose <see langword="get" /> accessor casts the result of <see cref="GetValue(BindableProperty)" /> to the appropriate type and returns it, and whose <see langword="set" /> accessor uses <see cref="SetValue(BindableProperty, object)" /> to set the value on the correct property.
/// Application developers should perform no other steps in the public property that defines the interface of the bound property.
/// </remarks>
public object GetValue(BindableProperty property)
{
if (property == null)
Expand Down Expand Up @@ -188,7 +226,12 @@ internal LocalValueEntry(BindableProperty property, object value, BindableContex
return resultArray;
}

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='IsSet']/Docs/*" />
/// <summary>
/// Determines whether or not a bindable property exists and has a value set.
/// </summary>
/// <param name="targetProperty">The bindable property to check if a value is currently set.</param>
/// <returns><see langword="true"/> if the target property exists and has been set. Otherwise <see langword="false"/>.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="targetProperty"/> is <see langword="null"/>.</exception>
public bool IsSet(BindableProperty targetProperty)
{
var bpcontext = GetContext(targetProperty ?? throw new ArgumentNullException(nameof(targetProperty)));
Expand All @@ -200,7 +243,12 @@ public bool IsSet(BindableProperty targetProperty)
}


/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='RemoveBinding']/Docs/*" />
/// <summary>
/// Removes a previously set binding from a bindable property.
/// </summary>
/// <param name="property">The bindable property from which to remove bindings.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="property"/> is <see langword="null"/>.</exception>
/// <remarks>When <paramref name="property" /> is not currently bound, nothing will happen.</remarks>
public void RemoveBinding(BindableProperty property)
{
BindablePropertyContext context = GetContext(property ?? throw new ArgumentNullException(nameof(property)));
Expand All @@ -209,7 +257,11 @@ public void RemoveBinding(BindableProperty property)
RemoveBinding(property, context);
}

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='SetBinding']/Docs/*" />
/// <summary>
/// Assigns a binding to a bindable property.
/// </summary>
/// <param name="targetProperty">The bindable property on which to apply <paramref name="binding"/>.</param>
/// <param name="binding">The binding to set for <paramref name="targetProperty"/>.</param>
public void SetBinding(BindableProperty targetProperty, BindingBase binding)
=> SetBinding(targetProperty, binding, SetterSpecificity.FromBinding);

Expand Down Expand Up @@ -245,7 +297,12 @@ internal void SetBinding(BindableProperty targetProperty, BindingBase binding, S
binding.Apply(BindingContext, this, targetProperty, false, specificity);
}

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='SetInheritedBindingContext']/Docs/*" />
/// <summary>
/// Sets the inherited context to a nested element.
/// </summary>
/// <param name="bindable">The object on which to set the inherited binding context.</param>
/// <param name="value">The inherited context to set.</param>
/// <remarks>For internal use only. This API can be changed or removed without notice at any time.</remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public static void SetInheritedBindingContext(BindableObject bindable, object value)
{
Expand Down Expand Up @@ -276,8 +333,14 @@ public static void SetInheritedBindingContext(BindableObject bindable, object va
bindable.OnBindingContextChanged();
}

/// <summary>
/// Applies all the current bindings to <see cref="BindingContext" />.
/// </summary>
protected void ApplyBindings() => ApplyBindings(skipBindingContext: false, fromBindingContextChanged: false);

/// <summary>
/// Raises the <see cref="BindingContextChanged"/> event.
/// </summary>
protected virtual void OnBindingContextChanged()
{
BindingContextChanged?.Invoke(this, EventArgs.Empty);
Expand All @@ -289,12 +352,23 @@ protected virtual void OnBindingContextChanged()
SetInheritedBindingContext(searchHandler, BindingContext);
}

/// <summary>
/// Raises the <see cref="PropertyChanged"/> event.
/// </summary>
/// <param name="propertyName">The name of the property that has changed.</param>
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

/// <summary>
/// Raises the <see cref="PropertyChanging"/> event.
/// </summary>
/// <param name="propertyName">The name of the property that is changing.</param>
protected virtual void OnPropertyChanging([CallerMemberName] string propertyName = null)
=> PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));

/// <summary>
/// This method removes all current bindings from the current context.
jfversluis marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
protected void UnapplyBindings()
{
foreach (var context in _properties.Values)
Expand Down Expand Up @@ -350,7 +424,13 @@ internal void SetDynamicResource(BindableProperty property, string key, SetterSp
OnSetDynamicResource(property, key, specificity);
}

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='SetValue'][1]/Docs/*" />
/// <summary>
/// Sets the value of the specified bindable property.
/// </summary>
/// <param name="property">The bindable property on which to assign a value.</param>
/// <param name="value">The value to set.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="property"/> is <see langword="null"/>.</exception>
/// <remarks>If <paramref name="property"/> is read-only, nothing will happen.</remarks>
public void SetValue(BindableProperty property, object value)
{
if (property == null)
Expand All @@ -364,14 +444,18 @@ public void SetValue(BindableProperty property, object value)
SetValueCore(property, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource, SetValuePrivateFlags.Default, SetterSpecificity.ManualValueSetter);
}

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='SetValue'][2]/Docs/*" />
/// <summary>
/// Sets the value of the specified bindable property.
/// </summary>
/// <param name="propertyKey">The key that identifies the bindable property to assign the value to.</param>
/// <param name="value">The value to set.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="propertyKey"/> is <see langword="null"/>.</exception>
/// <exception cref="InvalidOperationException">Thrown when the bindable property identified by <paramref name="propertyKey"/> is read-only.</exception>
public void SetValue(BindablePropertyKey propertyKey, object value)
{
if (propertyKey == null)
throw new ArgumentNullException(nameof(propertyKey));

if (propertyKey == null)
throw new ArgumentNullException(nameof(propertyKey));
SetValueCore(propertyKey.BindableProperty, value, SetValueFlags.ClearOneWayBindings | SetValueFlags.ClearDynamicResource, SetValuePrivateFlags.Default, SetterSpecificity.ManualValueSetter);
}

Expand All @@ -398,7 +482,13 @@ internal void SetValue(BindablePropertyKey propertyKey, object value, SetterSpec

}

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='SetValueCore']/Docs/*" />
/// <summary>
/// Method for internal use to set the value of the specified property.
/// </summary>
/// <param name="property">The bindable property to assign a value to.</param>
/// <param name="value">The value to set.</param>
/// <param name="attributes">The flags that are applied for setting this value.</param>
/// <remarks>For internal use only. This API can be changed or removed without notice at any time.</remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("go away")]
internal void SetValueCore(BindableProperty property, object value, SetValueFlags attributes = SetValueFlags.None)
Expand Down Expand Up @@ -588,10 +678,26 @@ void RemoveBinding(BindableProperty property, BindablePropertyContext context)
context.Binding = null;
}

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='CoerceValue'][1]/Docs/*" />
/// <summary>
/// Coerces the value of the specified bindable property.
/// This is done by invoking <see cref="BindableProperty.CoerceValueDelegate"/> of the specified bindable property.
/// </summary>
/// <param name="property">The bindable property to coerce the value of.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="property"/> is <see langword="null"/>.</exception>
/// <exception cref="InvalidOperationException">Thrown when <paramref name="property"/> is read-only.</exception>
/// <exception cref="ArgumentException">Thrown when the value is invalid according to the assigned logic in <see cref="BindableProperty.ValidateValueDelegate"/>.</exception>
/// <remarks>If <see cref="BindableProperty.CoerceValueDelegate"/> is not assigned to, nothing will happen.</remarks>
public void CoerceValue(BindableProperty property) => CoerceValue(property, checkAccess: true);

/// <include file="../../docs/Microsoft.Maui.Controls/BindableObject.xml" path="//Member[@MemberName='CoerceValue'][2]/Docs/*" />
/// <summary>
/// Coerces the value of the specified bindable property.
/// This is done by invoking <see cref="BindableProperty.CoerceValueDelegate"/> of the specified bindable property.
/// </summary>
/// <param name="propertyKey">The key that identifies the bindable property to coerce the value of.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="propertyKey"/> is <see langword="null"/>.</exception>
/// <exception cref="InvalidOperationException">Thrown when the bindable property identified by <paramref name="propertyKey"/> is read-only.</exception>
/// <exception cref="ArgumentException">Thrown when the value is invalid according to the assigned logic in <see cref="BindableProperty.ValidateValueDelegate"/>.</exception>
/// <remarks>If <see cref="BindableProperty.CoerceValueDelegate"/> is not assigned to, nothing will happen.</remarks>
public void CoerceValue(BindablePropertyKey propertyKey)
{
if (propertyKey == null)
Expand Down
Loading