0

I have an ObservableCollectiong<StringWrapper> (StringWrapper per this post) named Paragraphs bound to an ItemsControl whose ItemTemplate is just a TextBox bound to StringWrapper.Text.

XAML

<ItemsControl Name="icParagraphs" Grid.Column="1" Grid.Row="7" ItemsSource="{Binding Path=Paragraphs, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
    <ItemsControl.Template>
        <ControlTemplate TargetType="ItemsControl">
            <StackPanel Orientation="Vertical">
                <ItemsPresenter />
            </StackPanel>
        </ControlTemplate>
    </ItemsControl.Template>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
                <TextBox Name="tbParagraph" TextWrapping="Wrap" AcceptsReturn="False" Text="{Binding Path=Text}" Grid.Column="0" KeyUp="tbParagraph_KeyUp" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

C#

public class StringWrapper
{
    public string Text { get; set; }

    public StringWrapper()
    {
        Text = string.Empty;
    }

    public StringWrapper(string text)
    {
        Text = text;
    }
}

I'm trying to make it so when I press enter in a TextBox, I insert a StringWrapper in my ObservableCollection after the StringWrapper bound to the TextBox that's currently focused, which generates a new TextBox. So far, my code does this, though there are a couple glitches to work out.

My question is, how do I then set the focus to the newly generated TextBox? As far as I can tell, the control generation happens after the function that inserts the string returns.

I looked for something like an ItemsControl.ItemsSourceChanged event, but, at least, that name doesn't exist. I also tried attaching a handler to ObservableCollection.CollectionChanged, but that too seemed to fire before the TextBox was generated. Last, since the ItemsControl.Template is a StackPanel, I looked for a StackPanel.ControlAdded event, but couldn't find that either.

Ideas? Thanks!

Community
  • 1
  • 1
dx_over_dt
  • 13,240
  • 17
  • 54
  • 102

1 Answers1

0

You may have to handle CollectionChanged and then schedule the focus action to occur in the future using Dispatcher.BeginInvoke with a priority of Loaded. That should give the ItemsControl an opportunity to generate a container and perform layout.

Mike Strobel
  • 25,075
  • 57
  • 69
  • Could you please explain a little how to use the Dispatcher.BeginInvoke? Sorry not a xaml developer, if you show with little code will be really helpful – MSIslam Mar 31 '15 at 22:33
  • Dispatcher.BeginInvoke((Action)(() => { if (list.Count() > 0) { var lastTextBox = list.Last(x => x.Tag != null && x.Tag.ToString() == "MyTextBox"); if (lastTextBox != null) { lastTextBox.Focus(); } } }), DispatcherPriority.Loaded); – h3n Feb 26 '19 at 18:17