.netwpfdata-bindingitemtemplate

How to determine if an item is the last one in a WPF ItemTemplate?


I have some XAML:

<ItemsControl Name="mItemsControl">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding Mode=OneWay}" KeyUp="TextBox_KeyUp"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

that's bound to a simple ObservableCollection

private ObservableCollection<string> mCollection = new ObservableCollection<string>();

public MainWindow()
{
    InitializeComponent();

    this.mCollection.Add("Test1");
    this.mCollection.Add("Test2");
    this.mItemsControl.ItemsSource = this.mCollection;
}

Upon hitting the enter key in the last TextBox, I want another TextBox to appear. I have code that does it, but there's a gap:

private void TextBox_KeyUp(object sender, KeyEventArgs e)
{
    if (e.Key != Key.Enter)
    {
        return;
    }

    TextBox textbox = (TextBox)sender;

    if (IsTextBoxTheLastOneInTheTemplate(textbox))
    {
        this.mCollection.Add("A new textbox appears!");
    }
}

The function IsTextBoxTheLastOneInTheTemplate() is something that I need, but can't figure out how to write. How would I go about writing it?

I've considered using ItemsControl.ItemContainerGenerator, but can't put all the pieces together.


Solution

  • I was able to get a decent solution by referring to http://drwpf.com/blog/2008/07/20/itemscontrol-g-is-for-generator/. Not super-elegant, but it worked for me.

        private void TextBox_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key != Key.Enter)
            {
                return;
            }
    
            TextBox textbox = (TextBox)sender;
    
            var lastContainer = this.mItemsControl.ItemContainerGenerator.ContainerFromIndex(this.mItemsControl.Items.Count - 1);
    
            var visualContainer = (Visual)lastContainer;
    
            var containedTextbox = (TextBox)GetDescendantByType(visualContainer, typeof(TextBox));
    
            var isSame = textbox == containedTextbox;
    
            if (isSame)
            {
                 this.mCollection.Add("A new textbox appears!");
            }
        }
    
    
        public static Visual GetDescendantByType(Visual element, Type type)
        {
            if (element.GetType() == type) return element;
    
            Visual foundElement = null;
    
            if (element is FrameworkElement)
                (element as FrameworkElement).ApplyTemplate();
    
            for (int i = 0;
                i < VisualTreeHelper.GetChildrenCount(element); i++)
            {
                Visual visual = VisualTreeHelper.GetChild(element, i) as Visual;
                foundElement = GetDescendantByType(visual, type);
                if (foundElement != null)
                    break;
            }
    
            return foundElement;
        }