WPF - Viewmodel - 刷新数据时的绑定错误

时间:2010-11-04 15:13:38

标签: wpf refresh viewmodel

我有一个MVVM模式测试应用程序正在抛出很多

System.Windows.Data Error: 17 : Cannot get 'Item[]' value (type 'ChuteGroup') from 'Groups' (type 'ChuteGroupsModel'). BindingExpression:Path=Groups[0]; DataItem='MainViewModel' (HashCode=41802290); target element is 'ChuteView' (Name=''); target property is 'DataContext' (type 'Object') ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: index'

当我在viewmodel中输入“onRefresh”例程时会发生这种情况。我有一个名为“Current”的可观察集合,我在刷新例程中做的第一件事是清除Current集合中的条目。然后我得到了大量的这些数据错误17消息,因为我认为在后台绑定正在尝试更新,现在集合中没有任何东西,直到我重新填充并重新创建可观察集合中的每个条目。 / p>

有更好的方法吗?运行时性能似乎不受此影响,但我不喜欢输出窗口中的错误。我发现如果我没有清除它的集合,每次viewmodel刷新自己时它的大小只会增加一倍。由于此集合与54个UI元素结合使用,这些元素按索引绑定,因此集合的大小不能加倍,或者所有内容都不会指向正确的UI元素。

private void FetchData()
    {
        ChuteGroupsModel.isDuringRefresh = true;
        DataSet sqldata = new DataSet();
        SqlConnection conn = new SqlConnection("Data Source=(local);Initial Catalog=ScratchPaper;User ID=somecacct;Password=somepassword;Connect Timeout=5");
        SqlCommand cmd = new SqlCommand("Select chuteGroup, chuteGroupDef, TotalChutes, UpPackWave, UpColorId, UpPackWaveTS, DownPackWave, DownColorId, DownPackWaveTS from ChuteGroups Order by chuteGroup asc",conn);
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        try
        {
        da.Fill(sqldata);

        }
        catch (Exception Ex){ MessageBox.Show(Ex.ToString());}


       //DataSet sqldata = this.DataLayer.getDataSet("Select * from AvailableColors Order by ID asc", CommandType.Text, null);
        foreach (DataRow row in sqldata.Tables[0].Rows)
        {
            ChuteGroup group = new ChuteGroup((int)row.ItemArray[0], (string)row.ItemArray[1], (int)row.ItemArray[2], (string)row.ItemArray[3],(string)row.ItemArray[4], (DateTime)row.ItemArray[5], (string)row.ItemArray[6], (string)row.ItemArray[7], (DateTime)row.ItemArray[8]);
            Add(group);
        }
        ChuteGroupsModel.isDuringRefresh = false;
    }

 private void onRefresh(object sender, System.EventArgs e)
    {
        try
        {     
            if (ChuteGroupsModel.isDuringRefresh)
            {
                return;
            }
            Refresh();
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message.ToString());
        }
    }
 public void Refresh()
    {
        Current.Clear();  //Current is a static reference to my collection
        FetchData();
    }

2 个答案:

答案 0 :(得分:1)

您认为绑定错误是由于您的收集被清除所以是正确的。由于您没有遇到任何性能损失,我不会太担心它。

如果您对它们非常恼火,可以创建一个新的可观察集合类型以允许您设置新值。如果你在Reflector中打开ObservableCollection类,你将复制实现,并添加一个新的方法,如下所示:

public class ObservableList<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
    // ObservableCollection implementation here
    ...

    public void SetItems(IEnumerable<T> items)
    {
        this.CheckReentrancy();
        base.ClearItems();

        int i = 0;
        foreach (var item in items)
        {
            base.InsertItem(i, item);
            ++i;
        }

        this.OnPropertyChanged("Count");
        this.OnPropertyChanged("Item[]");
        this.OnCollectionReset();

    }
}

然后,您不是清除数据并一次添加一行,而是调用SetItems方法。

答案 1 :(得分:0)

我知道已经问了这个问题已经有一段时间了,但是我解决这类问题的一种方法是使用RemoveAt(0)(和/或你需要清除的任何位置),然后将数据添加到集合。 Clear()似乎存在某种时序问题,因为对于一些简短的时刻,来自数据绑定的调用返回一个空集合,从而返回输出消息。与更通用的清晰相比,这看起来可能看起来有点细节,也许是野蛮的,但它确实消除了错误并显着提高了性能。