调度程序调用和组合框添加项中出现空引用异常

本文关键字:引用 异常 调用 组合 添加 调度程序 | 更新日期: 2023-09-27 18:10:18

我在主UI中有一个组合框,我将显示一些可用的项目列表。我有一个后台工作线程,它将运行时检查可用的项目。

我在循环中运行这个线程,以便每次它都会检查可用的项目并更新到主UI组合框。

这是我的代码片段。
do
{
    iNumberofReaders = 0;
    this.Dispatcher.BeginInvoke((Action)(() =>
    {
        NumberOfCards.Items.Clear();
    }));
    //
    // Compose a list of the card readers which are connected to the
    // system and which will be monitored.
    //
    ArrayList availableReaders = this.ListReaders();
    this._states = new ReaderState[availableReaders.Count];
    for (int i = 0; i <= availableReaders.Count - 1; i++)
    {
        this._states[i].Reader = availableReaders[i].ToString();
    }
    result = (SmartcardErrorCode)UnsafeNativeMethods.GetStatusChange(
                this._context, 1000, this._states, this._states.Length);
    szAvailableReaders = new string[availableReaders.Count];
    for (int i = 0; i < availableReaders.Count; i++)
    {
        if (0 != this._states[i]._attribute)
        {
            szAvailableReaders[iNumberofReaders] = this._states[i]._reader;
            iNumberofReaders++;
        } // if
    } // for
    if (iNumberofReaders > 1)
    {
        this.Dispatcher.BeginInvoke((Action)(() =>
        {
            for (int j = 0; j < iNumberofReaders; j++)
            {
                NumberOfCards.Visibility =system.Windows.Visibility.Visible;
                NumberOfCards.Items.Add(szAvailableReaders[j]);
            } // for
        }));
    }
} while (SetThread);

但是这个代码在第二次迭代时会抛出

对象引用未设置为对象的实例

类型为"System"的未处理异常。"得到NullReferenceException发生

如果我注释combobox添加元素,那么它的工作很好。

add元素中的常量字符串也抛出相同的错误。所以我认为问题出在for循环和dispatcher begininvoke.

NumberOfCards.Items.Add("ABCD");

(NumberOfCards is ComboBox)

我观察到dispatcher开始调用的for循环中的奇怪行为。有人能帮忙吗?

调度程序调用和组合框添加项中出现空引用异常

您在单独的线程中修改szAvailableReaders数组,同时在GUI线程中读取它。

首先,您应该考虑使用Invoke而不是BeginInvoke,因为后者在GUI线程上排队请求,并且很容易创建一堆排队操作,这将不必要地占用CPU。

另外,在线程之间共享数据时,最简单的做法是避免共享同一个实例,而是为UI线程创建数据的不可变副本。这也适用于iNumberofReaders和线程之间共享的任何其他字段。

换句话说,背景循环应该是这样的:

do
{
    var availableReaders = this.ListReaders();
    // If you're only using `states` in this method,
    // make it a local variable:
    var states = availableReaders
        .Select(r => new ReaderState() { Reader = r.ToString() })
        .ToArray();
    // fill the data
    result = (SmartcardErrorCode)UnsafeNativeMethods
        .GetStatusChange(this._context, 1000, states, states.Length);
    // this is the important part: create a new instance of reader names.
    // LINQ also simplifies it a bit:        
    var availableReaders = states
        .Where(s => s._attribute != 0)
        .Select(s => s._reader)
        .ToList();
    // now that you have a local list, you can simply swap the field 
    // which is referencing it (since object assignments are atomic in .NET).
    // So the field gets a unique copy every time, and you can even go
    // an extra step forward by declaring it as a `ReadOnlyCollection<string>`:
    szAvailableReaders = new ReadOnlyCollection<string>(availableReaders);
    // Consider using `Invoke` here:        
    this.Dispatcher.BeginInvoke((Action)(() =>
    {
        NumberOfCards.Items.Clear();
        NumberOfCards.Items.AddRange(szAvailableReaders.ToArray());
    }));
} while (SetThread);

除此之外,这看起来像一个非常紧密的循环。我不确定你在这里读到什么,但你不应该使用某种"读者列表更改"事件,只在这种情况下更新组合吗?或者至少使用一个计时器,每秒钟轮询一下列表?