Пользовательский интерфейс не обновляется со списком ExpandoObject
Я реализовал динамический dataGrid, перейдя по этой ссылке.
Я использую конвертер для привязки значений из ExpandoObject
, Столбцы показывают значения, такие как общие единицы для школ.
Item ItemCount DefaultSchool School1 School2 School3
X-Item 200 100 50 50 0
Школы могут быть добавлены динамически в любое время. Теперь, если я добавлю School4 с 40 единицами, я хочу вычесть то же самое из школы по умолчанию (DefaultSchool = 60, School4 = 40).
Я могу сделать эти вычисления в конвертере, и ItemsSource также показывает обновленное значение, но оно не отражается на пользовательском интерфейсе.
Что я использую TextBox's LostFocus
событие с MyDataGrid.Items.Refresh
, он обновляет пользовательский интерфейс, но каждый раз при потере фокуса пользовательский интерфейс также мигает, как обновляющая веб-страница).
Мне просто нужно обновить текущую строку. Как я использую ExpandoObject
Я не могу использовать INotifyPropertyChanged
(Я верю?), Так что должно быть лучшим подходом в этом сценарии?
Так как мне обновить интерфейс?
4 ответа
По умолчанию DataGridColumn имеет однократную привязку, это означает, что он загружается и отображает значение только в первый раз, привязка синуса требует подключения событий, что приводит к небольшому снижению производительности, поэтому они могли бы поступить так. У нас была та же проблема, единственное решение - использовать шаблон ячейки, как показано ниже.
<DataTemplateGridColumn Header="DefaultSchool">
<DataTemplateGridColumn.CellTemplate>
<TextBlock Text="{Binding DefaultSchool}"/>
</DataTemplateGridColumn.CellTemplate>
</DataGridTemplateColumn>
Если вы генерируете столбец динамически, то вам понадобится что-то вроде этого.
var t = new DataTemplate();
t.VisualTree = new FrameworkElementFactory((typeof(TextBlock));
t.VisualTree.SetBinding(new Binding(columnName));
var c = new DataGridTemplateColumn();
c.CellTemplate = t;
c.Header = columnName;
dg.Columns.Add( c );
Я считаю, что это не проблема с ExpandoObject
не реализует INotifyPropertyChanged
(потому что это делает).
Я думаю, что ваша проблема - это сочетание INotifyCollectionChanged
и с помощью конвертера. Что происходит, так это то, что конвертеры вызываются при изменении свойства, но не вызываются при изменении коллекции. Это приведет к тому, что пользовательский интерфейс не будет обновляться при добавлении или удалении элемента из связанной коллекции.
Вы можете взглянуть на эти вопросы для получения дополнительной информации об этой проблеме:
- Как обновить IValueConverter на CollectionChanged?
- Почему конвертер не вызывается при изменении коллекции?
Вы можете увидеть, действительно ли это ваша проблема, установив точку останова в вашем конвертере и посмотреть, вызывается ли она при добавлении нового элемента. Если это действительно проблема, вы можете попытаться обойти это без использования конвертера, или использовать MultiValueConverter
который также получит Count
свойство (которое будет действовать только как триггер), например так:
<DataGrid>
<DataGrid.ItemsSource>
<MultiBinding Converter="{local:MyConverter}">
<Binding Path="Items" />
<Binding Path="Items.Count" />
</MultiBinding>
</DataGrid.ItemsSource>
</DataGrid>
public class MyConverter : MarkupExtension, IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Your converter logic which will use values[0] (the bound collection).
// Ignore anything else in the values[] array.
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
Попробуйте установить окно или текстовый контроль пользователя как этот текст. datacontext = this.datacontext, а у источника данных есть путь к нужным данным. Если вы не установите текстовый текст данных, то у источника данных не будет возможности привязаться к вашим объектам. А после, если он все еще не работает, попробуйте создать табличку с данными для ваших Предметов в ItemSource. И наконец, используйте ObservableCollection, чтобы вам не пришлось реализовывать эти INotifyProperty...
Убедитесь, что в вашей привязке XAML есть Mode = TwoWay.
INotifyCollectionChanged будет гарантировать, что привязки будут получать уведомления при добавлении / удалении элементов в коллекции, но если вы измените / обновите объект в коллекции (объект DefaultSchool), то INotifyCollectionChanged вам не поможет.
Вам необходимо реализовать INotifyPropertyChanged в классе School, чтобы привязки получали уведомления об обновлениях / модификациях объектов этого класса в коллекции.