Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF DataGridComboBoxColumn not working

Tags:

c#

.net

mvvm

wpf

xaml

I have a DataGridComboBoxColumn in a DataGrid in a WPF project set like this:

<DataGridComboBoxColumn Header="Master" SelectedItemBinding="{Binding MasterId}" SelectedValueBinding="{Binding Id}" DisplayMemberPath="Id" ItemsSource="{Binding Masters}" />

but when I run the project the column display only blank values and the combobox in edit mode does the same thing.

The DataGrid is set like this:

<DataGrid Name="ReadersGrid"  Grid.Row="0" Grid.Column="0" Margin="3" ItemsSource="{Binding Readers}" CanUserAddRows="True" CanUserDeleteRows="True" AutoGenerateColumns="False">

And the UserControl like this:

<UserControl x:Class="SmartAccess.Tabs.ReadersTab"
     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:SmartAccess.Tabs"
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300" DataContext="{StaticResource ReadersListViewModel}">

and the other columns, only text, work fine.

The ViewModel has these properties

public ObservableCollection<ReaderViewModel> Readers { get; set; }
public IEnumerable<ReaderViewModel> Masters => Readers.Concat(new List<ReaderViewModel> { new ReaderViewModel { Id = -1 } }).OrderBy(t => t.Id);

And the collection viewmodel has these properties

public long Id { get; set; }
public long MasterId { get; set; }

I'm displaying Id only for test, a description property will be added in future.

Why the ComboBoxColumn is not working?

like image 980
Matteo Bruni Avatar asked Mar 12 '23 00:03

Matteo Bruni


1 Answers

Your issue is caused by DataGridColumns: indeed they do not belong to the visual tree, so you cannot bind their properties to your DataContext.

You can find here a solution based on a kind of freezable "DataContext proxy", since Freezable objects can inherit the DataContext even when they are not in the visual tree.

Now if you put this proxy in the DataGrid's resources, it can be bound the the DataGrid's DataContext and can be retrieve by using the StaticResource keyword.

So you XAML will become:

<DataGridComboBoxColumn Header="Master" SelectedItemBinding="{Binding MasterId}"
    SelectedValueBinding="{Binding Id}" DisplayMemberPath="Id"
    ItemsSource="{Binding Data.Masters, Source={StaticResource proxy}}" />

Where proxy is the name of your resource.

I hope it can help you.

EDIT

I update my answer with the code copied from this link (because of @icebat's comment). This is the BindingProxy class:

public class BindingProxy : Freezable
{
    #region Overrides of Freezable

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    #endregion

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}

Then in the XAML you need to add:

<DataGrid.Resources>
    <local:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>
like image 198
Il Vic Avatar answered Mar 25 '23 02:03

Il Vic