Как получить привязку к элементу списка для обновления?
У меня есть приложение Windows WPF, следующее довольно стандартной архитектуре MVVM. У меня возникли проблемы с получением списка элементов, чтобы реагировать на изменения в свойствах, к которым они привязаны. Вот некоторые ключевые компоненты, которые участвуют в моей проблеме:
public class Contact { public string Name { get { return _name; } set { SetProperty( ref _name, value ); OnPropertyChanged( nameof(IsNotPlaceholder) ); } } public string Telephone { get { return _telephone; } set { SetProperty( ref _telephone, value ); } } public bool IsNotPlaceholder { get { return _name.Length > 0; } } private string _name = String.Empty; private string _telephone = String.Empty; } public class CustomerViewModel : INotifyPropertyChanged { public ObservableCollection<Contact> Contacts { get { return SelectedCustomer.Contacts } } }
Пока все идет хорошо. Теперь в представлении я хочу отобразить список контактов, и я хочу, чтобы
Name
поле должно быть всегда редактируемым, но я хочу, чтобы Telephone
поле становится редактируемым только в том случае, если запись контакта не является заполнителем. (Заполнители используются, когда пользователь создает новый контакт, своего рода фиктивную запись, которая сохраняется в базе данных только после того, как ей присвоено действительное имя.)Мой XAML выглядит примерно так:
<Control.Resources> <ResourceDictionary> <!--- One of two templates for displaying a contact. This version blocks editing of the record. --> <DataTemplate x:Key="DataTemplateContact"> <Grid Grid.Row="0" Grid.Column="0"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="75"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Text="Name:"/> <TextBox Grid.Row="0" Grid.Column="1" Focusable="False" Text="{Binding Name}"/> <TextBlock Grid.Row="1" Grid.Column="0" Text="Telephone:"/> <TextBox Grid.Row="1" Grid.Column="1" Focusable="False" Text="{Binding Telephone}"/> </Grid> </DataTemplate> <!--- One of two templates for displaying a contact. This one is switched in to allow record editing. --> <DataTemplate x:Key="DataTemplateContactSelected"> <Grid Grid.Row="0" Grid.Column="0"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="75"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Text="Name:"/> <TextBox Grid.Row="0" Grid.Column="1" Focusable="True" Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}"/> <TextBlock Grid.Row="1" Grid.Column="0" Text="Telephone:"/> <TextBox Grid.Row="1" Grid.Column="1" Focusable="True" IsEnabled="{Binding IsNotPlaceholder}" Text="{Binding Telephone,UpdateSourceTrigger=PropertyChanged}"/> </Grid> </DataTemplate> <!--- This list item container is used to swap between the editable and non-editable templates above. --> <Style TargetType="{x:Type ListBoxItem}" x:Key="ContactListContainerStyle"> <Setter Property="ContentTemplate" Value="{StaticResource DataTemplateContact}"/> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="ContentTemplate" Value="{StaticResource DataTemplateContactSelected}" /> </Trigger> </Style.Triggers> </Style> </ResourceDictionary> </Control.Resources> <ListBox ItemsSource="{Binding Contacts}" ItemContainerStyle="{StaticResource ContactListContainerStyle}" SelectedItem="{Binding SelectedContact}"/>
Все работает так, как и ожидалось, за исключением того, что
IsEnabled="{Binding IsNotPlaceholder}"
не "понимает", когда ему нужно обновить себя. То Contact
находится в моем модельном слое. Я настроил это так, чтобы любые изменения данных запускали событие, которое, в свою очередь, запускает событие в слое модели представления. Событие в слое view-model вызывает OnPropertyChanged( "" )
, что должно привести к тому, что все элементы пользовательского интерфейса будут повторно оценивать свои привязки. Но все же Telephone
поле не становится редактируемым.Как я могу заставить это работать?
Что я уже пробовал:
Я попробовал установить
IsEnabled="true"
в x:Key="DataTemplateContactSelected"
, а также Telephone
поле редактируется, когда я выбираю контакт в списке, так что эта часть работает нормально.Это моя привязка к
IsNotPlaceholder
это неудача.
Richard Deeming
OnPropertyChanged( nameof(IsPlaceholder) );
Разве это не должно быть
nameof(IsNotPlaceholder)
вместо этого?
Patrick Skelton
Хорошо подмечено, Ричард. Извините, все должно быть именно так, как вы говорите. Он действительно совпадает в реальном коде. Реальный код имеет свойство IsPlaceholder, но я изменил его для примера только для того, чтобы избавиться от необходимости в преобразователе отрицания в XAML. Сейчас я уточню этот вопрос.