I have a WPF form that contains a DataGrid. This DataGrid is editable. One column of the DataGrid contains a ComboBox with a list of lookup codes for the user to select from.
While editing, the user can add a new lookup code by calling a modal window. When control is returned to the DataGrid, the combobox does not have the new lookupcode.
How can I refresh the list in the combobox after an item is added?
Here is how my combobox is defined. Below is the column of the DataGrid and then my dictionary snippet.
<DataGridTemplateColumn Header="Type" Width="160">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding AddrType.Description}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox Name="cboAddrtype"
ItemsSource="{Binding Source={StaticResource addrTypeList}}"
SelectedValuePath="ID"
DisplayMemberPath="Description"
SelectedValue="{Binding AddrTypeID, UpdateSourceTrigger=PropertyChanged}"
Width="100" />
<Button ToolTip="New" Name="btnNewAddressType" Click="btnNewAddressType_Click">
<Image Source="Images\Add.png" Style="{StaticResource buttonImageStyle}" />
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
The method GetAddressTypes() returns an ObservableCollection.
<ObjectDataProvider x:Key="addrTypeList" IsAsynchronous="True"
MethodName="GetAddressTypes"
ObjectType="{x:Type components:AddressComponent}"/>
I would add the new address to the addrtypeList when the modal window is closed, or the object saved depending on your desired behavior. Because its an observableCollection it should update the combo box automatically.
Related
Here is a snippet of XAML:
<ComboBox ItemsSource="{Binding UnileverDataSet.Tables, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Margin="5" x:Name="TableNameComboBox">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding TableName}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<DataGrid Margin="5" AutoGenerateColumns="True" ItemsSource="{Binding UnileverDataSet.Tables[TableNameComboBox.SelectedIndex]}"
UnileverDataSet is a DataSet made up of about 12 DataTables
The idea here is that when the ComboBox value changes, the DataGrid should update based on the index value from the ComboBox.
Is this possible or should I look at another way of doing this?
If I do: UnileverDataSet.Tables[0], then all works and data displays correctly.
You can do element binding with combobox..
Your combox will display list of items in the "UnileverDataSet.Tables" collection. When ever your select a item in Combo box the selected item will bounded to the Datagrid Items source (since we are using element binding)
Here is the sample code
<DataGrid Margin="5" AutoGenerateColumns="True" ItemsSource="{Binding SelectedItem,ElementName=TableNameComboBox}">
So I have a custom control:
<Grid>
<StackPanel HorizontalAlignment="Center" Orientation="Vertical">
<CheckBox x:Name="chkboxListen" HorizontalAlignment="Center" Checked="chkboxListen_Checked" Unchecked="chkboxListen_Unchecked"/>
<MediaElement x:Name="mediaElementAudioPlayer" Volume="{Binding ElementName=sliderVol, Path=Value}" />
</StackPanel>
</Grid>
And it will reside within a DataGrid Template Column:
<DataGridTemplateColumn x:Name="callListenL" Header="Listen(L)" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<localControls:AudioPlay x:Name="audioPlayL" localControls:AudioPlay>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
My question is:
When I Check the chkboxListen CheckBox, how I can get the Information from the row of the DataGrid (Parent)? Each row has a myObject with an Id. I just need that Id.
Thank you in advance.
You can expose a property from within your user control and set the value of that property when the datagrid data binds.
For example, say your user control's property is called ParentRowId you could set it in code behind or use an Eval expression
<DataGridTemplateColumn x:Name="callListenL" Header="Listen(L)" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<localControls:AudioPlay x:Name="audioPlayL" ParentRowId='<%# Cint(Eval("Id")) %>' localControls:AudioPlay>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I have a list that I populate in the init of my viewmodel:
ListOfEmployees = new List<EmployeeBO>(employeeRepository.GetEmployees(true, true));
I am trying to get a combobox in a datagrid to populate from this list.
<DataGridTemplateColumn Header="U/M" MinWidth="145">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Name="cboUnitMeasure"
ItemsSource="{Binding Path=ListOfUnitMeasures}"
DisplayMemberPath="UnitMeasureDescription" SelectedValuePath="UnitMeasureValue"
SelectedValue="{Binding UnitMeasureValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Left" Width="140" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding UnitMeasureDescription}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
When the dg loads, the cell template displays the UnitMeasureDescription value, but when I click on the cell to edit, there are no items in the combobox. On the other hand, when I use a static resource from an xml file as the itemsource-using the same property names-the combobox contains the items:
<DataGridTemplateColumn Header="U/M" MinWidth="145">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Name="cboUnitMeasure"
ItemsSource="{Binding Source={StaticResource UnitMeasureData}}"
DisplayMemberPath="UnitMeasureDescription" SelectedValuePath="UnitMeasureValue"
SelectedValue="{Binding UnitMeasureValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Left" Width="140" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding UnitMeasureDescription}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I put a breakpoint just after populating ListOfEmployees in my vm and it contains items. I also verified the property names in the DisplayMemberPath and SelectedValuePath are correct. Not sure what I am doing wrong here.
Is "ListOfUnitMeasures" a property on the VM or a property of an EmployeeBO? Ok, assuming that the DataGrid's ItemsSource is set to the List<EmployeeBO> and that there's another list on the VM called "ListUnitOfMeasures", here's my explanation:
The DataContext of each row in the DataGrid will be equal to the elements in the DataGrid's ItemsSource. In your case, each row will use an EmployeeBO as its DataContext. And since the "ListOfUnitMeasures" isn't a property of Employee BO, the Binding on the ComboBox will not work and thus won't display anything.
One possible solution is change the Binding on your ComboBox to use a RelativeSource pointing back to the parent DataGrid as follows:
<ComboBox Name="cboUnitMeasure"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.ListOfUnitMeasures}"/>
I have a DataGrid that two of its columns are ComboBoxes (one contains few but not this is the problem).
I want, that when the user changes the first Combo's value, the ComboBox in the other column should bind to a property of its (this property is a collection). Say the First ComboBox is Category, I want that when the user changes its value, the other CB is populated with the values of (first combo's selected category).Vendors.
How should I do it, I don't use MVVM, just simple WPF.
I don't know what should be the right way to implement it, I hope I started it right.
I think, if I could get the other ComboBox (which is located in a different DataGridCell) from the first's SelectionChangeHandler that would be the best, because then I can reset its source on each selection change of the first one.
Note that I have the capability of reaching the current (the first's) DataGridCell, I am just looking for an efficient way to access the right DataGridCell sibling and then get its child (second) combo.
Also note that the selected category should vary from row to row, and the second ComboBox should depend on this row's category.
I actually tried to implement it so that the CollectionViewSource.Source is bound to the current item (i.e. the row's DataContext) but it doesn't seem to work.
I prefer to set the second combo's CollectionViewSource (VendorsCollection) thru an Action trigger or handler at the 1st ComboBox's SelectionChange.
The other ComboBoxes in that field don't seem to make a problem as they're all bound to each other, I might use CollectionViewSource.Filter, anyway it's not a problem to access them as they are simple siblings, not like the first one which is a distant cousin located deep in another DataGridCell.
Here is what is what I tried so far:
<DataGrid>
<DataGrid.Resources>
<CollectionViewSource x:Key="CategoriesCollection" Source="{Binding Context.CategoriesList, Source={x:Static Application.Current}, IsAsync=True}" />
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Category">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock DataContext="{Binding Category}" Text="{Binding Title}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<!--This is the first ComboBox-->
<ComboBox
IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding Source={StaticResource CategoriesCollection}}"
DisplayMemberPath="Title"
SelectionChanged="cbCategories_SelectionChanged"
SelectedItem="{Binding Category}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Style">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock DataContext="{Binding Finish.Style.Vendor}" Text="{Binding Contact.Title}"/>
<TextBlock DataContext="{Binding Finish.Style}" Text="{Binding Title}"/>
<TextBlock Text="{Binding Finish.Title}"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel>
<StackPanel.Resources>
<!--I want, that when the user selects a value in the first ComboBox,
the VendorsCollection below should be populated with the selected Category.Vendors,
or alternatively current row's data item.Category.Vendors,
I just donno how to access current row from these resources.-->
<CollectionViewSource x:Key="VendorsCollection" Source="{Binding Vendors, Source={StaticResource CategoriesCollection}}" />
<CollectionViewSource x:Key="StylesCollection" Source="{Binding Styles, Source={StaticResource VendorsCollection}}" />
<CollectionViewSource x:Key="FinishesCollection" Source="{Binding Finishes, Source={StaticResource StylesCollection}}" />
</StackPanel.Resources>
<ComboBox
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Source={StaticResource VendorsCollection}}"
SelectedItem="{Binding Finish.Style.Vendor}"
DisplayMemberPath="Contact.Title"/>
<ComboBox
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Source={StaticResource StylesCollection}}"
SelectedItem="{Binding Finish.Style}"
DisplayMemberPath="Title"/>
<ComboBox
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Source={StaticResource FinishesCollection}}"
SelectedItem="{Binding Finish}"
DisplayMemberPath="Title"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
I just came across your questions. Did you get your problem resolved? I think your question is similar to this one I got. Hope the solution there helps you too.
I have a Datagrid with a combo box bound column that works great as follows:
<tk:DataGridComboBoxColumn SelectedValueBinding="{Binding DefaultLocationID}"
SelectedValuePath="LocationID"
DisplayMemberPath="LocationName"
Header="Default Location"
ItemsSource="{Binding Source={StaticResource CustomerLocations}}">
</tk:DataGridComboBoxColumn>
Ultimately I want to customize the dropdown to show 'ID' and 'Name' together so a TemplateColumn seems to be the way to go. Starting small, I can't get the following simple example to work which should replace the standard DataGridComboBoxColumn. The dropdown appears fine, but when I 'select' a dropdown item, it does not accept and goes back to the previous value. I've tried variations on 'Mode=TwoWay' but no luck. Do I need a 'CellEditingTemplate' ?
DefaultLocationID is the foreign-key field being edited, while 'LocationID' is a column in 'CustomerLocations'.
<tk:DataGridTemplateColumn Header="Default Location">
<tk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox VerticalAlignment="Top"
SelectedItem="{Binding LocationID, Mode=TwoWay}"
SelectedValue="{Binding DefaultLocationID, Mode=TwoWay}"
ItemsSource="{Binding Source={StaticResource CustomerLocations}}"
SelectedValuePath="LocationID"
DisplayMemberPath="LocationName" >
</ComboBox>
</DataTemplate>
</tk:DataGridTemplateColumn.CellTemplate>
Thanks!!
Can you post the relevant parts of your CustomerLocations resource? Can you also post the type of class that your grid is binding to?
Try removing the SelectedValuePath, DisplayMemberPath and SelectedValue from the ComboBox.
If you want to display multiple pieces of data in your combobox see the below XAML
<ComboBox ...>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding LocationId}"} />
<TextBlock Text=" - "/>
<TextBlock Text="{Binding LocationName}"} />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>