简体   繁体   English

WPF后台线程调用

[英]WPF Background Thread Invocation

Maybe I'm mis-remembering how Winforms works or I'm overcomplicating the hell out of this, but here's my problem. 也许我错误地记得Winforms是如何工作的,或者我因此而过于复杂,但这是我的问题。

I have a WPF client app application that talks to a server over WCF. 我有一个WPF客户端应用程序,通过WCF与服务器通信。 The current user may "log out" of the WPF client, which closes all open screens, leaves only the navigation pane, and minimizes the program window. 当前用户可以“注销”WPF客户端,该客户端关闭所有打开的屏幕,仅保留导航窗格,并最小化程序窗口。 When the user re-maximizes the program window, they are prompted to log in. Simple. 当用户重新最大化程序窗口时,系统会提示他们登录。简单。

But sometimes things happen on background threads - like every 5 minutes the client tries to make a WCF calls that refreshes some cached data. 但有时事情发生在后台线程上 - 比如客户端每5分钟尝试进行一次刷新一些缓存数据的WCF调用。 And what if the user is logged out when this 5 minute timer triggers? 如果用户在5分钟计时器触发时退出怎么办? Well, then the user should be prompted to log back in...and this must of course happen on the UI thread. 那么,应该提示用户重新登录...这当然必须在UI线程上发生。

    private static ISecurityContext securityContext;
    public static ISecurityContext SecurityContext
    {
        get
        {
            if (securityContext == null)
            {
                // Login method shows a window and prompts the user to log in
                Application.Current.Dispatcher.Invoke((Action)Login); 
            }
            return securityContext;
        }
    }

    private static void Login()
    {
       if (securityContext == null) { \
         /* show login window and set securityContext */ 
         var w = new LoginWindow();
         w.ShowDialog();
         securityContext = w.GetSecurityContext();
       }
    }

So far so good, right? 到目前为止一切都那么好吧? But what happens when multiple threads hit this spot of code? 但是当多个线程遇到这个代码点时会发生什么?

Well, my first intuition was that since I'm syncrhonizing across the Application.Current.Dispatcher, I should be fine, and whichever thread hit first would be responsible for showing the login form and getting the user logged in... 好吧,我的第一个直觉是,因为我在Application.Current.Dispatcher上进行同步,我应该没问题,无论哪个线程首先命中,都要负责显示登录表单并让用户登录...

Not the case... 不是这样的......

  1. Thread 1 will hit the code and call ShowDialog on the login form 线程1将命中代码并在登录表单上调用ShowDialog

  2. Thread 2 will also hit the code and will call Login as soon as Thread 1 has called ShowDialog, since calling ShowDialog unblocked Thread 1 (I believe because of the way the WPF message pump works) 线程2也将命中代码并在线程1调用ShowDialog后立即调用Login,因为调用ShowDialog解锁线程1(我相信因为WPF消息泵的工作方式)

...the end effect being that I have multiple login forms popped up to the user at once. ...最终结果是我有多个登录表单一次弹出给用户。

All I want is a synchronized way of getting the user logged back into the application...what am I missing here? 我想要的只是让用户重新登录应用程序的同步方式......我在这里缺少什么?

Thanks in advance. 提前致谢。

Perhaps a little locking? 也许有点锁定?

You can monitor the entries and perhaps ignore (not block) the other polling actions. 您可以监视条目,也可以忽略(不阻止)其他轮询操作。 Use the single entry point to display the login form only once and wait... 使用单个入口点只显示一次登录表单并等待...

http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx

Also, consider caching the users credentials rather than re-prompting them, eg SecureString: 另外,请考虑缓存用户凭据而不是重新提示它们,例如SecureString:

http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx

PK :-) PK :-)

Sorry for the delayed follow-up. 对不起延迟的跟进。

I fixed the blocking problem a few days ago on the UI thread by basically implementing DoEvents for WPF: http://khason.net/blog/how-to-doevents-in-wpf/ 我几天前在UI线程上通过基本实现WPF的DoEvents修复了阻塞问题: http//khason.net/blog/how-to-doevents-in-wpf/

So now, many threads, both background and UI can invoke onto the UI thread, and if the window is already shown, will "emulate" the behavior of ShowDialog, but not block and not show a second Login window... Hope that makes sense to anyone reading. 所以现在,许多线程,后台和UI都可以调用UI线程,如果窗口已经显示,将“模拟”ShowDialog的行为,但不会阻止,也不会显示第二个登录窗口...希望这样做任何阅读的人都有意义

void ShowLoginWindow(Window window) 
          {
                if (window != null )
                {
                    if (window.Visibility != Visibility.Visible)
                    {
                        try
                        {
                            result = window.ShowDialog();
                        }
                        catch (Exception ex)
                        {
                        }
                    }
                    else
                    {
                        // don't block the UI thread, but wait till the dialog window returns 
                        while(window.Visibilit y== Visibility.Visible)
                        {
                            DoEvents();
                        }
                        return window.DialogResult;
                    }
                }
                return result;
        }

        void DoEvents()
        {
            DispatcherFrame f = new DispatcherFrame();
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
            (SendOrPostCallback)delegate(object arg)
            {
                DispatcherFrame fr = arg as DispatcherFrame;
                fr.Continue = false;
            }, f);
            Dispatcher.PushFrame(f);
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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