Tag Archives: Wpf

Wpf and WinRT Binding Modes

There are a number of different binding modes available which specify the direction that data should flow in the binding.

TERMINOLOGY

In the following the target is considered to be the property on the control that you are binding to and the source is considered to be the object that you are binding to it. So if you were binding to a textboxes text property that would be the target and the source would be the string bound to it.

BINDING MODES

  • TwoWay – updates the target property or the property whenever either the target property or the source property changes.
  • OneWay – updates the target property only when the source property changes.
  • OneTime – updates the target property only when the application starts or when the DataContext undergoes a change.
  • OneWayToSource – updates the source property when the target property changes.
  • Default – causes the default Mode value of target property to be used.

USEAGE

<TextBlock Name="IncomeText" Grid.Row="0" Grid.Column="1" Text="{Binding Path=TotalIncome, Mode=OneTime}"/>

NOTES

Not all binding modes are available on all platforms. Default mode is generally TwoWay for user editable controls and OneWay for controls that aren’t.

Caliburn Micro Part 4: The Event Aggregator

Welcome to the fourth part of this tutorial on the basics of Caliburn Micro, in the previous part we saw how actions worked. In this next part we will go through the basics of the Event Aggregator.

Description

The event aggregator is a service that allows View Models to communicate with each other using messages. A View Model can subscribe to as many messages as it wants and will be notified each time one of these messages is published by the same or a different View Model.

Step 1: New Components

In this example we will build a small application that changes the text in one View Model when buttons in another are pressed, we will build upon the application that we built in the past tutorials. In order to do this we will need two additional View Models, so lets start by creating the one containing the buttons. Create a new class, call it ButtonsViewModel and add code so that it looks as below.

public class ButtonsViewModel
{
    public void Button1()
    {
    }

    public void Button2()
    {
    }

    public void Button3()
    {
    }
}

Lets also make a View to go along with it as well called ButtonsView.

<UserControl x:Class="CaliburnMicroExample.ButtonsView"
             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" >
    <StackPanel Orientation="Vertical">
        <Button x:Name="Button1" Content="Button 1" />
        <Button x:Name="Button2" Content="Button 2" />
        <Button x:Name="Button3" Content="Button 2" />
    </StackPanel>
</UserControl>

Now that we have the buttons set up lets create the View Model that will display some text to the user. Create a new View Model and call it TextViewModel.

public class TextViewModel : PropertyChangedBase
{
    private string _text;

    public string Text
    {
        get { return _text; }
        set
        {
            _text = value;
            NotifyOfPropertyChange(() => Text);
        }
    }

    public TextViewModel()
    {
        Text = "No button pressed";
    }
}

Also create TextView to go along with it.

<UserControl x:Class="CaliburnMicroExample.TextView"
             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" >
    <Grid>
        <TextBlock x:Name="Text" VerticalAlignment="Center" />
    </Grid>
</UserControl>

Finally we need to update ShellViewModel and ShellView so that they contain the new View / View Model combos we have made. Start by changing ShellViewModel as below.

public class ShellViewModel
{
    public ButtonsViewModel ButtonsVM
    {
        get;
        set;
    }

    public TextViewModel TextVM
    {
        get;
        set;
    }

    public ShellViewModel()
    {
        ButtonsVM = new ButtonsViewModel();
        TextVM = new TextViewModel();
    }
}

Change ShellView as shown below.

<UserControl x:Class="CaliburnMicroExample.ShellView"
             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"
             xmlns:cal="http://www.caliburnproject.org"
             xmlns:local="clr-namespace:CaliburnMicroExample"
             mc:Ignorable="d" >
    <StackPanel Orientation="Horizontal">
        <local:ButtonsView cal:Bind.Model="{Binding ButtonsVM}" />
        <local:TextView cal:Bind.Model="{Binding TextVM}" />
    </StackPanel>
</UserControl>

If you run the program now you should see a small app with 3 buttons down the left hand side and some text displayed to the right.

Step 2: Implementing IHandle

We are going to be publishing messages from the ButtonsViewModel that will be picked up in the TextViewModel. To do this we need to make TextViewModel aware of the message that it is going to receive. Caliburn offers the IHandle interface which lets a View Model listen for a message of its choice, start by creating a new class and calling it ChangeTextMessage. This will act as the message that we send between our two View Models.

public class ChangeTextMessage
{
    public string Text
    {
        get;
        private set;
    }

    public ChangeTextMessage(string text)
    {
        Text = text;
    }
}

Now lets extend TextViewModel to support the IHandle interface, as you can see below once we received the message we set the text that is displayed to the text received in the message.

public class TextViewModel : PropertyChangedBase, IHandle<ChangeTextMessage>
{
    private string _text;

    public string Text
    {
        get { return _text; }
        set
        {
            _text = value;
            NotifyOfPropertyChange(() => Text);
        }
    }

    public TextViewModel()
    {
        Text = "No buttons pressed";
    }

    public void Handle(ChangeTextMessage message)
    {
        Text = message.Text;
    }
}

Step 3: Event Aggregator

Now that we have added the ability for TextViewModel to handle a message we need to start adding the capability for it to receive them and for ButtonsViewModel to send them. To do this we need to pass an instance of EventAggregator to each of our interested View Models, start by creating a new instance of it in the ShellViewModel constructor and passing it to the other two View Models.

public ShellViewModel()
{
    IEventAggregator events = new EventAggregator();

    ButtonsVM = new ButtonsViewModel(events);
    TextVM = new TextViewModel(events);
}

In TextViewModel save the passed in instance to a local variable.

private IEventAggregator _events;

public TextViewModel(IEventAggregator events)
{
    _events = events;

    Text = "No buttons pressed";
}

Do the same in ButtonsViewModel as well.

private IEventAggregator _events;

public ButtonsViewModel(IEventAggregator events)
{
    _events = events;
}

Step 4: Subscribe

The next step is to subscribe TextViewModel to the Caliburn message pipe, this is as simple as calling subscribe on the EventAggregator object that we passed in.

public TextViewModel(IEventAggregator events)
{
    _events = events;

    _events.Subscribe(this);

    Text = "No buttons pressed";
}

Step 5: Publish

The final thing we need to do is send a message every time a button is pressed in ButtonsViewModel, extend your code as shown below.

public void Button1()
{
    _events.PublishOnUIThread(new ChangeTextMessage("Button 1 Pressed"));
}

public void Button2()
{
    _events.PublishOnUIThread(new ChangeTextMessage("Button 2 Pressed"));
}

public void Button3()
{
    _events.PublishOnUIThread(new ChangeTextMessage("Button 3 Pressed"));
}

If you run the application now you should see that pressing buttons on the left changes the text on the right.

That’s it for this tutorial join us next time for a look at using Caliburn Micro in Windows Phone 8.1 and Windows Store projects.

Caliburn Micro Part 3: Actions

Welcome to the third part of this tutorial on the basics of Caliburn Micro, in the previous part we saw how to do some basic databinding and eventing. In this next part we will go through the basics of actions.

Long Syntax

Last time we saw how to bind the click event of a button to a function in the associated View Model, by setting the name of the button to the name of the function. This works well if you only want to bind to the default event but what if you wanted to bind to a different event or even pass parameters?

Lets start by changing out previous example to use the long syntax. Edit the xaml in ShellView to look as follows.

<Grid>
    <Button Content="Press Me" VerticalAlignment="Top">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <cal:ActionMessage MethodName="ChangeMessage" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>
    <TextBlock x:Name="Message" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>

You’ll need to add these two namespace references as well.

xmlns:cal="http://www.caliburnproject.org"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

If you run the app now you should see that it runs exactly the same as before. All we have done here is explicitly say which event we are listening for and which function in the View Model should be called.

Next lets look at how we can pass parameters with the action message, modify ShellView as follows so that it passes a parameter when the button is clicked.

<Button Content="Press Me" VerticalAlignment="Top">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <cal:ActionMessage MethodName="ChangeMessage">
                <cal:Parameter Value="2" />
            </cal:ActionMessage>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

Next edit the ChangeMessage function in ShellViewModel so that it takes an integer parameter.

public void ChangeMessage(int incrementBy)
{
    _pressCount += incrementBy;

    Message = "Presses = " + _pressCount;
}

If you run the app again you should notice that the count is now increased by two, this is because when the button is clicked it sends the action message to the View Model with the specified parameter which is then added to the count.

Short Syntax

If the above seemed like a quite a lot of xaml it can be shorted by using the short action message syntax. We can achieve what we did before by modifying ShellView like below.

<Button Content="Press Me" VerticalAlignment="Top" cal:Message.Attach="[Event Click] = [Action ChangeMessage(2)]" />

What we have done here is use one of Caliburn Micros attached properties to achieve the same as we did before but with much less xaml. I like this method as it simplifies the code somewhat, but in more complex cases it may be clearer to use the longer syntax.

In addition to passing literal values and binding expressions as parameters it is also possible to pass some special values that allow you access to some convenient information. These are as follows:

$eventArgs
Passes the EventArgs or input parameter to your Action.
$dataContext
Passes the DataContext of the element that the ActionMessage is attached to.
$source
The actual FrameworkElement that triggered the ActionMessage to be sent.
$view
The view (usually a UserControl or Window) that is bound to the ViewModel.
$executionContext
The action’s execution context, which contains all the above information and more.
$this
The actual UI element to which the action is attached. In this case, the element itself won’t be passed as a parameter, but rather its default property.

That’s it for this tutorial join us next time for a look at the Event Aggregator.

Caliburn Micro Part 2: The Basics of Databinding

Welcome to the second part of this tutorial on the basics of Caliburn Micro, in the previous part we saw how to setup a new project from scratch and display a window to the user. In this next part we will go through the basics of databinding which is where the true power of Caliburn Micro comes into play. We will be building upon the example shown in the previous part of this tutorial by adding some new functionality to it.

Databinding

Lets start simple by showing some text to the user. Extend ShellViewModel as shown below by adding a string property and setting it to HelloWorld in the constructor. Notice that we are now inheriting from PropertyChangedBase and we’ve added a call to NotifyOfPropertyChange in the setter of the property. PropertyChangedBase gives us access to NotifyOfPropertyChange which tells the view that it should display the new value every time the Message property is changed. This saves us from having to implement the INotifyPropertyChanged interface in all of our ViewModels.

using Caliburn.Micro;

namespace CaliburnMicroExample
{
    public class ShellViewModel : PropertyChangedBase
    {
        private string _message;

        public string Message
        {
            get { return _message; }
            set
            {
                _message = value;
                NotifyOfPropertyChange(() => Message);
            }
        }

        public ShellViewModel()
        {
            Message = "Hello World";
        }
    }
}

Next lets add a TextBlock to ShellView so that it can display our message to the user.

<Grid>
    <TextBlock x:Name="Message" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>

Now if you run up the application you should see a small windows with the text Hello World in the centre. By just giving the TextBlock the same name as out property Caliburn Micro automatically binds them together for us. This is not the only way to do it however, you could do it the traditional way by binding to the Text property of the TextBlock.

<Grid>
    <TextBlock Text="{Binding Message}" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>

Events

Now lets look at how Caliburn Micro handles events, in order to do this we will add a button to our application that lets us change the current text. First add a new function to ShellViewModel that changes the message as shown below.

using Caliburn.Micro;

namespace CaliburnMicroExample
{
    public class ShellViewModel : PropertyChangedBase
    {
        private string _message;

        public string Message
        {
            get { return _message; }
            set
            {
                _message = value;
                NotifyOfPropertyChange(() => Message);
            }
        }

        private int _pressCount;

        public ShellViewModel()
        {
            Message = "Hello World";
            _pressCount = 0;
        }

        public void ChangeMessage()
        {
            _pressCount++;

            Message = "Presses = " + _pressCount;
        }
    }
}

Now add a button to ShellView as shown below.

<Grid>
    <Button x:Name="ChangeMessage" Content="Press Me" VerticalAlignment="Top" />
    <TextBlock x:Name="Message" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>

That’s all there is to it, if you run the application now you should see that pressing the button changes the message displayed. The binding is achieved in pretty much the same way as with the TextBlock, Caliburn Micro looks for a function in the ViewModel with the same name as the Button and binds the two together so that the function is called on the button press. There are additional ways to do this which give you more control but we’ll look at those in a future tutorial.

Event Guards

The last thing we are going to cover in this tutorial is event guards. Event guards are used to only allow the handling of an event if a certain condition is met. To demonstrate this we will prevent the user from pressing the button more than 10 times. Add a new property to ShellViewModel called CanChangeMessage and also add a new NotifyOfPropertyChange to the Message setter.

public string Message
{
    get { return _message; }
    set
    {
        _message = value;
        NotifyOfPropertyChange(() => Message);
        NotifyOfPropertyChange(() => CanChangeMessage);
    }
}

public bool CanChangeMessage
{
    get { return _pressCount < 10; }
}

Now when you run the code you should see that the button becomes disabled after it has been pressed 10 times. Every time Caliburn Micro hooks up an event is also looks for a property with the same name plus the word can before it. It then uses the Boolean result of the property to determine whether the event should be handled or not. So in this case once the press count has reached 10 the property will always return false meaning no new click events will be handled and Caliburn Micro automatically disables the button for us.

In the next part of this blog series I will go through how Actions work in Caliburn Micro.

Caliburn Micro Part 1: Getting Started

In this blog series I’ll go through the steps needed to get up and running with Caliburn Micro, we’ll be using a wpf application as an example although caliburn micro also supports Silverlight, Windows Phone and Windows Store apps.

Step 1: Initial Setup

Start by creating a new wpf application in Visual Studio and grab the Caliburn Micro nugget package using the library package manager. Since Caliburn Micro takes care of creating all windows for you, delete MainWindow.xaml and remove the StartupUri attribute from App.xaml. After doing the previous App.xaml will look like this.

<Application x:Class="CaliburnMicroExample.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

Step 2: Creating a View Model

Since Caliburn Micro prefers a View-Model-First approach lets start by creating our first View Model. Add a new class to the project and call it ShellViewModel. Since we are just getting setup in this tutorial we won’t add any functionality to the VM. After you have created ShellViewModel it should look as below.

namespace CaliburnMicroExample
{
    public class ShellViewModel
    {
    }
}

Note that the names of View Models in Caliburn Micro must end with ViewModel although what you put before that is up to you.

Step 3: Creating a View

In order to display something to a user we’ll need a View to go along with the View Model, create a new wfp user control and call it ShellView. The xaml for the view you created should look as below.

<UserControl x:Class="CaliburnMicroExample.ShellView"
             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"
             Width="100" Height="100">
    <Grid>
            
    </Grid>
</UserControl>

Note that Views in Caliburn Micro must end with View and have the same name as the View Model, so having a View Model called MyViewModel would mean that the associating View is called MyView. This is so that Caliburn Micro can automatically bind them together.

Step 4: The Bootstrapper

Finally we need a Bootstrapper which will configure the Caliburn Micro framework and tell it what to do. Bootstrappers can do quite a lot of things beyond the scope of this tutorial so for now we will just configure one that initialises the framework and displays the first View. So create a new class and call it AppBootstrapper, then add code to make it look like the one below.

using Caliburn.Micro;

namespace CaliburnMicroExample
{
    public class AppBootstrapper : BootstrapperBase
    {
        public AppBootstrapper()
        {
            Initialize();
        }

        protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
        {
            DisplayRootViewFor<ShellViewModel>();
        }
    }
}

The last thing to do is to tell the application to use the bootstrapper on startup, to do this we need to edit App.xaml as shown below.

<Application x:Class="CaliburnMicroExample.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:CaliburnMicroExample">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <local:AppBootstrapper x:Key="bootstrapper" />
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

That’s all there is to it, if you run the application now you should see a small square window. You are now ready to take advantage of all the cool things that Caliburn Micro has to offer.

In the next part of this blog series I will go through how databinding and events work in Caliburn Micro.