在WPF网格中显示带索引的1-D数组

时间:2015-10-30 08:56:12

标签: c# .net arrays wpf datagrid

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

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

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

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

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

2 个答案:

答案 0 :(得分:0)

I found the basic idea here I have defined two converters, one for the index 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(); } } and one for the time 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(); } } Later I will pass the StartTime and SamplingRate in as properties. For this test I defined a ViewModel with a property public double[] MyData. In XAML, I defined a ListView as follows: <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> This is more or less doing what I wanted. I haven't yet tested whether the edited values are written back to the array. In fact I am pretty sure that Binding Mode=OneWay is wrong, but I think I will find a solution to that. My only doubt is whether it might cause a performance problem to create a text box for each value (there may be thousands).

答案 1 :(得分:0)

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

根据我目前的理解,编辑双值数组是不可能的。要编辑值,必须使用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>

最后我想再说一遍。问题的答案是&#34;你不能这样做&#34;。双向绑定到double数组是不可能的。您必须使用setter和getter方法将每个项目包装在对象中。