[IronPython] DataBinding from IronPython Object to WPF Property

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


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/7ab904b3/attachment.html>


More information about the Ironpython-users mailing list