#wpf #binding #listbox #ironpython
#wpf #привязка #listbox #ironpython
Вопрос:
Я только начинаю использовать IronPython с WPF и я не совсем понимаю, как предполагается выполнять привязку.
Обычно в WPF я бы просто сделал что-то вроде этого:
<ListBox Name="MyListBox">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<DockPanel>
<TextBlock Text="{Binding Path=From}" />
<TextBlock Text="{Binding Path=Subject}" />
</DockPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
</ListBox>
Затем в моем коде за:
MyListBox.ItemsSource = new ObservableCollection<Email>()
Но в IronPython у нас не может быть наблюдаемой коллекции объектов, только типов. Это не работает:
MyListBox.ItemsSource = new ObservableCollection[email]()
Поскольку он выдает исключение: «ожидаемый массив [тип], получен classobj»
Что я должен делать? Помогите, пожалуйста!
Комментарии:
1. Что значит, что это не работает? Он не компилируется? Это вызывает исключение? В чем ваше сообщение об ошибке?
Ответ №1:
Я разобрался с этим сам, у меня было несколько ошибок, а также не хватало нескольких ключевых моментов. Я надеюсь, что этот ответ может помочь кому-то еще.
Сначала было то, что вам нужно pyevent.py из каталога tutorial / в вашем каталоге IronPython.
Во-вторых, нам нужен вспомогательный класс:
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))
Затем вам нужно объявить свой класс данных следующим образом:
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")
Наконец, установите ItemSource для ListBox:
self.data = ObservableCollection[Email]()
self.MyListBox.ItemsSource = self.data
Спасибо за помощь по этой ссылке:http://palepoli.skr.jp/wp/2009/06/28/wpf-listview-databinding-for-ironpython /
Комментарии:
1. Кажется, что слишком много шаблонов. Интересно, разработал ли кто-нибудь библиотеку, которая делает это менее болезненным за последние 8 лет.
Ответ №2:
Расширяя ответ Бодена, вы можете захотеть немного улучшить NotifyPropertyChangedBase:
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))
С этим набором вы могли бы сделать что-то вроде:
class Email(NotifyPropertyChangedBase):
def __init__(self):
self.defineNotifiableProperty("From", "Subject")
Установив это, вы получите элементы @notify_property и @property.setter, установленные для всего в вызове defineNotifiableProperty.
Ответ №3:
IronPython чувствителен к регистру и не использует new
ключевое слово. Попробуйте:
MyListBox.ItemsSource = ObservableCollection[Email]()