【问题标题】:Two way bindable entry that supports basic types and nullable types支持基本类型和可空类型的两种方式可绑定条目
【发布时间】:2016-10-19 22:52:19
【问题描述】:

我正在尝试在 Xamarin.Forms 中通过 Entry 实现完美的 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 与 decimal? 等。同时指定 e.NewTextValue 的转换方式。

问题:下面的类型更改转换打破了双向绑定。

this.NumericText = (T)Convert.ChangeType(e.NewTextValue, typeof(T));

但是,这给了我一个错误(显然),因为 this.NumericText 在运行时之前是 T 类型。

所以,如果我希望该条目适用于可空整数,我需要将所有类型 T 替换为 int?以及将上面的代码更改为:

Convert.ToInt32(e.NewTextValue)

当我单步执行代码时,只要到达 Convert.ChangeType to T 行,它就会退出框架。没有错误并且页面被显示,但是在那个特定的可绑定条目之后的每个控件都没有值。

After stepping through the ConvertType function

如果我错过了任何信息,请告诉我。帮助将不胜感激!

【问题讨论】:

    标签: c# mvvm xamarin xamarin.forms


    【解决方案1】:

    我推荐使用值转换器,它比创建自定义控件和确认 MVVM 模式要容易得多。

    您可以在此处找到代码 sn-p - https://forums.xamarin.com/discussion/comment/60076/#Comment_60076

    【讨论】:

    • 值转换器工作,但不适用于可空类型。所以,如果我在 int?(Nullable) 和字符串之间进行转换,我不能返回 null。使它起作用的是,如果我返回默认值(int),即 0。
    • @TonyMykhaylovsky,当您说值转换器不适用于可空类型时,我不确定您的意思。当然可以,返回类型和value 参数是object 类型。如果您传入一个值类型,例如int,它将被装箱为object,从而减少手动从int 转换的需要?和不可为空的类型。
    【解决方案2】:

    我知道这已经有一年多了,但找到了一个可以帮助其他人的问题的解决方案。如果您对呈现的原始代码进行以下更改,则它可以工作:

    BindableEntry(条目扩展)代码:

    将 BindableEntry_TextChanged(object sender, 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。 希望这会有所帮助...

    【讨论】:

      猜你喜欢
      • 2019-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-08
      • 2014-03-25
      • 2011-06-13
      • 2019-11-26
      相关资源
      最近更新 更多