在WPF网格中显示带索引的一维数组

本文关键字:索引 一维数组 显示 WPF 网格 | 更新日期: 2023-09-27 18:19:49

我有一个双值的一维数组。

使用WPF,在具有数组索引(第一列)和数组值(第二列)两列的网格中显示值的最佳方式是什么?

第一列是只读的,但第二列应该是可编辑的。

事实上,数据代表了一个基于时间的值序列,在固定频率下,例如20kHz。我可以将每个样本的时间计算为(start_time+index/frequency)。

用索引、时间和数据三列显示数据的最佳方式是什么?

在WPF网格中显示带索引的一维数组

我在这里找到了的基本想法

我定义了两个转换器,一个用于索引

public class IndexConverter : IValueConverter
{
  public object Convert(object value, Type TargetType, object parameter, CultureInfo culture)
  {
      ListViewItem item = (ListViewItem) value;
      ListView listView = ItemsControl.ItemsControlFromItemContainer(item) as ListView;
      int index = listView.ItemContainerGenerator.IndexFromContainer(item);
      return index.ToString();
  }
  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
      throw new NotImplementedException();
  }
}

一个用于时间

public class SampleTimeConverter : IValueConverter
{
  private double StartTime    = 0.0 ;
  private double SamplingRate = 20000.0 ;
  public object Convert(object value, Type TargetType, object parameter, CultureInfo culture)
  {
    ListViewItem item = (ListViewItem) value;
    ListView listView = ItemsControl.ItemsControlFromItemContainer(item) as ListView;
    int    index = listView.ItemContainerGenerator.IndexFromContainer(item);
    double sampleTime = StartTime + index / SamplingRate ;
    return String.Format ( "{0:F5}", sampleTime ) ;
  }
  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
      throw new NotImplementedException();
  }
}

稍后,我将把StartTime和SamplingRate作为属性传入。

对于这个测试,我定义了一个具有属性public double[] MyData的ViewModel。

在XAML中,我定义了一个ListView,如下所示:

<Window.Resources>
  <local:IndexConverter      x:Key="IndexConverter"/>
  <local:SampleTimeConverter x:Key="SampleTimeConverter"/>
</Window.Resources>
<Grid>
  <ListView Name="listviewNames" ItemsSource="{Binding MyData}">
    <ListView.View>
      <GridView>
        <GridView.Columns>
          <GridViewColumn Header="Index" Width="100"
            DisplayMemberBinding="{Binding RelativeSource={RelativeSource FindAncestor, 
                                           AncestorType={x:Type ListViewItem}}, 
                                           Converter={StaticResource IndexConverter}}" />
          <GridViewColumn Header="Time" Width="200"
            DisplayMemberBinding="{Binding RelativeSource={RelativeSource FindAncestor, 
                                           AncestorType={x:Type ListViewItem}}, 
                                           Converter={StaticResource SampleTimeConverter}}" />
          <GridViewColumn Header="Value" Width="auto" >
            <GridViewColumn.CellTemplate>
              <DataTemplate>
                <TextBox Text="{Binding Mode=OneWay}" Width="200" BorderThickness="0"/>
              </DataTemplate>
            </GridViewColumn.CellTemplate>
          </GridViewColumn>
        </GridView.Columns>
      </GridView>
    </ListView.View>
  </ListView>
</Grid>

这或多或少是在做我想做的事。

我还没有测试编辑后的值是否会写回数组。事实上,我很确定绑定模式=单向是错误的,但我认为我会找到解决方案。

我唯一怀疑的是,为每个值创建一个文本框(可能有数千个)是否会导致性能问题。

我的第一个解决方案非常适合显示只读数据。

根据我目前的理解,编辑一个双值数组是不可能的。要编辑一个值,必须使用setter和getter方法将其定义为一个属性。

我并不是真的想这么做,因为这意味着为数组中的每个元素创建一个单独的对象。然而,如果我这样做,剩下的就很容易了,而且我可以不用第一个解决方案中使用的值转换器。

我为网格中的每个项目定义了一个类:

public class DataItem
{
  int         _index ;
  double      _sampleTime ;
  ViewModel   _vm ;
  public DataItem ( int Index, double SampleTime, ViewModel vm )
  {
    _index      = Index ;
    _sampleTime = SampleTime ;
    _vm         = vm ;
  }
  public int Index
  {
    get { return _index ; }
  }
  public double SampleTime
  {
    get { return _sampleTime ; }
  }
  public double Value
  {
    get { return _vm.MyData[_index] ; }
    set { _vm.MyData[_index] = value ; }
  }
}

我在一个简单的循环中创建视图模型中的对象。为了简单起见,我将索引和时间作为参数传递。我传入对ViewModel的引用,以便数组值的setter可以将编辑后的值存储回原始数组中。

  _items = new List<DataItem>() ;
  for ( int i = 0 ; i < darray.Length ; i++ )
  {
    _items.Add ( new DataItem ( i, startTime + samplingRate * i, this ) ) ;
  }

我把这段代码放在ViewModel的构造函数中,这对我来说已经足够好了。ViewModel有一个返回集合的Items属性。

在XAML中,我使用了DataGrid,因为它支持直接编辑。

<DataGrid x:Name="ValuesGrid"
          ItemsSource="{Binding Items}" 
          AutoGenerateColumns="False" 
          CanUserReorderColumns="False" 
          CanUserResizeRows="False" 
          CanUserAddRows="False"
          HorizontalGridLinesBrush="DarkGray"
          VerticalGridLinesBrush="DarkGray"
          >
  <DataGrid.Columns>
    <DataGridTextColumn Header="Index" Binding="{Binding Index}"       Width="10*" IsReadOnly="True"/>
    <DataGridTextColumn Header="Time"  Binding="{Binding SampleTime}"  Width="20*" IsReadOnly="True"/>
    <DataGridTextColumn Header="Value" Binding="{Binding Value}"       Width="20*" IsReadOnly="False"/>
  </DataGrid.Columns>
</DataGrid>

最后,我想重复一遍。这个问题的答案是"你做不到"。双向绑定到double数组是不可能的。必须使用值的setter和getter方法将每个项包装在对象中。