Подтвердить что ты не робот

Использование привязок для управления порядком столбцов в DataGrid

Проблема

У меня есть WPF Toolkit DataGrid, и я хотел бы иметь возможность переключаться между несколькими предустановленными порядками столбцов. Это проект MVVM, поэтому порядки столбцов хранятся в ViewModel. Проблема в том, что я не могу заставить привязки работать для свойства DisplayIndex. Независимо от того, что я пытаюсь, включая сладкий метод в этот учебник Josh Smith, я получаю:

DisplayIndex для DataGridColumn с идентификатором заголовка выходит за допустимые пределы. 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 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, все работает нормально, поэтому проблема определенно связана с привязками.


Обновление 5/1/2010

Я просто делал небольшое обслуживание моего проекта, и я заметил, что когда я его запускал, проблема, которую я обсуждал в этом посте, вернулась. Я знал, что он работал в последний раз, когда я его запускал, поэтому я в конечном итоге сузил проблему до того, что установил новую версию WPF Toolkit (февраль '10). Когда я вернулся к версии июня 2009 года, все снова работало нормально. Итак, теперь я делаю то, что должен был сделать в первую очередь: я включаю WPFToolkit.dll, который работает в моей папке решений и проверяет ее на управление версиями. Однако, к сожалению, новый инструментарий имеет потрясающее изменение.

4b9b3361

Ответ 1

(Мой предыдущий ответ был отключен, поэтому я удалил его - я попытаюсь ответить снова после воспроизведения ошибки на моей машине)

Проблема, с которой вы сталкиваетесь, связана с тем фактом, что когда привязки сначала оцениваются, свойство DataContext по-прежнему установлено на null. Это, по какой-то странной причине, еще неизвестное мне, заставляет привязку оценивать в -1. Однако, если вы установите DataContext до, привязки будут оценены, вы будете в порядке. К сожалению, это может быть возможно только при кодировании - следовательно, во время выполнения, а не во время разработки. Поэтому во время разработки я до сих пор не знаю, как обойти ошибку.

Чтобы сделать это, установите для свойства DataContext окно перед вызовом InitializeComponent таким образом:

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

Надеюсь, что это поможет.

Ответ 2

Установите FallbackValue=<idx> в привязке DisplayIndex, где <idx> - ваш индекс столбца. Например:

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

Ответ 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, не сработало для меня. У меня есть Datagrid в UserControl, то же, что и OP, и изменение порядка конструктора ViewModel, объявление DataContext и метод InitializeComponent() не помогли.

Метод Pakman FallbackValue работал очень хорошо, с другой стороны.