views:

70

answers:

5

I want to initiate a bound command, but I don't want to use a Button on my UserControl. In effect the UserControl is itself a Button. When it is clicked anywhere on its surface I want to initiate a bound command. Is there a way to give a UserControl a command?

In a side note: one command for one control and only a few certain out-of-the-box controls? This all seems a little clunky. I'm starting to think that MVVM is impractical. I can decouple my UI just fine with Interfaces and OOP. Anyway, I still have hope.

Also, I'm not willing to hack anything or use an expensive workaround. If I can't do this, I'm abandoning MVVM.

+4  A: 

If your UserControl is essentially a Button, why are you writing your own UserControl instead of using the Button class?

To add more info, here's what you do:

  1. Subclass Button, put any extra DependencyProperties that you need in there - it should be a very empty class (you could even have something like public class MyCoolButton : Button { }
  2. Add a Style whose TargetType is MyCoolButton - don't name the style so it applies to all MyCoolButtons
  3. Override the default Template of the style, then paste in your Xaml code. You might have to do some work here to handle the "Normal / Pushed / Disabled" states. If you're using v4.0, you can use VSM here.
Paul Betts
This is a workaround. You guys don't understand. I know how to "get it to work." I don't want it to just work, I want to love how it works, and I just don't love the command architecture. Most everything else about MVVM I do like, but this is clunky.
Jordan
@Jordan, The thing with Commands is that they only make sense if you have a Control that knows how to interpret CanExecute and knows what condition should trigger Execute. If you want to provide a custom interpretation of command binding, then you need to implement the appropriate interfaces. Thankfully, this kind of low-level implementation is less frequent in WPF, since you can usually style or template existing controls to take advantage of existing command patterns.
Dan Bryant
This is not a workaround, this is the *correct* way to do this.
Paul Betts
+1  A: 

I will agree with Paul Betts.

Quite often I create my own ListBoxItemContainerStyle using a button as the top container with nothing but a propertyless content presenter in it. This allows me to use the buttons functionality (like Command) without having the Windows chrome on it.

Putting it in the ListBoxItemContainerStyle also lets me make it so that when it is clicked it does not display the normal dotted border (FocusVisualStyle={x:Null}).

Are you using Visual Studio or Expression Blend to do your styling?

Additionally, some MVVM frameworks provide an interface for adding a command-ish ability to controls other than buttons. Caliburn has a pretty rich command pattern. I am not sure if it allows binding commands on non-button controls, however.

OffApps Cory
Helpful, but not exactly what I'm looking for. I know how to trick out the styles like that. I don't want to use a button! I want my command logic to make sense, and having to have a stupid button in place just to bind to commands doesn't. Thanks for the answer. :)
Jordan
A: 

WPF supports layers and transparency :

Panel.ZIndex

You can create anything that supports commanding on a superior transparent layer, the size you want, to act as a button.

Matthieu
This is what I mean by a hack.
Jordan
@Jordan, interestingly, the default control template for a WPF Button uses transparent layering in its implementation. the visibility of the various layers is animated to provide things such as hover-over and mouse-down effects.
Dan Bryant
+3  A: 

Take a look at the ICommandSource interface here: http://msdn.microsoft.com/en-us/library/system.windows.input.icommandsource.aspx. If you want a control to have a command, then your control should implement this interface. Examples of controls that implement this interface are ButtonBase and MenuItem. Hope this helps.

Michael Detras
I'm just sore about having limited lines of communication to the back end. Coming from the rich event-driven world of WinForms, its hard to get used to having narrow undefined pipes back to the logic layer. This answer is exactly what I wanted; a way to create my own command interface without having to use a stupid button! Thanks Michael.
Jordan
+1  A: 

The OP asked for an example of how you could use a button control, but with the content properly filling the entire button. You can do this using the ContentAlignment properties:

<Button HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
    <Button.Content>
        <Grid IsHitTestVisible="False">
            <Grid.RowDefinitions>
                <RowDefinition Height="30" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Text="Row0" />
            <TextBlock Grid.Row="1" Text="Row1" />
        </Grid>
    </Button.Content>
</Button>

This creates a button with two labels spaced using a Grid control. I mark the Grid to turn off HitTestVisible, as you have to decide which controls should interact like the button and which should interact like controls. For instance, you might have an embedded TextBox that you want to be clickable without clicking the button, in which case it should have HitTestVisible=True.

Dan Bryant