views:

626

answers:

4

Hi,

I have implemented a custom IComand class for one of my buttons. The button is placed in a page 'MyPage.xaml' but its custom ICommand class is placed in another class, not in the MyPage code behind. Then from XAML I want to bind the button with its custom command class and then I do:

MyPage.xaml:

    <Page ...>

         <Page.CommandBindings>
             <CommandBinding Command="RemoveAllCommand"
                CanExecute="CanExecute"
                Executed="Execute" />
         </Page.CommandBindings>

         <Page.InputBindings>
                <MouseBinding Command="RemoveAllCommand" MouseAction="LeftClick" />
         </Page.InputBindings>

             <...>
               <Button x:Name="MyButton"  Command="RemoveAllCommand" .../>
             <...>

    </Page>

and the custom command button class:

// Here I derive from MyPage class because I want to access some objects from 
// Execute method
public class RemoveAllCommand : MyPage, ICommand 
{

    public void Execute(Object parameter)
    {
        <...>
    }

    public bool CanExecute(Object parameter)
    {
        <...>
    }


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

}

My problem is how to say MyPage.xaml that Execute and CanExecute methods for the button is in another class and not the code behind where is placed the button. How to say these methods are in RemoveAllCommand Class in XAML page.

Also I want to fire this command when click mouse event is produced in the button so I do an input binding, is it correct?

Thanks

A: 

Since you have an ICommand, you can bind it to the Button through the Command property, and the button will use it, i.e. it will call CanExecute to enable/disable itself and the Execute method when the button is pressed. There is no need for any other input binding.

Now the problem is that the button has to find the command. A simple solution is to put an instance of the command in the DataContext of the button (or of its parents).

If the DataContext has a property called RemoveAll of type RemoveAllCommand, you can simply change your XAML button to:

<Button Command="{Binding RemoveAll}" .. />

and remove the CommandBinding and InputBinding

Timores
Hey, I have done it but with no success, I received error when building project: Cannot create an instance of type RemoveAllCommand.I explain it in my answer posted.
toni
A: 

hey!

Hey, I have done it but with no success, I received error when building project: Cannot create an instance of type RemoveAllCommand.

I have done it:

MyPage.xaml (I have removed CommandBinding and InputBinding from page):

<Page  x:Class="GParts.Pages.MyPage" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;
assembly=PresentationFramework.Aero"            
xmlns:Classes="clr-namespace:GParts.Classes"   
xmlns:Pages="clr-namespace:GParts.Pages">

<Page.Resources>
      <...>
         <Pages:RemoveAllCommand x:Key="RemoveAllCommandInstance"/>
      <...>
</Page.Resources>

<...>
<Button Command="{Binding RemoveAllCommandInstance}" ...>  
<...>
</Page>

In the custom Icommand class I have added a constructor with no parameters:

public class RemoveAllCommand : MyPage, ICommand 
{

    public RemoveAllCommand() { }

    ...
}

Thanks.

toni
Here the problem is that you should use {StaticResource RemoveAllCommandInstance} to get at the command.
Timores
A: 

Hey!

I have done another implementation, but it continues with no working. And despite of forcing e.CanExecute always to true in CanExecute method my button always appears disabled. Why?

In my new implementation it is like:

MyPage.xaml (I remove the CommandBinding and InputBinding), so the only diference is that:

      <Button Command="{x:Static Pages:RemoveAllCommandClass._routedCommand}" .../>

and my new custom class for this is:

public class RemoveAllCommandClass : MyPage
{
    // The custom command.
    // Note, the command binding is done in XAML.
    public static RoutedCommand _routedCommand  =  new RoutedCommand();

    // ExecutedRoutedEventHandler for the custom button remove all command.
    private void Execute(object sender, ExecutedRoutedEventArgs e)
    {
       // Do Stuff
       // Here I call a backgroundworker defined in another class
    }

    // CanExecuteRoutedEventHandler for the custom button remove all command.
    private void CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true; // Force to always true for debugging. Here when no 
                             // debugging is true when backgbround worker is not 
                             // running. 
    }

}

but the button always appears disabled despite of forcing it to true. Why?

Thanks

toni
The initialization of the _routedCommand should be:public static RoutedCommand _routedCommand = new RemoveAllCommandClass();
Timores
A: 

oK, Thanks, tomorrow I'll try it.

Now to avoid problems I have moved all in RemoveAllCommandClass Class to the code behind of MyPage and I have done some modifications.

1.- I added this to MyPage.xaml:

xmlns:local="clr-namespace:GParts"

then I have done:

<Page.CommandBindings>
    <CommandBinding Command="{x:Static local:Pages.MyPage._routedCommand}"
               Executed="Execute"
               CanExecute="CanExecute"/>
</Page.CommandBindings>


<Button Command="{x:Static local:Pages.MyPage._routedCommand}"  .../>

And all is ok and works. When I press button it executes background worker (bw) that is called in Execute method. bw is into another class. In background worker class I have a variable (isRunning) that indicates if the bw is executing. Before executing DoWork event I set it to true and when bw completes, at RunWorkerCompleted, I set it to false. So from CanExecute I check isRunning in bw class and I set to true e.canExecute if isRunning is false, and e.canExecute to false if isRunning is true. So the button is disabled by WPF automatically when bw is running but when bw finishes the button continues disabled and not returns to enabled until I press it again. Why is WPF not updating the button state to enabled when bw finishes until I press again the button?

Thanks.

toni
You should tell WPF that the command state has changed. There is the CanExecuteChanged event for this purpose.
Timores