Setting ItemSource to DataGridComboBoxColumn Using Separate Database Table

My first question is on StackExchange, so tell me if I go wrong.

I am converting old winforms code to WPF and I incline both of them along the way. I've been successful most of the time, but I am binding my first data table with data binding. It seems to be the hardest to convert as the binding is handled mostly in xaml and not in code.

As a side note, she uses CSLA, which to my knowledge is a MVVM-like code structure (still learning what it is).

With a little experimentation, I was able to create a functional data grid, but I need to implement one of the columns as a combo box. It is currently represented as a number (1-10), but I need a description that comes with a number that is in another table in the database.
The number that was originally displayed before switching it to the dropdown was incompatible. I want this value to be the currently selected item in the combo box.

Can't send images, so here I tried to show the structure of the database tables:

modreview

  • reviewnum
  • intcaseno
  • newreferral
  • screendate
  • right
  • noneligibilityreason (this is the one to be done in the combo box)

noneligreason (this is a subtable that aligns with the unlimited mind)

  • noneligreasonid
  • noneligreasondesc

Included in the code is this function, which seems to create a collection, which should be, I think, ItemsSource:

NERList.GetNameValueList();

      

As for the ItemsSource, I want all noneligreasondesc values. Of course, then the question arises as to whether the unlimited mind should correspond to non-eligrasonide. I found this example , which seems to do the same thing, but without the database, using classes instead:

I tried to duplicate this as I thought it should work here in my 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>

      

And the code behind:

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

      

}

Most of this code was generated when dragging from data sources, but the last line in the code behind is where I think I should have added the ItemSource. Not sure if it belongs to Loaded, but it looks like it's okay. Also not sure if there is a way to do this in XAML.

I realize I have duplicated the ItemsSource parameter in the XAML and code, but neither is working as expected, so I included both to show which options I tried.

Finally, I think I should show the old winforms code that I am trying to emulate in WPF transform (not sure if this is enough code). I think it uses a hidden combobox to set up the binding and then adds it to the 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;
    }

      

It's a pretty big program, and there might be some useful functionality in the CslaFactoryBusinessObjects classes, but I think I should learn how to do this in order to better understand data manipulation in WPF.

I've been looking for a solution for days and haven't found a case like mine. I'm just not sure how each of the binding properties work and how they are applied in this particular case. Finally had to drop the towel and make the bill here. Sorry for the length, but I wanted to be specific and show that I have been at this for a while.

Please, help!

+3


source to share


1 answer


There is a lot of useful information here, and a good start for the SO question.

Given your XAML binding:

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

      

This means that (for each row from the DataGrid, which in turn is an modreview

object / row from the DataTable inside the DataSet), the combobox control must use noneligibilityViewSource

for its list of selectable Items.

(For now, ignore the conflicting setting of the element source in the event Window_Loaded

).

It also says that for the combobox to be displayed (what is visually displayed in the control) must come from the Value property as specified in DisplayMemberPath

. This will match the same named property from the collection item specified ItemSource

.

Since the combobox items are provided by the ItemSource binding, then they will come from noneligibilityViewSource

, so the next question is what is inside that noneligibilityViewSource

?

You have declared a resource for this window:

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

      

The above said that the CollectionViewSource instance (aka noneligibilityViewSource

) comes from a property called noneligreason

on caseviewDataSet

. Given how DataSets work, I expect either a DataTable by name noneligreason

, or a custom DataSet with a property added to do this. Probably the first one.

You now have conflicting code in an event Window_Loaded

that programmatically sets the ItemSource for the combobox to something else. In particular, to the result of the call NERList.GetNameValueList();

. I say inconsistently because the XAML resource statement says that this list of non-limitation values ​​comes from the corresponding named property in the DataSet, while the code in this case uses a list of CSLA business object objects.

You will need to figure out which one you want to use.



PS: Probably if the noneligibility property on the DataSet contains data, then there is no need to pay performance again when accessing the database with a call NERList.GetNameValueList();

, because you already have the data.

Once you have determined which "source" contains the list of items for your field, ie. noneligreason

DataTable in caseviewDataSet

or from the list of CSLA business objects returned by the call NERList.GetNameValueList();

- only then can you know which property should be used for DisplayMemberPath and which property for SelectedValuePath.

So, if the ItemSource for the combobox matches the declared XAML, and the caseviewDataSet has another DataTable called noneligreason

, then from that you need to figure out what the property names are. For example, it might be noneligreasonid

and noneligreasondesc

, but it might be something different depending on what the table adapter is doing. Your binding DisplayMemberPath

may be noneligreasondesc

, and yours SelectedValuePath

may be noneligreasonid

.

If the ItemSource for the combobox is to come from a call to NERList.GetNameValueList();

, then again you need to determine what the property names of the returned objects are. From the naming convention, I assume it is "Name" and "Meaning", which means what DisplayMemberPath

should be Value

and SelectedValuePath

should be set to Name

. It's not a good guess, so go and have a look at this object, or use a debugger to check the values.

The property SelectedValueBinding

refers to a property on a string object modreview

that should contain the value of the selected combobox item, specifically the property SelectedValuePath

from the combobox item will be applied to the property SelectedValueBinding

in the instance modreview

.

The following MSDN documentation should help you understand what the different properties in the DataGridComboBoxColumn are for. https://msdn.microsoft.com/en-us/library/system.windows.controls.datagridcomboboxcolumn(v=vs.110).aspx

So, for example, your XAML can change to either one of the following two declarations:

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

      

or

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

      

Hope it helps.

+1


source







All Articles