WPF ComboBox 不更新源

发布于 2024-07-14 10:01:55 字数 2394 浏览 4 评论 0原文

我正在尝试让 WPF 组合框正常工作(在 WPFToolkit Datagrid 内),但无法正确对齐所有部分。 我正在使用 Linq to Entities,并将整体数据上下文设置为 Linq 查询的结果:


private void LoadDonationGrid()
{
    donationGrid.ItemsSource = from donations in entities.Donation
                   .Include("Family")
                   .Include("PledgeYear")
                   .Include("DonationPurpose")
               from donationPurposes in entities.DonationPurpose
               select new { donations, donationPurposes };
}

我的代码隐藏中还有一个 page 属性,它为组合框提供 ItemsSource:


private IEnumerable donationPurposeList;
public IEnumerable DonationPurposeList
{
    get
    {
        if (donationPurposeList == null)
        {
            donationPurposeList = from dp in entities.DonationPurpose
                                  select dp;
        }
        return donationPurposeList.ToList();
    }
}

组合框的 XAML 看起来像this:

<tk:DataGridTemplateColumn Header="Purpose">
    <tk:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=donations.DonationPurpose.Description, Mode=TwoWay}" />
        </DataTemplate>
    </tk:DataGridTemplateColumn.CellTemplate>
    <tk:DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <ComboBox Name="cboDonationPurpose"
                SelectedValue="{Binding Path=donations.DonationPurposeID, Mode=TwoWay}"
                ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Page},Mode=FindAncestor},Path=DonationPurposeList}"                                 
                DisplayMemberPath="Description"
                SelectedValuePath="DonationPurposeID"
                      />
        </DataTemplate>
    </tk:DataGridTemplateColumn.CellEditingTemplate>
</tk:DataGridTemplateColumn>

一切似乎都工作正常,即,适当的值显示在组合框中,一直到焦点离开组合框的位置。 此时,显示值将返回到原始值,而不是新选择的值。 我尝试使用 SelectedItem 而不是 SelectedValue,但最终选定的值未显示在 ComboBox 中。 我有点困惑:看起来这应该有用。

2009 年 3 月 2 日编辑:我仍然对此感到困惑。 我应该注意到,在我的数据网格中,任何简单的数据列(例如“DataGridTextColumn”)都会按照您的预期更新底层数据源。 但是对我的模板列(“DataGridTemplateColumn”)或组合框列(“DataGridComboBoxColumn”)的任何更新都不起作用:底层数据源永远不会更新。 当然,其他人也尝试过使用 WPF.Toolkit 数据网格并让这个场景发挥作用 - 但我已经查看了所有示例代码,并且我基本上按照它所说的去做(在我的限制范围内)解决方案),所以我很困惑为什么这不起作用。

有什么想法吗?

I'm trying to get a WPF combobox working (inside the WPFToolkit Datagrid), and I'm having trouble getting all the pieces aligned correctly. I'm using Linq to Entities, and I'm setting the overall datacontext to the results of a Linq query:


private void LoadDonationGrid()
{
    donationGrid.ItemsSource = from donations in entities.Donation
                   .Include("Family")
                   .Include("PledgeYear")
                   .Include("DonationPurpose")
               from donationPurposes in entities.DonationPurpose
               select new { donations, donationPurposes };
}

I also have a page property in my code-behind which provides the ItemsSource for the combobox:


private IEnumerable donationPurposeList;
public IEnumerable DonationPurposeList
{
    get
    {
        if (donationPurposeList == null)
        {
            donationPurposeList = from dp in entities.DonationPurpose
                                  select dp;
        }
        return donationPurposeList.ToList();
    }
}

The XAML for the combobox looks like this:

<tk:DataGridTemplateColumn Header="Purpose">
    <tk:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=donations.DonationPurpose.Description, Mode=TwoWay}" />
        </DataTemplate>
    </tk:DataGridTemplateColumn.CellTemplate>
    <tk:DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <ComboBox Name="cboDonationPurpose"
                SelectedValue="{Binding Path=donations.DonationPurposeID, Mode=TwoWay}"
                ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Page},Mode=FindAncestor},Path=DonationPurposeList}"                                 
                DisplayMemberPath="Description"
                SelectedValuePath="DonationPurposeID"
                      />
        </DataTemplate>
    </tk:DataGridTemplateColumn.CellEditingTemplate>
</tk:DataGridTemplateColumn>

And everything seems to work correctly, i.e., the appropriate values are displayed in the ComboBox, right up to the point where focus leaves the ComboBox. At that point, the displayed value returns to the original value, not to the newly selected value. I've tried using SelectedItem instead of SelectedValue, but that ends up with the selected value not showing in the ComboBox. I'm kinda mystified: it seems like this bit should be working.

Edited 3/2/09: I'm still puzzling over this. I should note that in my datagrid, any simple data columns (e.g., "DataGridTextColumn") update the underlying data source just as you'd expect. But any update to any of my templated columns ("DataGridTemplateColumn") or ComboBox columns ("DataGridComboBoxColumn") don't work: the underlying data source never gets updated. Surely other folks have tried to use the WPF.Toolkit datagrid and gotten this scenario to work -- but I've looked at all the sample code out there, and I'm doing basically what it says to do (within the constraints of my solution), so I'm scratching my head why this isn't working.

Any thoughts?

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

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

发布评论

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

评论(3

心如狂蝶 2024-07-21 10:01:55

我遇到了类似的问题(我为此花了几天的时间),我发现将 SelectedValue 绑定上的 UpdateSourceTrigger 更改为 PropertyChanged 就可以修复它。 我不知道为什么,但对我来说,在我进行此更改之前,数据源不会更新。

<ComboBox 
    ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UpdateTypesManager:MainWindow}}, Path=CardinalityTypes}" 
    DisplayMemberPath="CardinalityType"
    SelectedValue="{Binding CardinalityTypeId, UpdateSourceTrigger=PropertyChanged}"
    SelectedValuePath="Id" />

I had a similar problem (on which I spent days of frustration), and I found that changing the UpdateSourceTrigger on the SelectedValue binding to PropertyChanged fixed it. I don't know why, but for me, the datasource wasn't being updated until I made this change.

<ComboBox 
    ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UpdateTypesManager:MainWindow}}, Path=CardinalityTypes}" 
    DisplayMemberPath="CardinalityType"
    SelectedValue="{Binding CardinalityTypeId, UpdateSourceTrigger=PropertyChanged}"
    SelectedValuePath="Id" />
聊慰 2024-07-21 10:01:55

我能够让这个工作。 但我的设置略有不同。

  1. 我创建了一个 ViewModel 来充当与 View 的契约。
  2. 我绑定到 ComboBox.SelectedItem 属性而不是 ComboBox.SelectedValue 属性

因为我不知道您的数据源是什么,所以我自己编写了一个来模拟基本问题:在 WPF DataGrid 中正确绑定组合框。

以下是我的视图模型的组成:

public class RootViewModel
{
    public List<State> USStates { get; set; }
    public List<Customer> Customers { get; set; }

    public ViewModel()
    {
        Customers = new List<Customer>();
        Customers.Add(new Customer() { FirstName = "John", LastName = "Smith", State = new State() { ShortName = "IL" } });
        Customers.Add(new Customer() { FirstName = "John", LastName = "Doe", State = new State() { ShortName = "OH" } });
        Customers.Add(new Customer() { FirstName = "Sally", LastName = "Smith", State = new State() { ShortName = "IN" } });

        USStates = new List<State>();
        USStates.Add(new State() { ShortName = "OH" });
        USStates.Add(new State() { ShortName = "IL" });
        USStates.Add(new State() { ShortName = "IN" });
    }
}

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public State State { get; set; }
}

public class State
{
    public string ShortName { get; set; }

    public State() 
    {
        ShortName = string.Empty;
    }

    public override bool Equals(object obj)
    {
        if (obj is State)
        {
            State otherState = obj as State;
            return ShortName.Equals(otherState.ShortName);
        }
        else
        {
            return false;
        }
    }
}

在开始之前,我将窗口的 DataContext 设置为我正确构造的 RootViewModel 的实例。

<tk:DataGrid ItemsSource="{Binding Customers}" AutoGenerateColumns="False">
            <tk:DataGrid.Columns>
                <tk:DataGridTemplateColumn Header="State">
                    <tk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=State.ShortName, Mode=TwoWay}" />
                        </DataTemplate>
                    </tk:DataGridTemplateColumn.CellTemplate>
                    <tk:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <ComboBox 
                                x:Name="cboDonationPurpose" 
                                SelectedItem="{Binding Path=State, Mode=TwoWay}" 
                                ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window},Mode=FindAncestor}, Path=DataContext.USStates}" 
                                DisplayMemberPath="ShortName" 
                                SelectedValuePath="ShortName" />
                        </DataTemplate>
                    </tk:DataGridTemplateColumn.CellEditingTemplate>
                </tk:DataGridTemplateColumn>
            </tk:DataGrid.Columns>
        </tk:DataGrid>

为了使 SelectedItem 正确绑定,我需要确保我已经重写了实体上的 Equals 方法,因为在幕后,WPF 使用此方法来确定谁是 SelectedItem。 我认为这从一开始就是您的问题,导致您尝试绑定到 SelectedValue 而不是 SelectedItem。

I was able to get this working. But I set things up a wee bit differently.

  1. I created a ViewModel to act as a contract with the View.
  2. I bound to the ComboBox.SelectedItem Property instead of ComboBox.SelectedValue Property

Since I didn't know what your data source was I made up my own to simulate the basic problem: having a comboBox bind correctly within a WPF DataGrid.

Here is the composition of my View Model:

public class RootViewModel
{
    public List<State> USStates { get; set; }
    public List<Customer> Customers { get; set; }

    public ViewModel()
    {
        Customers = new List<Customer>();
        Customers.Add(new Customer() { FirstName = "John", LastName = "Smith", State = new State() { ShortName = "IL" } });
        Customers.Add(new Customer() { FirstName = "John", LastName = "Doe", State = new State() { ShortName = "OH" } });
        Customers.Add(new Customer() { FirstName = "Sally", LastName = "Smith", State = new State() { ShortName = "IN" } });

        USStates = new List<State>();
        USStates.Add(new State() { ShortName = "OH" });
        USStates.Add(new State() { ShortName = "IL" });
        USStates.Add(new State() { ShortName = "IN" });
    }
}

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public State State { get; set; }
}

public class State
{
    public string ShortName { get; set; }

    public State() 
    {
        ShortName = string.Empty;
    }

    public override bool Equals(object obj)
    {
        if (obj is State)
        {
            State otherState = obj as State;
            return ShortName.Equals(otherState.ShortName);
        }
        else
        {
            return false;
        }
    }
}

Before we begin, I set the DataContext of my Window to be an instance of my properly constructed RootViewModel.

<tk:DataGrid ItemsSource="{Binding Customers}" AutoGenerateColumns="False">
            <tk:DataGrid.Columns>
                <tk:DataGridTemplateColumn Header="State">
                    <tk:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=State.ShortName, Mode=TwoWay}" />
                        </DataTemplate>
                    </tk:DataGridTemplateColumn.CellTemplate>
                    <tk:DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <ComboBox 
                                x:Name="cboDonationPurpose" 
                                SelectedItem="{Binding Path=State, Mode=TwoWay}" 
                                ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window},Mode=FindAncestor}, Path=DataContext.USStates}" 
                                DisplayMemberPath="ShortName" 
                                SelectedValuePath="ShortName" />
                        </DataTemplate>
                    </tk:DataGridTemplateColumn.CellEditingTemplate>
                </tk:DataGridTemplateColumn>
            </tk:DataGrid.Columns>
        </tk:DataGrid>

In order for the SelectedItem to bind properly I need to ensure that I have overriden the Equals method on my entity since under the hood, WPF is using this method to determine who is the SelectedItem or not. I think this was fundamentally your problem from the beginning which caused you to try to bind to SelectedValue instead of SelectedItem.

翻了热茶 2024-07-21 10:01:55

您需要

IsSynchronizedWithCurrentItem = "True"

在 Xaml 中添加。

就这么简单...

You need to add

IsSynchronizedWithCurrentItem = "True"

in your Xaml.

It's as simple as that...

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