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).
我的第一个解决方案非常适合显示只读数据。
根据我目前的理解,编辑双值数组是不可能的。要编辑值,必须使用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方法将每个项目包装在对象中。