How do I bind to a ListBox in IronPython?

人盡茶涼 提交于 2019-12-04 10:41:11

I worked this out myself, I had a few things wrong and was missing a few key point as well. I hope this answer can help someone else.

First was that you need pyevent.py from the tutorial/ directory in your IronPython directory.

Second we need a helper class:

class NotifyPropertyChangedBase(INotifyPropertyChanged):
    """INotifyProperty Helper"""
    PropertyChanged = None
    def __init__(self):
        (self.PropertyChanged, self._propertyChangedCaller) = make_event()

    def add_PropertyChanged(self, value):
        self.PropertyChanged += value

    def remove_PropertyChanged(self, value):
        self.PropertyChanged -= value

    def OnPropertyChanged(self, propertyName):
        self._propertyChangedCaller(self, PropertyChangedEventArgs(propertyName))

Then you need to declare your data class like so:

class Email(NotifyPropertyChangedBase):
    """
        use setter getter.
        IronPython 2.6 or later.
    """
    @property
    def From(self):
        return self._From

    @From.setter
    def From(self, value):
        self._From = value
        self.OnPropertyChanged("From")

    @property
    def Subject(self):
        return self._Subject

    @Subject.setter
    def Subject(self, value):
        self._Subject = value
        self.OnPropertyChanged("Subject")

Finally set the ListBox's ItemSource:

self.data = ObservableCollection[Email]()
self.MyListBox.ItemsSource = self.data

Credit to this link for the help: http://palepoli.skr.jp/wp/2009/06/28/wpf-listview-databinding-for-ironpython/

Extending on boden's answer, you may want to enhance the NotifyPropertyChangedBase a bit:

class NotifyPropertyChangedBase(INotifyPropertyChanged):
    PropertyChanged = None
    def __init__(self):
        self.PropertyChanged, self._propertyChangedCaller = pyevent.make_event()

    def add_PropertyChanged(self, value):
        self.PropertyChanged += value

    def remove_PropertyChanged(self, value):
        self.PropertyChanged -= value

    def OnPropertyChanged(self, propertyName):
        if self.PropertyChanged is not None:
            self._propertyChangedCaller(self, PropertyChangedEventArgs(propertyName))

    def init_view(self, view):
        xaml = view
        self.view = XamlLoader(xaml).Root
        self.view.DataContext = self

    def declareNotifiable(self, *symbols):
        for symbol in symbols:
            self.defineNotifiableProperty(symbol)

    def defineNotifiableProperty(self, symbol):
        dnp = """
import sys
sys.path.append(__file__)
from NotifyProperty import *
@notify_property
def {0}(self):
    return self._{0}   

@{0}.setter
def {0}(self, value):
    self._{0} = value
""".format(symbol)
        d = globals()
        exec dnp.strip() in d
        setattr(self.__class__, symbol, d[symbol])
        exec("self.{0} = ''".format(symbol))

With that set, you could do sometihng like:

class Email(NotifyPropertyChangedBase):
    def __init__(self):
        self.defineNotifiableProperty("From", "Subject")

With that in place, you'll get the @notify_property and @property.setter items set for everything in the defineNotifiableProperty call.

IronPython is case-sensitive and does not use the new keyword. Try:

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