导航到从线程调用的WPF窗口

时间:2013-04-19 07:13:47

标签: c# wpf mvvm-light

昨天我遇到How to update gui in c# wpf from asynchronous method callback

的问题

没有人帮助我,但我发现了一些有用的东西:

System.Threading.Thread th = new System.Threading.Thread(new System.Threading.ThreadStart(delegate
{
    this.TargetWindow = new MessageListsWindow();
}));
th.SetApartmentState(System.Threading.ApartmentState.STA);
th.Start();

今天我在更改窗口时遇到问题,因为该操作出错:

  

跨线程操作无效:从创建它的线程以外的线程访问控件。

当我从同步方法调用它时,代码可以工作,但是当我异步调用它时它不会。

更改窗口的方法:

public void NavigateToWindow(CustomWindow targetWindow)
{
    CustomWindow currentWindow = findVisualParent<CustomWindow>(this);
    if(currentWindow != null)
    {
        currentWindow.Close();
        //targetWindow.Dispatcher.Invoke(new Action(() => targetWindow.Show()));
        //Application.Current.Dispatcher.BeginInvoke(new Action(() => targetWindow.Show()));
        //targetWindow.Dispatcher.Invoke(new Action(() => targetWindow.Show()));
        //currentWindow.Dispatcher.Invoke(new Action(() => targetWindow.Show()));
        targetWindow.Show();
    }
}
 private T findVisualParent<T>(DependencyObject child)
 where T : DependencyObject
    {
        // get parent item
        DependencyObject parentObject = VisualTreeHelper.GetParent(child);

        // we’ve reached the end of the tree
        if (parentObject == null) return null;

        // check if the parent matches the type we’re looking for
        T parent = parentObject as T;
        if (parent != null)
        {
            return parent;
        }
        else
        {
            // use recursion to proceed with next level
            return findVisualParent<T>(parentObject);
        }

注释代码是我尝试过的,未注释的行适用于同步方法。我已经在WPF中看到这些问题由dispatcher.invoke()处理。在我使用的窗口控件表单中:

this.Invoke((MethodInvoker)delegate
{
    //changing UI
});

我不知道如何使其发挥作用。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:3)

Dispatcher具有线程关联性 - 它为实例化它的线程提供服务。您已经创建了自己的线程,因此该线程将需要自己的调度程序。相反,您正在使用与另一个线程(您的主线程)相关联的调度程序。

我看到你在评论中尝试过各种各样的内容,但是当你尝试使用findVisualParent时,你是否已注释掉它并不清楚。因此,我无法确切地告诉您出错的地方,但可以告诉您,如果没有通过其调度程序执行此操作,您尝试从未创建的线程访问UI组件。

您需要跟踪代码并确切地找到哪条线路失败,看看您正在使用哪个线程并验证您使用的是正确的调度程序。

答案 1 :(得分:0)

如果您使用这种方法,则应先使用CheckAccess()方法,然后再调用窗口上的方法进行显示和关闭。

如果调用线程有权访问此对象,则CheckAccess()返回true。否则返回false,您需要使用Dispatcher调度方法调用。

if(currentWindow != null)
    {
        if(currentWindow.CheckAccess()) {
          currentWindow.Close();
        }
        else {
          currentWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
            ()=>{currentWindow.Close();},null);
        }

        if (targetWindow.CheckAccess()) {
            targetWindow.Show();
          }
        else {
            targetWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
            ()=>{targetWindow.Show();},null);
        }

    }

答案 2 :(得分:0)

我刚刚在一个全局的地方保存了UI调度程序,当我想从一个线程切换时,我称之为:

  

public void ChangetoWindow(){

     

dispatcher.Invoke(()=&gt; navigationService.Navigate(new Window())); }