2
votes

Lately ive been trying to make a grid that uses my UserControls to fill it in. The only problem i've encountered is that I cant use the WPF Binding stuff to link the user controls to my grid, making it for me very hard to nicely place them in the grid. My question: How can i bind the attributes in my ViewModel (which are stored in the Block class, which my ViewModel has an object of), to my UserControl Block, allowing it to use those variables (the X and Y, which are the row and column of the grid, position)?

Here is the code of my user control:

namespace Mortal_Pets.Views
public partial class BlockView : UserControl
{

    public BlockView()
    {
        InitializeComponent();
        DataContext = new BlockViewModel();
    }
}

<UserControl x:Class="Mortal_Pets.Views.BlockView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="30" d:DesignWidth="30">
<Canvas Background="{Binding Block.Color}" Grid.Row="{Binding Path=Block.XPosition}"  Grid.Column="{Binding Path=Block.YPosition}">

</Canvas>

Here is the ViewModel and Model class of the UserControl:

class BlockViewModel
{
    public Block Block { get; set; }

    public BlockViewModel()
    {
        Block = new Block();
        Block.XPosition = 5; //Does Not Work, But this is how i'd like to have it
        Block.YPosition = 5; //Does Not Work, But this is how i'd like to have it
        Block.Color = new SolidColorBrush(Colors.Black);
    }
}

class Block
{
    public int XPosition { get; set; }
    public int YPosition { get; set; }
    public Brush Color { get; set; }

    public Block()
    {

    }
}

Then following up we have my Window:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        BlockView view = new BlockView();
        view.SetValue(Grid.ColumnProperty, 5); //This does work, but is ugly and not really usefull for what i intend to do with it
        view.SetValue(Grid.RowProperty, 5); //This does work, but is ugly and not really usefull for what i intend to do with it
        BoardGrid.Children.Add(view); //This does work, but is ugly and not really usefull for what i intend to do with it
    }
}

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Mortal_Pets.Views" x:Class="Mortal_Pets.Views.MainWindow"
    Title="MainWindow" Height="700" Width="600"
Loaded="Window_Loaded">
<Grid x:Name="BoardGrid" Margin="10,50,10,10" Width="500" Height="500">
    <Grid.RowDefinitions>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
        <RowDefinition Height="25"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
        <ColumnDefinition Width="25"/>
    </Grid.ColumnDefinitions>
    <Label x:Name="ComboCounter" Content="{Binding Game.ComboCounter}" HorizontalAlignment="Left" Margin="-2,-61,0,0" VerticalAlignment="Top" Width="95" Grid.ColumnSpan="4"/>

</Grid>

Thanks in advance, Nick van der Meij

1
My bad, question added as well as i could (im not a native english speaker, so sorry for the crappy english..)BattleOn

1 Answers

1
votes

Got it to work based on knowledge found here and here. It is not pretty but this seems to be the only way it will work.

You did not share the MainViewModel (I guess because it was not necessary for the quick sample you gave). But since I needed it for binding and you will most probably work with it, here is my quick version:

class MainViewModel
{
    public List<BlockViewModel> Blocks { get; set; }

    public MainViewModel()
    {
        Blocks = new List<BlockViewModel> { new BlockViewModel() };
    }
}

You need to wrap the grid in an ItemsControl and use the ItemContainerStyle for binding the Grid.Column and Grid.Row:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="700" Width="600"
        xmlns:local="clr-namespace:WpfApplication1">

    <ItemsControl ItemsSource="{Binding Path=Blocks}">
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Grid.Row" Value="{Binding Block.YPosition}" />
                <Setter Property="Grid.Column" Value="{Binding Block.XPosition}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <local:BlockView/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid Margin="10,50,10,10" Width="500" Height="500" ShowGridLines="True">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="25"/>
                        <RowDefinition Height="25"/>
                        <RowDefinition Height="25"/>
                        <RowDefinition Height="25"/>
                        <RowDefinition Height="25"/>
                        <RowDefinition Height="25"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="25"/>
                        <ColumnDefinition Width="25"/>
                        <ColumnDefinition Width="25"/>
                        <ColumnDefinition Width="25"/>
                        <ColumnDefinition Width="25"/>
                        <ColumnDefinition Width="25"/>
                    </Grid.ColumnDefinitions>
                </Grid>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>    
</Window>

The BlockView now looks like this:

<UserControl x:Class="WpfApplication1.BlockView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" d:DesignHeight="30" d:DesignWidth="30">    
    <Canvas Background="{Binding Block.Color}">
    </Canvas>
</UserControl>