数据绑定到每个 KeyValuePair<string, List<T>> 中的最后一个条目
Databinding to last entry in each KeyValuePair<string, List<T>>
我有一个实现 INotifyChanged 的简单 OHLC 对象。每个 OHLC 对象都与特定蜡烛相关,并且是列表的一部分。每个列表都与特定股票相关,并存储在 ConcurrentDictionary 中。
我正在尝试将每只股票的最后一根蜡烛数据绑定到数据网格视图。这就是我设置数据绑定的方式。不是很优雅!
ConcurrentDictionary<string, List<OHLC>> candles= new ConcurrentDictionary<string, List<OHLC>>();
BindingList<OHLC> LastCandles = new BindingList<OHLC>();
. . .
form1.dataGridView1.DataSource = LastCandles;
. . .
public void OnUpdate()
{
//Update the appropriate candles
. . .
//Pull out the last candle by symbol and re-bind
BindingList<OHLC> lastBySymbol = new BindingList<OHLC>();
foreach (KeyValuePair<string, List<OHLC>> dict in candles)
{
if (dict.Value.Count > 0)
{
lastBySymbol.Add(dict.Value.Last());
}
}
LastCandles = lastBySymbol;
form1.dataGridView1.BeginInvoke((MethodInvoker)delegate
{
form1.dataGridView1.DataSource = LastCandles;
form1.dataGridView1.Refresh();
});
}
在这里设置数据绑定的最佳方法是什么,这样我就可以专注于更新集合而不必在每次更新时都重新绑定?我可以限制对 datagridview.Refresh() 的调用,这样它就不会在每次原子更新时都重新绘制,但不想重新绑定。
我知道如何将数据绑定一次到自定义对象的 BindingList 并使用 INotifyPropertyChanged 和对 datagridview.Refresh() 的简单调用将更新传播到 UI。我还可以在 XAML 中找到一些示例,这些示例显示了对 BindingList 中最后一项的数据绑定。但是我找不到任何绑定到列表字典的 'last-per-key' 的示例。
对于这方面的任何帮助,我将不胜感激。
注意:这将是问题的 WPF 解决方案,而不是 WinForms。
不要转换数据以适应视图,创建一个值转换器来处理该转换。
[ValueConversion(typeof(System.Collections.IEnumerable), typeof(object))]
public class LastItemConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
((System.Collections.IEnumerable)value)?.Cast<object>().Last();
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
throw new NotSupportedException();
}
然后使用数据绑定应用转换:
YourControl.xaml.cs:
public partial class YourControl : UserControl
{
public ConcurrentDictionary<string, List<OHLC>> Candles { get; } = ...;
}
YourControl.xaml:
<UserControl x:Class="YourNamespace.YourControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:YourNamespace"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<UserControl.Resources>
<local:LastItemConverter x:Key="lastItemConverter" />
</UserControl.Resources>
<Grid>
<DataGrid ItemsSource="{Binding Candles}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Key"
Binding="{Binding Key}" />
<DataGridTextColumn Header="Value"
Binding="{Binding Value, Converter={StaticResource lastItemConverter}}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
根据需要触发更新。
Windows Forms' DataGridView
有一种方法可以通过 CellFormatting
事件覆盖它格式化数据的方式。处理该事件,以便您可以更改将用于该列的值。如果你愿意,你也可以从这里设置单元格的样式。
form1.dataGridView1.CellFormatting += this.dataGridView1_CellFormatting;
//...
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
switch (dataGridView1.Columns[e.ColumnIndex].Name)
{
case "Value": // assuming this is the corresponding column name
if (e.Value is List<OHLC> asList)
{
var lastValue = asList.Last();
e.Value = lastValue;
// example of additional styling
if (lastValue.CostSavings > 0)
e.CellStyle.ForeColor = Color.Green;
}
return;
}
}
我有一个实现 INotifyChanged 的简单 OHLC 对象。每个 OHLC 对象都与特定蜡烛相关,并且是列表的一部分。每个列表都与特定股票相关,并存储在 ConcurrentDictionary
我正在尝试将每只股票的最后一根蜡烛数据绑定到数据网格视图。这就是我设置数据绑定的方式。不是很优雅!
ConcurrentDictionary<string, List<OHLC>> candles= new ConcurrentDictionary<string, List<OHLC>>();
BindingList<OHLC> LastCandles = new BindingList<OHLC>();
. . .
form1.dataGridView1.DataSource = LastCandles;
. . .
public void OnUpdate()
{
//Update the appropriate candles
. . .
//Pull out the last candle by symbol and re-bind
BindingList<OHLC> lastBySymbol = new BindingList<OHLC>();
foreach (KeyValuePair<string, List<OHLC>> dict in candles)
{
if (dict.Value.Count > 0)
{
lastBySymbol.Add(dict.Value.Last());
}
}
LastCandles = lastBySymbol;
form1.dataGridView1.BeginInvoke((MethodInvoker)delegate
{
form1.dataGridView1.DataSource = LastCandles;
form1.dataGridView1.Refresh();
});
}
在这里设置数据绑定的最佳方法是什么,这样我就可以专注于更新集合而不必在每次更新时都重新绑定?我可以限制对 datagridview.Refresh() 的调用,这样它就不会在每次原子更新时都重新绘制,但不想重新绑定。
我知道如何将数据绑定一次到自定义对象的 BindingList 并使用 INotifyPropertyChanged 和对 datagridview.Refresh() 的简单调用将更新传播到 UI。我还可以在 XAML 中找到一些示例,这些示例显示了对 BindingList 中最后一项的数据绑定。但是我找不到任何绑定到列表字典的 'last-per-key' 的示例。
对于这方面的任何帮助,我将不胜感激。
注意:这将是问题的 WPF 解决方案,而不是 WinForms。
不要转换数据以适应视图,创建一个值转换器来处理该转换。
[ValueConversion(typeof(System.Collections.IEnumerable), typeof(object))]
public class LastItemConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
((System.Collections.IEnumerable)value)?.Cast<object>().Last();
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
throw new NotSupportedException();
}
然后使用数据绑定应用转换:
YourControl.xaml.cs:
public partial class YourControl : UserControl
{
public ConcurrentDictionary<string, List<OHLC>> Candles { get; } = ...;
}
YourControl.xaml:
<UserControl x:Class="YourNamespace.YourControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:YourNamespace"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<UserControl.Resources>
<local:LastItemConverter x:Key="lastItemConverter" />
</UserControl.Resources>
<Grid>
<DataGrid ItemsSource="{Binding Candles}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Key"
Binding="{Binding Key}" />
<DataGridTextColumn Header="Value"
Binding="{Binding Value, Converter={StaticResource lastItemConverter}}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
根据需要触发更新。
Windows Forms' DataGridView
有一种方法可以通过 CellFormatting
事件覆盖它格式化数据的方式。处理该事件,以便您可以更改将用于该列的值。如果你愿意,你也可以从这里设置单元格的样式。
form1.dataGridView1.CellFormatting += this.dataGridView1_CellFormatting;
//...
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
switch (dataGridView1.Columns[e.ColumnIndex].Name)
{
case "Value": // assuming this is the corresponding column name
if (e.Value is List<OHLC> asList)
{
var lastValue = asList.Last();
e.Value = lastValue;
// example of additional styling
if (lastValue.CostSavings > 0)
e.CellStyle.ForeColor = Color.Green;
}
return;
}
}