xamarin.forms - Reactive Extensions for nested objects in Exrin VisualState -
i'm trying enable button bounded when binded property nested field entered, button disabled when properties filled data. should change?
this base visual state
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; } }
and visual state is
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 { { return get<beacon>(); } set { set(value); } } public override async void init() { beacon = new beacon(); } }
the beacon class notifies on property changed
public class beacon : document<guid>, inotifypropertychanged { private string m_proximityuuid; private int? m_major; private int? m_minor; [required] public string proximityuuid { { return m_proximityuuid; } set { if(m_proximityuuid != value) { m_proximityuuid = value; notifypropertychanged(); } } } [required] public int? major { { return m_major; } set { if (m_major != value) { m_major = value; notifypropertychanged(); } } } [required] public int? minor { { return m_minor; } set { if (m_minor != value) { m_minor = value; notifypropertychanged(); } } } public event propertychangedeventhandler propertychanged; // method called set accessor of each property. // callermembername attribute applied optional propertyname // parameter causes property name of caller substituted argument. private void notifypropertychanged([callermembername] string i_propertyname = "") { if (propertychanged != null) { propertychanged(this, new propertychangedeventargs(i_propertyname)); } } }
and 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 beaconaddvisualstate; public override task onnavigated(object i_args) { return base.onnavigated(i_args); } public irelaycommand addcommand { { return getcommand( () => { return new relaycommand( async (i_parameter) => { await r_model.addbeacon(i_parameter 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(); } }
the problem here trigger inpc inside beacon class, basevisualstate looking @ whether beacon (the object itself) changing.
hence either have bring properties outside of beacon, directly visualstate, or relay inpc event.
e.g. in set of beacon do
var beacon = value; set(value); value.onpropertychanged += (s,e) => { onpropertychanged(nameof(beacon)); }
that mean, each time property in beacon changed, beacon class has changed, , trigger inpc visualstate.
note: make sure event disposed on, when it's reset. mean not doing in anon func have shown above, doing += , tabbing create method.
Comments
Post a Comment