1

私はこれについて数日間困惑していて、かなり殴られましたが、正直なところ、私はまだそれほど経験がなく、DataGridViewに問題があります-これは一般的なトピックのようです。

public partial class frmMain : Form
{
    ServerConnection sabCom;
    private BindingSource jobSource = new BindingSource();
    private void timer1_Tick(object sender, EventArgs e)
    {
            if (bgUpdateThread.IsBusy == false)
            {
                bgUpdateThread.RunWorkerAsync(sabCom);
            }
        }
    }

    private void frmMain_Load(object sender, EventArgs e)
    {
        timer1.Interval = 3000;
        timer1.Start();
    }

    private void bgUpdateThread_DoWork(object sender, DoWorkEventArgs e)
    {
        ServerConnection s = e.Argument as ServerConnection;
        s.update();
        e.Result = s;
    }

    private void bgUpdateThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        this.sabCom = e.Result as ServerConnection;

        if (dgvQueueFormatted == false)
        {
            dgvQueue_Init();  //Applies formatting and loads column width. Inits data sources.
        }
        else
        {
            dgvQueue_Update();

        }
    }

    private void dgvQueue_Update()
    {
        dgvQueue.Refresh();
    }

    private void dgvQueue_Init()
    {
        try
        {
            jobSource.DataSource = sabCom.queue.jobs;
            dgvQueue.DataSource = jobSource;
            try
            {
                //Apply saved column spacing to the dgvQueue
                //Uses reflection to set dgvQueue to DoubleBuffer
            }
            catch
            { }
        }
        catch
        { }
    }

    private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
    {
        //Saves information about the dgvQueue on shutdown.
    }

キュークラス:

public class Queue  
{
    private string _status;
    public string status { get { return _status; } set { _status = value; } }
    private string _eta;
    public string eta { get { return _eta; } set { _eta = value; } }
    private List<Job> _jobs;
    public List<Job> jobs
    {
        get
        {
            return _jobs;
        }
        set
        {
            _jobs = value;
        }
    }
    private List<string> _categories;
    public List<string> categories { get { return _categories; } set { _categories = value; } }

    private XmlDocument xmld;
    private ServerConnection m_parent;
    private XmlNodeList _xmljobs;

    public Queue(ServerConnection srvConn)
    {
        //fetch the Queue xml
        m_parent = srvConn;
        xmld = new XmlDocument();
        _jobs = new List<Job>();
    }

    public void update()
    {
        updateXml();
        updateQueue();
        updateJobs();
    }

    private void updateXml()
    {
        //Loads xml file into xmld
    }

    private void updateQueue()
    {
        XmlNodeList elements = xmld.SelectNodes("queue");

        foreach (XmlNode element in elements)
        {
            _status = element.SelectSingleNode("status").InnerText;
            _eta = element.SelectSingleNode("eta").InnerText;
        }
    }

    private void updateJobs()
    {
        _xmljobs = xmld.SelectNodes("queue/job");
        jobs.Clear();

        foreach (XmlNode xmljob in _xmljobs)
        {
            Job t_job;

            _status = xmljob.SelectSingleNode("status").InnerText;
            _eta = xmljob.SelectSingleNode("eta").InnerText;

            //Create temp job to match against list.
            t_job = new Job(_status, _eta);
            jobs.Add(t_job);
        }
    }

ジョブクラス:実際には、さまざまなタイプの約30の値を保持しますが、それらはすべて同じ形式です。

public class Job
{
    private int _status;
    public int status { get { return _status; } set { _status = value; } }
    private string _eta;
    public string eta { get { return _eta; } set { _eta = value; } }


    public Job(string status, string eta)
    {
        _status = status;
        _eta = eta;
    }
}

DataGridViewを操作すると、次のエラーが発生します。

DataGridViewで次の例外が発生しました。

System.IndexOutOfRangeException:インデックスに値がありません。System.Windows.Forms.CurrencyManager.get_Item(Int32 index)at System.Windows.Forms.DataGridViewDataConnection.GetError(Int32 boundColumnIndex、Int32 columnIndex、Int32 rowIndex)

そして、デバッガーに入ると、最初のApplication.Run(new frmMain()でトリガーされます。一体何が間違っているのでしょうか。プログラムは正常に機能して更新されますが、デフォルトのエラーメッセージを抑制するためにイベントを処理することさえできません。

編集-回答!リストをクリアして再作成する代わりに、リスト内の値を更新するだけの方が効果的です。今のところ私はこのコードを持っています:

            t_job = _jobs.FirstOrDefault(c => c.nzo_id == t_nzo_id);
            if (t_job == null) //Job not in list, insert
            {
                t_job = new Job(t_status, i_index, t_eta, i_timeLeft, t_age, i_mbleft, i_mb, t_filename, i_priority, t_category, i_percentage, t_nzo_id, this);
                jobs.Add(t_job);
            }
            else //update object in current list
            {
                jobs[t_job.Index].status = t_status;
                jobs[t_job.Index].priority = i_priority;
                jobs[t_job.Index].category = t_category;
                jobs[t_job.Index].percentage = i_percentage;
                jobs[t_job.Index].timeleft = i_timeLeft;
                jobs[t_job.Index].mbleft = i_mbleft;
            } 

それを防ぎます!

4

1 に答える 1

1

問題は、たとえば 1 秒の更新間隔で、ユーザーがスクロールしている間、またはデータのフィールドにアクセスしようとしている間、データが常に削除され、再読み込みされていることです。これにより、バインディングは、まだそこにある可能性があると思われる値を呼び出しますが、そうではありません。そのため、インデックスが範囲外の例外を取得しています。

最初に行うことをお勧めするのは、あなたの updateJobs メソッドと、キュー リストのように更新される他のすべてのリストです。毎回リストをクリアするのではなく、最初に xml からのジョブが現在のジョブ リストに存在するかどうかを確認します。その場合、値が変更されている場合は現在の値を変更できます。それ以外の場合は何もしません。

ジョブが存在するかどうかを確認するには、次のように簡単です。

t_job = _jobs.FirstOrDefault(c => c.Filename == t_filename);

ジョブが存在しない場合、これはnullを返します。ファイル名が一意ではない可能性があると想定するため、実際に一意になるように変更することをお勧めします。

t_job = _jobs.FirstOrDefault(c => c.Filename == t_filename && c.nzo_id == t_nzo_id);

ここで対処しなければならないことの 1 つは、古いジョブが自動的に削除されないことです。そのため、新しい履歴ジョブが追加されるたびに、最初にキューに存在するかどうかを確認し、履歴に追加する前に削除してください。リスト。

プロパティを次のように変更します。

public int Index 
        { 
            get { return _index; } 
            set 
            { 
                if (_index != value)
                    _index = value; 
            } 
        }

それ以外の:

public int Index { get { return _index; } set { _index = value; } }

もう 1 つは、try catch 例外はコストがかかるため、代わりに次のようにすることです。

try { i_percentage = double.Parse(t_percentage); } catch { }

値がある場合は double になることがわかっているため、次のように変更できます。

if (!string.IsNullOrEmpty(t_percentage))
    i_percentage = double.Parse(t_percentage);

t_percentage の値が double になるかどうかわからない場合は、try-parse を使用できます。

if (!string.IsNullOrEmpty(t_percentage))
    double.TryParse(t_percentage,out i_percentage);

これにより、例外によるオーバーヘッドを回避できます。これはマイクロ最適化である可能性があり、実際に問題が発生しない場合は常に必要というわけではありませんが、数百のジョブがあり、それぞれが毎秒 10 程度のプロパティを更新する可能性があることを考えると、2 つでも10 個のプロパティが例外をスローします。

バックグラウンドワーカーが完了した後、メソッドでもう 1 つ: thisdgvQueue_Update()を呼び出すとResetBindings(true);、個々の項目だけでなく、データグリッド全体が更新されます。

次のように変更してみてください。

for (int i = 0; i < jobSource.List.Count; i++)
    jobSource.ResetItem(i);

違いは次のとおりです。

this.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, itemIndex));

あなたがResetBindingsと言うときと比較して:

this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
于 2011-06-04T15:15:52.150 に答える