views:

39

answers:

2

All I wanted was different bindings on different tabs, so switching tabs would toggle command availability. I thought CommandBindings worked that way.

But I've spent the last while trying to get this simple sample to work. Either I fundamentally misunderstand (and that would not be a first) or something's wrong.

I add a CommandBinding to textBoxA but NOT to textBoxB. Moving between them should enable and disable the button which is set to the corresponding command.

Adding the CommandBinding to the Window enables the button just fine, but that kind of kills the whole point of items-specific CommandBindings.

Using this XAML

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="500">
    <Canvas>
        <Button Canvas.Left="31" Canvas.Top="24" Content="Click Me" Name="button1" Width="100"/>
        <TextBox Canvas.Left="155" Canvas.Top="22" Height="23" Name="textBoxA" Width="120" Text="A" />
        <TextBox Canvas.Left="298" Canvas.Top="22" Height="23" Name="textBoxB" Width="120" Text="B" />
    </Canvas>
</Window>

Using this Code Behind

public MainWindow()
{
    InitializeComponent();

    button1.Command = ApplicationCommands.Open;

    var _Binding = new CommandBinding(button1.Command);
    textBoxA.CommandBindings.Add(_Binding);
    textBoxB.CommandBindings.Clear(); // nothing bound

    _Binding.CanExecute += (s, e) =>
    {
        e.CanExecute = true;
    };

    _Binding.Executed += (s, e) =>
    {
        MessageBox.Show("Hello");
    };
}

You'll see (if you try this code) that the button remains disabled, even as you move from one textbox to the other. (Even though textBoxA should enable the button because it implementes the button's CommandBinding).

How is this supposed to work?

Thank you in advance.

A: 

I cant see how this would work and it seems your missing the point (sorry) - CommandBindings are supposed to be applied to parent elements (putting it on the canvas will work as well). When the button is clicked then the RoutedCommand will 'bubble up' through the visual tree which means that any parent elements will have their events that have been bound to this command fired. The reason the button stays disabled is because you cant execute the open command at that point and the CommandBinding is not being evaluated as it is not in the execution path. see here:

http://msdn.microsoft.com/en-us/library/system.windows.input.commandbinding.aspx

Leom Burke
If you look here (http://stackoverflow.com/questions/1375483/wpf-textbox-interceping-routeduicommands) it shows that WPF has default bindings for a textbox (and probably other controls). I also know that copy/paste (for example) are defaulted for textbox. Not just on parent-like controls, such as canvas. Why would a textbox, for example, have a CommandBindings collection property if it couldn't do what I was suggesting. (BTW, thank you for the reply) Also, setting to Canvas (if there are two) has the same problem as my sample.
JerryNixon
As far as I know the purpose of the CommandBinding is to allow an element higher up the tree to listen and execute when a command is fired on an element lower down. Textboxes have the CommandBindings property because they are a UIElement and you can actually put a button inside a textbox with no problem and it would then pick up the buttons command events.
Leom Burke
A: 

I'll try to see if I can hit your scenario:

<Canvas>
    <Button ... Command="Open">
        <CommandBindings>
            <CommandBinding Command="Open" Executed="OnOpen"/>
        <CommandBindings>
    </Button>
    <TextBox ... >
        <CommandBindings>
            <CommandBinding Command="Open" Executed="OnOpen"/>
        <CommandBindings>
    </TextBox>
    <TextBox ... />
</Canvas>

And in code-behind:

private void OnOpen(object sender, ExecutedRoutedEventArgs e)
{
    MessageBox.Show("Hello");
}

The idea for CommandBindings is to be a short-cut for having common key-strokes work across buttons and other controls within a context (typically a usercontrol). Then each region can have different meanings for the Open-command (one will perhaps open a file - in another it will open the item selected in a ListView and so on).

In my example - hitting CTRL+O while either TextBox A or the button has the focus will trigger the 'Hello' MessageBox. But read the page Leom linked to for a deeper explanation.

Goblin
Thank you. So, my follow question would be that I want to use the Open Command, but I want a CommandBinding (say, OnOpen1()) when I am in TextBoxA and a different CommandBinding (say, OnOpen2()) when I am in TextBoxB. And, for good measure, I want the button disabled if I am in TextBoxC. A direct implementation, like yours, works fine. I realize that.
JerryNixon
Then you just exchange the Execute part of the CommandBinding in question. So, one eventhandler for TextBoxA and another for TextBoxB.However, you should remove the commandbinding for the button - then it should all work as it will respond to the CommandBinding that is 'nearest' in the VisualTree from logical focus - (TextBoxA's commandbinding if you are in TextBoxA and TextBoxB if you are there and so on).
Goblin