WPF Issues Binding ComboBox Within DataGrig

I'm having a problem getting a ComboBox to populate with the object that I am wanting to bind to it.  The object is a list of Users that contains 2 properties.  I've tried as many different ideas I've found but haven't had any luck so far.  In the XAML below I've got 2 different ComboBox columns.  Ideally I'd like to get the 1st column to work as I don't like having to click into the field to activate the ComboBox before it can be selected.  Fingers crossed that it is something more obvious to you :)

Thanks,
Greg



    <Grid>

        <DataGrid x:Name="gvDefaultCWWSchedule" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,10,10,25" AutoGenerateColumns="False" Grid.Column="2" Grid.Row="0" Grid.ColumnSpan="3"
                  AllowDrop="True" IsReadOnly="False" SelectionMode="Single" Background="Beige"  CanUserAddRows="False">
            <DataGrid.Columns>

                <DataGridTemplateColumn Width="150">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox  ItemsSource="{Binding Users, RelativeSource={RelativeSource AncestorType=DataGridCell}}" SelectedItem="{Binding Uid, UpdateSourceTrigger=PropertyChanged}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

                <DataGridComboBoxColumn Width="150">
                    <DataGridComboBoxColumn.ElementStyle>
                        <Style TargetType="ComboBox">
                            <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.UsersFinal}"/>
                            <Setter Property="IsReadOnly" Value="True"/>
                            <Setter Property="SelectedValue" Value="{Binding Name}"/>
                        </Style>
                    </DataGridComboBoxColumn.ElementStyle>
                    
                    <DataGridComboBoxColumn.EditingElementStyle>
                        <Style TargetType="ComboBox">
                            <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path=DataContext.UsersFinal}"/>
                            <Setter Property="IsReadOnly" Value="True"/>
                            <Setter Property="SelectedValue" Value="{Binding Name}"/>
                        </Style>
                    </DataGridComboBoxColumn.EditingElementStyle>
                </DataGridComboBoxColumn>

                <DataGridTextColumn Binding="{Binding WeekNumber}" />

            </DataGrid.Columns>
        </DataGrid>


    </Grid>

Open in new window



    public partial class Test : Window
    {
        public Test()
        {
            InitializeComponent();
            BindDefaultCWWSchedule();
        }


        private void BindDefaultCWWSchedule()
        {
            // THIS IS COMING FROM MY DB 
            List<CurrentUser> UsersFinal = new List<CurrentUser>();
            UsersFinal.Add(new CurrentUser { Uid = 1, Name = "JOHN" });
            UsersFinal.Add(new CurrentUser { Uid = 2, Name = "BILL" });
            UsersFinal.Add(new CurrentUser { Uid = 3, Name = "MARY" });


            List<CWWDefaultScheduleWeek> DefaultSchedules = new List<CWWDefaultScheduleWeek>();
            DefaultSchedules.Add(new CWWDefaultScheduleWeek { Users = UsersFinal, WeekNumber = 1 });
            DefaultSchedules.Add(new CWWDefaultScheduleWeek { Users = UsersFinal, WeekNumber = 2 });
            DefaultSchedules.Add(new CWWDefaultScheduleWeek { Users = UsersFinal, WeekNumber = 3 });
            DefaultSchedules.Add(new CWWDefaultScheduleWeek { Users = UsersFinal, WeekNumber = 4 });
            
            gvDefaultCWWSchedule.ItemsSource = DefaultSchedules;
        }

    }


    public class CurrentUser
    {
        public int Uid { get; set; }
        public string Name { get; set; }
    }


    public class CWWDefaultScheduleWeek
    {
        public List<CurrentUser> Users { get; set; }
        public int WeekNumber { get; set; }
    }

Open in new window

Screenshot---3-26-2015---4-02-07-PM.png
Greg_L_WERAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Aaron JabamaniTechnical ArchitectCommented:
You mean, in the first column , you want the first item to selected by default in the combo box?
ambienceCommented:
Shouldnt it be?

<DataTemplate>
<ComboBox  ItemsSource="{Binding Path=Users}" />
</DataTemplate>

The context for each DataGridColumn is the item that it is being bound to.

The SelectedITem binding is incorrect. Following is one option

 SelectedItem="{Binding SelectedUser, UpdateSourceTrigger=PropertyChanged}"

which requires following changes

    public class CWWDefaultScheduleWeek
    {
        public List<CurrentUser> Users { get; set; }
        public CurrentUser SelectedUser { get; set; }
        public int WeekNumber { get; set; }
    }
Greg_L_WERAuthor Commented:
Hi apeter... I was just hoping to get this control working... though both types of views would be best.  The way column is displayed (see image DDL Image 3.png attached) is that the DDL is already visible so you can directly access the items... where as the 2nd column you have to click into the field which activates the DDL.  Column 1 just makes selection more efficient.

Hi ambience... switching it as suggested does cause the object to bind to the combo box but the problem is that the items that are displayed are not the names... it is the whole? object.  See image (DDL Image 2.png)  below... the XAML is below.

Thanks,
Greg

                <!--<DataGridTemplateColumn Width="150">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox  ItemsSource="{Binding Users, RelativeSource={RelativeSource AncestorType=DataGridCell}}" SelectedItem="{Binding Uid, UpdateSourceTrigger=PropertyChanged}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>-->


                <DataGridTemplateColumn Width="150">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox  ItemsSource="{Binding Path=Users}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

Open in new window

DDL-Image-2.png
DDL-Image-3.png
Become a CompTIA Certified Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

ambienceCommented:
Right, so you can either


1 - overload ToString() to get a better display, which is quickest but ugliest solution.

2 - A better solution is to use a DataTemplate, e.g.

            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>

Im sure there are a few other ways as well, but these should do.
Greg_L_WERAuthor Commented:
Thanks ambience... forgive my ignorance on this... first project I've really worked with XAML.... outside of my DataGrid this ComboBox Template works as expected when I bind it using "gvDefaultCWWSchedule1.ItemsSource = UsersFinal;"  

Problem I'm having is to get the same result but the combobox is within DataGrid I thought using <DataGridComboBoxColumn>.  Clearly I'm missing something here... appreciate any ideas you may have.

Thanks,
Greg

        <ComboBox x:Name="gvDefaultCWWSchedule" VerticalAlignment="Top">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>

Open in new window

ambienceCommented:
OK that snippet was supposed to be merged with the working XAML. Here's how it should look like

                <DataGridTemplateColumn Width="150">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox  ItemsSource="{Binding Path=Users}" >
                                <ComboBox.ItemTemplate>
                                    <DataTemplate>
                                        <StackPanel Orientation="Horizontal">
                                            <TextBlock Text="{Binding Name}" />
                                        </StackPanel>
                                    </DataTemplate>
                                </ComboBox.ItemTemplate>
                            </ComboBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Greg_L_WERAuthor Commented:
Thanks ambience... that works great!  Last (I think ;) question.  I'm now needing to iterate through each row in the DataGrid and get the Uid (from the CurrentUser) for the selected ComboBox User.  Thanks in advance for your help.

Thanks,
Greg

PS - Any resources that you would recommend for WPF basics?  Sadly much of my web development experience doesn't extend to WPF.


    public class CWWDefaultScheduleWeek
    {
        public IEnumerable<CurrentUser> Users { get; set; }
        public CurrentUser SelectedUser { get; set; }
        public int WeekNumber { get; set; }
    }

    public class CurrentUser
    {
        public int Uid { get; set; }
        public string Name { get; set; }
    }

Open in new window

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.