views:

2215

answers:

4

I'm trying to use Prism and the MVVM pattern to develop an application. In my UI, I have a previous and next button defined. For use in a calling web services, I've defined an enum that will tell me the direction I need to traverse. So, in this instance, the buttons map directly to an enum value. The enum definition is very simple and is as follows:

namespace CodeExpert.Book.Helpers
{
    public enum BookDirection { Previous = -1, NotSet = 0, Next = 1, }
}

I've defined my command and delegate in my ViewModel and assigned the propery correctly. The relevant code is:

public DelegateCommand PreviousNextCommand { get; set; }

public IndexEntriesViewModel(GlobalVariables globalVariable, IndexEntryOperations currentOperator)
{
    //a bunch of initialization code.
    InitializeCommands();
}

void InitializeCommands()
{
    PreviousNextCommand =
     new DelegateCommand(OnPreviousNextCommandExecute);
}

private void OnPreviousNextCommandExecute(BookDirection parameter)
{

    //Code to process based on BookDirection
}

So, based on this config, I want to pass a BookDirection enum value to the CommandParameter. I can't, however, get the XAML right for this. Here's the XAML I've tried that seems the most correct to me:

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        x:Class="CodeExpert.Book.Views.Index"
        d:DesignWidth="1024"
        d:DesignHeight="768"
        xmlns:helpers="clr-namespace:CodeExpert.Book.Helpers"
        xmlns:command="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation"
        xmlns:common="clr-namespace:System.Windows;assembly=System.Windows.Controls"
        xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
        xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
        xmlns:input="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input">

    <Button x:Name="ButtonPrevious"
        HorizontalAlignment="Left"
        Margin="2,1,0,1"
        Width="25"
        Content="<"
        Grid.Column="1"
        Grid.Row="1"
        Height="20"
        command:Click.Command="{Binding Path=CurrentIndexViewModel.PreviousNextCommand}">
     <command:Click.CommandParameter>
      <helpers:BookDirection.Previous />
     </command:Click.CommandParameter>
    </Button>

</UserControl>

I get no intellisense for the BookDirection for the enum and get an error at design & compile time saying The type 'BookDirection' does not contain adefinition for 'Previous'. Is there no way to pass that enum, or am I simply missing something? I have it working now by setting the parameter type to string instead of BookDirection, but then I have to parse text and the code smells. I've done some Google searches and the closest thing I've come to an answer is here - http://stackoverflow.com/questions/359699/passing-an-enum-value-as-command-parameter-from-xaml Unfortunately, Silverlight doesn't support the x:static binding extension, so I can't use the exact technique described in that answer.

Any help would be much appreciated.

A: 

I haven't tried it myself but you may have some success to use a ValueConverter from something like string to your enum. That was the impression I got from looking around for enums in Silverlight xaml.

Nigel Sampson
A: 

Did you ever find a solution to this problem? This might help a bit: http://www.orkpad.com/Blog/post/2009/03/09/I-Command-Silverlight.aspx

Ciaran
A: 

First, I am not sure if you can pass an Enum directly from XAML in Silverlight. In anycase here is a little problem in Prism. See the Command is getting set before the CommandParameter, what happens when the command is getting set internally Prism calls UpdateEnabledState(), which internally calls CanExecute(object parameter) on your DelegateCommand passing it the CommandParameter ( which remember has not been set yet )

here is the basic code from DelegateCommand.cs in Prism

 bool ICommand.CanExecute(object parameter)
    {
        return CanExecute((T)parameter);
    }

since parameter is "null" at this point, the cast throws an exception. Here is how I got around this issue.

Your Enum.

namespace CodeExpert.Book.Helpers
{
    public enum BookDirection { Previous = -1, NotSet = 0, Next = 1, }
}

here is my delegate declaration, note the use of object..rather than the Enum itself. I also expose properties from the ViewModel which will expose the 2 different directions.

public DelegateCommand<object> PreviousNextCommand { get; set; }

public BookDirection Previous { get { return BookDirection.Previous; }}
public BookDirection Next { get { return BookDirection.Next; }}

now in your OnPreviousNextCommandExecute make sure you receive an object and cast it back to the proper enum

private void OnPreviousNextCommandExecute(object parameter)
{

    BookDirection direction = (BookDirection)parameter;

    //Code to process based on BookDirection
}

and in XAML bind directly to the exposed BookDirection properties.

<Button Content="Next"  Commands:Click.Command="{Binding PreviousNextCommand}" Commands:Click.CommandParameter="{Binding Next}" />
<Button Content="Previous" Commands:Click.Command="{Binding PreviousNextCommand}" Commands:Click.CommandParameter="{Binding Previous}" />

I am not sure about your binding situation as in my case I set my DataContext directly to the ViewModel. But this should work for you.

Sorry for my poor English and eloquence, hope this puts you on the right track.

Stan R.
Stan, your English and eloquence were just fine. I've actually had this project on the back burner for a bit, but expect to be around to it again this week. I'm going to try your technique out.
Steve Brouillard
Hey Steve, I was wondering if you had a chance to try this out. I am curious if it worked out for you.
Stan R.
+1  A: 

Binding enums are really a troublesome operation, even in WPF. But there seems to be an elegant solution to it, which is available at the Caliburn framework.

The solution, however, is not available in the framework code, but in it's LOB Samples. Look for the BindableEnum and BindableEnumCollection<T> classes on the Caliburn.Silverlight.ApplicationFramework project.

HTH.

Adriano Machado