为什么我得到“无效的跨线程访问”;当使用Dispatcher.BeginInvoke()时

本文关键字:Dispatcher BeginInvoke 访问 无效 线程 为什么 | 更新日期: 2023-09-27 18:04:52

我正在寻找标题,以提高我的应用程序的性能,我碰到了一个问题。我想从另一个线程更新UI,从我可以收集我应该使用Dispatcher.BeginInvoke为此,但当我运行下面的代码我得到一个关于无法访问其他线程的错误。什么好主意吗?

错误是An Unhandled exception of type 'System.UnauthorizedAccessException' occurred in System.Windows.ni.dll

附加信息:无效的跨线程访问。"

public void StartPlaneThread()
    {
        var thread = new System.Threading.Thread(DoSomething);
        thread.Start();
    }
    private void DoSomething()
    {
        DispatcherTimer TimerTask;
        TimerTask = new DispatcherTimer();
        TimerTask.Tick += new EventHandler(NewPlaneMovement);
        TimerTask.Interval = new TimeSpan(0, 0, 0, 0, 10);
        TimerTask.Start();
    }
    int NewPlaneTop;
    int newPlaneBottom;
    int newPlaneLeft;
    int newPlaneRight;
    private void NewPlaneMovement(object sender, EventArgs e)
    {
        Dispatcher.BeginInvoke(() =>
            GetUiData() );
        Dispatcher.BeginInvoke(() =>
            SetUiData());



        PlaneFlight = PlaneFlight - 1;
        if (PlaneFlight < -10)
        {
            PlaneFlight = -10;
        }
    }
    private void SetUiData()
    {
        double NewTop = Convert.ToDouble(NewPlaneTop - PlaneFlight);
        PlaneObj.Margin = new Thickness(newPlaneLeft, NewTop, newPlaneRight, newPlaneBottom);
    }
    private void GetUiData()
    {
        NewPlaneTop = Convert.ToInt32(PlaneObj.Margin.Top);
        newPlaneBottom = Convert.ToInt32(PlaneObj.Margin.Bottom);
        newPlaneLeft = Convert.ToInt32(PlaneObj.Margin.Left);
        newPlaneRight = Convert.ToInt32(PlaneObj.Margin.Right);
    }

为什么我得到“无效的跨线程访问”;当使用Dispatcher.BeginInvoke()时

Dispatcher.BeginInvoke()仅在您想要在主UI线程上发生的更改时使用,即在运行时修改UI,当有另一个线程(可能是主线程)正在进行时显示ProgressBar。

直接调用DoSomething,不使用任何线程。同样,直接调用SetUiData,但是这样修改函数:

private void SetUiData()
{
    double NewTop = Convert.ToDouble(NewPlaneTop - PlaneFlight);
    Dispatcher.BeginInvoke(() =>
        PlaneObj.Margin = new Thickness(newPlaneLeft, NewTop, newPlaneRight, newPlaneBottom);
    }
}

最后直接调用GetUiData而不调用Dispatcher.BeginInvoke(),并使用function,因为该函数中没有修改ui。

DispatcherTimer的想法是你在主线程中启动它,它也在主线程中触发。所以不要创建任何线程,只创建DispatcherTimer。您也不需要Dispatcher.BeginInvoke(),因为tick将在主线程中。