2
votes

Does anyone have an example of binding a ComboBox to a Selected Item of a DataGrid? I have tried a bunch of ways, but I can't seem to get it to work. I am fairly new to MVVM so I am doing something wrong. Any help would be appreciated. I have the datacontext of the grid that the combobox is in set to the datagrid, but when I select a row from the datagrid the combobox does not change. All of the text boxes are populated with the data from the datagrid, but the combobox does not change. The combobox in question is cmbRoles.

Thank you,

RG

Here is the XAML:

<UserControl x:Class="Compliance.Views.UserAdministrationView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:Compliance"
         xmlns:views="clr-namespace:Compliance.Views"
         xmlns:helpers="clr-namespace:Compliance.Helpers"
         xmlns:vm="clr-namespace:Compliance.ViewModels"
         xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
         mc:Ignorable="d" 
         d:DesignHeight="1000" d:DesignWidth="800">
<UserControl.Resources>
    <helpers:ActiveStatusConverter x:Key="ActiveStatusConverter"/>
</UserControl.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Row="0" Margin="15">
        <Label Content="User" Height="25" FontSize="14" HorizontalContentAlignment="Center" />
        <Grid HorizontalAlignment="Center" VerticalAlignment="Top" DataContext="{Binding ElementName=usersDG, Path=SelectedItem}">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" MinHeight="35" />
            </Grid.RowDefinitions>
            <telerik:Label Content="User Name: " Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" />
            <TextBox Grid.Column="1" Grid.Row="0" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180" >
                <TextBox.Text>
                    <Binding Path="UserName" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
                </TextBox.Text>                    
            </TextBox> 
            <telerik:Label Content="First Name: " Grid.Column="2" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" />
            <TextBox Grid.Column="3" Grid.Row="0" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180">
            <TextBox.Text>
                <Binding Path="FirstName" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
            </TextBox.Text>
            </TextBox>
            <telerik:Label Content="Last Name: " Grid.Column="4" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" />
            <TextBox Grid.Column="5" Grid.Row="0" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180">
            <TextBox.Text>
                <Binding Path="LastName" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
            </TextBox.Text>
            </TextBox>
            <telerik:Label Content="Email: " Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" />
            <TextBox Grid.Column="1" Grid.Row="1" MinHeight="23" HorizontalAlignment="Left" VerticalAlignment="Center" MinWidth="180" MaxWidth="180">
                <TextBox.Text>
                    <Binding Path="Email" Mode="TwoWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True"/>
                </TextBox.Text>
            </TextBox>
            <telerik:Label Content="Active Status: " Grid.Column="2" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" />
            <telerik:RadComboBox x:Name="comBoxActiveStatus" Grid.Column="3" Grid.Row="1" MinHeight="23" MinWidth="180" HorizontalAlignment="Left" VerticalAlignment="Center"
                    SelectedItem="{Binding Path=ActiveStatus, 
                                    Converter={StaticResource ResourceKey=ActiveStatusConverter}, 
                                    Mode=TwoWay, 
                                    ValidatesOnExceptions=True, 
                                    NotifyOnValidationError=True}">
            </telerik:RadComboBox>
            <telerik:Label Content="Role: " Grid.Column="4" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" />
            <telerik:RadComboBox x:Name="cmbRoles" DisplayMemberPath="RoleName" 
                        Grid.Column="5" 
                        Grid.ColumnSpan="3"
                        Grid.Row="1" 
                        MinHeight="23" 
                        HorizontalAlignment="Left" 
                        ItemsSource="{Binding}" 
                        Margin="5" 
                        VerticalAlignment="Center" 
                        MinWidth="180" 
                        SelectedItem="{Binding RoleName}"
                        IsSynchronizedWithCurrentItem="True">
            </telerik:RadComboBox>
            <Button Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="3" Content="Save User" Width="100"  />
            <Button Grid.Column="4" Grid.Row="2" Grid.ColumnSpan="3" Content="Add User"  Width="100"  />
        </Grid>
    </StackPanel>
    <Border CornerRadius="10" BorderThickness="5" Grid.Row="1" VerticalAlignment="Top" HorizontalAlignment="Center">
        <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Label Content="Users" Grid.Row="0" Height="25" FontSize="14" HorizontalContentAlignment="Center" />
            <telerik:RadGridView x:Name="usersDG" ItemsSource="{Binding Users}" AutoGenerateColumns="False" ShowGroupPanel="False" IsReadOnly="True">
                <telerik:RadGridView.Columns>
                    <telerik:GridViewDataColumn DataMemberBinding="{Binding UserName}" Header="User Name" />
                    <telerik:GridViewDataColumn DataMemberBinding="{Binding FirstName}" Header="First Name" />
                    <telerik:GridViewDataColumn DataMemberBinding="{Binding LastName}" Header="Last Name" />
                    <telerik:GridViewDataColumn DataMemberBinding="{Binding Email}" Header="Email" />
                    <telerik:GridViewDataColumn DataMemberBinding="{Binding Role.RoleName}" Header="Role Name" />
                    <telerik:GridViewDataColumn DataMemberBinding="{Binding ActiveStatus, Converter={StaticResource ActiveStatusConverter}}" Header="Active Status" />
                </telerik:RadGridView.Columns>
            </telerik:RadGridView>
        </Grid>
    </Border>
</Grid>

2
What's the date in the ComboBox supposed to be? How will it relate to the SelectedItem in the DataGrid?d.moncada
The data in the combobox is the role the user has for the application. This is a user amdinistration screen. They will be able to add a new user or edit an existing user by selecting them from the datagrid and editing their properties. I have done this before with another WPF application, but I have decided to learn the MVVM design pattern and I am trying to stick to the pattern.RG21
Have you tried SelectedItem="{Binding Role.RoleName}" for your combobox?d.moncada
Yes. The combobox does not change, and there are no errors in the output window either.RG21

2 Answers

2
votes

Expanding and taking a different take on Hannish's Answer above, I too assume you are using a Master Details type arrangement, where you want the Details DataContext to be set to the DataGrid Selected Row.

I also had alot of trouble with ComboBox Binding in this setup too.

I don't use Telerik Controls for my applications, however I tend to create a Property for the DataGrid Selected Row, and bind my details to this.

The DataGrid XAML would be something like;

<DataGrid x:Name="grdResults" 
    DataContext="{Binding DataGridDataContextCollection}" 
    ItemsSource="{Binding}"
    SelectedItem="{Binding DataContext.SelectedRow, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">

I do it this way, as I have Behaviours I've set for the Rows which run off items in the DataGrid DataContext.

I then have a Property for the Selected ComboBox Item also, and Bind the ComboBox to this.

For the ComboBox ItemSource, the issue is, that you have an ObservableCollection of Items which you need to Bind your ComboBox to, but these of course won't be a member of your DataGrid Selected Row, and in turn your details DataContext.

So for Binding the ComboBox ItemSource and SelectedItem, you must refer to the DataContext of your View, rather than that of the Details.

If you have it available in your DataGrid DataContext, also bind the ComboBox Text Property to the DataGrid SelectedRow Name value, assuming the two are the same! This helps update the DataGrid updated also.

The XAML I use for the ComboBox is something like;

<ComboBox x:Name="cmbRoles" 
    SelectedItem="{Binding DataContext.SelectedRole, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" 
    SelectedValuePath="Role_ID" 
    SelectedValue="{Binding Role_ID, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}"
    ItemsSource="{Binding DataContext.RoleItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" 
    Text="{Binding RoleName, Mode=TwoWay}"
    DisplayMemberPath="RoleName" 
    IsSynchronizedWithCurrentItem="True" 
    HorizontalAlignment="Left"/>

To be 100% sure, I then sync the ComboBox SelectedItem to the DataGrid SelectedRow by setting the DataGrid SelectedRow ID value from within your ComboBox SelectedItem Setter. This of course isn't strictly necessary.

I hope this helps!

0
votes

If I understood correctly, you have a RadGridView with all users, and some sort of Details form in which you edit the values for the selected row.

So, you have to modify a couple of things:

1: The ItemsSource in the combobox is set to {Binding}, so it will just bind to the datacontext of its parent element to get the items list. In this case the parent is the Grid with the DataContext set (correctly) to the RadGrid's selected item (here: DataContext="{Binding ElementName=usersDG, Path=SelectedItem}", it's ok).

The problem is that you have to populate the ItemsSource of the ComboBox with the list of possible Roles. I usually use a static ObservableCollection for such lists (so I make sure they are the same all around the application). Something like this:

ItemsSource="{x:Static local:Lists.RolesList}"

You may have an enum or something else, but the important thing there is that you populate the ItemsSource property with all the options that may be selected.

2: Since you will populate the list in the combobox with Role objects, the SelectedItem must be bound to such an object, which has to exist as a public property (with INPC or a DependecyProperty) inside the User object. You need to set it up like this:

SelectedItem="{Binding Role, Mode=TwoWay}"

Remember that the datacontext of your combo is an User object, as selected in the RadGrid. The user class must have a property Role.

I think that'll do it, let me know if you have any more problems. Best regards!