Travis Banger
Travis Banger

Reputation: 717

Trying to Bind a Nested Property Model to a DataGrid

My DataGrid contains 2 columns of ComboBox. The easy way is to use a List<string> but since I require extra functionality (the ability to dynamically disable some drop down menu items) my code behind uses nested properties: the top-level for the DataGrid and the lower-level for the ComboBox.

See relevant code below (in different attempts and variations):

Left Column XAML:

<DataGridTemplateColumn Header=" Left Column ">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox ItemsSource="{Binding SteelThickness, RelativeSource={RelativeSource AncestorType=Window}}" SelectedItem="{Binding LeftValues, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" SelectionChanged="ComboBox_SelectionChanged" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Right Column XAML:

<DataGridTemplateColumn Header=" Right Column ">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox ItemsSource="{Binding Caliber, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay}" DisplayMemberPath="Thickness" SelectedItem="{Binding Thickness, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" SelectionChanged="ComboBox_SelectionChanged">
                <ComboBox.ItemContainerStyle>
                    <Style TargetType="{x:Type ComboBoxItem}">
                        <Setter Property="IsEnabled" Value="{Binding Enabled}"/>
                    </Style>
                </ComboBox.ItemContainerStyle>
            </ComboBox>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

GridModel.cs:

public class GridModel : PropertyChangedBase
{
    public int Item { get; set; }

    private string _LeftValues;
    public string LeftValues
    {
        get
        {
            return _LeftValues;
        }
        set
        {
            if (_LeftValues != value)
            {
                _LeftValues = value;
                RaisePropertyChanged("LeftValues");
            }
        }
    }

    private string _RightValues;
    public string RightValues
    {
        get
        {
            return _RightValues;
        }
        set
        {
            if (_RightValues != value)
            {
                _RightValues = value;
                RaisePropertyChanged("RightValues");
            }
        }
    }
}

Main:

public List<string> SteelThickness { get; set; }
public List<Selectable> Caliber { get; set; }
public List<GridModel> content4VisualGrid = new List<GridModel>();

public MainWindow()
{
    InitializeComponent();

    SteelThickness = new List<string> { "0.3750", "0.4375", "0.5000", "0.6250", "0.7500", "0.8650", "1.0000" };

    Caliber = new List<Selectable> { new Selectable("0.3750"), 
                                        new Selectable("0.4375"), 
                                        new Selectable("0.5000"), 
                                        new Selectable("0.6250"), 
                                        new Selectable("0.7500"), 
                                        new Selectable("0.8650"), 
                                        new Selectable("1.0001") };

Another, better version of GridModel.cs:

public class GridModel : PropertyChangedBase
{
    public int Item { get; set; }

    public string LeftValue { get; set; }

    private Selectable _Selectable;
    public  Selectable Selectable
    {
        get
        {
            return _Selectable;
        }
        set
        {
            if (_Selectable != value)
            {
                _Selectable = value;
                RaisePropertyChanged("Selectable");
            }
        }
    }
}

Selectable.cs:

public class Selectable : PropertyChangedBase
{
    private string _Thickness;
    public  string  Thickness
    {
        get
        {
            return _Thickness;
        }
        set
        {
            if (_Thickness != value)
            {
                _Thickness = value;
                RaisePropertyChanged("Thickness");
            }
        }
    }

    private bool _Enabled;
    public  bool  Enabled
    {
        get
        {
            return _Enabled;
        }
        set
        {
            if (_Enabled != value)
            {
                _Enabled = value;
                RaisePropertyChanged("Enabled");
            }
        }
    }
}

Upvotes: 0

Views: 445

Answers (1)

dev hedgehog
dev hedgehog

Reputation: 8791

This code looks familiar to me. Have I maybe answered your question on msdn forums lol?

However, when you set Binding between SelectedItem and a property, the Binding will not search for the property inside Selectable class but you are trying to do that. Its why binding in right column keeps beaking. To put it in simple words: To look up for a property inside selected item and to use the property for binding to ComboBox.SelectedItem is like looking up inside itself which logically doesnt make any sense lol. Read the sentence again and you will notice there is not chance it will ever work :)

On the other side Binding between SelectedItem and LeftValues will work because GridModel is the owner class of each row.

I remember your code from msdn. You really made a mess in design. You don't have a proper ViewModel.

I suggest you to first create few very simple examples to understand MVVM and WPF's hierarchical thinking.

In DataGrid you have GridModel is owner of each row. Inside a row you have ComboBox with SteelThickness as ItemsSource. To put all this in WPF's hierarchical thinking words: GridModel class is parent of SteelThickness. One SteelTickness is for WPF System a child of one GridModel instance.

Here are few links for good understanding of MVVM Pattern:

http://www.codeproject.com/Articles/36545/WPF-MVVM-Model-View-View-Model-Simplified

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

Upvotes: 1

Related Questions