如果我理解正确,您有一组项目,并且您有几个字段(特别是出价/要价),所有这些都将每秒更新一次。听起来可能发生的事情是,在更改数据网格的 ItemsSource 的过程中,您丢失了一些重要状态,这会导致按钮上的事件处理程序出现问题。
即使您更新所有项目,重要的区别是您应该更新项目,而不是完全清除当前绑定到数据网格的集合。与仅更新现有集合的内容相比,将 ItemsSource 更改为新的将导致数据网格需要做更多的工作。如果您使用的是 ObservableCollection,这可能意味着使您的视图模型项可变,以便您可以简单地更新出价/要价。如果您的视图模型项是可变的并实现 INotifyPropertyChanged,则出价/要价更新将反映在数据网格或与对象的这些属性的任何其他绑定中。这样做的好处是相同的对象保持绑定到 ItemsControl 中的相同容器,因此在每次更新期间,您的按钮绝对不会发生任何事情。现在,如果您的包含出价/要价的视图模型对象是不可变的,您应该仍然能够实现这一点。每秒钟,您只需遍历您的项目集合并使用 SetItem 将每个现有项目替换为新项目。在后一种情况下要记住的重要一点是,每一秒,数据网格仍然收到通知,通知 ObservableCollection 发生了变化,因此,每行上的绑定将导致行的 DataContext/单元格/按钮进行更新。
这里有一个简单的例子来说明我如何解决这个问题。我将假设在 .NET 4.0 中使用数据网格(如果您使用的是 3.5 的工具包,这应该是相同的)。我将采用第一种方法,我的 CurrencyPair 对象是可变的。
首先,一些简单的视图模型代码带有一个自包含的计时器来每秒更新几个货币对的出价/要价:
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));
}
}
}
第二,视图,在这个例子中就是我的主窗口。
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="4"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DataGrid Grid.Row="0"
ItemsSource="{Binding Pairs}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="*"/>
<DataGridTextColumn Header="Bid" Binding="{Binding Bid}" Width="*"/>
<DataGridTextColumn Header="Ask" Binding="{Binding Ask}" Width="*"/>
<DataGridTemplateColumn Header="Buy">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="BUY"
Click="OnBuyClicked"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<GridSplitter Grid.Row="1" Height="4" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
<ListBox Grid.Row="2"
ItemsSource="{Binding Orders}"/>
</Grid>
</Window>
最后,我在这个 XAML 后面有一些代码来处理 BUY 按钮的点击并在视图中初始化一个视图模型(请注意,除了如何更新对集合的出价/询价之外的其他做法items 可能不是处理事情的最佳方式,具体取决于您的应用程序将如何增长)。
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);
}
}
希望这个例子有帮助!