NamelessCoder
NamelessCoder

Reputation: 13

Accessing Grid.Children.Add in MVVM (WPF)

So I have this idea of adding several buttons to a grid, then arranging them, and the number of buttons added is related to a number I enter. All works fine, until I try to make it work under MVVM.

Code that works in the MainWindow.xaml.cs:

 private void Button_Click(object sender, RoutedEventArgs e)
    {
        int i = 0, j = 0;
        Brush[] bs = { Brushes.BurlyWood, Brushes.Honeydew };

        for (i = 0; i < 3; i++)
        {
            for (j = 0; j < 3; j++)
            {
                Button btn = new Button();
                btn.Height = 50;
                btn.Width=50;
                btn.SetValue(Grid.RowProperty, i);
                btn.SetValue(Grid.ColumnProperty, j);
                if ((i + j) % 2 == 0)
                {
                   btn.Background=bs[0];
                }
                else btn.Background = bs[1];

                GameGrid.Children.Add(btn);
            }
        }
    }

So basically, I press a button and it adds 3x3 buttons, colored nicely and spread appropriately. But then I get to the MVVM:

private void ButtonClickCommand()
    {
        RowCount = GridNumber;
        ColumnCount=GridNumber;
        int i = 0, j = 0;

        Brush[] bs = { Brushes.BurlyWood, Brushes.Honeydew };

        for (i = 0; i < GridNumber; i++)
        {
            for (j = 0; j < GridNumber; j++)
            {
                Button btn = new Button();
                btn.Height = 50;
                btn.Width = 50;
               // btn.Command = StartCommand; Ill add that later
                btn.SetValue(Grid.RowProperty, i);
                btn.SetValue(Grid.ColumnProperty, j);
                if ((i + j) % 2 == 0)
                {
                    btn.Background = bs[0];
                }
                else btn.Background = bs[1];

                somebuttonlist.Add(btn);
            }
        }

    }

Here I have a List of buttons, which should accept the new created buttons, then transfer them to the grid. Code of the button list:

 private List<Button> _bslist = new List<Button>();
    public List<Button> somebuttonlist
    {
        get
        {
            return _bslist;
        }
        set
        {
            _bslist = value;
            NotifyPropertyChanged();

        }
    }

And xaml code:

 <ItemsControl ItemsSource="{Binding somebuttonlist}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate> 
                <Grid Name="GameGrid" Visibility="{Binding GameVis}"
                vm:GridHelpers.RowCount="{Binding RowCount}"
                vm:GridHelpers.ColumnCount="{Binding ColumnCount}">
                </Grid>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

Don't mind all the bindings, they work properly when I use the non-MVVM format. So how do I properly transfer the working code into the View Model? Is there a way to access the children accordingly?

Upvotes: 1

Views: 1152

Answers (2)

zmechanic
zmechanic

Reputation: 1990

This is not the right way of doing things with MVVM. What you are trying to do now is to pull visual code into your ViewModel. Ideally, ViewModels should leave in a separate project without any references to visual stuff. This way, referencing Button will result in broken code unless you add a reference for System.Windows.Controls and this reminds you that you do things the wrong way.

What you are trying to do is doable in pure MVVM way, but will result in much more code, which also be convoluted to you if you haven't got a grasp on MVVM yet. Also note, that in real life, it is acceptable to have some code behind for complicated scenarios. For this you just create a custom control to encapsulate all code behind logic.

The nice solution in your case can be a custom control, that encapsulates Grid and logic to populate it with buttons. You also add dependency properties for Rows and Columns, so you can bind to them in XAML, and define a command which is invoked when button is clicked. This may be a good example: How to create bindable commands in Custom control?

Upvotes: 1

Lunyx
Lunyx

Reputation: 3284

It looks like you are binding to a List, which does not notify when new records are inserted or any record is deleted. The NotifyPropertyChanged() that you have only kicks off when the reference to that list is modified, so for example, setting it to a new List() or a different List. Try changing it to an ObservableCollection instead, which sends an event for when the number of records in the collection get modified.

Upvotes: 1

Related Questions