Click here to Skip to main content
15,887,434 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I have a Windows WPF application, following a fairly standard MVVM architecture. I am having trouble getting a list of items to respond to changes in the properties they are bound to. Here are some key components that are involved in my problem:

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 } }
}


So far, so good. Now, in the view, I want to display a list of contacts, and I want the Name field to be editable always but I want the Telephone field to become editable only when the contact record is not a placeholder. (The placeholders are used when the user creates a new contact, sort-of a dummy record that only gets saved to the database once it has been given a valid name.)

My XAML looks something like this:

<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}"/>


Everything works as expected, with the exception that the IsEnabled="{Binding IsNotPlaceholder}" does not 'realise' when it needs to update itself. The Contact is in my model-layer. I have set this up so that any data changes fire an event, which in turn fires an event in the view-model layer. The event in the view-model layer calls OnPropertyChanged( "" ), which should cause all UI elements to re-evaluate their bindings. But still the Telephone field does not become editable.

How can I get this working?

What I have tried:

I have tried setting the IsEnabled="true" in x:Key="DataTemplateContactSelected", and the Telephone field is editable when I select the contact in the list, so this part is working fine.

It is my binding to IsNotPlaceholder that is failing.
Posted
Updated 7-Jun-17 4:36am
v3
Comments
Richard Deeming 7-Jun-17 10:32am    
OnPropertyChanged( nameof(IsPlaceholder) );

Shouldn't that be nameof(IsNotPlaceholder) instead?
Patrick Skelton 7-Jun-17 10:35am    
Well spotted, Richard. Sorry, it should indeed be as you say. It does match in the real code. The real code has a property IsPlaceholder but I changed it for the example just to get rid of the need for a negation converter in the XAML. I will update the question now.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900