简体   繁体   中英

Using WPF/MVVM, how do I immediately restore focus to my application after closing extnernal process?

I have a full screen WPF application that launches external processes when the user selects an item from a listbox. Navigation with the listbox is done primarily with the keyboard and not the mouse. What is the cleanest way to immediately return focus to the listbox once the user closes the external app? I've got it working, but the solution is not ideal as far as I'm concerned and is a bit "hacky".

Here's the XAML:

<ListBox SelectedIndex="{Binding ActiveSelection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                 IsSynchronizedWithCurrentItem="True" x:Name="ListBoxSelector">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

And the code:

private void Button_Click(object sender, RoutedEventArgs e)
{
    var process = Process.Start(@"C:\Windows\system32\mspaint.exe");
    process.WaitOnExit()
    ActiveSelection += 1;
    ActiveSelection -= 1;
}

So basically changing the ActiveSelection (and then back again so the same thing is still selected) seems to focus the listbox instantly once the MSPaint program closes. So I've achieved the desired outcome, but I think there's probably a better and cleaner solution.

Focus is a view concern.

So a direct approach would be to have whatever model/service your Process.Start is raise an event when the process exits, have the VM pick that up and raise an event in turn, and finally have the view react by setting the focus.

Alternatively, the VM could set a property say CurrentlyInExternalApplication that when set to false by the aforementioned event would cause a trigger (similar to your existing one) to fire.

You can try to run child process in a new thread and call process.WaitForExit() after it is started. Then, after child process is closed you can make your app focus using Dispatcher since the current thread is not a UI thread.

var process = Process.Start(@"C:\Windows\system32\mspaint.exe");
process.WaitForExit();
Dispatcher.Invoke(() => MainWindow.Current.MakeFocus()); // sample line

Your MainWindow should have a static property Current and it should be set when your main app is started.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM