Bizarre Command Issue
- I have a window that is Outlook like, it is broken into 2 regions (a side bar, and a main content region). The regions are populated with various user controls, depending on the current task being worked on. The main menu is also a user control, which allows new menu items to be added to it, or have all its "extra" items cleared. I have defined commands to load each of these tasks (i.e. ViewEstimates or ViewJobs commands). The command bindings for all these tasks are defined in the window itself, so when the command is executed by an element in one of the user controls, it bubbles up to the window before being intercepted.
So, if the user clicks an element that has the ViewEstimates command assigned to it, the sidebar is loaded with a treeview of all estimates, the main content is loaded with the currently selected estimate details, and some menu items are added to the main menu (to add a new estimate, and view estimates).
Everything works as expected, accept one issue I really can't even begin to figure out what's going on....
If "ViewEstimates" is executed from the "Home" user control, the commands that assigned to the new menu items are always disabled (and only the commands in the menu items, anywhere else they are linked, works correctly)...period. If "ViewEstimates" is executed from anywhere else (like a button in the sidebar), which calls the exact same code as if it's called from the "Home" control, the menu items work correctly.
The reason I am stumped, is if it's executeding the EXACT same code, how does the result differ like this? I know the "ViewEstimates" command is being executed and handled, because if it weren't the "ViewEstimates" GUI wouldn't load. There is only one set of code that runs when the "ViewCommands" command is executed...regardless of where it's executeds from, so what could be different?
Any ideas?
Toutes les réponses
- OK, Ia lot of troubleshooting, and I have discovered the problem, though I am not sure how to fix it....
My first clue was that the trouble arises with controls that launch a "change gui command", and the control is in my sidebar and windows "content" areas. Part of my code that executes when the "change gui" commands are executed is to clear these content areas completely (including the control that launched the command), then reload them with the new content.
If any of the controls that are cleared are command controls, that's when the CanExecute gets messed up. I can only assume that clearing these controls, somehow breaks the command bindings, and thus any other controls subscribed to the commands in the window don't work as expected.
However, if I launch the command from a control not in either of these areas that get cleared (even if this happens after I "break" it), everything works correctly. So I know the command binding are still in place, it seems that in senario a, the links get broken somehow.
Any ideas, how to safely remove these controls, keeping my command bindings to other controls in the window intact? - To better illiustrate, rather than trying to sort through my ramblings, here's a simple page that reproduces the problem.
If you click "Save" from the toolbar, the content grid will be cleared, and all toolbar buttons remain enabled.
If you click save from the content grid, the gird will be cleared, and all toolbar buttons mysteriously are disabled. CommandManager.InvalidateRequerySuggested() does not resolve the issue.
However, as the Debug.Write shows, the CommandBinding.Count remains at 3
Code Block<Window x:Class="Testing_Window"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Testing_Window"
Height="300"
Width="300"
>
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Save" CanExecute="Command_CanExecute" Executed="Save_Executed"/>
<CommandBinding Command="ApplicationCommands.Close" CanExecute="Command_CanExecute" Executed="Close_Executed"/>
<CommandBinding Command="ApplicationCommands.Print" CanExecute="Command_CanExecute" Executed="Print_Executed"/>
</Window.CommandBindings>
<DockPanel LastChildFill="True">
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<Button Command="ApplicationCommands.Save" Content="Save"/>
<Button Command="ApplicationCommands.Close" Content="Close"/>
<Button Command="ApplicationCommands.Print" Content="Print"/>
</ToolBar>
</ToolBarTray>
<Grid x:Name="TestGrid">
<Button Command="ApplicationCommands.Save" Content="Save"/>
</Grid>
</DockPanel>
</Window>Code Blockpublic partial class Testing_Window : Window
{
public Testing_Window()
{
InitializeComponent();
}
private void Command_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void Save_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Save Executed");
System.Diagnostics.Debug.WriteLine(this.CommandBindings.Count);
TestGrid.Children.Clear();
System.Diagnostics.Debug.WriteLine(this.CommandBindings.Count);
}
private void Close_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Close Executed");
}
private void Print_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Print Executed");
}
} - One further tidbit....
If the bindings are attached directly to the control (as opposed to the window), they remain in tact. Though, this kind of defeats the purpose of a cental command if I have to attach a binding to every control, especially when the handlers will reside on a component other than which the control resides on.
If the above code is modified as follows, the Close button will properly remain enabled, even if the Save command is launched frm the "content" save button.
Code Block<ToolBarTray DockPanel.Dock="Top"><ToolBar>
<Button Command="ApplicationCommands.Save" Content="Save"/>
<Button Command="ApplicationCommands.Close" Content="Close"><Button.CommandBindings>
<CommandBinding Command="ApplicationCommands.Close" CanExecute="Command_CanExecute" Executed="Close_Executed"/>
</Button.CommandBindings>
</Button>
<Button Command="ApplicationCommands.Print" Content="Print"/>
</ToolBar>
</ToolBarTray> I'm running into the same issue. In my case however, the malfunctioning bindings are in menu bar items that are being dynamically created in code. This is the best description of the problem I've seen, so I tried your workaround. Since my items are created in code, I don't have to declare new CommandBindings for each item, I just copy all the Binding objects from the parent's CommandBindings collection each time I create a new menu item. This allows the original bindings to still be defined in a separate component.
I'd still like to know if this is really a bug - is there a better way to do this - or will it be fixed in a future framework version?
You can resolve this by setting Focusable="True" in TestGrid.
<Grid x:Name="TestGrid" Focusable="True">
<Button Command="ApplicationCommands.Save" Content="Save"/>
</Grid>

