Xamarin 可绑定行为的 "PropertyChanged Event" 能否直接处理其视图的 属性?
Can "PropertyChanged Event" of Xamarin bindable behavior directly handle property of its view?
我想用可绑定行为处理视图的属性。
是否有任何方法可以直接访问事件处理程序中连接的视图?
将 "AssociatedObject" 更改为静态会导致绑定问题。
我该怎么办?
public class CustNameBehavior : Behavior<Label>
{
public Label AssociatedObject { get; private set; }
public static readonly BindableProperty MyNameProperty = BindableProperty.Create(nameof(MyName), typeof(string), typeof(CustNameBehavior), null, BindingMode.OneWay, propertyChanged: OnMyNameChanged);
private static void OnMyNameChanged(BindableObject bindable, object oldValue, object newValue)
{
CustNameBehavior target = (CustNameBehavior)bindable;
if (target != null)
{
var value = (string)newValue;
if (string.IsNullOrWhiteSpace(value))
{
AssociatedObject.Text = "Empty!"; => this is inaccessible. because of non static.
}
else
{
AssociatedObject.Text = value; => this is inaccessible. because of non static.
}
}
}
protected override void OnAttachedTo(Label bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
bindable.BindingContextChanged += Bindable_BindingContextChanged;
}
protected override void OnDetachingFrom(Label bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= Bindable_BindingContextChanged;
AssociatedObject = null;
}
private void Bindable_BindingContextChanged(object sender, EventArgs e)
{
base.OnBindingContextChanged();
BindingContext = AssociatedObject.BindingContext;
}
public string MyName
{
get => (string)GetValue(MyNameProperty);
set
{
SetValue(MyNameProperty, value);
}
}
}
OnMyNameChanged
处理程序必须是静态的,因为 MyNameProperty
也是静态的(好吧,从技术上讲,这也许是可行的,但它会很脆弱并且会跳过箍)。无论如何,您希望 AssociatedObject
是非静态的,因为每个 CustNameBehavior
实例都需要一个,其他任何东西都可能不会按预期运行。
但是,您可以从OnMyNameChanged
访问非静态方法和属性,因为CustNameBehavior
的实例是通过bindable
传递的范围。此外,此实例通过 AssociatedObject
持有对 Label
的引用。因此,您可以通过 target
访问 AssociatedObject
(已经转换为 CustNameBehavior
的 bindable
),因此您的方法将变为
private static void OnMyNameChanged(BindableObject bindable, object oldValue, object newValue)
{
CustNameBehavior target = (CustNameBehavior)bindable;
if (target != null && target.AssociatedObject != null)
{
var value = (string)newValue;
if (string.IsNullOrWhiteSpace(value))
{
target.AssociatedObject.Text = "Empty!";
}
else
{
target.AssociatedObject.Text = value;
}
}
}
请注意 我添加了一个检查 AssociatedObject
是否为 null
,因为我假设 OnMyNameChanged
在行为之前被调用被绑定。
恕我直言,如果您将实例逻辑单独移动到一个方法中会更好
private static void OnMyNameChanged(BindableObject bindable, object oldValue, object newValue)
{
CustNameBehavior target = (CustNameBehavior)bindable;
target?.SetLabelName((string)newValue);
}
private void SetLabelName(string name)
{
if(AssociatedObject != null)
{
AssociatedObject.Text = string.IsNullOrEmpty(name) ? "Empty!" : name;
}
}
你还必须从OnAttachedTo
设置AssociatedObject.Text
,因为MyNameProperty
暂时不会设置,这会导致AssociatedObject.Text
不正在更新。您可以为此目的重用 SetLabelName
,这样,您就不必重复检查字符串是否为空的逻辑。
protected override void OnAttachedTo(Label bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
SetLabelName((string)GetValue(MyNameProperty));
bindable.BindingContextChanged += Bindable_BindingContextChanged;
}
我想用可绑定行为处理视图的属性。
是否有任何方法可以直接访问事件处理程序中连接的视图?
将 "AssociatedObject" 更改为静态会导致绑定问题。
我该怎么办?
public class CustNameBehavior : Behavior<Label>
{
public Label AssociatedObject { get; private set; }
public static readonly BindableProperty MyNameProperty = BindableProperty.Create(nameof(MyName), typeof(string), typeof(CustNameBehavior), null, BindingMode.OneWay, propertyChanged: OnMyNameChanged);
private static void OnMyNameChanged(BindableObject bindable, object oldValue, object newValue)
{
CustNameBehavior target = (CustNameBehavior)bindable;
if (target != null)
{
var value = (string)newValue;
if (string.IsNullOrWhiteSpace(value))
{
AssociatedObject.Text = "Empty!"; => this is inaccessible. because of non static.
}
else
{
AssociatedObject.Text = value; => this is inaccessible. because of non static.
}
}
}
protected override void OnAttachedTo(Label bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
bindable.BindingContextChanged += Bindable_BindingContextChanged;
}
protected override void OnDetachingFrom(Label bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= Bindable_BindingContextChanged;
AssociatedObject = null;
}
private void Bindable_BindingContextChanged(object sender, EventArgs e)
{
base.OnBindingContextChanged();
BindingContext = AssociatedObject.BindingContext;
}
public string MyName
{
get => (string)GetValue(MyNameProperty);
set
{
SetValue(MyNameProperty, value);
}
}
}
OnMyNameChanged
处理程序必须是静态的,因为 MyNameProperty
也是静态的(好吧,从技术上讲,这也许是可行的,但它会很脆弱并且会跳过箍)。无论如何,您希望 AssociatedObject
是非静态的,因为每个 CustNameBehavior
实例都需要一个,其他任何东西都可能不会按预期运行。
但是,您可以从OnMyNameChanged
访问非静态方法和属性,因为CustNameBehavior
的实例是通过bindable
传递的范围。此外,此实例通过 AssociatedObject
持有对 Label
的引用。因此,您可以通过 target
访问 AssociatedObject
(已经转换为 CustNameBehavior
的 bindable
),因此您的方法将变为
private static void OnMyNameChanged(BindableObject bindable, object oldValue, object newValue)
{
CustNameBehavior target = (CustNameBehavior)bindable;
if (target != null && target.AssociatedObject != null)
{
var value = (string)newValue;
if (string.IsNullOrWhiteSpace(value))
{
target.AssociatedObject.Text = "Empty!";
}
else
{
target.AssociatedObject.Text = value;
}
}
}
请注意 我添加了一个检查 AssociatedObject
是否为 null
,因为我假设 OnMyNameChanged
在行为之前被调用被绑定。
恕我直言,如果您将实例逻辑单独移动到一个方法中会更好
private static void OnMyNameChanged(BindableObject bindable, object oldValue, object newValue)
{
CustNameBehavior target = (CustNameBehavior)bindable;
target?.SetLabelName((string)newValue);
}
private void SetLabelName(string name)
{
if(AssociatedObject != null)
{
AssociatedObject.Text = string.IsNullOrEmpty(name) ? "Empty!" : name;
}
}
你还必须从OnAttachedTo
设置AssociatedObject.Text
,因为MyNameProperty
暂时不会设置,这会导致AssociatedObject.Text
不正在更新。您可以为此目的重用 SetLabelName
,这样,您就不必重复检查字符串是否为空的逻辑。
protected override void OnAttachedTo(Label bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
SetLabelName((string)GetValue(MyNameProperty));
bindable.BindingContextChanged += Bindable_BindingContextChanged;
}