[IronPython] DataBinding from IronPython Object to WPF Property

Curt Hagenlocher curt at hagenlocher.org
Thu Aug 6 02:38:15 CEST 2009


Oops -- I should have pointed out that pyevent.py is in the standard
IronPython distribution; probably in a directory called "samples" or
"tutorial". (Network service in the bus is flaky, so I'm finding it hard to
check.)


On Wed, Aug 5, 2009 at 5:35 PM, Curt Hagenlocher <curt at hagenlocher.org>wrote:

> Python's __setattr__ hook makes INotifyPropertyChanged easy to implement if
> you're willing to pay the performance penalty. Just derive from a class like
> this one:
>
> class PropertyChangeNotifier(INotifyPropertyChanged):
>     def __init__(self, *trackedNames):
>         self._PropertyChanged, self._OnPropertyChanged =
> pyevent.MakeEvent()
>         self._trackedNames = trackedNames
>     def add_PropertyChanged(self, handler):
>         self._PropertyChanged += handler
>     def remove_PropertyChanged(self, handler):
>         self._PropertyChanged -= handler
>     def __setattr__(self, name, value):
>         object.__setattr__(self, name,value)
>         if name != "_PropertyChanged" and name != "_OnPropertyChanged":
>             if len(self._trackedNames) == 0 or name in self._trackedNames:
>                 self._OnPropertyChanged(self,
> PropertyChangedEventArgs(name))
>   On Wed, Aug 5, 2009 at 1:50 PM, Steve Apiki <
> sapiki at appropriatesolutions.com> wrote:
>
>> Hi Dino,
>>
>> Thanks for your quick answer and for making things clear on
>> INotifyPropertyChanged.
>>
>> I'd like to have my own derived classes for this project so I think I'm
>> going to steer clear of ExpandoObject and look into implementing
>> INotifyPropertyChanged.
>>
>> And I tried out your suggestion for #2, creating a new class:
>>
>> class Context(object):
>>    def __init__(self):
>>        self.person = Person("Alfred")
>>
>> and then assigning a new Person as the person attribute of the context:
>>
>> label.DataContext = a_context
>>
>> def button_click(sender, args):
>>    a_context.person = Person("Mathilda")
>>
>> which works (for now) as long as I do the UpdateTarget() and presumably
>> will work as well with implementing INotifyPropertyChanged.
>>
>> Thanks,
>>
>> --Steve
>>
>> ----- Original Message -----
>> From: "Dino Viehland" <dinov at microsoft.com>
>> To: "Discussion of IronPython" <users at lists.ironpython.com>
>> Sent: Wednesday, August 5, 2009 4:11:26 PM GMT -05:00 US/Canada Eastern
>> Subject: Re: [IronPython] DataBinding from IronPython Object to WPF
>> Property
>>
>> IronPython doesn't actually support INotifyPropertyChanged - it only
>> supports custom type descriptor so that WPF can get at the values
>> but it doesn't get the change notifications.
>>
>> You could make an instance of ExpandoObject which does support it:
>>
>> import clr
>> clr.AddReference('Microsoft.Scripting.Core')
>> from Microsoft.Dynamic import ExpandoObject
>> a = ExpandoObject()
>> a.name = 'Foo'
>>
>> Or you could implement INotifiyPropertyChanged on the Person object
>> and use a property which fires the event changed notification.
>>
>> My only thought on #2 would be to add another point of indirection.
>> So rather than updating the global a_person update a_person.real_value
>> and have that update fire a bunch of changed events.
>>
>>
>> > -----Original Message-----
>> > From: users-bounces at lists.ironpython.com [mailto:users-
>> > bounces at lists.ironpython.com] On Behalf Of Steve Apiki
>> > Sent: Wednesday, August 05, 2009 12:58 PM
>> > To: users at lists.ironpython.com
>> > Subject: [IronPython] DataBinding from IronPython Object to WPF
>> > Property
>> >
>> > Hello,
>> >
>> > I'm working with IronPython 2.6 Beta 1.
>> >
>> > I have the following Python class:
>> >
>> > class Person(object):
>> >     def __init__(self, name):
>> >         self.name = name
>> >
>> > I'd like to be able to bind the name property of an instance of this
>> > class to a WPF textbox control.
>> >
>> > I can do this easily enough either in XAML or in code. When the
>> > application starts, the textbox displays the person's name as expected.
>> >
>> > However, if I make changes to the name, say, in response to a button
>> > click:
>> >
>> > def button_click(sender, args):
>> >     a_person.name += ", jr."
>> >
>> > I don't see these changes reflected in the textbox.
>> >
>> > I can make this work by calling UpdateTarget on the binding expression
>> > explicitly:
>> >
>> >     exp = BindingOperations.GetBindingExpression(textbox,
>> > TextBox.TextProperty)
>> >     exp.UpdateTarget()
>> >
>> > but I had thought this would work without the explicit step, since it
>> > appears that IronPython supports INotifyPropertyChange.
>> >
>> > Two questions:
>> >
>> > (1) Is it possible to get databinding to work this way without having
>> > to explicity UpdateTarget?
>> >
>> >
>> > (2) Say instead of the click handler above, we had:
>> >
>> > def button_click(sender, args):
>> >     global a_person
>> >     a_person = Person("Fred")
>> >
>> > In this case, the textbox remains bound to the first Person (which is
>> > no longer accessible from Python). Is there any way to get the binding
>> > to re-sync to the new object, short of setting a completely new binding
>> > to Person("Fred") in code?
>> >
>> >
>> > Full example follows.
>> >
>> > Thanks,
>> >
>> > --Steve
>> >
>> > -----------------------------------------
>> >
>> > import clr
>> > clr.AddReferenceByName("PresentationFramework, Version=3.0.0.0,
>> > Culture=neutral, PublicKeyToken=31bf3856ad364e35")
>> > clr.AddReferenceByName("PresentationCore, Version=3.0.0.0,
>> > Culture=neutral, PublicKeyToken=31bf3856ad364e35")
>> > clr.AddReferenceByPartialName("IronPython")
>> > clr.AddReference("IronPython.Modules")
>> >
>> > from System.Windows import Application, Window
>> > from System.Windows.Controls import StackPanel, Button, TextBox
>> > from System.Windows.Data import Binding, BindingMode, BindingOperations
>> >
>> > class Person(object):
>> >     def __init__(self, name):
>> >         self.name = name
>> > a_person = Person("Al")
>> >
>> > button = Button()
>> > button.Content = "Test"
>> >
>> > textbox = TextBox()
>> > textbox.DataContext = a_person
>> > binding = Binding("name")
>> > binding.Source = a_person
>> > binding.Mode = BindingMode.OneWay
>> > textbox.SetBinding(TextBox.TextProperty, binding)
>> >
>> > def button_click(sender, args):
>> >     """ click handler """
>> >     a_person.name += ", jr."
>> >
>> >     # if you uncomment the following, the textbox is updated
>> >     # with each button click. If you don't, the text never changes.
>> >     #exp = BindingOperations.GetBindingExpression(textbox,
>> > TextBox.TextProperty)
>> >     #exp.UpdateTarget()
>> >
>> > button.Click += button_click
>> >
>> >
>> > window = Window()
>> > stackpanel = StackPanel()
>> > stackpanel.Children.Add(button)
>> > stackpanel.Children.Add(textbox)
>> > window.Content = stackpanel
>> >
>> > Application().Run(window)
>> >
>> >
>> >
>> >
>> >
>> >
>> > _______________________________________________
>> > Users mailing list
>> > Users at lists.ironpython.com
>> > http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>>
>> _______________________________________________
>> Users mailing list
>> Users at lists.ironpython.com
>> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>> _______________________________________________
>> Users mailing list
>> Users at lists.ironpython.com
>> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/ironpython-users/attachments/20090805/46f5e6ad/attachment.html>


More information about the Ironpython-users mailing list