I have learnt a lot from Andy O'Neill's WPF: Entity Framework MVVM Walk Through 2 example as I learn WPF and MVVM etc. Generally though I always seem to struggle on comboboxes and getting the ItemsSource, SelectedValue and SelectedValuePath set up correctly to successfully show data in the combobox. The Binding is really tricky in combination with the particular comboxbox control design. In Andys example I was trying to put a combobox inside an ItemsControl thats inside a ContentControl (Popup) thats inside a grid on a UserControl. I cannot get the data from MyObservableCollection to show in the ItemsSource. I have tried all manner of versions of comboc control construction and Binding including {Binding DataContext.MyObservableCollection, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=UserControl} , RelativeSource={RelativeSource AncestorType={x:Type local:UserControl}} and replacing UserControl with the ViewModels , and using FindAncestor etc. The DataContext is set to the ViewModel where the observable collection is and its got data in it, but seems cant get binding to work.
Any tips to look at for this type of situation would be greatly appreciated or even an answer from the great man himself Mr Andy O'Neill (
anonymous user
ONeill) . wow imagine that
thanks
Scott
Great man?
Bear in mind that was not intended to be the final in the walk through series.
I moved on to other things.
In particular:
You should copy data from an entity object to a viewmodel to edit/display.
Then back to an entity object for any update.
I use automapper to do this.
( The sample uses buddy classes for dataattributes and partial inheritance so you can work with entity objects. )
I also use a collection of predicates for validation which (inevitably) doesn't quite fit in with attributes.
HaHa the great man reference worked you replied. Well to be serious I can take this opportunity to say a big thanks for this example it has been very helpful to understand what the overall layout, structure of an app can look like. Most other examples were of just code snippets on how to do a particular thing but this was perfect for my level as it gave the overall view and direction on how to build the whole app.
But hey no reply on my little problem! Cant stick a combobox on the Popup and populate it from an observable collection in the List View Model. Seemed so simple.
I understand you must be very busy if you cant give me a tip on it. Peter has been guide enough to try and help.
thanks again looking forward to Step 3, 4, 5, 6...
Scott
Hi Scott,
in following demo you can see how to bind ComboBoxColumn in DataGrid in UserControl.
XAML MainWindow:
<Window x:Class="Window064"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1.WpfApp064"
xmlns:uc="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"
mc:Ignorable="d"
Title="Demo ComboBox in UserControl" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<uc:Window064UC1/>
</Grid>
</Window>
ViewModel as DataContext in MainWindow (and UserControl), View property for rows in DataGrid, MasterList as Lookup values for ItemsSource in DataGridComboBoxColumn, LoadDemoData for loading data (e.g. EF).
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Namespace WpfApp064
Public Class ViewModel
Public Sub New()
LoadDemoData
End Sub
Private cvsChild As New CollectionViewSource
Private colChild As New ObservableCollection(Of Data)
Public ReadOnly Property View As ICollectionView
Return cvsChild.View
End Get
End Property
Private colMaster As New ObservableCollection(Of Master)
Public ReadOnly Property MasterList As ObservableCollection(Of Master)
Return colMaster
End Get
End Property
Private Sub LoadDemoData()
Dim rnd As New Random
For i = 1 To 10
colMaster.Add(New Master With {.ID = i, .MasterInfo = $"Master {i}"})
For i = 1 To 100
colChild.Add(New Data With {.ID = i, .Info = $"Row {i}", .FKMaster = rnd.Next(1, 11)})
cvsChild.Source = colChild
End Sub
End Class
Public Class Data
Public Property ID As Integer
Public Property FKMaster As Integer
Public Property Info As String
End Class
Public Class Master
Public Property ID As Integer
Public Property MasterInfo As String
End Class
End Namespace
XAML UserControl (no CodeBehind)
<UserControl x:Class="Window064UC1"
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:WpfControlLibrary1"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid.Resources>
<CollectionViewSource x:Key="ItemsCVS" Source="{Binding MasterList}" />
</Grid.Resources>
<DataGrid ItemsSource="{Binding View}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID}"/>
<DataGridTextColumn Header="Info" Binding="{Binding Info}"/>
<DataGridComboBoxColumn Header="Lookup"
ItemsSource="{Binding Source={StaticResource ItemsCVS}}"
DisplayMemberPath="MasterInfo"
SelectedValuePath="ID"
SelectedValueBinding="{Binding FKMaster}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
Result:
I am using comments because I am getting "Access Denied" when trying to answer
Hi Peter thanks for the response. I gave referencing the collectionview as the grids resource but still no joy.
. Sorry I didnt load up any code as to give you better information. The combobox Im trying to wire up is actually
in an ItemControl thats inside a contentcontrol which is a Popup panel inside the Grid of a UserControl. So Ive put the xaml below now for better explanation.
I still a bit suspicious of my attempts though because the combobox I would describe as "empty" as you just see the std empty cell and empty dropdown list. Other times I can see a drop down list that has something in it but text is not visible however in this case nothing.
I am using comments because get "Access Denied" when trying to post answer
Hi Peter thanks for the response. I gave referencing the collectionview as the grids resource but still no joy.
. Sorry I didnt load up any code as to give you better information. The combobox Im trying to wire up is actually
in an ItemControl thats inside a contentcontrol which is a Popup panel inside the Grid of a UserControl. So Ive put the xaml below now for better explanation (sorry cant isnert into comments).
I still a bit suspicious of my attempts though because the combobox I would describe as "empty" as you just see the std empty cell and empty dropdown list. Other times I can see a drop down list that has something in it but text is not visible however in this case nothing.
<UserControl x:Name="TypeUserControl" x:Class="LBAContractRegister.Views.Lists.TypeListView"
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"
mc:Ignorable="d"
xmlns:local="clr-namespace:LBAContractRegister.Views.Lists"
xmlns:cnvtr="clr-namespace:LBAContractRegister.Converters"
xmlns:helpers="clr-namespace:LBAContractRegister.Helpers"
d:DesignHeight="180" d:DesignWidth="660">
<DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding Types}"
HeadersVisibility="Column"
SelectedItem="{Binding SelectedType,Converter={cnvtr:DataGridItemConverter}, Mode=TwoWay}"
SelectionMode="Single"
CanUserAddRows="False"
CanUserDeleteRows="False"
Background="Transparent">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Contract Type Description">
<DataGridTemplateColumn.CellTemplate >
<DataTemplate >
<TextBox x:Name="FocusTextBox" Text="{Binding TheEntity.Type1, Mode=TwoWay}" Width="460" IsReadOnly="True" BorderBrush="Transparent"
Style="{StaticResource TextboxStyle}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Retention Type">
<DataGridTemplateColumn.CellTemplate >
<DataTemplate >
<TextBox Text="{Binding TheEntity.IDRetention, Mode=TwoWay}" Width="60" IsReadOnly="True" BorderBrush="Transparent"
Style="{StaticResource TextboxStyle}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<ContentControl Template="{StaticResource EditPopUp}" Margin="0,0,0,0" >
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl Width="300" >
<helpers:EditRow LabelFor="Contract Type:" >
<TextBox Text="{Binding EditVM.TheEntity.Type1
UpdateSourceTrigger=PropertyChanged,
NotifyOnSourceUpdated=True,
NotifyOnValidationError=True,
Mode=TwoWay}" Style="{StaticResource TextboxStyle}"/>
</helpers:EditRow>
<helpers:EditRow LabelFor="Retention ID:" >
UpdateSourceTrigger=PropertyChanged,
NotifyOnSourceUpdated=True,
NotifyOnValidationError=True,
Mode=TwoWay}" Style="{StaticResource TextboxStyle}"/>
</helpers:EditRow>
<helpers:EditRow LabelFor="Retention ID:" >
<ComboBox ItemsSource="{Binding Retentions, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type local:UserControl}}}"
DisplayMemberPath="RecordType" SelectedValue="{Binding EditVM.TheEntity.IDRetention}" SelectedValuePath="IDRetention"/>
</helpers:EditRow>
</ItemsControl>
</ScrollViewer>
</ContentControl>
<TextBlock Text="{Binding ErrorMessage}" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<helpers:Throbber x:Name="Throbber" Visibility="{Binding ThrobberVisible}"/>
</Grid>
</UserControl>
Hi Scott,
I cannot reproduce your code because I don't know yours additional classes.
I reduce your code and this code works fine:
XAML MainWindow:
<Window x:Class="WpfApp1.Window90"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp90"
xmlns:uc="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"
mc:Ignorable="d"
Title="Window90" Height="450" Width="800">
<Window.DataContext>
<local:TypeListViewModel/>
</Window.DataContext>
<uc:Window90UC1/>
</Grid>
</Window>
XAML UserControl:
<UserControl x:Class="WpfControlLibrary1.Window90UC1"
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:WpfControlLibrary1"
mc:Ignorable="d"
d:DesignHeight="180" d:DesignWidth="660">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<DataGrid Grid.Row="1"
AutoGenerateColumns="False"
ItemsSource="{Binding Types}"
HeadersVisibility="Column"
SelectedItem="{Binding SelectedType, Mode=TwoWay}"
SelectionMode="Single"
CanUserAddRows="False"
CanUserDeleteRows="False"
Background="Transparent">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Contract Type Description">
<DataGridTemplateColumn.CellTemplate >
<DataTemplate >
<TextBox x:Name="FocusTextBox"
Text="{Binding TheEntity.Type1, Mode=TwoWay}"
Width="460"
IsReadOnly="True"
BorderBrush="Transparent"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Retention Type">
<DataGridTemplateColumn.CellTemplate >
<DataTemplate >
<TextBox Text="{Binding TheEntity.IDRetention, Mode=TwoWay}"
Width="60"
IsReadOnly="True"
BorderBrush="Transparent"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<ContentControl Margin="0,0,0,0" >
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl Width="300" >
<ComboBox ItemsSource="{Binding Retentions}"/>
</ItemsControl>
</ScrollViewer>
</ContentControl>
<TextBlock Text="{Binding ErrorMessage}"
HorizontalAlignment="Right"
VerticalAlignment="Center"/>
</Grid>
</UserControl>
And classes:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace WpfApp90
public class TypeListViewModel : CrudVMBase
public TypeListViewModel()
: base()
Types = new ObservableCollection<TypeVM>();
for (int i = 1; i < 50; i++)
Types.Add(new TypeVM() { TheEntity = new Ent() { Type1 = $"Type {i}", IDRetention = $"IDRet {i}" } });
Retentions = new List<string>();
for (int i = 1; i < 10; i++) Retentions.Add($"Ret {i}");
public ObservableCollection<TypeVM> Types { get; set; }
public object SelectedType { get; set; }
public string ErrorMessage { get; set; } = "no error";
public List<string> Retentions { get; set; }
public class CrudVMBase : INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
internal void OnPropertyChanged([CallerMemberName] string propName = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
public class TypeVM
public Ent TheEntity { get; set; }
public class Ent
public string Type1 { get; set; }
public string IDRetention { get; set; }
Result: