【问题标题】:Using bindings to control column order in a DataGrid使用绑定来控制 DataGrid 中的列顺序
【发布时间】:2011-01-08 17:39:24
【问题描述】:

问题

我有一个 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 月)这一事实。当我恢复到 09 年 6 月的版本时,一切都恢复正常了。所以,我现在正在做我应该首先做的事情:我将 WPFToolkit.dll 包含在我的解决方案文件夹中,并将其检入到版本控制中。不过很遗憾,较新的工具包发生了重大变化。

【问题讨论】:

    标签: wpf data-binding xaml mvvm wpftoolkit


    【解决方案1】:

    在 DisplayIndex 绑定中设置 FallbackValue=&lt;idx&gt;,其中 &lt;idx&gt; 是列的索引。例如:

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

    【讨论】:

    • 完美运行 - 也很优雅。
    • 这是要走的路,放下手。
    【解决方案2】:

    (我之前的回答离题了——所以我删除了它——我会在我的机器上重现错误后再次尝试回答)

    您遇到的问题源于第一次评估绑定时,DataContext 属性仍设置为null。这出于某种奇怪的原因,但我不知道,导致绑定在-1 进行评估。但是,如果您确保设置 DataContext before 绑定被评估,你会没事的。不幸的是,这可能只能在代码隐藏中实现 - 因此在运行时而不是在设计时。所以在设计时我仍然不知道如何规避错误。

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

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

    希望这会有所帮助。

    【讨论】:

    • 这很有趣。如果我运行我的测试应用程序,你的修复工作完美。在我的真实应用程序中,有问题的DataGrid 实际上在UserControl 中,并且由于某种原因,如果我应用DataContextSpy(我直到现在才尝试,因为它对我的测试应用程序失败了) ,即使我不推迟拨打InitializeComponent(),它也能正常工作。我认为这一定是因为我只是将Content 设置在ContentControl 上,而不是做window.Show()。无论如何,感谢您花时间为我解决这个问题(+1 和√)。
    【解决方案3】:

    我将其添加为答案,因为我还不能发表评论。 DisplayIndex的值设置为-1的原因是:

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

    DataGrid 要求每列的 DisplayIndex 属性 必须是从 0 到列数 -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 相同,并且更改 ViewModel 构造函数、DataContext 声明和 InitializeComponent() 方法的顺序没有帮助。

    另一方面,Pakman 的 FallbackValue 方法效果很好。

    【讨论】:

      猜你喜欢
      • 2010-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-15
      • 2018-08-31
      相关资源
      最近更新 更多