Reputation: 1781
Goal
I am aiming to achieve the following:
Visual Output
Code...
Models
I have 2 models
public class Person
{
public string Name { get; set; }
public Position Position { get; set; }
}
public class Position
{
public int PositionId { get; set; }
public string PositionTitle { get; set; }
}
View Model
public class ViewModel : BaseViewModel
{
public ViewModel()
{
People = new ObservableCollection<Person>();
People.Add(new Person { Name = "Name 1", Position = new Position { PositionId = 1, PositionTitle = "Position Title 1" } });
People.Add(new Person { Name = "Name 2", Position = new Position { PositionId = 1, PositionTitle = "Position Title 1" } });
People.Add(new Person { Name = "Name 3", Position = new Position { PositionId = 2, PositionTitle = "Position Title 2" } });
Positions = new ObservableCollection<Position>();
Positions.Add(new Position { PositionId = 1, PositionTitle = "Position Title 1" });
Positions.Add(new Position { PositionId = 2, PositionTitle = "Position Title 2" });
}
private ObservableCollection<Person> people;
public ObservableCollection<Person> People
{
get { return people; }
set
{
people = value;
OnPropertyChanged();
}
}
private ObservableCollection<Position> _positions;
public ObservableCollection<Position> Positions
{
get { return _positions; }
set
{
_positions = value;
OnPropertyChanged();
}
}
}
public class Person
{
public string Name { get; set; }
public Position Position { get; set; }
}
public class Position
{
public int PositionId { get; set; }
public string PositionTitle { get; set; }
}
View
<DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTemplateColumn Header="Position Title">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=DataContext.Positions, RelativeSource={RelativeSource AncestorType=DataGrid}}"
DisplayMemberPath="PositionTitle"
SelectedValue="{Binding Path=Position}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Question
How do I set the SelectedItem/Index of Position to what the Person's Position is set to?
Upvotes: 0
Views: 53
Reputation: 7943
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=DataContext.Positions,
RelativeSource={RelativeSource AncestorType=DataGrid}}"
DisplayMemberPath="PositionTitle"
SelectedItem="{Binding Path=Position,
UpdateSourceTrigger=PropertyChanged,
Mode=TwoWay}" />
</DataTemplate>
Nope.. doesn't work
Full answer, for all inconsistencies in the code:
namespace PeoplePosition
{
public class Position
{
public int PositionId { get; }
public string PositionTitle { get; }
public Position(int positionId, string positionTitle)
{
PositionId = positionId;
PositionTitle = positionTitle;
}
}
}
using Simplified;
namespace PeoplePosition
{
public class Person : BaseInpc // Implementation of the "INPC" interface
{
private string _name;
private Position _position;
public string Name { get => _name; set => Set(ref _name, value); }
public Position Position { get => _position; set => Set(ref _position, value); }
}
}
If you need to ensure equality of instances by value, then you need to override the Equals and GetHashCode methods (as @mm8 already wrote). But for mutable types, this is a bad decision, which in some cases can lead to bugs.
If you need to set the values of a reference type corresponding to some collection, then you do not need to re-create instances of this type, but assign one of the elements of the collection that already contains all the valid values.
using System.Collections.ObjectModel;
namespace PeoplePosition
{
public class ViewModel
{
public ViewModel()
{
Positions.Add(new Position(1, "Position Title 1"));
Positions.Add(new Position(2, "Position Title 2"));
People.Add(new Person { Name = "Name 1", Position = Positions[0] });
People.Add(new Person { Name = "Name 2", Position = Positions[0] });
People.Add(new Person { Name = "Name 3", Position = Positions[1] });
}
public ObservableCollection<Person> People { get; }
= new ObservableCollection<Person>();
public ObservableCollection<Position> Positions { get; }
= new ObservableCollection<Position>();
}
}
<Window x:Class="PeoplePosition.PeoplePositionsWindow"
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:PeoplePosition"
mc:Ignorable="d"
Title="PeoplePositionsWindow" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<UniformGrid Columns="1">
<DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False" IsReadOnly="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTemplateColumn Header="Position Title">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=DataContext.Positions,
RelativeSource={RelativeSource AncestorType=DataGrid}}"
DisplayMemberPath="PositionTitle"
SelectedItem="{Binding Path=Position,
UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Binding="{Binding Position.PositionId, Mode=OneWay}"
Header="PositionId"/>
<DataGridTextColumn Binding="{Binding Position.PositionTitle, Mode=OneWay}"
Header="Position Title"/>
</DataGrid.Columns>
</DataGrid>
</UniformGrid>
</Window>
Upvotes: 0
Reputation: 169360
You could override the Equals
method of your Position
class to define that two objects with the same id should be considered equal:
public class Position
{
public int PositionId { get; set; }
public string PositionTitle { get; set; }
public override bool Equals(object obj) =>
obj is Position p && PositionId == p.PositionId;
public override int GetHashCode() => PositionId.GetHashCode();
}
Upvotes: 1