0

昨天我遇到了如何从异步方法回调更新 c# wpf 中的 gui 的问题

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

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
});

我不知道该怎么做才能让它工作。任何帮助,将不胜感激。

4

3 回答 3

3

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

我看到你在评论中尝试了各种各样的东西,但不清楚你是否findVisualParent在尝试过的时候注释掉了。因此,我无法准确告诉您哪里出了问题,但可以告诉您,您正试图从一个未通过其调度程序创建的线程访问 UI 组件。

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

于 2013-04-19T07:27:36.123 回答
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);
        }

    }
于 2013-04-19T07:24:18.840 回答
0

我刚刚将 UI 调度程序保存在一个全局位置,当我想从一个线程切换时,我调用了这样的东西:

公共无效ChangetoWindow(){

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

于 2014-08-30T20:18:15.167 回答