使用绑定来控制DataGrid中的列顺序

时间:2010-01-24 07:11:21

标签: wpf data-binding xaml mvvm wpftoolkit

问题

我有一个WPF工具包DataGrid,我希望能够在多个预设列顺序之间切换。这是一个MVVM项目,因此列顺序存储在ViewModel中。问题是,我无法获得DisplayIndex属性的绑定。无论我尝试什么,包括this Josh Smith tutorial中的甜蜜方法,我都会得到:

  

带有标题'ID'的DataGridColumn的DisplayIndex超出范围。 DisplayIndex必须大于或等于0且小于Columns.Count。参数名称:displayIndex。实际值为-1。

是否有解决方法?

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


ViewModel代码

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的更新版本(2010年2月)。当我回到2009年6月的版本时,一切都恢复正常。所以,我现在正在做一些我本应该做的事情:我包括在我的解决方案文件夹中工作的WPFToolkit.dll并将其检入版本控制。不幸的是,更新的工具包发生了重大改变。

3 个答案:

答案 0 :(得分:12)

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

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

答案 1 :(得分:4)

(我以前的回答偏离了轨道 - 所以我删除了它 - 我会在我的机器上再现错误后再尝试回答)

您遇到的问题源于第一次评估绑定时,DataContext属性仍设置为null。由于一些奇怪的原因,我还不知道,导致绑定在-1进行评估。但是,如果确保在之前设置DataContext ,则会对评估的绑定进行评估,您就可以了。不幸的是,这可能只能在代码隐藏中实现 - 因此在运行时,而不是在设计时。所以在设计时我还是不知道如何规避错误。

为此,请在调用DataContext之前设置窗口的InitializeComponent属性:

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

希望这有帮助。

答案 2 :(得分:1)

我添加此作为答案,因为我还没有发表评论。 DisplayIndex的值设置为-1的原因是:

  

在添加之前,DisplayIndex属性的默认值为-1   到DataGrid.Columns集合。该值在更新时更新   列被添加到DataGrid。

     

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

     

对DisplayIndex值的限制由a强制执行   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相同,并且更改ViewModel构造函数的顺序,DataContext声明和InitializeComponent()方法没有帮助。< / p> 另一方面,帕克曼的FallbackValue方法非常有效。