[Python.NET] How to handle INotifyPropertyChanged interface

Tony Roberts tony at pyxll.com
Mon Apr 4 08:31:06 EDT 2016


I've fixed the crash bug and added a couple of tests (see PR #196, already
merged into develop).

For an example of how to implement an event declared on an interface see
testEvents in src/tests/test_subclass.py. Note that it's a pretty simple
implementation and isn't thread safe so may need modifying if you need it
to be.

This could be wrapped up into something a bit more friendly, but it works
for now.

Best regards,
Tony


On Sun, Apr 3, 2016 at 6:57 PM Denis Akhiyarov <denis.akhiyarov at gmail.com>
wrote:

> is it possible to workaround this non-implemented feature by using
> ___setattr__() hook? seems like people were able to do this in ironpython:
>
> http://stackoverflow.com/questions/3856905/
>
> On Sun, Apr 3, 2016 at 10:40 AM, Tony Roberts <tony at pyxll.com> wrote:
>
>> Yeah, it looks like the crash is probably because of the missing event
>> implementation as suspected. I'm a bit surprised that it didn't fail
>> earlier when trying to instantiate the type.
>>
>> If you do get a chance to take a look at adding that functionality be
>> sure to submit a pull request!
>>
>> Best regards,
>> Tony
>>
>>
>> On Sun, Apr 3, 2016 at 4:30 PM Hansong Huang <hhspiny at live.com> wrote:
>>
>>> Tony,
>>>
>>> thanks for the hint.
>>>
>>> the event PropertyChanged was declared in INotifyPropertyChanged
>>> interface by pythonnet, but obviously not implemented.
>>> [('PropertyChanged', <unbound event 'PropertyChanged'>),
>>>
>>> anyway, the stackoverflow only happens if both following are present
>>> 1. the class is derived from INotifyPropertyChanged interface
>>> 2. the class exposes property back to .Net vis @clrproperty
>>>
>>> which seems to prove that it is the PropertyChanged event that is not
>>> implemented in python class resulted in the crash.
>>>
>>> I was not sure if .Net event can be handled by pythonnet. I found a few
>>> examples with IronPython, but there, a python class of "event" seems to be
>>> implemented instead.
>>>
>>> Below is the stack trace
>>>
>>>
>>>   [External Code]
>>>   clr.dll!CallDescrWorkerInternal () Unknown
>>>   clr.dll!CallDescrWorkerWithHandler(struct CallDescrData *,int) Unknown
>>>   clr.dll!CallDescrWorkerReflectionWrapper(struct CallDescrData *,class
>>> Frame *) Unknown
>>>   clr.dll!RuntimeMethodHandle::InvokeMethod(class Object *,class
>>> PtrArray *,class SignatureNative *,bool) Unknown
>>>   mscorlib.ni.dll!00007fffb86e1ca4() Unknown
>>>   mscorlib.ni.dll!00007fffb8618272() Unknown
>>>   mscorlib.ni.dll!00007fffb867fc4a() Unknown
>>>   [External Code]
>>>   mscorlib.ni.dll!00007fffb86dbaf5() Unknown
>>>   mscorlib.ni.dll!00007fffb86d281f() Unknown
>>>   System.ni.dll!00007fffb77556d4() Unknown
>>>   System.ni.dll!00007fffb7755637() Unknown
>>>   System.ni.dll!00007fffb775541d() Unknown
>>>   PresentationFramework.ni.dll!00007fff96c1ca70() Unknown
>>>   PresentationFramework.ni.dll!00007fff96c23902() Unknown
>>>   PresentationFramework.ni.dll!00007fff96c22ea1() Unknown
>>>   PresentationFramework.ni.dll!00007fff96c22693() Unknown
>>>   PresentationFramework.ni.dll!00007fff96c223c9() Unknown
>>>   PresentationFramework.ni.dll!00007fff96c21a03() Unknown
>>>   PresentationFramework.ni.dll!00007fff96c0d84c() Unknown
>>>   PresentationFramework.ni.dll!00007fff96b97299() Unknown
>>>   PresentationFramework.ni.dll!00007fff96b9720e() Unknown
>>>   PresentationFramework.ni.dll!00007fff96c852f0() Unknown
>>>   WindowsBase.ni.dll!00007fff9f6f9bc9() Unknown
>>>   WindowsBase.ni.dll!00007fff9f6f9ac6() Unknown
>>>   WindowsBase.ni.dll!00007fff9f6fca2b() Unknown
>>>   mscorlib.ni.dll!00007fffb86ca79e() Unknown
>>>   mscorlib.ni.dll!00007fffb86ca637() Unknown
>>>   mscorlib.ni.dll!00007fffb86ca5f2() Unknown
>>>   WindowsBase.ni.dll!00007fff9f913810() Unknown
>>>   WindowsBase.ni.dll!00007fff9f6fc784() Unknown
>>>   WindowsBase.ni.dll!00007fff9f6f7c24() Unknown
>>>   WindowsBase.ni.dll!00007fff9f6f8061() Unknown
>>>   WindowsBase.ni.dll!00007fff9f6f9e53() Unknown
>>>   WindowsBase.ni.dll!00007fff9f6f9d82() Unknown
>>>   WindowsBase.ni.dll!00007fff9f6f9bc9() Unknown
>>>   WindowsBase.ni.dll!00007fff9f6f9ac6() Unknown
>>>   WindowsBase.ni.dll!00007fff9f6f7583() Unknown
>>>   WindowsBase.ni.dll!00007fff9f6f94ff() Unknown
>>>   WindowsBase.ni.dll!00007fff9f8c496a() Unknown
>>>   clr.dll!UMThunkStub () Unknown
>>>   user32.dll!UserCallWinProcCheckWow() Unknown
>>>   user32.dll!DispatchMessageWorker() Unknown
>>>   WindowsBase.ni.dll!00007fff9f730ee8() Unknown
>>>   WindowsBase.ni.dll!00007fff9f70d8fc() Unknown
>>>   PresentationFramework.ni.dll!00007fff96af98b3() Unknown
>>>   PresentationFramework.ni.dll!00007fff96af969d() Unknown
>>>   clr.dll!CallDescrWorkerInternal () Unknown
>>>   clr.dll!CallDescrWorkerWithHandler(struct CallDescrData *,int) Unknown
>>>   clr.dll!CallDescrWorkerReflectionWrapper(struct CallDescrData *,class
>>> Frame *) Unknown
>>>   clr.dll!RuntimeMethodHandle::InvokeMethod(class Object *,class
>>> PtrArray *,class SignatureNative *,bool) Unknown
>>>   mscorlib.ni.dll!00007fffb86e1c20() Unknown
>>>   mscorlib.ni.dll!00007fffb8618272() Unknown
>>>   [External Code]
>>>   clr.dll!UMThunkStub () Unknown
>>>   [External Code]
>>> > WPFPy.py!threadStart Line 256 Python
>>>   [External Code]
>>>
>>>
>>> ------------------------------
>>> From: tony at pyxll.com
>>> Date: Sun, 3 Apr 2016 15:20:47 +0000
>>> Subject: Re: [Python.NET] How to handle INotifyPropertyChanged interface
>>> To: hhspiny at pine.cc; pythondotnet at python.org
>>>
>>>
>>> What's the full stack trace?
>>>
>>> I suspect it's something to do with the event declared on the interface
>>> not being implemented. The managed type constructed doesn't define any
>>> events, so that would cause the construction of the type of fail - which is
>>> probably the error you're getting (although without the stack trace it's
>>> just an educated guess).
>>>
>>> It shouldn't be too hard to add events to the derived type if someone
>>> wanted to have a go at implementing it. The code is in the
>>> CreateDerivedType method in src/runtime/classderived.cs. To be consistent
>>> with how methods and properties work, it would need a clrevent function
>>> adding to the clr module (src/runtime/resource/clr.py) - maybe it could
>>> work like this:
>>>
>>> class MyClass(INotifyPropertyChanged):
>>>     OnPropertyChanged = clr.clrevent(event_attributes, event_type)
>>>
>>> Then in classderived.cs the class any clrevents on the python class
>>> could be added to the managed type using TypeBuilder.DefineEvent.
>>>
>>> So, anyway - short answer is that what you're trying to do won't work
>>> without changes to pythonnet; but the changes required shouldn't be too
>>> hard if you wanted to have a go.
>>>
>>> Best regards,
>>> Tony
>>>
>>>
>>> On Sun, Apr 3, 2016 at 3:37 PM Hansong Huang <hhspiny at live.com> wrote:
>>>
>>> It seems inheriting from INotifyPropertyChanged is the cause
>>>
>>> self.window = System.Windows.Markup.XamlReader.Load(outStream)
>>> self.window.DataContext = MyViewModel()
>>> class MyViewModel(System.Object):
>>>     __namespace__ = "WPFPyDemo"
>>>     def __init__(self):
>>>         super(MyViewModel,self).__init__()
>>>         self._inputText = "Line - in"
>>>     @clr.clrproperty(str)
>>>     def inputText(self):
>>>         return self._inputText
>>>     @inputText.setter
>>>     def inputText(self,value):
>>>         self._inputText = value
>>>         self.OnPropertyChanged("inputText")
>>>
>>> The above code works fine.
>>>
>>> but if switch inheritance to
>>> class MyViewModel(System.ComponentModel.INotifyPropertyChanged):
>>> and nothing else changed, python gives
>>>
>>> "The process terminates due to StackOverflowException"
>>>
>>> Not sure why.
>>>
>>>
>>> Thanks for the help
>>>
>>> ------------------------------
>>> From: hhspiny at live.com
>>> To: pythondotnet at python.org
>>> Subject: How to handle INotifyPropertyChanged interface
>>> Date: Thu, 31 Mar 2016 20:38:38 -0400
>>>
>>>
>>> I am still trying to figure out how to implement WPF MVVM with
>>> Python.Net.
>>> Previously, I have successfully used System.Dynamic.ExpandoObject as a
>>> ViewModel container
>>>
>>> self.window = System.Windows.Markup.XamlReader.Load(outStream)
>>> self.window.DataContext = DotNetExpandoObject()
>>>
>>> where DotNetExpandoObject is a wrapper class for
>>> System.Dynamic.ExpandoObject
>>> class DotNetExpandoObject(System.Dynamic.ExpandoObject):
>>> ...  in which I redefined __getattr__ and __setattr__
>>>
>>> it works flawlessly as System.Dynamic.ExpandoObject implements
>>> INotifyPropertyChange interface already
>>>
>>> Now, I would like to get away from using System.Dynamic.ExpandoObject
>>> but to implement my own
>>>
>>> I first tried to expose a python class back to .Net
>>> class MyViewModel(System.Object):
>>>     __namespace__ = "WPFPyDemo"
>>>     def __init__(self):
>>>         super(MyViewModel,self).__init__()
>>>         self._inputText = "Line - in"
>>>     @clr.clrproperty(str)
>>>     def inputText(self):
>>>         return self._inputText
>>>     @inputText.setter
>>>     def inputText(self,value):
>>>         self._inputText = value
>>>         self.OnPropertyChanged("inputText")
>>>
>>> self.window.DataContext = MyViewModel()
>>>
>>> The one direction data binding works fine, and the "Line - in" text
>>> correctly shows up in the textblock control.
>>> obviously this is not sufficient as there is no INotifyPropertyChange
>>> interface.
>>>
>>> So, I inherit the interface , and tries to implement the typical C# code
>>> " public event PropertyChangedEventHandler PropertyChanged"
>>>
>>> -- not sure how to handle event in Python.Net, the follow code probably
>>> is completely wrong
>>>
>>> class ViewModel(System.ComponentModel.INotifyPropertyChanged):
>>>     __namespace__ = "WPFPy"
>>>     def __init__(self):
>>>         super(ViewModel, self).__init__()
>>>         self.PropertyChanged =
>>> System.ComponentModel.PropertyChangedEventHandler
>>>     def OnPropertyChanged(self, propertyName):
>>>         if self.PropertyChanged != None:
>>>             PropertyChanged(self,
>>> System.ComponentModel.PropertyChangedEventArgs(propertyName))
>>>
>>> class MyViewModel(ViewModel):
>>>     __namespace__ = "WPFPyDemo"
>>>     def __init__(self):
>>>         super(MyViewModel,self).__init__()
>>>         self._inputText = "Line - in"
>>>
>>>     @clr.clrproperty(str)
>>>     def inputText(self):
>>>         return self._inputText
>>>     @inputText.setter
>>>     def inputText(self,value):
>>>         self._inputText = value
>>>         self.OnPropertyChanged("inputText")
>>>
>>>
>>> The process terminates due to StackOverflowException.
>>> Looks like the error happens when WFP recoganized INotifyPropertyChange
>>> interface and tries to access MyViewModel class via it.
>>> _________________________________________________
>>> Python.NET mailing list - PythonDotNet at python.org
>>> https://mail.python.org/mailman/listinfo/pythondotnet
>>>
>>>
>> _________________________________________________
>> Python.NET mailing list - PythonDotNet at python.org
>> https://mail.python.org/mailman/listinfo/pythondotnet
>>
>
> _________________________________________________
> Python.NET mailing list - PythonDotNet at python.org
> https://mail.python.org/mailman/listinfo/pythondotnet
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/pythondotnet/attachments/20160404/d6d99926/attachment-0001.html>


More information about the PythonDotNet mailing list