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

C# 在WPF网格中显示带索引的一维数组,c#,.net,arrays,wpf,datagrid,C#,.net,Arrays,Wpf,Datagrid,我有一个双值的一维数组 使用WPF,在具有两列数组索引(第一列)和数组值(第二列)的网格中显示值的最佳方式是什么 第一列是只读的,但第二列应该是可编辑的 事实上,数据表示固定频率(例如20kHz)下基于时间的值序列。我可以将每个样本的时间计算为(开始时间+索引/频率) 用索引、时间和数据三列显示数据的最佳方式是什么?我找到了基本思路 我定义了两个转换器,一个用于索引 public class IndexConverter : IValueConverter { public object C

我有一个双值的一维数组

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

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

事实上,数据表示固定频率(例如20kHz)下基于时间的值序列。我可以将每个样本的时间计算为(开始时间+索引/频率)

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

我找到了基本思路

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

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作为属性

对于这个测试,我定义了一个ViewModel,其属性为
public double[]MyData

在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>

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

我还没有测试是否将编辑的值写回数组。事实上,我非常确定bindingmode=OneWay是错误的,但我认为我会找到解决方法


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

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

根据我目前的理解,编辑双值数组是不可能的。要编辑值,必须使用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 ) ) ;
  }
\u items=新列表();
for(int i=0;i
我把这段代码放在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方法将每个项包装在对象中