Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Silverlight MVVM - Button Enable & Visibility properties

So I'm working in MVVM application & I'm starting to put some of the shine & polish on the functionality.

On the left side of my page, I am displaying these values:

DateActivated
DateCompleted
DateTrialClosed
DateAccountingClosed

If there's a date in the DB, I'm displaying it in a textblock. If there's not, I'm displaying a button to the user, saying "Activate Work Order", "Complete Work Order", etc...

I'm binding the visibility of each of these 8 (4 textblock, 4 button) controls to a unique property in my ViewModel of type Windows.Visibility. In my setter of the SelectedWorkOrder, I evaluate the current value of the SelectedWorkOrder.DateActivated property (for example) and set the visibility properties accordingly. This is slightly verbose for me, but it's working as expected.

My next step is to disable any visible buttons after the first one (logic is simple... can't click button 2 until button 1 has been clicked. Can't click button 3 until both 1 & 2 have been clicked). I'm not sure what the best way to implement this is. As an FYI on this, I have a boolToVisibility value converter already in my project... I'm just not sure that implementing it would be any different than I am doing now (see VM code below).

Currently I have this for my XAML:

<TextBlock Text="Proposed:" />
<TextBlock Text="Activated:" />
<TextBlock Text="Eng Completed:" />
<TextBlock Text="Trial Close:" />
<TextBlock Text="Accounting Close:" />
<TextBlock Text="{Binding SelectedWorkOrder.EstimatedStartDate}" Visibility="{Binding ProposedVisibility}" />
<TextBlock Text="{Binding SelectedWorkOrder.DateActivated}" Visibility="{Binding ActivatedTextBlockVisibility}" />
<Button Content="Activate Work Order" Visibility="{Binding ActivatedButtonVisibility}" />
<TextBlock Text="{Binding SelectedWorkOrder.DateCompleted}" Visibility="{Binding EngineeringCompletedTextBlockVisibility}" />
<Button Content="Work Order Eng Complete" Visibility="{Binding EngineeringCompletedButtonVisibility}" />
<TextBlock Text="{Binding SelectedWorkOrder.DateClosed}" Visibility="{Binding TrialCloseTextBlockVisibility}" />
<Button Content="Close Work Order (Trial)" Visibility="{Binding TrialCloseButtonVisibility}" />
<TextBlock Text="{Binding SelectedWorkOrder.DateClosed}" Visibility="{Binding AccountingCloseTextBlockVisibility}" />
<Button Content="Close Work Order (Actual)" Visibility="{Binding AccountingCloseButtonVisibility}" />

VM Code:

if (_SelectedWorkOrder.DateActivated.ToShortDateString() != "1/1/0001")
{
    ActivatedTextBlockVisibility = Visibility.Visible;
    ActivatedButtonVisibility = Visibility.Collapsed;
}
else
{
    ActivatedTextBlockVisibility = Visibility.Collapsed;
    ActivatedButtonVisibility = Visibility.Visible;
}

(The date is set to 1/1/0001 in my database access layer as I'm instantiating a new DateTime if Is DBNull.Value = true)

like image 552
Scott Silvi Avatar asked May 06 '11 20:05

Scott Silvi


1 Answers

I had a similar problem this evening :-)

I think the best way to do this kind of stuff is binding visibility to a property in the ViewModel.

You can use a converter for each of these variables (so you can return a Visibility.Collapsed or a Visibility.Visible when expected ;-)).

You can use the "CanExecute" method for each of these buttons so the button 2 is not able to be executed until button1 is pressed (with a boolean variable for example). You hace to use commands for this so the code associated to each button will be in the ModelView.

If you need examples I can paste them from my job on monday :-).

A little example by coding it here directly (I don't have silverlight installed here).

Your view should be like this:

<Button Content="Activate Work Order" Command="{Binding ActivateWorkOrderCommand}" />

You can search examples of how to use Commands in MVVM, here you have a simple example.

For the converters, if you still prefer to hide and show the buttons, you should declare a new Class that implements IValueConverter:

public class UniversalConverter : IValueConverter {
      public object Convert(object value, Type targetType, 
                         object parameter, CultureInfo culture) {
if(_SelectedWorkOrder.DateActivated.ToShortDateString() != "1/1/0001")
{
          return Visibility.Collapsed;
      }
else { return Visibility.Visible;
}

So your view should link the converter too:

<Button Content="Activate Work Order" Visibility="{Binding DateActivated, Converter={StaticResource DateConverter}}" />

Hope this help you ;-)

like image 90
zapico Avatar answered Oct 26 '22 07:10

zapico