DataGridComboBoxColumn not updating model WPF - c#

I'm using Datagrid in WPF and DataGridComboBoxColumn. Please find the code below:
<DataGrid>...
<DataGridComboBoxColumn Header="Category" Width="200"
SelectedValueBinding="{Binding SelectedCategory, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="CategoryName"
SelectedValuePath="CategoryID">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding CategoriesList}"></Setter>
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding CategoriesList}"></Setter>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
The model is as follows:
public CategoryModel SelectedCategory { get; set; }
public ObservableCollection<CategoryModel> CategoriesList
{
get;
set;
}
Now when ever I change the selection in combobox it shows a red border, unable to commit the changes to the source.

This is wrong:
<DataGridComboBoxColumn Header="Category" Width="200"
SelectedValueBinding="{Binding SelectedCategory, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="CategoryName">
remove the SelectedValuePath or you get a type missmatch. I doubt you need the UpdateSourceTrigger either... Try to ommit.

Related

Binding ancestor element in WPF [duplicate]

This question already has answers here:
Binding Visibility for DataGridColumn in WPF
(4 answers)
Closed 4 years ago.
I am struggling to hide columns of a Datagrid by binding the Visibility property to a property of the viewModel. ItemsSource works fine and I have many lines in the grids, to the Datacontext is set properly. Can you please help me with what I am doing wrong ? Thanks
<StackPanel>
<DataGrid ItemsSource="{Binding SortedPlanning}" IsReadOnly="True" AutoGenerateColumns="False" CanUserResizeRows="False">
<DataGrid.Columns >
<DataGridTextColumn Header ="NNI" Binding="{Binding SortedPlanning.Nni}" Width="80" Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StackPanel}}, Path=ColumnVisibility}">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header ="Nom" Binding="{Binding LastName}" Width="120" Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=ColumnVisibility}">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header ="Prénom" Binding="{Binding FirstName}" Width="80" Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=ColumnVisibility}">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGridTextColumn>
<DataGridTextColumn Header ="Campagne" Binding="{Binding Campaign}" Width="120">
<DataGridTextColumn.ElementStyle>
<Style>
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid>
</StackPanel>
View model :
public interface IPlanningViewModel : IDisposable
{
ObservableCollection<PlanningEntry> SortedPlanning { get; }
Visibility ColumnVisibility { get; }
bool FilterGrid { get; set; }
DateTime FromDate { get; set; }
DateTime ToDate { get; set; }
}
I expect columns "NNI", "Nom" and "Prénom" to be bound to the ColumnVisibility of the VM, but it does not happen.
You will have use below syntax.
It should resolve your issue.
<DataGridTextColumn Visibility="{Binding Path=DataContext.ColumnVisibility, RelativeSource={RelativeSource AncestorType=DataGrid}}" />

Binding to DataGridComboBox

I know this has been asked a few times, but I cannot get the binding to work on my DataGridComboBox, it never displays at all. Can someone show me the error of my ways?
c#
IList<ServiceCodes> servicecodes = App.GetInfo.GetServiceCodes();
newinvoice.INVItemsDataGrid.DataContext = servicecodes;
newinvoice.ShowDialog();
XAML
<DataGrid x:Name="INVItemsDataGrid" DataContext="{Binding}">
<DataGrid.Columns>
<DataGridComboBoxColumn x:Name="INVSCDropDown" DisplayMemberPath="CodeName" SelectedValuePath="CodeName" SelectedValueBinding="{Binding CodeName}" />
</DataGrid.Columns>
</DataGrid>
Thanks for your help as always.
The first thing you need to do is to set the ItemsSource property of the DataGrid to an IEnumerable.
Once you have done this, you could bind the ComboBox to another or the same IEnumerable like this:
<DataGrid x:Name="INVItemsDataGrid" ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridComboBoxColumn x:Name="INVSCDropDown" DisplayMemberPath="CodeName" SelectedValuePath="CodeName" SelectedValueBinding="{Binding CodeName}">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=., RelativeSource={RelativeSource AncestorType=DataGrid}}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=., RelativeSource={RelativeSource AncestorType=DataGrid}}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
...although it doesn't make much sense to bind the ComboBox and the DataGrid to the same source collection. But you should at least get the idea.

How can I bind to the count of the items source in XAML using a style and a DataTrigger?

I can bind to the Item source if I call the list by name but, I have not been able to get the binding to work generically by getting the Count of the Items on each individual combobox.
Here is what I would like to do in XAML. What do I need to change for this binding to work?
<Grid.Resources>
<Style TargetType="ComboBox">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items.Count}" Value="0">
<Setter Property="IsEnabled" Value="False"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<ComboBox
ItemsSource="{Binding MyList}"
SelectedItem="{Binding SelectedElement}"
ItemTemplate="{StaticResource MyTemplate}">
</ComboBox>
Include the RelativeSource component in your binding:
<DataTrigger Binding="{Binding Path=Items.Count, RelativeSource={RelativeSource Self}}"
Value="0"
>
The way you currently have it the binding subsystem will look for the Items.Count property on whatever you have set as the DataContext of the ComboBox.

WPF DataGrid ComboBox SelectedItem Property Setter

I am looking for an example of how to use the SelectedItem property inside a combobox in a WPF DataGrid, I have
<DataGridComboBoxColumn SelectedValueBinding="{Binding CID, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
SelectedValuePath="CID"
Header="CID"
Width="70">
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding DataContext.ListCustomerCollection,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/>
<Setter Property="DisplayMemberPath" Value="Name"/>
<Setter Property="SelectedItem" Value="{Binding DataContext.Customer, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"></Setter>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding DataContext.ListCustomerCollection, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/>
<Setter Property="DisplayMemberPath" Value="Name"/>
<Setter Property="HorizontalAlignment" Value="Center"></Setter>
<Setter Property="SelectedItem" Value="{Binding DataContext.Customer, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"></Setter>
</Style>
</DataGridComboBoxColumn.ElementStyle>
The DataContext I bind to (ListCustomerCollection) is a List object
List<Customer>
so the property in the ViewModel property I have set is
private Customer m_Customer = null;
public Customer Customer
{
get { return m_Customer; }
set
{
m_Customer = value;
OnPropertyChanged("Customer");
}
}
So how do I writethe XAML to set the above property with the SelectedItem?
If property resides in window's ViewModel, you have to get window's DataContext like you did for ItemsSource.
<Setter Property="SelectedItem"
Value="{Binding DataContext.Customer,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window}}"/>

DataGridComboBoxColumn binding

I have seen a few posts on here with people getting confused on how to bind to a DataGridComboBoxColumn,
I have
<DataGridComboBoxColumn SelectedItemBinding="{Binding Collection}" DisplayMemberPath="Name" Header="Name" Width="70">
which didnt work..
So I used
<DataGridComboBoxColumn ItemBinding="{Binding Collection}" DisplayMemberPath="Name"> Header="Name" Width="70">
Which again didn't work, why is binding to a datagridcombo different to a original combo box.
<ComboBox ItemsSource="{Binding Collection}" DisplayMemberPath="Name" HorizontalAlignment="Left">
which does work
What is the correct method of binding to a combo box inside a DataGrid?
---Edit---
I might have found the problem, I have a DataGrid binding to a ItemSource, however, I want the ComboBoxColumn to be bounded to a different Itemsource, is this possible?
Cheers
You need to bind to ItemsSource property. Set it in EditingElementStyle.
<DataGridComboBoxColumn>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Collection}"/>
<Setter Property="DisplayMemberPath" Value="Name"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
In case you want ItemsSource to bind to collection which is outside of DataGrid underlying source object, you can do that as well.
Say you have collection AnotherCollection residing in ViewModel of Window/UserControl, you can bind with it using RelativeSource markup extension.
Also, you have to set SelectedItemBinding to the property where you want to set the value selected from ComboBox and declare same style under ElementStyle of DataGridComboBoxColumn.
Suppose property name is Name to which you want to bind.
<DataGridComboBoxColumn SelectedItemBinding="{Binding Name}">
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource"
Value="{Binding DataContext.AnotherCollection,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window}}"/>
<Setter Property="DisplayMemberPath" Value="Name"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource"
Value="{Binding DataContext.AnotherCollection,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window}}"/>
<Setter Property="DisplayMemberPath" Value="Name"/>
</Style>
</DataGridComboBoxColumn.ElementStyle>
</DataGridComboBoxColumn>

Categories