自定义 Xamarin 表单控件的数据绑定失败,但适用于普通控件
Data binding fails for a custom Xamarin forms control but works for a normal one
我有一个简单的自定义控件,我在我的 Xamarin 表单应用程序的 ContentPage
(实际上是一个 LoginPage)中使用它。自定义控件有一个名为 EntryText
的 属性,我试图将其绑定到 LoginViewModel
的 Email
属性.
如果我将 Email
与自定义控件的 EntryText
绑定,它似乎不起作用。但是,如果我将 Email
绑定到像 Entry
的 Text
这样的普通控件,它确实可以正常工作。我在这里做错了什么?
我的自定义控件:
public class FlakeEntry2 : StackLayout
{
public Entry Entry;
public Label ErrorLabel;
public FlakeEntry2()
{
Entry = new Entry { };
Children.Add(Entry);
ErrorLabel = new Label
{
FontAttributes = FontAttributes.Italic,
TextColor = Color.Red,
};
Children.Add(ErrorLabel);
}
#region Text property which I am trying to bind
public static readonly BindableProperty EntryTextProperty = BindableProperty.Create(
propertyName: nameof(EntryText),
returnType: typeof(string),
declaringType: typeof(FlakeEntry2),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: EntryTextPropertyChanged);
public string EntryText
{
get { return GetValue(EntryTextProperty)?.ToString(); }
set { SetValue(EntryTextProperty, value); }
}
private static void EntryTextPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (FlakeEntry2)bindable;
control.Entry.Text = newValue?.ToString();
}
#endregion
}
我尝试绑定的视图 (LoginPage) 如下所示:
<StackLayout Orientation="Vertical" Spacing="10">
<custom:FlakeEntry2 x:Name="Email" EntryText="{Binding Email}" /> <!--This does not work-->
<Entry Text="{Binding Email}"/> <!--This works-->
</StackLayout>
最后,ViewModel 几乎是标准的并且实现了 INotifyPropertyChanged
。 Email
属性 看起来像:
private string _email;
public string Email
{
get { return _email; }
set
{
_email = value;
NotifyPropertyChanged();
}
}
我尝试添加一个基于 XAML 的自定义控件(当前的控件仅基于 C#)。
我已尝试将 BindingContext={Binding}
显式添加到 LoginPage
中使用的自定义控件。
我已经阅读了很多博客,但无济于事。有人可以指出我正确的方向吗?
我听说 WPF 和 XF 绑定甚至 XAML 语法之间有些不同,但我对 WPF 知之甚少。
随便。
如何使用级联绑定并控制您的组件,避免暴露其内部视图?
我一直使用这种方法并且对我来说效果很好,看看它是否也适合你:
public class FlakeEntry2 : StackLayout
{
private Entry Entry;
private Label ErrorLabel;
public FlakeEntry2()
{
Entry = new Entry { };
ErrorLabel = new Label
{
FontAttributes = FontAttributes.Italic,
TextColor = Color.Red,
};
this.Entry.SetBinding(Entry.TextProperty, new Binding(nameof(EntryText), source: this));
// You'll need to do the same to label's and other properties you need expose, but you get rid of the 'OnChanged' methods
Children.Add(Entry);
Children.Add(ErrorLabel);
}
#region Text property which I am trying to bind
public static readonly BindableProperty EntryTextProperty = BindableProperty.Create(
propertyName: nameof(EntryText),
returnType: typeof(string),
declaringType: typeof(FlakeEntry2),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay);
public string EntryText
{
get { return GetValue(EntryTextProperty)?.ToString(); }
set { SetValue(EntryTextProperty, value); }
}
#endregion
}
您的 XAML 和 VM 上的任何内容都不应更改。
我有一个简单的自定义控件,我在我的 Xamarin 表单应用程序的 ContentPage
(实际上是一个 LoginPage)中使用它。自定义控件有一个名为 EntryText
的 属性,我试图将其绑定到 LoginViewModel
的 Email
属性.
如果我将 Email
与自定义控件的 EntryText
绑定,它似乎不起作用。但是,如果我将 Email
绑定到像 Entry
的 Text
这样的普通控件,它确实可以正常工作。我在这里做错了什么?
我的自定义控件:
public class FlakeEntry2 : StackLayout
{
public Entry Entry;
public Label ErrorLabel;
public FlakeEntry2()
{
Entry = new Entry { };
Children.Add(Entry);
ErrorLabel = new Label
{
FontAttributes = FontAttributes.Italic,
TextColor = Color.Red,
};
Children.Add(ErrorLabel);
}
#region Text property which I am trying to bind
public static readonly BindableProperty EntryTextProperty = BindableProperty.Create(
propertyName: nameof(EntryText),
returnType: typeof(string),
declaringType: typeof(FlakeEntry2),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: EntryTextPropertyChanged);
public string EntryText
{
get { return GetValue(EntryTextProperty)?.ToString(); }
set { SetValue(EntryTextProperty, value); }
}
private static void EntryTextPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (FlakeEntry2)bindable;
control.Entry.Text = newValue?.ToString();
}
#endregion
}
我尝试绑定的视图 (LoginPage) 如下所示:
<StackLayout Orientation="Vertical" Spacing="10">
<custom:FlakeEntry2 x:Name="Email" EntryText="{Binding Email}" /> <!--This does not work-->
<Entry Text="{Binding Email}"/> <!--This works-->
</StackLayout>
最后,ViewModel 几乎是标准的并且实现了 INotifyPropertyChanged
。 Email
属性 看起来像:
private string _email;
public string Email
{
get { return _email; }
set
{
_email = value;
NotifyPropertyChanged();
}
}
我尝试添加一个基于 XAML 的自定义控件(当前的控件仅基于 C#)。
我已尝试将 BindingContext={Binding}
显式添加到 LoginPage
中使用的自定义控件。
我已经阅读了很多博客,但无济于事。有人可以指出我正确的方向吗?
我听说 WPF 和 XF 绑定甚至 XAML 语法之间有些不同,但我对 WPF 知之甚少。
随便。
如何使用级联绑定并控制您的组件,避免暴露其内部视图?
我一直使用这种方法并且对我来说效果很好,看看它是否也适合你:
public class FlakeEntry2 : StackLayout
{
private Entry Entry;
private Label ErrorLabel;
public FlakeEntry2()
{
Entry = new Entry { };
ErrorLabel = new Label
{
FontAttributes = FontAttributes.Italic,
TextColor = Color.Red,
};
this.Entry.SetBinding(Entry.TextProperty, new Binding(nameof(EntryText), source: this));
// You'll need to do the same to label's and other properties you need expose, but you get rid of the 'OnChanged' methods
Children.Add(Entry);
Children.Add(ErrorLabel);
}
#region Text property which I am trying to bind
public static readonly BindableProperty EntryTextProperty = BindableProperty.Create(
propertyName: nameof(EntryText),
returnType: typeof(string),
declaringType: typeof(FlakeEntry2),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay);
public string EntryText
{
get { return GetValue(EntryTextProperty)?.ToString(); }
set { SetValue(EntryTextProperty, value); }
}
#endregion
}
您的 XAML 和 VM 上的任何内容都不应更改。