Question

I'm trying to display on datagrid name and sex of a person. User should be able to enter name and select sex from combobox. I want combobox to be visible all the time, so I'm using DataGridTemplateColumn. However whenever I add new person to list, sex is not displayed on combobox but I'm sure it is set. But if I select anything from combobox, selection will be shown, and data on model will be updated. Is there anything to make this work? Notice: I'm using Caliburn.

This is my View:

<Window x:Class="WpfPetApp.ShellView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <DataGrid x:Name="TestDataGrid" Grid.Row="0" ColumnWidth="*" HeadersVisibility="Column" SelectedItem="{Binding SelectedTestDataGrid, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        CanUserDeleteRows="False" 
                        CanUserAddRows="False" 
                        CanUserResizeColumns="False"
                        CanUserReorderColumns="False"
                        CanUserResizeRows="False"
                        CanUserSortColumns="True"
                        AutoGenerateColumns="False" 
                        SelectionMode="Single" >
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Binding="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox ItemsSource="{Binding ElementName=TestDataGrid, Path=DataContext.Sexes}" SelectedValue="{Binding Sex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
        <Button x:Name="AddRow" Grid.Row="1">Add</Button>
    </Grid>
</Window>

ViewModel:

public class ShellViewModel : PropertyChangedBase, IShell
{
    private Person _selectedTestDataGrid;

    public ObservableCollection<Person> TestDataGrid { get; set; }
    public ObservableCollection<Sex> Sexes { get; set; }

    public Person SelectedTestDataGrid
    {
        get { return _selectedTestDataGrid; }
        set
        {
            if (Equals(value, _selectedTestDataGrid)) return;
            _selectedTestDataGrid = value;
            NotifyOfPropertyChange(() => SelectedTestDataGrid);
        }
    }

    public ShellViewModel()
    {
        TestDataGrid = new ObservableCollection<Person>();
        Sexes = new ObservableCollection<Sex>();

        Sexes.Add(Sex.Male);
        Sexes.Add(Sex.Female);
    }

    public void AddRow()
    {
        var rnd = new Random(DateTime.Now.Millisecond);
        var male = rnd.Next() % 2 == 0;
        TestDataGrid.Add(new Person { Name = Guid.NewGuid().ToString(), Sex = (male ? Sex.Male : Sex.Female) });
    }
}

And model:

public class Person
{
    public string Name { get; set; }
    public Sex Sex { get; set; }
}

public class Sex
{
    public static readonly Guid MaleSexId = new Guid("9BF621E2-98FC-45FB-A4AC-4A930AD95CF7");
    public static readonly Guid FemaleSexId = new Guid("425B1B2A-B47D-4C25-A5AF-D3A0ABC95A75");

    public static Sex Male
    {
        get
        {

            return new Sex(MaleSexId);
        }
    }

    public static Sex Female
    {
        get
        {
            return new Sex(FemaleSexId);
        }
    }

    private readonly Guid _sexId;

    public Sex(Guid sexId)
    {
        _sexId = sexId;
    }

    public Guid Value
    {
        get { return _sexId; }
    }

    public override string ToString()
    {
        return _sexId == MaleSexId ? "male" : _sexId == FemaleSexId ? "female" : "unknown";
    }
}

And a screen of app: https://www.dropbox.com/s/fi1ef3z07vb09yw/2014-04-26%2013_07_22-.png

Any help will be appreciated.

Was it helpful?

Solution

No item is selected on addition of row because ItemsSource and SelectedValue refers to completely different instances.

I don't know why you are always returning new instance every time Sex.Male and Sex.Female is accessed. So, when ItemsSource gets set, new instance of Male and Female gets added and when you add row, new instance of Male/Female is returned which is not there in ItemSource and hence no item was selected.


Either set Sex property to already added instance in ComboBox like this:

TestDataGrid.Add(new Person { Name = Guid.NewGuid().ToString(),
                              Sex = (male ? Sexes.First() : Sexes.Last()) });

OR

Always return same instance from Male/Female:

public class Sex
{
    private static Sex male = new Sex(MaleSexId);
    public static Sex Male
    {
        get
        {

            return male;
        }
    }

    private static Sex female = new Sex(FemaleSexId);
    public static Sex Female
    {
        get
        {
            return female;
        }
    }

    .....
}

Ideally Sex should have been Enum, no need of it having a class for it.

public enum Sex
{
   Male,
   Female
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top