不会为 DataGrid 中的每一行调用 ComboBox 的绑定

发布于 2024-12-10 03:41:24 字数 1264 浏览 0 评论 0原文

我正在尝试在 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;
    }
}

由于某种原因,为前 39 行调用 AllPlayers 函数,然后从先前创建的列表中获取数据。我可以从调试信息中看到这一点(它在 39 次调用后停止打印)。而且组合框中的列表也不是唯一的。我不明白这种行为背后的逻辑。我需要为每一行调用 AllPlayers 。

I'm trying to create combobox inside DataGridTemplateColumn but it should contain different values depending on the row. Here is my code:

<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 will return different list after each call.

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;
    }
}

For some reason the AllPlayers function is called for the first 39 rows and then the data is taken from previously created lists. I can see that from debug info (it stops printing after 39 calls). And also lists in comboboxes are not unique. I do not understand the logic behind this behavior. I need AllPlayers be called for every row.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

烟花肆意 2024-12-17 03:41:24

显示您与网格的绑定。我将使 Players 成为您绑定到网格的集合的公共属性。在 39+ 列表的 ctor 中构建 AllPlayers。假设您的 39+ 名单是球队,并且具有名称、经理、城市、球员属性。即使您在模板中内置了球员,他们也不会直接与球队相关联(无需遍历视觉树)。

Show your binding to the grid. I would make Players a Public property of the collection you bind to the grid. In the ctor for the list of 39+ build the AllPlayers there. Lets assume your list of 39+ is teams and has properties Name, Manager, City, Players. Even if you get the players built in the template they are not directly associated with the team (without walking the visual tree).

又怨 2024-12-17 03:41:24

您的方法不正确。首先您不应该信任数据网格虚拟化发生的顺序。因此,基于计数器的加载不同列表的方法是不稳定的。

当数据网格行去虚拟化时,您的组合框将变得可见,并需要项目源并从 Window.AllPlayers 属性获取它。但是 counter 的顺序将根据滚动而改变。如果您突然滚动跳过一些行范围,或者使用延迟滚动,则计数器将始终出错。如果您来回滚动,计数器将会被搞砸(因为我没有看到任何代码来减少计数器)...

所以底线是请不要使用这种方法。

现在您说您不想从单个项目加载列表。 counter 变量可能指的是数据网格的 ItemsSource 中当前行的 Index。如果是这样,您至少可以使用多转换器来实现相同的目的。

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;
    }
    .....
}

该代码仅用于说明目的,可能无法编译。

希望这会有所帮助。

Your approach is not correct.. firstly you should not trust the order in which the datagrid virtualization takes place. Hence the counter based approach to load different lists is happening erratically.

When a datagrid row is de-virtualized, your combobox becomes visible and demands the items source and gets it from the Window.AllPlayers property. But the order of counter will be screwed based on scrolling. If you suddenly scroll skipping a few range of rows or if you are using deferred scrolling the counter will be always wrong. If you scroll back and forth the counter will get screwed (as I dont see any code to decrement the counter)...

So bottom line is please dont use that approach.

Now you said that you dont want to load list from individual item. The counter variable probably refers to the Index of current row in the datagrid's ItemsSource. If so you could atleast use a multi-converter for the same.

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>

Multi converter code:

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;
    }
    .....
}

The code is only for illustrative purpose and may not compile.

Hope this helps.

岁月无声 2024-12-17 03:41:24

我没有使用计数器来计算索引,只是出于调试目的来计算调用函数的次数,并使用它为每个组合框创建唯一的列表。我的原始代码与您提供的方法相同。这是转换器:

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 中添加新字段找到了解决方案,并且它们没有分配给任何字段。这些字段包含组合框的列表,我为每个对象单独初始化这些列表。它工作得很好。但我仍然很困惑为什么之前的方法不起作用。我感觉这只是 WPF 中的错误。

I did not use counter to count indexes but just for debug purposes to count number of time the function was called and use it to create unique list for each combobox. My original code has the same approach you offered. Here is the converter:

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

Again I create unique list for debug purposes. This does not work either!!!

I found solution by adding new fields in DataLayer of type Object and they are not assigned to any fields. Those fields contains List for comboboxes and I initialize these list individually for each object.. It works great. But it is still puzzling me why the previous approach did not work. I have feeling that this is just bug in WPF.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文