markgoo
markgoo

Reputation: 1

How to do some simple layout and operations using WPF with MVVM?

I just start looking into WPF and MVVM, and I'm considering I need to start using MVVM.

I have a winform application, with a main panel, on the left of the main panel there are some buttons, on the right side of the main panel is a zone to place different child panels(one panel at one time), after clicking a main forms botton, a child panel's method will be called.

Is it possible to use MVVM to do such layout and operations?

Upvotes: 0

Views: 297

Answers (3)

Rachel
Rachel

Reputation: 132568

The main ViewModel would contain properties for

  • ViewModelBase CurrentPage
  • ICommand ChangePageCommand
  • ObservableCollection<ViewModelBase> AvailablePages

The main View would contain

  • ContentControl for hosting the CurrentPage
  • A Menu area across the left side of the screen displaying AvailablePages
  • Clicking a link in the Menu area would call the ChangePage command to switch the CurrentPage to the selected AvailablePage.

  • DataTemplates would be used to display ChildViews based on what ChildViewModel is being displayed in CurrentPage

Since the main ViewModel has access to all available pages, it can execute methods on the ChildViewModels if needed, and the ChangePageCommand can be called from the ChildViewModels

I wrote an example of such an interface here if you're interested, although it only shows an example of switching the CurrentPage, not navigating through AvailablePages

Upvotes: 1

Sascha
Sascha

Reputation: 10347

Sorry for misunderstanding at the first time. I've created a small sample. Here's the XAML code:

<Window x:Class="S4SO.ContainerBinding.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="520" Width="425">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="80" />
      <RowDefinition Height="400" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="400" />
    </Grid.ColumnDefinitions>
    <ContentControl Content="{Binding ContentContent}" Grid.Row="1" Height="400" Width="400" />
    <StackPanel Orientation="Horizontal">
      <Button Content="Use button" Command="{Binding UseButton}" />
      <Button Content="Use Textbox" Command="{Binding UseTextbox}" />
    </StackPanel>
  </Grid>
</Window>

The window is bound to a viewmodel, For simplicity I took MVVMLight as base:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows.Controls;
using System.Windows;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight;

namespace S4SO.ContainerBinding {
  public class ViewModel : ViewModelBase {
    private object _ContentContent;

    public object ContentContent {
      get { return _ContentContent; }
      set {
        if ( _ContentContent.GetType() == value.GetType() )
            return;
        _ContentContent = value;
        RaisePropertyChanged( "ContentContent" );
      }
    }

    public ICommand UseButton { get; set; }

    public void CommandUseButton () {
      ContentContent = new Button() {
        Content = "A button",
        Width = 400,
        Height = 400,
        VerticalContentAlignment = VerticalAlignment.Center,
        HorizontalContentAlignment = HorizontalAlignment.Center
      };
    }

    public bool CanUseButton () {
      return !( _ContentContent is Button );
    }

    public ICommand UseTextbox { get; set; }

    public void CommandUseTextbox () {
      ContentContent = new TextBox() {
        Text = "Content here",
        Width = 400,
        Height = 400,
        VerticalContentAlignment = VerticalAlignment.Center,
        HorizontalContentAlignment = HorizontalAlignment.Center
      };
    }

    public bool CanUseTextbox () {
      return !( _ContentContent is TextBox );
    }

    public ViewModel () {
      _ContentContent = new Label() {
        Content = "Please choose content!",
        Width = 400,
        Height = 400,
        HorizontalContentAlignment = HorizontalAlignment.Center,
        VerticalContentAlignment = VerticalAlignment.Center
      };
      UseButton = new RelayCommand( () => CommandUseButton(), () => CanUseButton() );
      UseTextbox = new RelayCommand( () => CommandUseTextbox(), () => CanUseTextbox() );
    }

  }
}

Definitely not production level, but it shows a direction and hopefully is now more what you asked for. I have used simple controls and did not dig into binding those dynamically created controls. Binding via code behind isn't straightforward like binding syntax in XAML. I'll keep that up to you if this is the right direction.

Upvotes: 0

Martin Doms
Martin Doms

Reputation: 8748

Sure. Both the left and the right panels will be bound to a single ViewModel (which is the VM which represents the current panel on the right). The buttons on the left will call operations (probably via commands) on the ViewModel.

When the active VM changes (ie, when a different panel is shown on the right side) then the data context of the left panel is changed to the new VM.

You will probably want some kind of container VM to represent the whole window, with several child ViewModels representing each of the possible panels on the right. Only one of these is set as the active panel at any given time. Does this make sense?

Upvotes: 1

Related Questions