带按钮列的WPF datagrid实时更新

带按钮列的WPF datagrid实时更新,wpf,datagrid,Wpf,Datagrid,我有一个数据网格,其中包含货币符号的出价和要价。数据每秒钟更新一次。我通过创建viewmodel实体的新集合来更新数据,并每秒将该集合绑定到datagrid 问题是: 因为我的datagrid包含一个带有按钮“buy”的模板列,所以该按钮也会每秒重新创建一次!这意味着,当用户将按钮悬停时,悬停样式将闪烁,因为按钮每秒都会重新创建。此外,如果在用户按下鼠标左键时重新创建按钮,则有时不会正确触发单击事件 有什么建议吗?如何解决用按钮列实时更新数据网格的问题?您研究过这个问题吗 表示动态数据集合,该集

我有一个数据网格,其中包含货币符号的出价和要价。数据每秒钟更新一次。我通过创建viewmodel实体的新集合来更新数据,并每秒将该集合绑定到datagrid

问题是: 因为我的datagrid包含一个带有按钮“buy”的模板列,所以该按钮也会每秒重新创建一次!这意味着,当用户将按钮悬停时,悬停样式将闪烁,因为按钮每秒都会重新创建。此外,如果在用户按下鼠标左键时重新创建按钮,则有时不会正确触发单击事件

有什么建议吗?如何解决用按钮列实时更新数据网格的问题?

您研究过这个问题吗

表示动态数据集合,该集合在添加、删除项或刷新整个列表时提供通知

这应该只刷新那些已更改的项目,而不是整个网格。

您查看了吗

表示动态数据集合,该集合在添加、删除项或刷新整个列表时提供通知


这应该只刷新那些已更改的项目,而不是整个网格。

如果我理解正确,您有一个项目集合,您有两个字段(特别是bid/ask),所有这些字段都将每秒更新一次。听起来可能发生的情况是,在更改数据网格的ItemsSource的过程中,您丢失了一些重要的状态,这会给按钮上的事件处理程序带来问题

即使您更新了所有项,重要的区别是您应该更新这些项,而不是完全清除当前绑定到datagrid的集合。将ItemsSource更改为新的将导致数据网格所做的工作比仅更新现有集合的内容要多得多。如果您使用的是ObservableCollection,这可能意味着使viewmodel项可变,这样您就可以简单地更新出价/出价。如果viewmodel项是可变的,并且实现了INotifyPropertyChanged,则bid/ask更新将反映在datagrid或对象的这些属性的任何其他绑定中。这样做的好处是,相同的对象被绑定到ItemsControl中的相同容器,因此在每次更新期间,按钮绝对不会发生任何变化。现在,如果包含bid/ask的viewmodel对象是不可变的,您应该仍然能够实现这一点。每隔一秒钟,您只需遍历项目集合,并使用SetItem将现有的每个项目替换为新的项目。在后一种情况下,需要记住的重要一点是,每隔一秒钟,datagrid仍然会收到通知,说明ObservableCollection中发生了更改,因此,每行上的绑定都会导致行/单元格/按钮的DataContext更新

这里有一个我如何处理这个问题的快速示例。我将假设在.NET4.0中使用datagrid(如果您在3.5中使用toolkit,这应该是相同的)。我将采用第一种方法,其中CurrencyPair对象是可变的

首先,一些简单的viewmodel代码,带有一个独立的计时器,用于每秒更新几个货币对出价/出价:

public class CurrencyPairsViewModel
{
    private readonly Dispatcher _dispatcher = Dispatcher.CurrentDispatcher;
    private readonly ObservableCollection<string> _orders = new ObservableCollection<string>();
    private readonly ObservableCollection<CurrencyPair> _pairs = new ObservableCollection<CurrencyPair>();
    private readonly Random _rand = new Random();
    private readonly System.Timers.Timer _timer = new System.Timers.Timer(1000);
    private readonly Action _update;

    public CurrencyPairsViewModel()
    {
        this._timer.Elapsed += OnIntervalElapsed;
        this._update = new Action(this.Update);
        this._pairs.Add(new CurrencyPair("USD/GBP"));
        this._pairs.Add(new CurrencyPair("AUD/USD"));
        this._pairs.Add(new CurrencyPair("WOW/CAD"));
        this._timer.Start();
    }

    public ObservableCollection<string> Orders { get { return this._orders; } }

    public ObservableCollection<CurrencyPair> Pairs { get { return this._pairs; } }

    public void Buy(CurrencyPair pair)
    {
        this._orders.Add(string.Format("Buy {0} at {1}", pair.Name, pair.Ask));
    }

    private void OnIntervalElapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        this._dispatcher.Invoke(this._update);
    }

    private void Update()
    {
        foreach (var pair in this._pairs)
        {
            pair.Bid = this._rand.NextDouble();
            pair.Ask = pair.Bid + 0.01;
        }
        this._timer.Start();
    }
}

public class CurrencyPair : INotifyPropertyChanged
{
    private readonly string _name;

    private double _ask;
    private double _bid;

    public CurrencyPair(string name)
    {
        this._name = name;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public double Ask
    {
        get { return this._ask; }
        set
        {
            this._ask = value;
            this.OnPropertyChanged("Ask");
        }
    }

    public double Bid
    {
        get { return this._bid; }
        set
        {
            this._bid = value;
            this.OnPropertyChanged("Bid");
        }
    }

    public string Name { get { return this._name; } }

    protected void OnPropertyChanged(string name)
    {
        if (null != this.PropertyChanged)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
}

希望这个例子有帮助

如果我理解正确,您有一个项目集合和几个字段(特别是出价/出价),所有这些字段都将每秒更新一次。听起来可能发生的情况是,在更改数据网格的ItemsSource的过程中,您丢失了一些重要的状态,这会给按钮上的事件处理程序带来问题

即使您更新了所有项,重要的区别是您应该更新这些项,而不是完全清除当前绑定到datagrid的集合。将ItemsSource更改为新的将导致数据网格所做的工作比仅更新现有集合的内容要多得多。如果您使用的是ObservableCollection,这可能意味着使viewmodel项可变,这样您就可以简单地更新出价/出价。如果viewmodel项是可变的,并且实现了INotifyPropertyChanged,则bid/ask更新将反映在datagrid或对象的这些属性的任何其他绑定中。这样做的好处是,相同的对象被绑定到ItemsControl中的相同容器,因此在每次更新期间,按钮绝对不会发生任何变化。现在,如果包含bid/ask的viewmodel对象是不可变的,您应该仍然能够实现这一点。每隔一秒钟,您只需遍历项目集合,并使用SetItem将现有的每个项目替换为新的项目。在后一种情况下,需要记住的重要一点是,每隔一秒钟,datagrid仍然会收到通知,说明ObservableCollection中发生了更改,因此,每行上的绑定都会导致行/单元格/按钮的DataContext更新

这里有一个我如何处理这个问题的快速示例。我将假设在.NET4.0中使用datagrid(如果您在3.5中使用toolkit,这应该是相同的)。我将采用第一种方法,其中CurrencyPair对象是可变的

首先,一些简单的viewmodel代码,带有一个独立的计时器,用于每秒更新几个货币对出价/出价:

public class CurrencyPairsViewModel
{
    private readonly Dispatcher _dispatcher = Dispatcher.CurrentDispatcher;
    private readonly ObservableCollection<string> _orders = new ObservableCollection<string>();
    private readonly ObservableCollection<CurrencyPair> _pairs = new ObservableCollection<CurrencyPair>();
    private readonly Random _rand = new Random();
    private readonly System.Timers.Timer _timer = new System.Timers.Timer(1000);
    private readonly Action _update;

    public CurrencyPairsViewModel()
    {
        this._timer.Elapsed += OnIntervalElapsed;
        this._update = new Action(this.Update);
        this._pairs.Add(new CurrencyPair("USD/GBP"));
        this._pairs.Add(new CurrencyPair("AUD/USD"));
        this._pairs.Add(new CurrencyPair("WOW/CAD"));
        this._timer.Start();
    }

    public ObservableCollection<string> Orders { get { return this._orders; } }

    public ObservableCollection<CurrencyPair> Pairs { get { return this._pairs; } }

    public void Buy(CurrencyPair pair)
    {
        this._orders.Add(string.Format("Buy {0} at {1}", pair.Name, pair.Ask));
    }

    private void OnIntervalElapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        this._dispatcher.Invoke(this._update);
    }

    private void Update()
    {
        foreach (var pair in this._pairs)
        {
            pair.Bid = this._rand.NextDouble();
            pair.Ask = pair.Bid + 0.01;
        }
        this._timer.Start();
    }
}

public class CurrencyPair : INotifyPropertyChanged
{
    private readonly string _name;

    private double _ask;
    private double _bid;

    public CurrencyPair(string name)
    {
        this._name = name;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public double Ask
    {
        get { return this._ask; }
        set
        {
            this._ask = value;
            this.OnPropertyChanged("Ask");
        }
    }

    public double Bid
    {
        get { return this._bid; }
        set
        {
            this._bid = value;
            this.OnPropertyChanged("Bid");
        }
    }

    public string Name { get { return this._name; } }

    protected void OnPropertyChanged(string name)
    {
        if (null != this.PropertyChanged)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
}

希望这个例子有帮助

谢谢你的建议!我已经尝试使用ObservableCollection而不是简单的列表。结果是一样的,因为每一个买卖对都是每秒更新一次的。。。所以我需要的是一种只刷新单元格而不刷新整行的功能。@dlang-也许吧
public partial class MainWindow : Window
{
    private readonly CurrencyPairsViewModel _model = new CurrencyPairsViewModel();

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this._model;
    }

    private void OnBuyClicked(object sender, RoutedEventArgs e)
    {
        var pair = (CurrencyPair)((Button)sender).DataContext;
        this._model.Buy(pair);
    }
}