0

I have defined a button in my View (AXML) with the following code:

<Button Content="Fetch Data" Command="{Binding readInventoryFilesCommand}" CommandParameter="{Binding Path=Text, ElementName=browseFolderTextBox}" Name="button1" />

The button works as expected but I would like it to be enabled/disabled if a ListView has been populated with elements.

  • If no elements in the listView --> Button IsEnabled set to false
  • If there are elements in the listView --> Button IsEnabled set to true

I tried to play around with IsEnabled="{Binding ... but I am not getting code completion in Visual Studio C# Express and it is hard to guess the alternatives.

The command looks like this:

internal class ReadInventoryFilesCommand : ICommand
{
    public ReadInventoryFilesCommand(ResourceViewModel viewModel)
    {
        _viewModel = viewModel;
    }

    private ResourceViewModel _viewModel;

    #region ICommand Members

    event EventHandler ICommand.CanExecuteChanged
    {
        add
        {
            CommandManager.RequerySuggested += value;
        }
        remove
        {
            CommandManager.RequerySuggested -= value;
        }
    }

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

    void ICommand.Execute(object parameter)
    {
        _viewModel.ReadInventroyFiles(parameter.ToString());
    }
    #endregion
}

EDIT This is the current code after Bobs advice:

internal class ReadInventoryFilesCommand : ICommand
    {
        public ReadInventoryFilesCommand(ResourceViewModel viewModel)
        {
            _viewModel = viewModel;
            _viewModel.PropertyChanged+= (s,e) => { 
                if (e.PropertyName == "CanUpdate") RaiseCanExecuteChanged();
            };
        }

        private ResourceViewModel _viewModel;

        event EventHandler ICommand.CanExecuteChanged;

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

        void ICommand.Execute(object parameter)
        {
            _viewModel.ReadInventroyFiles(parameter.ToString());
        }

        void RaiseCanExecuteChanged() {
            var handler = this.CanExecuteChanged;
            if (handler != null) handler(this,EventArgs.Empty);
        }
    }

It generates the following errors:

An explicit interface implementation of an event must use event accessor syntax 
3
  • Does the command correctly implement canexecute and OnCanExecuteChanged? Commented Oct 21, 2013 at 7:37
  • where on earth did you get that canexecutechanged implementation from? Where are you raising the event? Commented Oct 21, 2013 at 7:45
  • @BobVale, this is legacy code. That is all the code related to this issue really! Commented Oct 21, 2013 at 7:47

4 Answers 4

2

You need to raise the CanExecuteChanged event from your command when it can execute.

EDIT

As gehho mentioned in the comments, you won't need to bind to the buttons IsEnabled property when using the ICommand interface as the Button will use the CanExecute function to determine whether it is enabled.

You will however need to raise the CanExecuteChanged event to inform the command that the value has changed.

END EDIT

Assuming _viewModel implements INotifyPropertyChanged you can hook when your viewmodel changes and raise the changed event on your command:

I've provided two versions, one using the explicit implementation of ICommand the other just implementing the properties and methods without the explicit ICommand prefix. Both should work. I would usually use version 2 unless there was a conflict on the methods that had a specific requirement.

EDIT VERSION 1 - Explicit Implementation

internal class ReadInventoryFilesCommand : ICommand
{
  public ReadInventoryFilesCommand(ResourceViewModel viewModel)
  {
    _viewModel = viewModel;
    _viewModel.PropertyChanged+= (s,e) => { 
                                  if (e.PropertyName == "CanUpdate") RaiseCanExecuteChanged();
                                 };
  }

  event EventHandler ICommand.CanExecuteChanged { add; remove; }

  private ResourceViewModel _viewModel;

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

  void ICommand.Execute(object parameter)
  {
    _viewModel.ReadInventroyFiles(parameter.ToString());
  }

  void RaiseCanExecuteChanged() {
    var handler = ((ICommand)this).CanExecuteChanged;
    if (handler != null) handler(this,EventArgs.Empty);
  }
}

EDIT Version 2

internal class ReadInventoryFilesCommand : ICommand
{
  public ReadInventoryFilesCommand(ResourceViewModel viewModel)
  {
    _viewModel = viewModel;
    _viewModel.PropertyChanged+= (s,e) => { 
                                  if (e.PropertyName == "CanUpdate") RaiseCanExecuteChanged();
                                 };
  }

  public event EventHandler CanExecuteChanged;

  private ResourceViewModel _viewModel;

  public bool CanExecute(object parameter)
  {
    return _viewModel.CanUpdate;
  }

  public void Execute(object parameter)
  {
    _viewModel.ReadInventroyFiles(parameter.ToString());
  }

  void RaiseCanExecuteChanged() {
    var handler = this.CanExecuteChanged;
    if (handler != null) handler(this,EventArgs.Empty);
  }
}
Sign up to request clarification or add additional context in comments.

12 Comments

Sorry, but as explained I am new to this. Where does the different code from above belong to.
This is to replace your existing definition for the command class
I tried it and get: The name 'RaiseCanExecutedChanged' does not exist in the current context Commands\ReadInventoryFilesCommand.cs
@theAlse it's a typo, I'll correct the answer, it should be RaiseCanExecuteChanged
Maybe it should be mentioned that, when using commands with buttons, it is not required to set the IsEnabled property of the Button manually. This is done automatically by the Button itself based on the return value of the CanExecute(object) method of the used ICommand.
|
2

This is the default behaviour when binding IsEnabled to Items.Count.

For example

<ListView x:Name="RulesList" />
<Button IsEnabled="{Binding Items.Count, ElementName=RulesList}" />

In this example Button will be disabled when the ListView has no items and will be enabled when it has 1 or more items.

Comments

1

I think you can use binding with converters: Code Windows1.xaml:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300"
        xmlns:converters="clr-namespace:WpfApplication1"
        >
    <Window.Resources>
        <converters:CoverterItemsSource2Enabled x:Key="converter" />
    </Window.Resources>
    <Grid Margin="0,0,-256,0">
        <ListView x:Name="listView" HorizontalAlignment="Left" Margin="10,10,0,10" VerticalAlignment="Stretch" Width="196">
            <ListView.View>
                <GridView>
                    <GridViewColumn/>
                </GridView>
            </ListView.View>
        </ListView>
        <Button Content="Button" HorizontalAlignment="Left" Margin="211,10,0,0" VerticalAlignment="Top" IsEnabled="{Binding Path=Items, ElementName=listView, Converter={StaticResource converter} }" Width="75"/>

    </Grid>
</Window>

Code converter:

namespace WpfApplication1
{
    class CoverterItemsSource2Enabled : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                return false;
            if(value is ItemCollection)
            {
                if ((value as ItemCollection).Count > 0)
                    return true;
            }
            return false;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

2 Comments

However the code uses a command so the CanExecute logic should really be handled by the command.
Yes, but i also read about IsEnabled properties trying, It will work.
0

Are you talking about this?:

private void ListView1_SourceUpdated(object sender, DataTransferEventArgs e)
 {
   Button1.IsEnabled==(ListView1.Items.Count>0);
 }

1 Comment

Yes, but I was hoping this can somehow be done in accordance with the MVVM guidelines, which is to separate code and design!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.