2
votes

I guess it's a simple Data Binding issue but I can't make it work. I have a DataGrid, a ViewModel with an Observable Collection and a class that represents objects in this collection. The DataGrid has two columns: A DataGridTextColumn and a DataGridTemplateColumn. The binding of the data with the DataGridTextColumn works but the binding with the DataGridTemplateColumn doesn't. The corresponding column simply remains empty.

Here is the code:

This is my DataGrid:

<DataGrid x:Name="tdg_Memory" Grid.Column="1" Margin="0" Grid.Row="4" VerticalScrollBarVisibility="Visible" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="MemoryIndexColumn" Header="Index"/>
        <DataGridTemplateColumn x:Name="MemorySolutionColumn" CellTemplate="{DynamicResource MemorySolutionCellTemplate}" Header="Solution"/>
    <DataGrid.Columns>
<DataGrid>

This is the DataTemplate:

<DataTemplate x:Key="MemorySolutionCellTemplate">
    <Grid x:Name="grd_RootGrid" Height="Auto" Width="Auto" HorizontalAlignment="Left" VerticalAlignment="Top">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Label x:Name="lbl_ValueCaption" Content="Value:" Margin="0" Grid.Row="0" Height="Auto" VerticalAlignment="Top" HorizontalAlignment="Right"/>
        <Label x:Name="lbl_FitnessCaption" Content="Fitness:" Margin="0" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Top"/>
        <Label x:Name="lbl_ValueValue" Content="65665" Grid.Column="1" Height="Auto" Margin="12,0,0,0" VerticalAlignment="Top" HorizontalAlignment="Left"/>
        <Label x:Name="lbl_FitnessValue" Content="121212" Grid.Column="1" Margin="12,0,0,0" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top"/>
    </Grid>
</DataTemplate>

The data binding occurs in code behind:

// setting the itemsSource (seems to work)
jobItem.tdg_Memory.ItemsSource = jobModel.Memory;

// binding of the first column (DataGridTextColumn) seems to work
Binding memoryIndexColumnBinding = new Binding();
memoryIndexColumnBinding.Path = new PropertyPath("Index");
jobItem.MemoryIndexColumn.Binding = memoryIndexColumnBinding;

And here is the ViewModel:

// the observable collection that holds the data for the DataGrid
private ThreadSafeObservableCollection<MemoryItemRepresentative> _memory;

    public ThreadSafeObservableCollection<MemoryItemRepresentative> Memory {
        get { return _memory; }
        set {
            _memory = value;

            FirePropertyChanged("Memory");
        }
    }

Here are the objects included in the collection:

public class MemoryItemRepresentative : ViewModelBase {

        private int _index;

        public int Index {
            get { return _index; }
            set {
                _index = value;

                FirePropertyChanged("Index");
            }
        }

        private MPBILSolution _solution;

        public MPBILSolution Solution {
            get { return _solution; }
            set {
                _solution = value;

                FirePropertyChanged("Solution");
            }
        }

        public MPBILPropabilityVector PropabilityVector;

        public MemoryItemRepresentative () {

        }
    }

And the MBILSolution is (but that should be irrelevant for that problem):

public class MPBILSolution : ISolution {

    public int Position { get; set; }
    public BinaryNumber Value { get; set; }
    public double Fitness { get; set; }

}

What I want to do now is to have the DataGrid first column (the DataGridTextColumn) be bound to the Index property of the MemoryItemRepresentative class which works fine.

Furthermore I want to display the contents of the MPBILSolution object (consisting of Properties Position, Value and Fitness) be bound to the second column (the DataGridTemplateColumn). For that reason I have built the DataTemplate that comprise a label for the Value property and a label for the Fitness property.

I have not posted the actual binding code which is not working because my problem seems to be that the corresponding column of the DataGrid always remains empty. At least the static labels inside the DataTemplate (which are used for captioning) should be visible ?

So I am very thankful for any help. Any further code on request ...

Appendix:

Well now the actual binding seems to make problems: In the DataGrid I can now see the DataTemplate inside the column but the values of the MPBILSolution object are missing:

Here is how I do the binding of this object to the DataTemplate:

DataTemplate memorySolutionCellTemplate = (DataTemplate)jobItem.FindResource("MemorySolutionCellTemplate");

        DependencyObject o = memorySolutionCellTemplate.LoadContent();

        Label l = (Label)VisualTreeAssistant.FindFrameworkElement(o, "lbl_FitnessValue");


        Binding fitnessValueBinding = new Binding();
        fitnessValueBinding.Path = new PropertyPath("Fitness");
        fitnessValueBinding.Mode = BindingMode.OneWay;
        l.SetBinding(Label.ContentProperty, fitnessValueBinding);

The object l seems to get the correct Label object so the problem seems to lie in the last four lines of this binding block ?

Please help again :)

1
Why DynamicResource? If you can use StaticResource do so, DynamicResource can be quiet about errors i think (possibly check the Output window)...H.B.
@H.B. SOLVED! You did solve it ! Post your comment as answer and I will explain what happened :)marc wellman
Show me your moves then!H.B.
You cannot modify a DataTemplate at runtime, what you do there is you create one instance from the template and modify that, not going to affect anything. You need to create the full template either statically or dynamically. (Also don't use labels for values, read the documentation, Labels provide certain functionality (access keys) and are not meant for this)H.B.
The problem is not the instance of the DataTemplate but the instance of the controls described by the DataTemplate which you create via LoadContent, any changes to this instance derived from the DataTemplate do not affect the DataTemplate (the description) itself. As i said, you cannot modify the desciption, people tried and failed. You can create the full template XAML in code and then parse it to a DataTemplate using XamlReader.H.B.

1 Answers

1
votes

Why DynamicResource? If you can use StaticResource do so, DynamicResource can be quiet about errors i think (possibly check the Output window)...