Привязка ComboBox не вызывается для каждой строки в DataGrid
Я пытаюсь создать выпадающий список внутри 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 ответа
Я не использовал счетчик для подсчета индексов, а просто для целей отладки, чтобы подсчитать количество раз, когда была вызвана функция, и использовать его для создания уникального списка для каждого выпадающего списка. Мой оригинальный код имеет тот же подход, который вы предложили. Вот конвертер:
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.
Покажите свою привязку к сетке. Я бы сделал Players публичной собственностью коллекции, которую вы привязали к сетке. В ctor для списка 39+ соберите AllPlayers там. Предположим, ваш список из 39+ состоит из команд и имеет свойства Имя, Менеджер, Город, Игроки. Даже если вы получаете игроков, встроенных в шаблон, они не связаны напрямую с командой (без обхода визуального дерева).
Ваш подход неверен. Во-первых, вы не должны доверять порядку, в котором происходит виртуализация сетки данных. Следовательно, подход, основанный на счетчике, для загрузки разных списков происходит хаотично.
Когда строка сетки данных де-виртуализирована, ваш комбинированный список становится видимым, запрашивает источник элементов и получает его из 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;
}
.....
}
Код только для иллюстрации и может не компилироваться.
Надеюсь это поможет.