我正在尝试使用Entry在Xamarin.Forms中实现完美的MVVM。
我的模型包含其类型包括string,int?,decimal?,bool?等的属性。每当我绑定到字符串类型时,双向绑定都有效,因为text属性具有字符串类型(它们匹配)。但是一旦你尝试绑定回模型并且属性是int或int ?,它就不会更新模型的属性值。
在我的研究期间以及在Xamarin支持的帮助下,这是一个关于如何处理可空类型的非常有用的线程:
Nullable type in x:TypeArguments
XAML代码:
<controls:NullableIntEntry Grid.Column="1" Grid.Row="14" NumericText="{Binding BusinessOwnership, Mode=TwoWay}" x:Name="lblBusinessOwnership"></controls:NullableIntEntry>
BindableEntry(条目扩展名)代码:
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Reflection;
using Xamarin.Forms;
namespace CreditBuilderApp.Controls
{
public class BindableEntry<T> : Entry
{
static bool firstLoad;
public static readonly BindableProperty NumericTextProperty =
BindableProperty.Create("NumericText", typeof(T), typeof(BindableEntry<T>),
null, BindingMode.TwoWay, propertyChanged: OnNumericTextChanged);
static void OnNumericTextChanged(BindableObject bindable, object oldValue, object newValue)
{
var boundEntry = (BindableEntry<T>)bindable;
if (firstLoad && newValue != null)
{
firstLoad = false;
boundEntry.Text = newValue.ToString();
}
}
public T NumericText
{
get { return (T)GetValue(NumericTextProperty); }
set { SetValue(NumericTextProperty, value); }
}
public BindableEntry()
{
firstLoad = true;
this.TextChanged += BindableEntry_TextChanged;
}
private void BindableEntry_TextChanged(object sender, TextChangedEventArgs e)
{
if (!String.IsNullOrEmpty(e.NewTextValue))
{
this.NumericText = (T)Convert.ChangeType(e.NewTextValue, typeof(T));
}
else
{
this.NumericText = default(T);
}
}
}
}
NullableIntEntry和NullableDecimalEntry(指定类型的可绑定条目扩展名):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CreditBuilderApp.Controls
{
public class NullableIntEntry : BindableEntry<Int32?>
{
}
public class NullableDecimalEntry : BindableEntry<Decimal?>
{
}
}
型号:
private int? _businessOwnership { get; set; }
public int? BusinessOwnership
{
get { return _businessOwnership; }
set
{
if (_businessOwnership != value)
{
_businessOwnership = value;
RaisePropertyChanged();
}
}
}
我实际上能够绑定到整数,十进制,浮点数,基本上任何不是字符串的类型,这是朝着正确方向迈出的一步。但是,为了实现这一点,我必须在上面创建BindableEntry并指定它是什么类型。 (将T替换为int?,将T替换为十进制?等,ALONG指定如何生成e.NewTextValue。
问题:以下类型更改转换打破了双向绑定。
this.NumericText = (T)Convert.ChangeType(e.NewTextValue, typeof(T));
但是,这给了我一个错误(显然),因为this.NumericText在运行时之前是T类型。
所以,如果我希望该条目可以为可空整数工作,我需要用int替换所有类型的T?以及将上述代码更改为:
Convert.ToInt32(e.NewTextValue)
当我单步执行代码时,每当我将Convert.ChangeType转到T行时,它都会退出框架。没有错误,页面显示,但该特定可绑定条目之后的每个控件都没有值。
After stepping through the ConvertType function
如果我错过任何信息,请告诉我。帮助将不胜感激!
答案 0 :(得分:1)
我建议使用值转换器,它比创建自定义控件和确认MVVM模式容易得多。
您可以在此处找到代码段 - https://forums.xamarin.com/discussion/comment/60076/#Comment_60076
答案 1 :(得分:0)
我知道这已经超过一年了,但找到了一个可以帮助他人的问题的解决方案。如果您对原始代码进行了以下更改,则可以使用:
BindableEntry(条目扩展名)代码:
将BindableEntry_TextChanged(对象发件人,TextChangedEventArgs e)更改为
private void BindableEntry_TextChanged(object sender, TextChangedEventArgs e)
{
if (!string.IsNullOrEmpty(e.NewTextValue))
{
var t = typeof(T);
t = Nullable.GetUnderlyingType(t);
if (typeof(T) == typeof(decimal?))
{
var results = decimal.TryParse(e.NewTextValue, out var tmpValue) ?
tmpValue : (decimal?) null;
if (results != null)
NumericText = (T)Convert.ChangeType(results, t);
else
NumericText = default(T);
}
else if (typeof(T) == typeof(double?))
{
var results = double.TryParse(e.NewTextValue, out var tmpValue) ?
tmpValue : (double?)null;
if (results != null)
NumericText = (T)Convert.ChangeType(results, t);
else
NumericText = default(T);
}
else if (typeof(T) == typeof(int?))
{
var results = int.TryParse(e.NewTextValue, out var tmpValue) ?
tmpValue : (int?)null;
if (results != null)
NumericText = (T)Convert.ChangeType(results, t);
else
NumericText = default(T);
}
}
else
{
NumericText = default(T);
}
}
我找到了缺失的部分来实现这项工作here。 希望这会有所帮助...