使用单独的数据库在 DataGridComboBoxColumn 中设置 ItemSource Table

Setting ItemSource in DataGridComboBoxColumn Using Separate Database Table

我的第一个 StackExchange 问题,如果我做错了什么请告诉我。

我正在将旧的 winforms 代码转换为 WPF,并且一直在学习这两种代码。大多数时候我都取得了成功,但我正在处理涉及数据绑定的第一个数据 Table。这似乎是最难转换的事情,因为绑定主要在 xaml 而不是代码中处理。

补充说明一下,它使用了CSLA,据我理解是类似于MVVM的代码结构(还在学习这些是什么)。

经过一些试验,我设法创建了一个正常运行的数据网格,但我需要将其中一列实现为组合框。它目前表示为一个数字(1-10),但我需要与数字一起的描述,它在数据库中的不同 table 中。
在将其切换到组合框之前最初显示的数字是非资格原因。我希望这个值是组合框中当前选中的项目。

不能 post 图片,所以这是我尝试显示数据库的结构 tables:

modreview

noneligreason(这是符合 noneligibilityreason 的 subtable)

代码包含这个函数,它似乎创建了一个集合,我认为应该是 ItemsSource:

NERList.GetNameValueList();

至于 ItemsSource,我想要所有 noneligreasondesc 值。当然,还有使非资格原因与非限制性原因相匹配的问题。我发现 this example,它似乎做同样的事情,但没有数据库,而是使用 类:

我试图复制它,因为我认为它应该可以在我的 XAML:

中使用
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfTestProject"       x:Class="WpfTestProject.MainWindow"
    Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Window.Resources>
    <local:caseviewDataSet x:Key="caseviewDataSet"/>
    <CollectionViewSource x:Key="modreviewViewSource" 
                          Source="{Binding modreview, Source={StaticResource caseviewDataSet}}"/>
    <CollectionViewSource x:Key="noneligibilityViewSource"
                          Source="{Binding noneligreason, Source={StaticResource caseviewDataSet}}"/>
</Window.Resources>
<Grid DataContext="{StaticResource modreviewViewSource}">
    <Grid.RowDefinitions>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <DataGrid x:Name="modreviewDataGrid" 
              RowDetailsVisibilityMode="VisibleWhenSelected" 
              ItemsSource="{Binding}" 
              EnableRowVirtualization="True" 
              AutoGenerateColumns="False">            
        <DataGrid.Columns>
            <DataGridTextColumn x:Name="reviewnumColumn" Width="SizeToHeader" Header="reviewnum" Binding="{Binding reviewnum}"/>
            <DataGridTextColumn x:Name="intcasenoColumn" Width="SizeToHeader" Header="intcaseno" Binding="{Binding intcaseno}"/>
            <DataGridCheckBoxColumn x:Name="newreferralColumn" Width="SizeToHeader" Header="newreferral" Binding="{Binding newreferral}"/>
            <DataGridTemplateColumn x:Name="screendateColumn" Width="Auto" Header="screendate">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <DatePicker SelectedDate="{Binding screendate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridCheckBoxColumn x:Name="eligibleColumn" Width="SizeToHeader" Header="eligible" Binding="{Binding eligible}"/>
            <DataGridComboBoxColumn x:Name="noneligibilityreasonColumn" Width="SizeToHeader" Header="noneligibilityreason"
                                    ItemsSource="{Binding Source={StaticResource noneligibilityViewSource}}"
                                    SelectedValueBinding="{Binding noneligibilityreason}"
                                    DisplayMemberPath="Value"
                                    SelectedValuePath="Key"
                                        />

        </DataGrid.Columns>
    </DataGrid>
</Grid>

后面的代码:

using CslaFactoryBusinessObjects;
...

namespace WpfTestProject
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {

            WpfTestProject.caseviewDataSet caseviewDataSet = ((WpfTestProject.caseviewDataSet)(this.FindResource("caseviewDataSet")));
            // Load data into the table modreview. You can modify this code as needed.
            WpfTestProject.caseviewDataSetTableAdapters.modreviewTableAdapter caseviewDataSetmodreviewTableAdapter = new WpfTestProject.caseviewDataSetTableAdapters.modreviewTableAdapter();
            caseviewDataSetmodreviewTableAdapter.Fill(caseviewDataSet.modreview);
            System.Windows.Data.CollectionViewSource modreviewViewSource =     ((CollectionViewSource)(this.FindResource("modreviewViewSource")));
            modreviewViewSource.View.MoveCurrentToFirst();

            noneligibilityreasonColumn.ItemsSource = NERList.GetNameValueList();
    }
}

}

大部分代码是在我从数据源拖放时生成的,但后面代码的最后一行是我认为我应该添加 ItemsSource 的地方。不确定它是否属于 Loaded,但似乎在那里可能没问题。也不确定是否有办法在 XAML 中执行此操作。

我意识到我在 XAML 和代码中复制了 ItemsSource 的设置,但都没有正常工作,所以我将两者都包括在内以显示我尝试过的选项。

最后,我认为我应该展示我试图在 WPF 转换中模拟的旧 winforms 代码(不确定代码是否足够)。我认为它使用隐藏的组合框来设置绑定,然后将其添加到 table:

//from Program.cs used in setupModRvwGrdHdr()
public static void ListControlBinding(ref UltraCombo comboBox, object lkupdataSource, string displayMember,
                                          string valueMember, object objDataSource, string objProp) {
        comboBox.DataSource = lkupdataSource;
        comboBox.DisplayMember = displayMember;
        if (!string.IsNullOrEmpty(valueMember))
            comboBox.ValueMember = valueMember;
        if (objDataSource != null)
            comboBox.DataBindings.Add("Value", objDataSource, objProp);
    }


//from the code for the specific winform
private void setupModRvwGrdHdr() {
        cbNonEligReason.DataBindings.Clear();
        grdModReviews.DataSource = bsModRvws;

        Program.ListControlBinding(ref cbNonEligReason, NERList.GetNameValueList(), "Value", "Key", bsModRvws,
            "NonEligibleReasonIDStr");
        cbNonEligReason.DisplayLayout.Bands[0].Columns["Key"].Hidden = true;
        cbNonEligReason.DisplayLayout.Bands[0].Columns["Value"].Header.Caption = "Noneligiblity Reason";

        grdModReviews.DisplayLayout.Bands[0].Columns["reviewnum"].CellActivation = Activation.NoEdit;
        grdModReviews.DisplayLayout.Bands[0].Columns["intcaseno"].Hidden = true;
        grdModReviews.DisplayLayout.Bands[0].Columns["noneligibilityreason"].Hidden = true;

        grdModReviews.DisplayLayout.Bands[0].Columns["screendate"].Hidden = false;
        grdModReviews.DisplayLayout.Bands[0].Columns["screendate"].Header.Caption = "Date of Screen";
        grdModReviews.DisplayLayout.Bands[0].Columns["screendate"].Width = 100;
        grdModReviews.DisplayLayout.Bands[0].Columns["screendate"].EditorComponent = dteModRvwDate;

        grdModReviews.DisplayLayout.Bands[0].Columns["eligible"].Hidden = false;
        grdModReviews.DisplayLayout.Bands[0].Columns["eligible"].Header.Caption = "Eligible";
        grdModReviews.DisplayLayout.Bands[0].Columns["eligible"].Width = 70;

        grdModReviews.DisplayLayout.Bands[0].Columns["NonEligibleReasonIDStr"].Hidden = false;
        grdModReviews.DisplayLayout.Bands[0].Columns["NonEligibleReasonIDStr"].Header.Caption =
            "Reason for Noneligibility";
        grdModReviews.DisplayLayout.Bands[0].Columns["NonEligibleReasonIDStr"].Width = 250;
        grdModReviews.DisplayLayout.Bands[0].Columns["NonEligibleReasonIDStr"].EditorComponent = cbNonEligReason;
        grdModReviews.DisplayLayout.Bands[0].Columns["NonEligibleReasonIDStr"].Nullable =
            Infragistics.Win.UltraWinGrid.Nullable.Nothing;
    }

这是一个相当大的程序,CslaFactoryBusinessObjects 中可能有一些有用的函数 类,但我认为我应该学习如何执行此操作以更好地理解 WPF 中的数据操作。

几天来我一直在寻找解决方案,但没有找到与我的案例足够相似的案例。我只是不确定每个绑定属性的确切工作方式以及它们在这种特定情况下的应用方式。最后只好认输,在这里算了一笔账。抱歉,篇幅太长了,但我想说得更具体一点,表明我已经有一段时间了。

请帮忙!

这里有很多有用的信息,也是一个 SO 问题的良好开端。

鉴于您的 XAML 绑定:

<DataGridComboBoxColumn x:Name="noneligibilityreasonColumn" Width="SizeToHeader" Header="noneligibilityreason"
                                    ItemsSource="{Binding Source={StaticResource noneligibilityViewSource}}"
                                    SelectedValueBinding="{Binding noneligibilityreason}"
                                    DisplayMemberPath="Value"
                                    SelectedValuePath="Key"
                                        />

这就是说(对于 DataGrid 中的每一行 - 这又是 DataSet 内 DataTable 中的一个 modreview 对象/行)组合框控件应该使用 noneligibilityViewSource 的 selectable 项目列表。

(暂时忽略Window_Loaded事件中物品来源的矛盾设置)

它还表示组合框的显示(在控件中可视化显示的内容)应该来自 "Value" 属性,如 DisplayMemberPath 中指定的那样。这将对应于 ItemSource 指定的集合中的同名 属性 项目。

由于组合框的项目是由 ItemSource 绑定提供的,因此它将来自 noneligibilityViewSource,所以下一个问题是这个 noneligibilityViewSource 中的内容是什么?

您已将其声明为此 Window 的资源:

<CollectionViewSource x:Key="noneligibilityViewSource" Source="{Binding noneligreason, Source={StaticResource caseviewDataSet}}" />

以上说明 CollectionViewSource 实例(又名 noneligibilityViewSource)来自 caseviewDataSet 上名为 noneligreason 的 属性。考虑到 DataSet 的工作方式,我期待一个名为 noneligreason 的 DataTable 或一个为此添加了 属性 的自定义 DataSet。可能是前者。

现在,您在 Window_Loaded 事件中有相互矛盾的代码,该代码以编程方式将组合框的 ItemSource 设置为其他内容。具体到 NERList.GetNameValueList(); 的调用结果。我说矛盾是因为 XAML 资源声明说这个非资格值列表来自 DataSet 上相应命名的 属性,而事件中的代码说使用 CSLA 业务对象列表。

你必须弄清楚你想要 to/should 使用哪一个。

PS:很可能,如果DataSet中的不合格属性包含数据,那么就不需要付出再次访问数据库的性能损失调用 NERList.GetNameValueList(); 因为您已经有可用的数据。

一旦您确定哪个 "source" 包含您的组合框的项目列表 - 即。 caseviewDataSet 中的 noneligreason DataTable 或调用 NERList.GetNameValueList(); 返回的 CSLA 业务对象列表 - 只有这样您才能知道哪个 属性 应该用于 DisplayMemberPath 和其中 属性 用于 SelectedValuePath。

因此,如果组合框的 ItemSource 符合声明的 XAML 并且 caseviewDataSet 有另一个名为 noneligreason 的数据表,那么您需要从中找出属性的名称.例如,它可能是 noneligreasonidnoneligreasondesc,但也可能是其他内容,具体取决于 table 适配器的作用。您的绑定 DisplayMemberPath 可以是 noneligreasondesc 并且您的 SelectedValuePath 可以是 noneligreasonid.

如果组合框的 ItemSource 应来自对 NERList.GetNameValueList(); 的调用,那么您需要确定返回的对象的 属性 名称是什么。从命名约定我猜它是 "Name" 和 "Value" 这意味着 DisplayMemberPath 应该是 ValueSelectedValuePath 应该设置为 Name.猜测是不好的,所以去看看那个对象,或者使用调试器检查值。

SelectedValueBinding 属性 指的是 modreview 行对象上的 属性 应该包含所选组合框项目的值,具体来说 SelectedValuePath 属性 来自组合框项目将应用于 SelectedValueBinding 属性 modreview 实例。

以下 MSDN 文档应该可以帮助您了解 DataGridComboBoxColumn 上的各种属性的用途。 https://msdn.microsoft.com/en-us/library/system.windows.controls.datagridcomboboxcolumn(v=vs.110).aspx

例如,您的 XAML 可以更改为以下两个声明之一:

<DataGridComboBoxColumn x:Name="noneligibilityreasonColumn" Width="SizeToHeader" Header="noneligibilityreason"
                                        ItemsSource="{Binding Source={StaticResource noneligibilityViewSource}}"
                                        SelectedValueBinding="{Binding noneligibilityreason}"
                                        DisplayMemberPath="noneligreasondesc"
                                        SelectedValuePath="noneligreasonid"
                                            />

<DataGridComboBoxColumn x:Name="noneligibilityreasonColumn" Width="SizeToHeader" Header="noneligibilityreason"
                                        ItemsSource="{Binding Source={StaticResource noneligibilityViewSource}}"
                                        SelectedValueBinding="{Binding noneligibilityreason}"
                                        DisplayMemberPath="Value"
                                        SelectedValuePath="Name"
                                            />

希望对您有所帮助。