Exrin VisualState中嵌套对象的Reactive Extensions

时间:2017-08-20 22:35:57

标签: xamarin.forms exrin

我尝试在输入绑定属性嵌套字段时启用有界的按钮,但即使所有属性都填充了数据,该按钮也会被禁用。 我应该改变什么?

这是我的基本视觉状态

public class BaseVisualState : Exrin.Framework.VisualState
{
public BaseVisualState() : this(null)
{
}

public BaseVisualState(IBaseModel i_Model) : base(i_Model)
{
PropertyObservable = Observable.FromEventPattern(
                (EventHandler<PropertyChangedEventArgs> i_Event) => new PropertyChangedEventHandler(i_Event),
                i_EventChanged => this.PropertyChanged += i_EventChanged,
                i_EventChanged => this.PropertyChanged -= i_EventChanged);
        }

        public IObservable<EventPattern<PropertyChangedEventArgs>> PropertyObservable { get; private set; }
    }

我的视觉状态是

public class BeaconAddVisualState : BaseVisualState
    {
        private readonly IBeaconAddModel r_Model;

        public BeaconAddVisualState(IBeaconAddModel i_Model)
            : base(i_Model)
        {
            r_Model = i_Model;
        }

        [Binding(BindingType.TwoWay)]
        public Beacon Beacon
        {
            get
            {
                return Get<Beacon>();
            }

            set
            {
                Set(value);
            }
        }

        public override async void Init()
        {
            Beacon = new Beacon();
        }
    }

信标类通知属性已更改

public class Beacon : Document<Guid>, INotifyPropertyChanged
    {
        private string m_ProximityUuid;
        private int? m_Major;
        private int? m_Minor;

        [Required]
        public string ProximityUuid
        {
            get
            {
                return m_ProximityUuid;
            }

            set
            {
                if(m_ProximityUuid != value)
                {
                    m_ProximityUuid = value;
                    notifyPropertyChanged();
                }
            }
        }

        [Required]
        public int? Major
        {
            get
            {
                return m_Major;
            }

            set
            {
                if (m_Major != value)
                {
                    m_Major = value;
                    notifyPropertyChanged();
                }
            }
        }

        [Required]
        public int? Minor
        {
            get
            {
                return m_Minor;
            }

            set
            {
                if (m_Minor != value)
                {
                    m_Minor = value;
                    notifyPropertyChanged();
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        // This method is called by the Set accessor of each property.
        // The CallerMemberName attribute that is applied to the optional propertyName
        // parameter causes the property name of the caller to be substituted as an argument.
        private void notifyPropertyChanged([CallerMemberName] string i_PropertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(i_PropertyName));
            }
        }
    }

这是viewmodel

public class BeaconAddViewModel : BaseAuthViewModel
    {
        private readonly IBeaconAddModel r_Model;
        private readonly IDisposable r_Subscription;

        public BeaconAddViewModel(IBeaconAddModel i_Model)
            : base(new BeaconAddVisualState(i_Model))
        {
            r_Model = i_Model;
            r_Subscription = State.PropertyObservable.Where(
                i_Arg => i_Arg.EventArgs.PropertyName == nameof(State.Beacon.ProximityUuid)
                         || i_Arg.EventArgs.PropertyName == nameof(State.Beacon.Major) || i_Arg.EventArgs.PropertyName == nameof(State.Beacon.Minor)).Subscribe(
                i_Arg =>
                    {
                        AddCommand.OnCanExecuteChanged();
                    });
        }

        private BeaconAddVisualState State => VisualState as BeaconAddVisualState;

        public override Task OnNavigated(object i_Args)
        {
            return base.OnNavigated(i_Args);
        }

        public IRelayCommand AddCommand
        {
            get
            {
                return GetCommand(
                    () =>
                        {
                            return new RelayCommand(
                                async (i_Parameter) =>
                                    {
                                        await r_Model.AddBeacon(i_Parameter as Beacon);
                                        await NavigationService.Navigate("Beacons");
                                    }, (i_Obj) => !string.IsNullOrEmpty(State.Beacon.ProximityUuid) && State.Beacon.Major.HasValue && State.Beacon.Minor.HasValue;
                        });
            }
        }

        public override void Disposing()
        {
            base.Disposing();
            r_Subscription?.Dispose();
        }
    }

2 个答案:

答案 0 :(得分:0)

这里的问题是你在Beacon类中触发INPC,但是BaseVisualState只是在看Beacon(对象本身)是否在改变。

因此,你必须将Beacon之外的属性直接带入VisualState,或者转发INPC事件。

e.g。在你的灯塔集中

var beacon = value;
Set(value);
value.OnPropertyChanged += (s,e) => { OnPropertyChanged(nameof(Beacon)); }

这意味着,每次更改Beacon中的任何属性时,都会说Beacon类本身已更改,并触发VisualState的INPC。

注意:确保事件在重置时处理掉。这意味着不会像上面所示那样在anon函数中执行它,而是执行+ =并将其选中以创建另一种方法。

答案 1 :(得分:0)

感谢亚当的帮助。 这就是id到底做了什么,也许它可以帮助别人

public class BeaconAddVisualState : BaseVisualState
    {
        private readonly IBeaconAddModel r_Model;
        private Beacon m_Beacon;

        public BeaconAddVisualState(IBeaconAddModel i_Model)
            : base(i_Model)
        {
            r_Model = i_Model;
        }

        [Binding(BindingType.TwoWay)]
        public Beacon Beacon
        {
            get
            {
                return m_Beacon;
            }

            set
            {
                if(m_Beacon != value)
                {
                    if(m_Beacon != null)
                    {
                        m_Beacon.PropertyChanged -= m_Beacon_PropertyChanged;
                    }

                    m_Beacon = value;
                    m_Beacon.PropertyChanged += m_Beacon_PropertyChanged;
                    OnPropertyChanged();
                }
            }
        }

        public override async void Init()
        {
            Beacon = new Beacon();
        }

        public override void Disposing()
        {
            if (m_Beacon != null)
            {
                m_Beacon.PropertyChanged -= m_Beacon_PropertyChanged;
            }

            base.Disposing();
        }

        private void m_Beacon_PropertyChanged(
            object i_Sender,
            System.ComponentModel.PropertyChangedEventArgs i_EventArgs)
        {
            OnPropertyChanged(nameof(Beacon));
        }
    }