Patrick Skelton Ответов: 0

Как получить привязку к элементу списка для обновления?


У меня есть приложение 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. Сейчас я уточню этот вопрос.

0 Ответов