JohnG79 JohnG79 - 2 months ago 53
C# Question

Using a IConverter to deal with {NewItemPlaceholder} in WPF / XAML / MVVM

Here is my DataTemplate:

<converter:PlaceholderConverter x:Key="_placeholderConverter"/>

<!-- Data(Display)Template for data objects of x:Type Customer-->
<DataTemplate DataType="{x:Type model:Customer}">
<!-- Customer Properties will be vertically stacked -->
<ContentControl >
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text="{Binding LastName}"/>
<TextBlock Text="{Binding Phone}"/>

And the two different 'container's:

<RowDefinition Height="25"/>
<RowDefinition Height="100"/>
<RowDefinition Height="*"/>

<Button Grid.Row="0"
Command="{Binding DeleteCommand}"/>

<DataGrid Grid.Row="1"
ItemsSource="{Binding Customers}"
SelectedItem="{Binding SelectedCustomer}"

ItemsSource="{Binding Customers, Mode=OneWay}"/>

And the app:

enter image description here

  1. How to remove the {NewItemPlaceholder}? [Done, solution below].

  2. How to prevent the binding error that mention "{NewItemPlaceholder}" when clicking in one of the empty rows in the table above intending on adding a new row (I can still add rows).

The errors:

...Cannot convert '{NewItemPlaceholder}' from type 'NamedObject' to type 'CustomerExample.Model.Customer'...

...ConvertBack cannot convert value '{NewItemPlaceholder}' (type 'NamedObject'). BindingExpression:Path=SelectedCustomer; DataItem='CustomerViewModel'...

I can write an IConverter implementation, but how to tie it in to the XAML?

thanks in advance :-)

Here is the implementation of the IConverter:

public class PlaceholderConverter : IValueConverter
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
if (value != null && value.ToString() == "{NewItemPlaceholder}")
return DependencyProperty.UnsetValue;
return value;

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
throw new NotImplementedException();

and to bind to individual items, the XAML goes something like:

<TextBlock Text="{Binding Name, Converter={StaticResource PlaceholderConverter}}"/>

But I think I need to add it 'globally' to the data collection elements, not to where individual properties are being bound.

Answer Source

You don't need a Binding Converter. Instead, bind the ListBox to a CollectionViewSource that wraps the Custumers collection. The CollectionViewSource skips the NewItemPlaceholder element from the source collection.

    <CollectionViewSource x:Key="CustomersCVS" Source="{Binding Customers}"/>

<ListBox ItemsSource="{Binding Source={StaticResource CustomersCVS}}"/>

You also don't need a Converter for the SelectedItem Binding. Just set the Binding's TargetNullValue property:

<DataGrid SelectedItem="{Binding SelectedCustomer,
    TargetNullValue={x:Static CollectionView.NewItemPlaceholder}}" .../>