[IronPython] DataBinding from IronPython Object to WPF Property

Steve Apiki sapiki at appropriatesolutions.com
Thu Aug 6 07:23:18 CEST 2009


Hi Curt,

Thanks, just what I needed and the performance is definitely acceptable if you keep trackedNames to a minimum.

--Steve

----- Original Message -----
From: "Curt Hagenlocher" <curt at hagenlocher.org>
To: "Discussion of IronPython" <users at lists.ironpython.com>
Sent: Wednesday, August 5, 2009 8:35:15 PM GMT -05:00 US/Canada Eastern
Subject: Re: [IronPython] DataBinding from IronPython Object to WPF Property


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 


_______________________________________________
Users mailing list
Users at lists.ironpython.com
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com



More information about the Ironpython-users mailing list