Let's look at a simple ViewModel implementation.  This is using the MEF adapter for NoMvvm.

    [ViewModel("Main")]
    public sealed class MainViewModel : ViewModel
    {
        private readonly Telescope _telescope;

        [ImportingConstructor]
        public MainViewModel([Import(typeof(Telescope))] Telescope telescope)
        {
            _telescope = telescope;
        }

        public async void Refresh()
        {
            This.Planets = null;
            This.IsBusy = true;
            This.CanRefresh = false;

            try
            {
                This.Planets = await _telescope.MeasurePlanets();
            }
            finally
            {
                This.IsBusy = false;
                This.CanRefresh = true;
            }
        }
    }

Here is the associated View:

<Window 
    x:Class="NoMvvm.Demo.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="NoMvvm Demo" Height="350" Width="525">

    <!--This converter just helps us bind a bool to a Visibility-->
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="Converter" />
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>

        <!--Refresh button-->
        <Button HorizontalAlignment="Left" Width="150" Height="30" Command="{Binding Refresh}">Refresh</Button>

        <!--List of our planets-->
        <ListView Grid.Row="1" ItemsSource="{Binding Planets}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Planet" DisplayMemberBinding="{Binding Name}" />
                    <GridViewColumn Header="Diameter" DisplayMemberBinding="{Binding Diameter, StringFormat={}{0} KM}" />
                </GridView>
            </ListView.View>
        </ListView>

        <!--Our busy indicator-->
        <TextBlock 
            Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" 
            Text="Please Wait..." Visibility="{Binding IsBusy, Converter={StaticResource Converter}}" />

    </Grid>
</Window>

In your View's .cs file:

    [View("Main")]
    public partial class MainView : Window
    {
        public MainView()
        {
            InitializeComponent();
        }
    }

Put aside the usage of the async CTP for now.

Take notice of a few things:

  • What is "This"?
  • I don't have to implement properties?
  • I don't have to implement INotifyPropertyChanged?
  • Where is ICommand???
  • How does CanExecute work?

"This" is a readonly property to access your ViewModel as type dynamic.  It is just a helper to prevent code like ((dynamic)this).MyProperty.

By default the ViewModel class will look for methods with signatures matching Action or Action<dynamic> and automatically create a dynamic property with the same name implementing ICommand.  Additionally, the creation of a CanX dynamic property will automatically interact with the CanExecute method of that ICommand.

Additionally, you could implement the same ViewModel like this:

    [ViewModel("Main")]
    public sealed class MainViewModel : ViewModel
    {
        private readonly Telescope _telescope;

        [ImportingConstructor]
        public MainViewModel([Import(typeof(Telescope))] Telescope telescope)
        {
            _telescope = telescope;

            This.Refresh = (Action)async delegate
            {
                This.Planets = null;
                This.IsBusy = true;
                This.CanRefresh = false;

                try
                {
                    This.Planets = await _telescope.MeasurePlanets();
                }
                finally
                {
                    This.IsBusy = false;
                    This.CanRefresh = true;
                }
            };
        }
    }

Or even like this:

            dynamic viewModel = new ViewModel();
            viewModel.Refresh = (Action)async delegate
            {
                viewModel.Planets = null;
                viewModel.IsBusy = true;
                viewModel.CanRefresh = false;

                try
                {
                    viewModel.Planets = await _telescope.MeasurePlanets();
                }
                finally
                {
                    viewModel.IsBusy = false;
                    viewModel.CanRefresh = true;
                }
            };

Looks, great so far.  Sign up me up!

Last edited Aug 24, 2011 at 3:30 AM by jonathanpeppers, version 14

Comments

No comments yet.