“Not Responding” in window title when running in new process

前端 未结 8 1282
清酒与你
清酒与你 2021-02-07 14:39

I have a long running method that must run on UI thread. (Devex - gridView.CopyToClipboard())

I do not need the UI to be responsive while c

相关标签:
8条回答
  • 2021-02-07 14:57

    You can use DisableProcessWindowsGhosting win32 function:

    [DllImport("user32.dll")]
    public static extern void DisableProcessWindowsGhosting();
    

    This actually doesn't prevent the window from freezing, but prevents the "Not Respongind" text in the title.

    0 讨论(0)
  • 2021-02-07 15:04

    There are several possible approaches

    • Hide the main form for the period of the operation
    • Somehow clone/serialize the control and pass it to a thread with another UI dispatcher
    • Get the selected cells via gridView.GetSelectedCells() and then put their contents to the clipboard asynchronously

    It would be more helpful if you've uploaded the GridView library somewhere, so that we could look inside.

    0 讨论(0)
  • 2021-02-07 15:05

    Okay, the 'Not Responding' and window artifacting you've described are just symptoms of running a long term activity on your UI thread. The UI thread is blocked, so the UI is frozen. There is no avoiding this. To be honest, it's just 'lucky' that your application appears as responsive as it does.

    As far as I can see every workaround that has been described here is just a hack to fudge the fact that your UI thread is frozen. Don't do this. Fix your program so the UI thread isn't frozen.

    Ask yourself: do my users really need to copy all the rows from this view? Can the data be filtered in some way to limit the rows? If not, there is a property called MaxRowCopyCount which limits the number of rows that are copied - can this be leveraged without breaking your workflow?

    Finally, if all else fails, is there some other medium you can use (perhaps an intermediate file), to which data can be copied on a background thread?

    0 讨论(0)
  • 2021-02-07 15:07

    The timeout, documented in IsHungAppWindow, cannot be changed. Don't use global state to manage a local problem.

    You have to optimize the part that causes unresponsiveness. For example use caching, virtual grid (DevExpress calls it "server mode"), paging, delegate the sorting to an ibindinglistview filter that does a database query (uses database index) instead of in-memory sorting (no indexing) or implement IAsyncOperation on your clipboard data so you would only need to populate the data when the user does a paste.

    0 讨论(0)
  • 2021-02-07 15:11

    I'm unclear whether your user needs to see the screen that is "unresponsive". If it unnecessary, you might try letting the application run in the background after the main thread for this app is closed; or you may minimize the app.

    If it is necessary to see the application and for it to appear to be working, can you segment your "copy to clipboard" function such that is is threaded and takes in either an array or the gridview and an index range. The advantage to this is that your main thread on your subordinate process would never hang. The disadvantage is that people don't like to work with threading and delegates in C#.

    0 讨论(0)
  • 2021-02-07 15:16

    You could start the process hidden and then check if responding and bring it back into view when complete....your splash screen would show its still "responding".

     Process proc = new Process();
     proc.StartInfo.FileName = "<Your Program>.exe"
    
     proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    

    Edit: You could also create a Timer event watching the other process and roll your own timeout logic

        DateTime dStartTime = DateTime.Now;
        TimeSpan span = new TimeSpan(0, 0, 0);
        int timeout = 30; //30 seconds        
    
        private void timer1_Tick(Object myObject, EventArgs myEventArgs)
        {
            while (span.Seconds < timeout)
            {
                Process[] processList = Process.GetProcessesByName("<YourProcess.exe>");
                if (processList.Length == 0)
                {
                    //process completed
                    timer1.Stop();
                    break;
                }
                span = DateTime.Now.Subtract(dStartTime);
            }
            if (span.Seconds > timeout)
            {
                Process[] processList = Process.GetProcessesByName("<YourProcess.exe>");
    
                //Give it one last chance to complete
                if (processList.Length != 0)
                {
                    //process not completed
                    foreach (Process p in processList)
                    {
                        p.Kill();
                    }
                }
                timer1.Stop();
            }
        }
    

    Edit2

    You could use pInvoke "ShowWindow" to accomplish hiding and showing the window too after its started

    private const int SW_HIDE = 0x00;
    private const int SW_SHOW = 0x05;
    
    [DllImport("user32.dll")]
    static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    
    0 讨论(0)
提交回复
热议问题