Привязка ComboBox не вызывается для каждой строки в DataGrid - PullRequest
0 голосов
/ 13 октября 2011

Я пытаюсь создать комбинированный список внутри DataGridTemplateColumn, но он должен содержать разные значения в зависимости от строки. Вот мой код:

<dg:DataGridTemplateColumn x:Name ="NameColumn" Header="Player Name">
    <dg:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox
                SelectedValue="0"
                DisplayMemberPath="FullName"
                SelectedValuePath="Id"
                ItemsSource="{Binding AllPlayers, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"/>
        </DataTemplate>
    </dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>

AllPlayers будет возвращать другой список после каждого вызова.

public List<Player> AllPlayers
{
    get 
    {
        counter = counter + 1;
        Debug.Print("getting all players " + counter);

        List<Player> lst = new List<Player>();

        for (int i=0; i < 5; i++) 
        {
            Player p = new Player();
            p.Id = counter + i;
            p.FullName = "Name " + counter + i;
            lst.Add(p);
        }

        return lst;
    }
}

По какой-то причине функция AllPlayers вызывается для первых 39 строк, а затем данные берутся из ранее созданных списков. Я вижу это из отладочной информации (она перестает печатать после 39 звонков). А также списки в выпадающих списках не являются уникальными. Я не понимаю логику такого поведения. Мне нужно, чтобы AllPlayers вызывались для каждой строки.

Ответы [ 3 ]

0 голосов
/ 13 октября 2011

Ваш подход неверен. Во-первых, вы не должны доверять порядку, в котором происходит виртуализация сетки данных. Следовательно, подход, основанный на счетчике, для загрузки разных списков происходит хаотично.

Когда строка сетки данных де-виртуализируется, ваш комбинированный список становится видимым, запрашивает источник элементов и получает его из свойства Window.AllPlayers. Но порядок counter будет ввернут на основе прокрутки. Если вы неожиданно пропустите прокрутку, пропустив несколько строк, или если вы используете отложенную прокрутку, counter всегда будет неправильным. Если вы прокрутите вперед и назад, counter будет ввернут (поскольку я не вижу никакого кода для уменьшения счетчика) ...

Итак, суть в том, пожалуйста, не используйте этот подход.

Теперь вы сказали, что не хотите загружать список из отдельного элемента. Переменная counter, вероятно, относится к Index текущей строки в сетке данных ItemsSource. Если это так, то вы можете хотя бы использовать мульти-конвертер для того же.

Combobox XAML:

    <ComboBox
        SelectedValue="0"
        DisplayMemberPath="FullName"
        SelectedValuePath="Id" >
        <ComboBox.ItemsSource>
            <MultiBinding Converter="{StaticResource RowWiseListConverter}">
                <!--The current row item-->
                <Binding BindsDirectlyToSource="True" /> 

                <!---The items source of the data grid.-->
                <Binding Path="ItemsSource"
                         RelativeSource="{RelativeSource
                                 AncestorType={x:Type DataGrid}}"/>
            </MultiBinding>
        </ComboBox.ItemsSource>
    </ComboBox>

Код мультиконвертера:

public class RowWiseListConverter : IMultiValueConverter
{
    public object Convert(
            object[] values,
            Type targetType,
            object parameter,
            CultureInfo culture)
    {
        var item = values[0];
        var list = values[1] as System.Collections.IEnumerable;

        if (item != null && list != null)
        {
            var counter = list.Cast<object>().ToList().IndexOf(item);

            List<Player> lst = new List<Player>();
            for (int i = 0; i < 5; i++)
            {
                Player p = new Player();
                p.Id = counter + i;
                p.FullName = "Name " + counter + i;
                lst.Add(p);
            }

            return lst; 
        }

        return null;
    }
    .....
}

Код только для иллюстрации и может не компилироваться.

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

0 голосов
/ 13 октября 2011

Я использовал счетчик не для подсчета индексов, а только для целей отладки, чтобы подсчитать количество раз, когда была вызвана функция, и использовать ее для создания уникального списка для каждого списка.Мой оригинальный код имеет тот же подход, который вы предложили.Вот конвертер:

Public Function Convert(ByVal value() As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IMultiValueConverter.Convert
    Dim playerReportRow As MainAdminDS.PlayerReportRow = value(0).Row
    'Dim sourceList As MainAdminDS.PRSourceDataTable = SmallReportForm.GetSmallReportForm().PRSource
    Dim sourceList As MainAdminDS.PRSourceDataTable = value(1)

    Dim sourceListView As New List(Of MainAdminDS.PRSourceRow)

    Dim rand As New Random
    For i As Integer = 0 To sourceList.Count - 1
        If (sourceList(i).PRSource_Id = playerReportRow.PlayerReport_Source Or rand.Next(0, 2) = 0) Then
            sourceListView.Add(sourceList(i))
        End If
    Next

    Return sourceListView
End Function

Снова я создаю уникальный список для целей отладки.Это также не работает !!!

Я нашел решение, добавив новые поля в DataLayer типа Object, и они не были назначены никаким полям.Эти поля содержат список для выпадающих списков, и я инициализирую эти списки индивидуально для каждого объекта. Это прекрасно работает.Но меня все еще удивляет, почему предыдущий подход не сработал.Я чувствую, что это просто ошибка в WPF.

0 голосов
/ 13 октября 2011

Покажите свою привязку к сетке. Я бы сделал Players публичной собственностью коллекции, которую вы привязали к сетке. В ctor для списка 39+ соберите AllPlayers там. Предположим, ваш список из 39+ состоит из команд и имеет свойства Имя, Менеджер, Город, Игроки. Даже если вы получаете игроков, встроенных в шаблон, они не связаны напрямую с командой (без обхода визуального дерева).

...