1

In my appplication I am trying to focus a textbox so I can type straight away after the Form is loaded.
When the Form is shown, I can see is the cursor blinking in the TextBox but if I type something nothing happens.
I need to click the Window to start entering text in the TextBox. If I run my application normally from Visual Studio, it will work perfectly, but if my application is run using the Task Scheduler, then this happens.
Do you have any advice?

Below is my code:

this.TopMost = true;
textbox.Focus();

I also tried textbox.Select(); but it doesn't work anyway.

Jimi
  • 29,621
  • 8
  • 43
  • 61
Tak
  • 3,536
  • 11
  • 51
  • 93
  • 3
    It sounds like your [form is not activated.](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.form.activate?view=netframework-4.8) – Crowcoder Feb 24 '20 at 11:00
  • @Crowcoder when I add `this.Activate()` then the task schedular call my application the form appears but it keeps kinda flickering like focus then not focus then focus and so on. – Tak Feb 24 '20 at 12:50
  • It is very unusual to have a scheduler run an application that requires user interaction. Have you considered other options? – Crowcoder Feb 24 '20 at 12:58
  • @Crowcoder Other options like what? I want my application runs once someone unlocks the screen or logins in. – Tak Feb 24 '20 at 13:01
  • OK, just thought I'd ask. People often ask for a solution to the wrong problem. – Crowcoder Feb 24 '20 at 13:04

2 Answers2

4

The problem: when the application is run by a Task Scheduler Action, the main Window is shown non-active and the System notifies the User flashing the application's icon in the Task Bar. This is by design.

A simple workaround is to set the startup Window's WindowState = FormWindowState.Minimized in the Form Designer, then set it back to FormWindowState.Normal after the Window has completed loading its content and it's ready to be presented, raising the Shown event.

Setting FormWindowState.Normal causes a call to ShowWindow with nCmdShow set to SW_SHOWNORMAL:

Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.

The Window is now shown as usual, active and ready to receive input.
Also, the code sets explicitly the Control that should receive the input, using the ActiveControl property.

I suggested to make the Shown handler async and add a small delay before re-setting the WindowState property, to prevent the Task Bar icon from getting stuck in a blinking state.

If the Window needs to be repositioned or resized, this needs to be done after the WindowState has been reset, since the Window is in a minimized state before that and won't cache position an size values.
The Form's StartPosition should be set to FormStartPosition.Manual

private async void MainForm_Shown(object sender, EventArgs e)
{
    await Task.Delay(500);
    this.WindowState = FormWindowState.Normal;
    this.ActiveControl = [A Control to activate];
}
Jimi
  • 29,621
  • 8
  • 43
  • 61
0

My Solution is based on Jimi answer but using the Windows API, there is no need to set the Form WindowState property in the Form Designer.

''' <summary>
''' Focuses and brings a window to the foreground
''' </summary>
''' <param name="hwnd">The Window handle</param>
''' <param name="errInfo">Returns error information if any</param>
''' <returns>Returns True if the function succeeded otherwise returns False</returns>
Public Shared Function FocusWindow(hwnd As Integer, ByRef errInfo As Exception) As Boolean

    Try

        If hwnd <= 0 Then Throw New ArgumentException("Invalid window handle.", NameOf(hwnd))

        Dim pHandle = New IntPtr(hwnd)

        ShowWindow(pHandle, ShowWindowEnum.ShowMinimized)
        ShowWindow(pHandle, ShowWindowEnum.ShowNormal)

        If SetForegroundWindow(hwnd) Then
            Return True
        Else
            Throw New Win32Exception(Marshal.GetLastWin32Error, "Win32 method SetForegroundWindow failed.")
        End If

    Catch ex As Exception
        errInfo = ex
        Return False
    End Try

End Function

<DllImport("user32.dll")> Friend Shared Function ShowWindow(hWnd As IntPtr, flags As ShowWindowEnum) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

<DllImport("User32.dll", EntryPoint:="SetForegroundWindow", SetLastError:=True)> Friend Shared Function SetForegroundWindow(hWnd As Integer) As Boolean
End Function

Friend Enum ShowWindowEnum

    Hide = 0
    ShowNormal = 1
    ShowMinimized = 2
    ShowMaximized = 3
    ShowNormalNoActivate = 4
    Show = 5
    Minimize = 6
    ShowMinNoActivate = 7
    ShowNoActivate = 8
    Restore = 9
    ShowDefault = 10
    ForceMinimized = 11

End Enum

Usage

Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown

    If Handle <> IntPtr.Zero Then
        Dim errInfo As Exception = Nothing
        FocusWindow(CInt(Handle), errInfo)
    End If

End Sub
Ahmed Osama
  • 348
  • 1
  • 9