Search code examples
c#wpfeventsselectionchangedlost-focus

Event priority: LostFocus is called after SelectionChange


Evening all, I've run into an issue with the SelectionChanged (TabControl) event being call before the LostFocus (TextBox) event.

This is a problem since the SelectionChanged is triggered during a tab change, that intern resets the ListView.SelectedIndex (TabControl>TabItem>ListView) to -1.

The textbox uses LostFocus to update/validate it's textbox.text which depend upon the SelectedIndex. The text in the textbox is stored/retrieved from a List<string> and because the index changed, the List happens to go out of bounds.

I've looked around, tired a few things also a "hack-y" approach which didn't really help.

<TabControl SelectionChanged="SelectionChanged_Tab"
    <TabItem .../>
    <TabItem .../>
</TabControl>
<Grid>
   <Label .../>
   <TextBox Name="Name" LostFocus="Lost_Focus" .../>
</Grid>

Code:

private void SelectionChanged_Tab(object sender, SelectionChangedEventArgs e)
{
    if (e.Source is TabControl)
    {
        ListView1.SelectedIndex = -1;
        ListView2.SelectedIndex = -1;
    }
}

private void Lost_Focus(object sender, RoutedEventArgs e)
{
    TextBox textbox = sender as TextBox;
    int Index = ListView.SelectedIndex;

    if (string.IsNullOrEmpty(textbox.Text) || textbox.Text == "0")
    {
        textbox.Text = "0";
    }

    switch (textbox.Name)
    {
        case "Name":
            SomeList[Index].AProperty = textbox.Text;
            break;
    }
}

Solution

  • OK, so after think about the problem from a different perspective, I decided to simple make the TabControl, an Focus-able event and simple make it focus when selection changes:

    <TabControl SelectionChanged="SelectionChanged_Tab" Focusable="True"
        <TabItem .../>
        <TabItem .../>
    </TabControl>
    

    Code:

    private void SelectionChanged_Tab(object sender, SelectionChangedEventArgs e)
    {
        if (e.Source is TabControl)
        {
            ListView2.Focus();
            ListView1.SelectedIndex = -1;
            ListView2.SelectedIndex = -1;
        }
    
        if (ListView2.SelectedIndex == -1)
        {
            ListView1.Focus();
        }
    }
    

    I know it's not the most elegant solution (In the process or re-factoring) but this seems to get the job done.