2

Binding ItemsControl to an ObservableCollection<T> places an extra {NewItemPlaceholder} in the control at runtime. How can I remove it?

N.B. I have seen posts related to this problem but those are limited to DataGrid where you can set CanUserAddRows or IsReadOnly properties to get rid of this item. ItemsControl doesn't have any such property.

XAML

Here's my ItemsControl (MyPoints is ObservableCollection<T> in the underlying ViewModel):

<ItemsControl ItemsSource="{Binding MyPoints}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <Canvas />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>

  <ItemsControl.ItemContainerStyle>
    <Style TargetType="FrameworkElement">
      <Setter Property="Canvas.Left" Value="{Binding Path=X}" />
      <Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
    </Style>
  </ItemsControl.ItemContainerStyle>

  <ItemsControl.ItemTemplate>
    <DataTemplate DataType="{x:Type vm:PointVM}">
      <Ellipse Width="10" Height="10" Fill="#88FF2222" />
    </DataTemplate>       
  </ItemsControl.ItemTemplate>
</ItemsControl>

This displays an extra point at 0,0. Live Property Explorer shows that this point is bound to the {NewItemPlaceholder} object.

Community
  • 1
  • 1
dotNET
  • 33,414
  • 24
  • 162
  • 251
  • Actually it works fine for me when adding points from ViewModel this way: `MyPoints = new ObservableCollection { new MyPoint { X = 2, Y = 3}, new MyPoint { X = 40, Y = 60} };` Is your ObservableCollection binded to somewhere else as well? – aniski May 13 '16 at 09:38

2 Answers2

2

MSDN writes the following:

When a CollectionView that implements IEditableCollectionView has NewItemPlaceholderPosition set to AtBeginning or AtEnd, the NewItemPlaceholder is added to the collection. The NewItemPlaceholder always appears in the collection; it does not participate in grouping, sorting, or filtering.

Link: MSDN

Hopefully if you set the NewItemPlaceholderPosition to something else, the placeholder will disappear from the collection.

Edit:

If your ObservableCollection<T> is being binded to somewhere else as well (e.g.: to a DataGrid, you have to set the CanUserAddRows to false), you have to deal with that other item. It would add a new NewItemPlaceholder to your collection.

aniski
  • 1,263
  • 1
  • 16
  • 31
  • `ObservableCollection` doesn't appear to implement `IEditableCollectionView`. Or am I missing something? – dotNET May 13 '16 at 07:32
  • Could you add the xaml part of the `ItemsControl`'s settings to your question, please? – aniski May 13 '16 at 07:45
  • Updated my question. – dotNET May 13 '16 at 09:27
  • I changed `ObservableCollection` to `List` and could still see the extra item. I went as far as actually removing the dependency property to which `ItemsControl.ItemsSource` was binding and instead used direct binding with the VM property, but can still see the unwanted item in the `ItemsControl`. Pretty much done here. :( – dotNET May 13 '16 at 11:41
  • Try to create a new project, and add only the `ObservableCollection` and the `ItemsControl`. That must work. Then try to build up other xaml elements which are using the collection. – aniski May 13 '16 at 13:57
  • Your guess was correct. My `ObservableCollection` was bound to a `DataGrid` too, which was actually responsible for the extra item. I have fixed it now. – dotNET May 13 '16 at 18:08
  • Thanks for sharing this info, I'm glad we've solved it! – aniski May 13 '16 at 18:23
1

Finally finally!

After spending a day, the solution turned out to be simple (although not ideal). ItemTemplateSelector allows me to select a template based on the item type, so I can create a simple selector to get rid of the extra item:

public class PointItemTemplateSelector : DataTemplateSelector
{
  public override DataTemplate SelectTemplate(object item, DependencyObject container)
  {
    if (item == CollectionView.NewItemPlaceholder)
      return (container as FrameworkElement).TryFindResource("EmptyDataTemplate") as DataTemplate;
    else
      return (container as FrameworkElement).TryFindResource("MyDataTemplate") as DataTemplate;
  }
}

MyDataTemplate and EmptyDataTemplate should be defined in the Resources section of your ItemsControl. EmptyDataTemplate doesn't need to have any content.

Edit

@KAI's guess (see accepted answer) was correct. My ObservableCollection<T> was bound to a DataGrid which was causing this problem. I'll still keep my answer here as it provides a solution for other related situations.

dotNET
  • 33,414
  • 24
  • 162
  • 251