Trying to add a combobox within datagrid which has an itemsource already - c#

If I have a combo box by iteself with an item source e.g.:
<ComboBox ItemsSource="{Binding Combobox.Options}"/>
This works fine. Where Combobox.Options is a list of strings {"option1","option 2",... etc}
However, I want to have a combobox within a datagrid which has an item source:
e.g.:
<DataGrid CanUserAddRows="False" AutoGenerateColumns="False" SelectionMode="Single" ItemsSource="{Binding Users.Table.Tables[0]}">
But I keep getting an empty combo box when I add it into a datagrid template column. I have also tried the Find Ancestor Relative soure but also got an empty combo box.

Finally managed to find the problem. Needed to add a DataContext when getting the list for the item source within the datagrid:
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}"/>

Related

How to allow selection for DataGridComboBoxColumn

I have this DataGridComboBoxColumn:
<DataGridComboBoxColumn x:Name="OtherComboboxCol"
Header="Other"
SortMemberPath="Other"
IsReadOnly="False"
DisplayMemberPath="{Binding Other}"
SelectedValueBinding="{Binding Other, Mode=TwoWay}"
ItemsSource="{Binding TripOtherStringList, Source={StaticResource StringProvider}"
Width="100">
</DataGridComboBoxColumn>
My problem is that for some reason, I am unable to actually select a choice in a drop-down menu as a combobox should. When I click on a cell in the column, nothing happens. There does not seem to be a way to select any of the choices in TripOtherStringList. There's not even a dropdown arrow for the combobox and it just looks like a TextBlock.
What am I missing?
If you want to see the ComboBox all the time , create a template column. Read more here.
Bottom line : For comboboxes, always use a template column.

Unable to bind Contact object to controls without editing the collection

I have a collection of Contact objects that I've bound as follows in a WPF form:
<ComboBox Name="Name"
Text="{Binding Path=Contact.FullName}"
ItemsSource="{Binding ContactsCollection}"
SelectedItem="{Binding Path=Contact, Mode=TwoWay}"
IsEditable="true"
IsTextSearchEnabled="True"
TextBoxBase.TextChanged="Name_TextChanged"/>
<TextBox Name="Position" Text="{Binding Path=Contact.Position}"/>
<TextBox Name="Phone" Text="{Binding Path=Contact.PhoneNumber}"/>
I'd like the contact to be selected when the user starts typing in the combo 'IsTextSearchEnabled=true'.
The problem is that I'd like the items in the collection to remain read-only. Once a contact has been selected, any text deletes or additions modify the contact name in the collection.
How can I bind a collection to a combobox, enable search and prevent edits to the collection?
I could be missing something here, but if you don't want an editable ComboBox, try not setting the ComboBox.IsEditable property to True. Using this simple code, I can display items in a ComboBox and make selections by typing (when the ComboBox is focused) without editing anything:
<ComboBox ItemsSource="{Binding Items}" IsTextSearchEnabled="True" Height="25" />
Thanks for your input. It sorted me out. Removing the SelectedItem property and setting Position and PhoneNumber in the PropertyChanged event was what I needed.

ComboBox to select first Value when created

I have a combo box in a ItemControl. xaml is
<ComboBox ItemsSource="{Binding DataContext.NodeMembershipFunction,
RelativeSource={RelativeSource AncestorType={x:Type ItemsControl},
AncestorLevel=1}}"
DisplayMemberPath="_Name"
SelectedValue="{Binding Condition, Mode=TwoWay}"
SelectedValuePath="_Type">
</ComboBox>
My combobox works fine with above so I am not posting any code to explain above.
My problem is that when I add a new item to my ItemControl, the combox has nothing selected (which is correct according to the code I have). Is there any way to add a trigger or something in above which selects first item only when nothing is selected eg on adding new itemcontrol?
Set IsSynchronizedWithCurrentItem="True" on comboBox instance so that it always be in sync with current item of collection.
<ComboBox IsSynchronizedWithCurrentItem="True"..../>
Moreover, adding item in collection won't make SelectedItem to go away unless you are re-initializing the entire list.
I would suggest to use ObservableCollection<T> for property NodeMembershipFunction in case not doing it already and add item directly to the collection instead of repopulating it.

Why doesn't the DataGrid correctly rebind to its source list after I've sorted the grid?

Background
I have a DataGrid that doesn't appear to display the data correctly after I remove an item from its data source list when the data grid is sorted.
This is my grid:
<DataGrid Name="fileGrid"
SelectionMode="Single" SelectionUnit="FullRow" AutoGenerateColumns="False"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectionChanged="fileGrid_SelectionChanged" PreviewKeyDown="PreviewKeyDownHandler">
<DataGrid.Columns>
<!-- other columns removed for brevity -->
<DataGridTextColumn Header="Installation" SortMemberPath="Customer.CompanyName" Width="*"
x:Name="columnCompanyName"
Binding="{Binding Path=Customer.CompanyName}"
IsReadOnly="True">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
I can delete an item from the list, e.g. by calling
public void DeleteAndRebind(PanelData panelData)
{
_panelDataList.Remove(panelData);
Rebind();
}
Where Rebind() is defined as
public void Rebind()
{
fileGrid.ItemsSource = _panelDataList;
fileGrid.SelectedItem = _panelDataList.FirstOrDefault();
fileGrid.Items.Refresh();
}
and the grid appears correctly correctly, with the row corresponding to panelData removed.
The Problem
However, if I sort the grid by any columns and then call DeleteAndRebind(panelData) the DataGrid still contains the item that I deleted, even though _panelDataList doesn't.
Question
Why doesn't the DataGrid display the updated _panelDataList when I sort the grid and then delete an item from it?
In WPF, there is no need to detach or rebind data source collections. Once you have data bound a data collection property to an ItemsSource property, then you should leave the ItemsSource property and the control alone.
<DataGrid ItemsSource="{Binding CollectionProperty}" ... />
All data manipulations should be done on the collection itself. So to change the collection, you just do this:
CollectionProperty = new ObservableCollection<YourDataType>();
CollectionProperty.FillWithData(); // An imaginary data access method
To remove an item from the collection, you just do this:
CollectionProperty.Remove(CollectionProperty.ElementAt(indexOfItemToRemove));
To add an item to the collection, you just do this:
CollectionProperty.Add(new YourDataType());

Combobox not rendering in wpf datafrid

I have my data grid "dgSubsytem" column defined like below
<my:DataGridComboBoxColumn x:Name="cmbSubSysSupplier_SRV" Header="Supplier" Width="160"
ItemsSource="{Binding RelativeSource}" SelectedValueBinding="{Binding SupplierId}" />
As you see from the code i am having a combo box inside a grid .
Item source of this combo box is a datatable which is bound to it in the code behind .
Item source of the grid also another datatable bound in code behind .
code of binding item source of combobox in code behind is as follows
cmbSubSysSupplier_SRV.ItemsSource = dsComboBox.Tables[3].DefaultView;
cmbSubSysSupplier_SRV.DisplayMemberPath="FullName" ;
cmbSubSysSupplier_SRV.SelectedValuePath = "SupplierId";
Problem is combo box itself not rendering . But I can see the value of the Supplier rendered as text . What is the problem?
There are 2 parts here:
List of values to be populated in ComboBox: ItemsSource, should be bound using a StaticResource, with a List<X> fields exposed from your ViewModel.
The actual value (here X) should be bound to SelectedItemBinding using binding to data item.
No binding in code behind required.
At what point does your code-behind stuff run?
You're setting the ItemsSource in two places - in the XAML and in the Code-Behind. Whichever one runs second will overwrite the value of the first one, so only the last value set will be used.
I suspect your XAML is getting run last, and RelativeSource is probably not a property on your DataContext, so your ComboBox ends up being bound to nothing.
To fix it, simply remove your ItemsSource binding in the XAML for the DataGridComboBoxColumn
<my:DataGridComboBoxColumn x:Name="cmbSubSysSupplier_SRV"
Header="Supplier" Width="160"
SelectedValueBinding="{Binding SupplierId}" />
In addition, the DefaultView of a DataTable will return an object of type DataView, and DataView does not have properties called FullName or SupplierId, so your SelectedValuePath and DisplayMemberPath properties won't work.
I'd recommend building a list of KeyValuePair<int,string> out of your data items, and bind your ComboBoxColumn.ItemsSource to that list, then switch the SelectedValuePath to "Key" and the DisplayMemberPath to "Value"
I personally fought with DataGridComboBoxColumn for long time and i think the way is to use DataGridTemplateColumn. Here is an exemple :
Looks a lot of code but evective.
Put the collection as resource :
<Grid.Resources>
<CollectionViewSource x:Key="StructuresCollection" Source="{Binding StructuresList, Mode=OneTime}"/>
</Grid.Resources>
<DataGridTemplateColumn Header="Structure" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Structures.Name}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate >
<DataTemplate>
<ComboBox x:Name="CStructures" SelectedItem="{Binding Structures}" DisplayMemberPath="Name" SelectedValue="{Binding IDStructure, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="{Binding IDStructure}" ItemsSource="{Binding Source={StaticResource StructuresCollection}}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

Categories