Dependent observable property in Matlab. Does it work?

扶醉桌前 提交于 2019-12-04 05:23:19

It might be syntactically correct, but the listener callback will never execute. Example:

classdef MyClass < handle
    properties (Access = public)
        a
    end
    properties (SetAccess = private, Dependent, SetObservable)
        b
    end
    methods
        function val = get.b(this)
            val = this.a;
        end
    end
end

Now try:

c = MyClass();
lh = addlistener(c, 'b', 'PostSet',@(o,e)disp(e.EventName));
c.a = 1;
disp(c.b)

As you can see the 'PostSet' callback is never executed.


EDIT

The way I see it, SetObservable should really be set on a not b. Its because b is read-only and can only change if a changes. Now the PostSet event would notify us that both properties have changed.

Use the same example I used above, simply move SetObservable from b to a. Of course now you listen to the event as:

lh = addlistener(c, 'a', 'PostSet',@(o,e)disp(e.EventName));

EDIT#2

Sorry I didn't pay attention to the fact that you have composition (BClass has an instance of AClass as private property).

Consider this possible solution:

AClass.m

classdef AClass < handle
    properties (SetObservable)
        a                        %# observable property
    end
end

BClass.m

classdef BClass < handle
    properties (Access = private)
        aClassInst               %# instance of AClass
        lh                       %# event listener on aClassInst.a
    end
    properties (Dependent, SetAccess = private)
        b                        %# dependent property, read-only
    end
    events (ListenAccess = public, NotifyAccess = private)
        bPostSet                 %# custom event raised on b PostSet
    end
    methods
        function this = BClass(aClass)
            %# store AClass instance handle
            this.aClassInst = aClass;
            %# listen on PostSet event for property a of AClass instance
            this.lh = addlistener(this.aClassInst, 'a',  ...
                'PostSet', @this.aPostSet_EventHandler);
        end
        function val = get.b(this)
            val = this.aClassInst.a;
        end
    end
    methods (Access = private)
        function aPostSet_EventHandler(this, src, evt)
            %# raise bPostSet event, notifying all registered listeners
            notify(this, 'bPostSet')
        end
    end
end

Basically we set property a of AClass as observable.

Next inside the constructor of BClass, we register a listener for the AClass instance passed to listen on property a changes. In the callback we notify listeners of this object that b has changed as well

Since we can't really raise a PostSet manually, I created a custom event bPostSet which we raise in the previous callback function. You can always customize the event data passed, refer to the documentation to see how.

Here is a test case:

%# create the objects
a = AClass();
b = BClass(a);

%# change property a. We will not recieve any notification
disp('a.a = 1')
a.a = 1;

%# now lets listen for the 'bChanged' event on b
lh = addlistener(b, 'bPostSet',@(o,e) disp('-- changed'));

%# try to change the property a again. We shall see notification
disp('a.a = 2')
a.a = 2;

%# remove event handler
delete(lh)

%# no more notifications
disp('a.a = 3')
a.a = 3;

The output was:

a.a = 1
a.a = 2
-- changed
a.a = 3

Notice how we only interact with the BClass instance when we register our listener. Of course since all classes derive from handle class, the instance a and the private property aClassInst both refer to the same object. So any changes to a.a are immediately reflected on b.aClassInst.a, this causes the internal aPostSet_EventHandler to execute, which in turn notify all registered listeners to our custom event.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!