I need to bind a List to a UniformGrid into a WP Window using WPF MVVM.
I had in mind to do something like this:
Into my VM:
private List<Rat> rats;
private UniformGrid uniformGrid;
public List<Rat> Rats
{
get { return rats; }
set
{
if (rats != value)
{
//update local list value
rats = value;
//create View UniformGrid
if (uniformGrid == null)
uniformGrid = new UniformGrid() { Rows=10};
else
uniformGrid.Children.Clear();
foreach(Rat rat in value)
{
StackPanel stackPanel = new StackPanel();
Ellipse ellipse = new Ellipse(){Height=20, Width=20, Stroke= Brushes.Black};
if (rat.Sex== SexEnum.Female)
ellipse.Fill= Brushes.Pink;
else
ellipse.Fill= Brushes.Blue;
stackPanel.Children.Add(ellipse );
TextBlock textBlock = new TextBlock();
textBlock.Text= rat.Name + " (" + rat.Age +")";
stackPanel.Children.Add( textBlock );
uniformGrid.Children.Add(stackPanel);
}
OnPropertyChanged("Rats");
}
}
}
The VM is correctly informed when the list needs to be refreshed into the view via an event. So at this point I would need my View to be correctly bound to the VM. I made it this way:
<GroupBox x:Name="GB_Rats" Content="{Binding Rats}" Header="Rats" HorizontalAlignment="Left" Height="194" Margin="29,10,0,0" VerticalAlignment="Top" Width="303">
Is this the correct global approch?
Concretely, when attempting to run the code, this line fails to execute:
uniformGrid = new UniformGrid() { Rows=10};
->
An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationCore.dll
Additional information: The calling thread must be STA, because many UI components require this.
This lets me think that I should not proceed this way from a MVVM point of view.
Thx for your kind assistance.
The
ViewModel
isn't supposed to instantiate any UI controls, this should be the View's responsibility.So in your code you shouldn't try to create
StackPanels
,Ellipses
etc.Also try to use the types that already have Change notification - for instead of
List<T>
useObservableCollection<T>
MSDN, i wouldn't recommend replacing a whole list when its value change.The right way to do this in the MVVM pattern is to create a
DataTemplate
for theRat
like this:ViewModel:
Model - Rat and Sex:
As you want to present the Models value of Sex in one of two colors you should use a
IValueConverter
for that:This is then used in your window:
Window:
Note the
DataTemplate
that is assigned to theComboBox.ItemTemplate
property and the declaration of theConverters:SexToColorConverter
and its usage to change the color of the ellipse in theFill
binding.Update 4.4.2016 16:30 Window using a
GroupBox
withCheckBoxes
to display the listI guess the target is to also select the Rats, depending on how MVVM purist you want to be you'd add a List of
RatViewModels
, that have a bool IsChecked property and bind theItemsSource
to aObservableCollection<RatViewModel>
and synchronize this list with your ModelsList<Rat>