2010-01-24 61 views
12

问题使用绑定在数据网格

我有一个WPF工具包DataGrid,我想能够几个预置柱订单之间进行切换来控制列的顺序。这是一个MVVM项目,所以列订单存储在ViewModel中。问题是,我无法获得绑定为DisplayIndex属性工作。不管我怎么努力,包括甜方法this Josh Smith tutorial,我得到:

的的DisplayIndex与头“ID”的DataGridColumn超出范围。 DisplayIndex必须大于或等于0且小于Columns.Count。参数名称:displayIndex。实际值为-1。

有没有什么解决方法呢?

我在下面列出了我的测试代码。如果您发现任何问题,请告诉我。


视图模型代码

public class MainViewModel 
{ 
    public List<Plan> Plans { get; set; } 
    public int IdDisplayIndex { get; set; } 
    public int NameDisplayIndex { get; set; } 
    public int DescriptionDisplayIndex { get; set; } 

    public MainViewModel() 
    { 
     Initialize(); 
    } 

    private void Initialize() 
    { 
     IdDisplayIndex = 1; 
     NameDisplayIndex = 2; 
     DescriptionDisplayIndex = 0; 
     Plans = new List<Plan> 
     { 
      new Plan { Id = 1, Name = "Primary", Description = "Likely to work." }, 
      new Plan { Id = 2, Name = "Plan B", Description = "Backup plan." }, 
      new Plan { Id = 3, Name = "Plan C", Description = "Last resort." } 
     }; 
    } 
} 

计划类

public class Plan 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Description { get; set; } 
} 

窗口代码 - 这款采用Josh Smith's DataContextSpy

<Window 
    x:Class="WpfApplication1.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:WpfApplication1" 
    xmlns:mwc="http://schemas.microsoft.com/wpf/2008/toolkit" 
    Title="Main Window" Height="300" Width="300"> 
    <Grid> 
     <mwc:DataGrid ItemsSource="{Binding Plans}" AutoGenerateColumns="False"> 
      <mwc:DataGrid.Resources> 
       <local:DataContextSpy x:Key="spy" /> 
      </mwc:DataGrid.Resources> 
      <mwc:DataGrid.Columns> 
       <mwc:DataGridTextColumn 
        Header="ID" 
        Binding="{Binding Id}" 
        DisplayIndex="{Binding Source={StaticResource spy}, Path=DataContext.IdDisplayIndex}" /> 
       <mwc:DataGridTextColumn 
        Header="Name" 
        Binding="{Binding Name}" 
        DisplayIndex="{Binding Source={StaticResource spy}, Path=DataContext.NameDisplayIndex}" /> 
       <mwc:DataGridTextColumn 
        Header="Description" 
        Binding="{Binding Description}" 
        DisplayIndex="{Binding Source={StaticResource spy}, Path=DataContext.DescriptionDisplayIndex}" /> 
      </mwc:DataGrid.Columns> 
     </mwc:DataGrid> 
    </Grid> 
</Window> 

注:如果我只是使用普通的号码DisplayIndex,一切工作正常,那么问题肯定是绑定。


更新2010年5月1日

我只是在做我的项目很少的维护,我注意到,当我跑了,我在这个帖子讨论这个问题回来了。我知道它在我上次运行它的时候起作用,所以我最终将问题缩小到了我已经安装了WPF Toolkit的新版本(10年2月)。当我回到2009年6月份的版本时,一切正常。所以,我现在正在做一些我应该首先完成的工作:我将WPFToolkit.dll包含在我的解决方案文件夹中,并将其检入版本控制。但不幸的是,新的工具包有一个突破性的变化。

回答

4

(我以前的答案是方式偏离了轨道 - 所以我删除了 - 我会尽量在我的机器上重现错误后,再次回答)

您遇到的问题来源于这样的事实,当绑定第一次评估时,DataContext属性仍设置为null。这个,出于某种奇怪的原因,我还不知道,导致绑定评估在-1。但是,如果您确定在之前设置DataContext,则评估绑定即可。不幸的是,这可能只有在代码隐藏时才有可能 - 因此在运行时期间,而不是在设计时间内。所以在设计时我仍然不知道如何规避错误。

要做到这一点,因此设置窗口的DataContext属性调用之前InitializeComponent

public MainWindow() 
{ 
    DataContext = new MainViewModel(); 
    InitializeComponent(); 
} 

希望这有助于。

+0

嗯,这很有趣。如果我运行我的测试应用程序,您的修复程序完美运行在我的真实应用程序中,所讨论的DataGrid实际上是在一个UserControl中,并且由于某种原因,如果我应用了'DataContextSpy'(我之前没有尝试过,因为它没有通过测试应用程序) ,即使我不推迟调用InitializeComponent(),它也可以工作。我认为这一定是因为我只是在ContentControl上设置Content,而不是做'window.Show()'。无论如何,感谢您花时间为我解决这个问题(+1和√)。 – devuxer 2010-01-24 21:41:23

12

在您的DisplayIndex绑定中设置FallbackValue=<idx>,其中<idx>是您的列索引。例如:

DisplayIndex="{Binding Source={StaticResource spy}, Path=DataContext.IdDisplayIndex, FallbackValue=0}" /> 
+2

完美 - 而且优雅。 – ShadowChaser 2012-02-10 16:42:52

+1

这是走下坡路的方式。 – 2013-01-30 17:18:43

1

由于我还不能评论,我添加了这个答案作为答案。为什么的DisplayIndex的值设置为-1的原因是:

的的DisplayIndex财产有它被添加 到DataGrid.Columns收集之前的-1的默认值。将 列添加到DataGrid时更新此值。

DataGrid要求每列 的DisplayIndex属性必须是从0到列Count-1的唯一整数。因此,当一列的DisplayIndex更改时, 的更改通常会导致其他列的DisplayIndex也发生更改。

对DisplayIndex值的限制由 ValidateValueCallback机制强制执行。如果您尝试设置值为 无效,则会引发运行时异常。

当DisplayIndex属性的值发生更改时,会引发 DataGrid.ColumnDisplayIndexChanged事件。

来源:http://msdn.microsoft.com/en-us/library/vstudio/system.windows.controls.datagridcolumn.displayindex(v=vs.100).aspx

所以我想这是可以检查这个值时,它使用的是上述事件的发生变化。

Aviad提到的解决方案并不适合我。我有一个UserControl中的Datagrid,与OP相同,并且更改构造函数ViewModelDataContext声明和InitializeComponent()方法的顺序没有任何帮助。

帕克曼的FallbackValue方法工作得很好,另一方面。