1
votes

EDIT: Well, looks like the binding to the ChessPiece item was a Resharper issue - I shut it off, and the error went away. Unbelievable.

I've been trying to bind items in a collection to grid location. I've been able to bind a collection and draw the items, but in the XAML, I'm unable to reference the property I need.

As per this example: http://wpf.2000things.com/2011/12/21/455-using-itemcontainerstyle-to-bind-data-elements-in-a-collection-to-a-grid/

The code:

public class ChessPiece
{
    public string Text { get; set; }
    public int Row { get; set; } // 0..n-1
    public int Column { get; set; } // 0..n-1

    public ChessPiece(string text, int row, int col)
    {
        Text = text;
        Row = row;
        Column = col;
    }
}

public class MainViewModel : ViewModelBase
{

    public ObservableCollection<ChessPiece> ChessPieces { get; private set; }
    /// <summary>
    /// Initializes a new instance of the MainViewModel class.
    /// </summary>
    public MainViewModel()
    {
        ChessPieces = new ObservableCollection<ChessPiece>();
        ChessPieces.Add(new ChessPiece("QR-BLK", 1, 1));
        ChessPieces.Add(new ChessPiece("QN-BLK", 1, 2));
        ChessPieces.Add(new ChessPiece("QB-BLK", 0, 3));

        ////if (IsInDesignMode)
        ////{
        ////    // Code runs in Blend --> create design time data.
        ////}
        ////else
        ////{
        ////    // Code runs "for real"
        ////}
    }
}

XAML:

<Window x:Class="MVVMLightTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding Main, Mode=OneWay, Source={StaticResource Locator}}" Height="550" Width="525">
    <Grid Margin="0,0,0,0">
        <ItemsControl ItemsSource="{Binding ChessPieces}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid ShowGridLines="True">
                        <Grid.RowDefinitions >
                            <RowDefinition Height="162.667"></RowDefinition>
                            <RowDefinition Height="171.333"></RowDefinition>
                            <RowDefinition Height="165.333"/>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="162"></ColumnDefinition>
                            <ColumnDefinition Width="206">/>
                            <ColumnDefinition Width="263"/>
                        </Grid.ColumnDefinitions>
                    </Grid>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Label Content="{Binding Text}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemContainerStyle>
                <Style>
                    <Setter Property="Grid.Row" Value="{Binding Row}"/>
                    <Setter Property="Grid.Column" Value="{Binding Column}"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
        </ItemsControl>
    </Grid>
</Window>

In the mainviewmodel, I have an observablecollection of chesspieces, which I populate with new chesspieces.

I can bind to the Row property at other levels of the XAML, just not in the Style setter where I'm trying to tie it to a grid location - the collection is accessible to bind to, but not an individual item.

Any help would be most appreciated!

1
Please give us an MCVE instead of dumping abbreviated code or snippets on us. It'll help everyone understand your problem better, keep your question neat, and make it more likely you'll get nice answersNic
A guess, put the style in the ItemsControl.Rsources.XAMlMAX
@Giallo it worked fine for me when I created list of 64 elements. Does it mean that in your case all values overlap each other in one cell or you see nothing at all?dkozl
@dkozl I get a Cannot Resolve Property "Column" in DataContext of Type 'Giallo.MainViewModel', which is my view model for the page. It's just those setters, which can only see the ChessPieces observable collection, rather than the ChessPiece.Row or ChessPiece.Column. Really not sure how to resolve this.Giallo
@Giallo if ChessPieces is ObservableCollection<ChessPiece> then each item DataContext will be of ChessPiece type hence your style should (and does) work finedkozl

1 Answers

0
votes

This is nigh-on impossible to do with simple bindings. The container, not the control generated by the template, is what you need to set the Row/Grid on, and getting to it is not fun.

My solution, while ugly was to create my own special Grid, and use ArrangeOverride:

class DynamicGrid : Grid
{
    protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize)
    {
        UIElementCollection elements = base.InternalChildren;
        for (int i = 0; i < elements.Count; i++)
        {
            elements[i].SetValue(Grid.RowProperty, correctRow);
        }

        return base.ArrangeOverride(arrangeSize);
    }
}

Obviously thats just the structure, you'll have to determine the best way to get the data needed to set the row/column into this object. The good news is, when you set this Grid as the ItemsPanelTemplate, you can do your regular bindings to any DPs you set up on your custom Grid:

     <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <local:DynamicGrid />
            </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>

Of course, getting to the right piece of data will be non-trivial, but compared to setting the container Grid.Row property from inside the template, its much easier.