Routed Command Question - wpf

I'd like to implement a custom command to capture a Backspace key gesture inside of a textbox, but I don't know how. I wrote a test program in order to understand what's going on, but the behaviour of the program is rather confusing. Basically, I just need to be able to handle the Backspace key gesture via wpf commands while keyboard focus is in the textbox, and without disrupting the normal behaviour of the Backspace key within the textbox. Here's the xaml for the main window and the corresponding code-behind, too (note that I created a second command for the Enter key, just to compare its behaviour to that of the Backspace key):
<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">
<Grid>
<TextBox Margin="44,54,44,128"
Name="textBox1" />
</Grid>
</Window>
And here's the corresponding code-behind:
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for EntryListView.xaml
/// </summary>
public partial class Window1 : Window
{
public static RoutedCommand EnterCommand = new RoutedCommand();
public static RoutedCommand BackspaceCommand = new RoutedCommand();
public Window1()
{
InitializeComponent();
CommandBinding cb1 = new CommandBinding(EnterCommand, EnterExecuted, EnterCanExecute);
CommandBinding cb2 = new CommandBinding(BackspaceCommand, BackspaceExecuted, BackspaceCanExecute);
this.CommandBindings.Add(cb1);
this.CommandBindings.Add(cb2);
KeyGesture kg1 = new KeyGesture(Key.Enter);
KeyGesture kg2 = new KeyGesture(Key.Back);
InputBinding ib1 = new InputBinding(EnterCommand, kg1);
InputBinding ib2 = new InputBinding(BackspaceCommand, kg2);
this.InputBindings.Add(ib1);
this.InputBindings.Add(ib2);
}
#region Command Handlers
private void EnterCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
MessageBox.Show("Inside EnterCanExecute Method.");
e.CanExecute = true;
}
private void EnterExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Inside EnterExecuted Method.");
e.Handled = true;
}
private void BackspaceCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
MessageBox.Show("Inside BackspaceCanExecute Method.");
e.Handled = true;
}
private void BackspaceExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Inside BackspaceExecuted Method.");
e.Handled = true;
}
#endregion Command Handlers
}
}
Any help would be very much appreciated. Thanks!
Andrew

Try adding the input bindings and command bindings to the textblock instead of the main window.
In XAML:
<TextBox x:Name ="tb1"/>
In Code
tb1.CommandBindings.Add(cb2);
....
tb1.InputBindings.Add(ib2);
I'm not sure why, but when you hit the backspace, the textblock prevents the keydown event from bubbling up to the window. (You can test this by adding a handler to the KeyDown event on the main window. When you press Enter, the handler fires, but when you press backspace, the event handler does not). Since RoutedCommands are based on RoutedEvents, as described in this post by Josh Smith, it means that the command on the window never fires.

Related

WPF not load a control

I write a very easy UserControl
here the Xaml code
<UserControl x:Name="Test1" x:Class="WpfAppXtesting.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfAppXtesting"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" Loaded="Test1_Loaded">
<Grid x:Name="GridRoot" Background="Aqua">
<TextBlock x:Name="status" HorizontalAlignment="Left" Height="137" Margin="100,137,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="483" FontSize="48"/>
</Grid>
and here the code behind
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
this.GridRoot.DataContext = this;
}
private void UserControl1_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "Connected":
status.Text = ((App)sender).Connected.ToString() ;
break;
}
}
private void Test1_Loaded(object sender, RoutedEventArgs e)
{
(Application.Current as App).PropertyChanged += UserControl1_PropertyChanged;
}
}
the problem is , when import this control in a Window in same project The design mode gets this error.
NullReferenceException: Object reference not set to an instance of an object.
if I run the project everything was good.
If I commented the line in Loaded method
the control was right shown in design mode.
Any Idea?
thanks
Do not assume that Application.Current is your application at design time. For example, when you are using Expression Blend, Current is Expression Blend. At design time, MainWindow is not your application's main window. Typically operations that cause a user/custome control to fail at design time include the following.
Casting Current to your custom subclass of App.
Casting MainWindow to your custom subclass of Window.
Here are two approaches to writing code for design time. The first approach is to write defensive code by checking the null condition. The second approach is to check whether design mode is active by calling the GetIsInDesignMode method. You can read about GetIsInDesignMode at here.
Solution 1:
private void Test1_Loaded(object sender, RoutedEventArgs e)
{
var app = Application.Current as App;
if( app != null)
{
app.PropertyChanged += UserControl1_PropertyChanged;
}
}
Solution 2 :
private void Test1_Loaded(object sender, RoutedEventArgs e)
{
if (!DesignerProperties.GetIsInDesignMode(this))
{
// Design-mode specific functionality
(Application.Current as App).PropertyChanged += UserControl1_PropertyChanged;
}
}

How to get all windows close when you select 'Close All Windows' on the app's taskbar icon?

So I've been doing research on this for quite a few weeks now, and haven't really come up with an answer on why this doesn't work properly... I've even researched JumpLists to see if this was what I was looking for, but also to no avail. This problem relates to when you attempt to select 'Close All Windows' by right clicking an app's icon on the task bar...
For example, here is an EXTREMELY small and simple WPF application I wrote to demonstrate the problem I am having. Here is the app's icon in the task bar with its choices on the context menu for it...
contextmenutoolbar
I am selecting the choice 'Close all windows', for reference (the bottom one, with the X to the left of it).
This is a WPF application and here is the code for App.xaml:
<Application x:Class="CloseAllWindows.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Application.Resources>
</Application.Resources>
</Application>
Here is App.xaml.cs, which launches the MainWindow. It also sets the application's MainWindow property to the MainWindow that is instantiated. It also sets ShutdownMode to be only when the main window is closed... I don't want the application to still run if the main window is closed and some secondary windows are left open.
using System.Windows;
namespace CloseAllWindows
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
ShutdownMode = ShutdownMode.OnMainWindowClose;
var mainWindow = new MainWindow();
Application.Current.MainWindow = mainWindow;
mainWindow.Show();
}
}
}
Here is the code for MainWindow.xaml:
<Window x:Class="CloseAllWindows.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CloseAllWindows"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<Button Content="NewWindow" Click="ButtonBase_OnClick"></Button>
</StackPanel>
</Window>
And here is the code behind for it... which launches a secondary window when I click a button. It is setting the parent window (Owner property) to the main window, like all the examples I've seen say it should be set, and then call Show() on it.
using System;
using System.ComponentModel;
using System.Windows;
namespace CloseAllWindows
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var childWindow = new ChildWindow {Owner = this};
childWindow.Show();
}
}
}
Here is the code for the child window, ChildWindow.xaml:
<Window x:Class="CloseAllWindows.ChildWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CloseAllWindows"
mc:Ignorable="d"
Title="ChildWindow" Height="300" Width="300">
<Grid>
</Grid>
</Window>
And it's corresponding code behind, ChildWindow.xaml.cs:
using System;
using System.Windows;
namespace CloseAllWindows
{
/// <summary>
/// Interaction logic for ChildWindow.xaml
/// </summary>
public partial class ChildWindow : Window
{
public ChildWindow()
{
InitializeComponent();
}
}
}
As you can see, these classes do not do very much... it was the simplest example of code I could write that shows the problem I am having. So the issue is, if I select Close all windows from the task bar context menu, it never closes all the windows. Instead, it will close the one child window, and still leave the main window open. Interestingly, I hear the windows dialogue chime when I do this, almost like its getting interrupted by something, but I have no idea what.
It also appears to act very randomly... if I spawn 20 windows, it will sometimes close 6 of the windows, then all of them... sometimes it will close a few windows one by one, then close the rest... sometimes it will close all child windows and leave only the main window open. Needless to say, I am pretty baffled as to the behaviour since it doesn't seem to follow any noticeable pattern... any help greatly appreciated! And hopefully the example is good enough to explain what I am trying to get at....
Well you could add an event that will close every window the event is implanted in. try this example:
step 1: add a class to your project call it whatever you want, I called it CloseWindowListener, add this code to your class:
public static class CloseWindowListener
{
public static event EventHandler<EventArgs> ClosingWindows;
public static void CloseWindows()
{
var CWindows = ClosingWindows;
if (CWindows != null)
{
CWindows(null, EventArgs.Empty);
}
}
}
step 2: Add the event handler to the window you desire to close when it is called.
public partial class TestWindow1 : Window
{
public TestWindow1 ()
{
InitializeComponent();
CloseWindowListener.ClosingWindows += CloseWindowListener_ClosingWindows;
}
private void CloseWindowListener_ClosingWindows(object sender, EventArgs e)
{
this.Close();
}
}
step 3: simply call the event from your main window or where ever you want.
private void button_Click_1(object sender, RoutedEventArgs e)
{
CloseWindowListener.CloseWindows();
}

focus visual not showing when navigating focus programically

Whenever I try to move focus programmatically the focus visual (the dotted rectangle) does not display.
What can be done to force this visual to display?
<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="525" Loaded="OnLoaded">
<StackPanel>
<TextBlock x:Name="a" Focusable="True">A</TextBlock>
<TextBlock Focusable="True">B</TextBlock>
<Button Focusable="False" Click="OnClick">Move Focus</Button>
</StackPanel>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Keyboard.Focus(a);
}
private void OnClick(object sender, RoutedEventArgs e)
{
var request = new TraversalRequest(FocusNavigationDirection.Next);
var elementWithFocus = Keyboard.FocusedElement as UIElement;
if (elementWithFocus != null)
elementWithFocus.MoveFocus(request);
}
}
If you look (in reflector/ilspy) at the KeyboardNavigation's ShowFocusVisual you'll find that the framework will only show it if the last input was from the keyboard (or if an internal static property based on the KeyboardCues system parameter info is true). So I don't think there is a good way to do this short of using reflection to temporarily set that property or asynchronously focusing the element and forcing a keyboard action (maybe using the winforms SendKeys or keybd_event api) but I wouldn't recommend either.

Mapping TouchMove Events to MouseMove Events in WPF

I'm implementing a simple drag and drop feature in a WPF application. I want this application to run on both desktops with no touch support and also on tablets with only touch support.
Currently I have a MouseMove and TouchMove handler, both implementing the same logic (Starting the DoDragDrop()).
How can I route the input from touch to the mouse handler or visa versa to reduce redundant code? Further how would one route a simple tap to a click event?
I just done a quick test and one way to do this is to create a Global event handler.
Since TouchEventArgs and MouseButtonEventArgs derive from InputEventArgs, your global handler will just implement InputEventArgs
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
//private void Button_TouchMove(object sender, TouchEventArgs e)
//{
// TouchEventArgs derives from InputEventArgs
//}
// private void Button_MouseMove(object sender, MouseButtonEventArgs e)
//{
// MouseButtonEventArgs derives from InputEventArgs
//}
private void GlobalHandler(object sender, InputEventArgs e)
{
// This will fire for both TouchEventArgs and MouseButtonEventArgs
// If you need specific information from the event args you can just cast.
// e.g. var args = e as MouseButtonEventArgs;
}
}
Xaml:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid >
<Button MouseMove="GlobalHandler" TouchMove="GlobalHandler"/>
</Grid>
</Window>
Hope this helps

Adding programatically a command to a listbox in WPF

In my WPF application there is a listbox with items. The listbox is populated via a xmldataprovider from XAML and then binding it to Itemssource property of the listbox.
Well, from XAML, I bind a comand to the listbox by doing:
<ListBox.CommandBindings>
<CommandBinding
Command="{x:Static local:mainApp.MyCmd}"
CanExecute="CanExecute"
Executed ="Executed" />
</ListBox.CommandBindings>
but I don't know how to programatically bind a command to each listboxitem. How to do it?
Thanks in advance.
First sorry by not posting it as a comment. I can't put all this in a comment.
Ok, yes I am not using the Executed and CanExecute properties of the ICommandSource despite I have registered and implemented them in custom class (in xaml they are commented too). I have specified them in routedCommand but not in custom class, I have done it in the constructor of the window by doing this:
WinMain code behind:
public WinMain()
{
InitializeComponent();
// Command binding. If I don't do this Executed and CanExecute are not executed
CommandBindings.Add(new CommandBinding(rcmd,
CommandBinding_Executed, CommandBinding_CanExecute));
}
and then I implement these methods in WinMain code behind too as it:
// ExecutedRoutedEventHandler
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
// Do stuff
}
// CanExecuteRoutedEventHandler
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
// cBgWorkers is a class that check if a background worker is running
e.CanExecute = !cBgWorkers.isRunning;
//if (LayoutListBox != null) LayoutListBox.IsEnabled = !cBgWorkers.isRunning;
}
and In WinMain XAML I invoke the command like this:
<Classes:CommandListBox x:Name="LayoutListBox"
Command="{x:Static local:WinMain.rcmd}"
... >
<...>
</Classes:CommandListBox>
And in my custom class CommandListBox I have a CanExecuteChanged in which you can see I enabled or disabled the control depending on whether the background worker is finished or not:
private void CanExecuteChanged(object sender, EventArgs e)
{
this.Enabled = !cBgWorkers.isRunning;
}
but in custom class I haven't implement the event handler you say, OnSelected.
WIthout implementing it all goes ok, the custom control invoke command, and CanExecute method is reached, and CanExecute gets correct value, true or false depending on background worker is finished or not, and the CanExecuteChanged in custom control is raised when CanExecute changes its value. When background worker starts it gets disabled but when it finished it doesn't get enabled. I have debugged, and when background worker finishes I can see CanExecuteChanged is executed and this.Enabled is getting correct value (true) but for some reason in the UI the control continues disabled despite it gets its correct value and despite in RunWOrkerCompleted (in background worker) I force to update UI with CommandManager.InvalidateRequerySuggested().
I solve this by uncomment line:
if (LayoutListBox != null) LayoutListBox.IsEnabled = !cBgWorkers.isRunning;
in CanExecute method. I don't understand what happens.
Then If I do what you say It is not necessary to do it:
CommandBindings.Add(new CommandBinding(rcmd,
CommandBinding_Executed, CommandBinding_CanExecute));
and CommandBinding_Executed & CommandBinding_CanExecute implementations. Am I right?
but if I remove these methods where can I set this.enabled = !cBgWorkers.isRunning ?
I would like WPF to set automatically isEnabled property for my custom control. How to do this?
Thanks in advance.
I am applying the article you say about attached behaviors with a few changes to adapt it to my ListBox. It doesn't work well or perhaps I am doing something wrong. What I want is avoid that ListBox members (listBoxItems) can be select when a long task (background worker) is running. So one of the method of the article that I have modified is:
static void OnListBoxItemSelected(object sender, RoutedEventArgs e)
{
// Only react to the Selected event raised by the ListBoxItem
// whose IsSelected property was modified. Ignore all ancestors
// who are merely reporting that a descendant's Selected fired.
if (!Object.ReferenceEquals(sender, e.OriginalSource))
return;
ListBoxItem item = e.OriginalSource as ListBoxItem;
if (item != null)
{
// (*) See comment under
item.IsEnabled = !cBgWorkers.isRunning;
if (!cBgWorkers.isRunning)
{
item.BringIntoView();
}
}
}
(*) cBgWorkers is a public static Class that has some methods and properties.
One of the properties is isRunning that indicates no background workers is currently running. Then If no background workers is running, listbox members have to be enabled otherwise they have to be disabled so when user clicks over one listbox item the current page don't change to another one because I disabled it before (each listBox items has attached one page in my main application).
When one of the background workers (bw) or all are running and I select listbox item all is ok: listbox item is disabled because there are bw running and it avoid tho change the current page to another one. Of course, If I disabled the listbox item (or listbox items) I can't select it again because it is disabled and that is my problem, because I want that when bw finish the listbox items that have been disabled while bw were running, they get enabled again. Unfortunately with attached behavior as I see it isn't done by WPF automatically and commands have this advantage (controls update automatically by WPF). so, how to disabled/re-enabled listbox items when bw is running or not respectively?
As far as I know and see, one advantage of attached behaviors is that I think it is more efficient because they are not invoking actions constantly (only when the action, for example, selection, is produced). Commands are constantly (not often) checking if actions binded to controls can be executed (so If they can be executed, WPF automatically enables controls otherwise they appear disabled), right?
Thanks.
you could try creating a custom control that derives from ListBoxItem and implementing the ICommandSource interface. I can't think of a more simple solution as of now.
I have done your solution. I have done a custom user control deriving from listbox and implementing ISourceCommand as you said and it works now!!!! ;)
My custom class:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Input;
namespace GParts.Classes
{
public class CommandListBox : ListBox, ICommandSource
{
public CommandListBox() : base()
{
}
// ICommand Interface Members
// Make Command a dependency property so it can use databinding.
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(CommandListBox),
new PropertyMetadata((ICommand)null,
new PropertyChangedCallback(CommandChanged)));
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
// Make Command a dependency property so it can use databinding.
public static readonly DependencyProperty ExecutedProperty =
DependencyProperty.Register(
"Executed",
typeof(object),
typeof(CommandListBox),
new PropertyMetadata((object)null));
public object Executed
{
get
{
return (object)GetValue(ExecutedProperty);
}
set
{
SetValue(ExecutedProperty, value);
}
}
// Make Command a dependency property so it can use databinding.
public static readonly DependencyProperty CanExecuteProperty =
DependencyProperty.Register(
"CanExecute",
typeof(object),
typeof(CommandListBox),
new PropertyMetadata((object)null));
public object CanExecute
{
get
{
return (object)GetValue(CanExecuteProperty);
}
set
{
SetValue(CanExecuteProperty, value);
}
}
// Make CommandTarget a dependency property so it can use databinding.
public static readonly DependencyProperty CommandTargetProperty =
DependencyProperty.Register(
"CommandTarget",
typeof(IInputElement),
typeof(CommandListBox),
new PropertyMetadata((IInputElement)null));
public IInputElement CommandTarget
{
get
{
return (IInputElement)GetValue(CommandTargetProperty);
}
set
{
SetValue(CommandTargetProperty, value);
}
}
// Make CommandParameter a dependency property so it can use databinding.
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register(
"CommandParameter",
typeof(object),
typeof(CommandListBox),
new PropertyMetadata((object)null));
public object CommandParameter
{
get
{
return (object)GetValue(CommandParameterProperty);
}
set
{
SetValue(CommandParameterProperty, value);
}
}
// Command dependency property change callback.
private static void CommandChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
CommandListBox clb = (CommandListBox)d;
clb.HookUpCommand((ICommand)e.OldValue,(ICommand)e.NewValue);
}
// Add a new command to the Command Property.
private void HookUpCommand(ICommand oldCommand, ICommand newCommand)
{
// If oldCommand is not null, then we need to remove the handlers.
if (oldCommand != null)
{
RemoveCommand(oldCommand, newCommand);
}
AddCommand(oldCommand, newCommand);
}
// Remove an old command from the Command Property.
private void RemoveCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = CanExecuteChanged;
oldCommand.CanExecuteChanged -= handler;
//newCommand.Execute(null);
//newCommand.CanExecute(null);
}
// Add the command.
private void AddCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = new EventHandler(CanExecuteChanged);
canExecuteChangedHandler = handler;
if (newCommand != null)
{
newCommand.CanExecuteChanged += canExecuteChangedHandler;
//newCommand.Execute(Executed);
//newCommand.CanExecute(CanExecute);
}
}
private void CanExecuteChanged(object sender, EventArgs e)
{
if (this.Command != null)
{
RoutedCommand command = this.Command as RoutedCommand;
// If a RoutedCommand.
if (command != null)
{
if (command.CanExecute(CommandParameter, CommandTarget))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
// If a not RoutedCommand.
else
{
if (Command.CanExecute(CommandParameter))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
}
}
// Keep a copy of the handler so it doesn't get garbage collected.
private static EventHandler canExecuteChangedHandler;
}
}
and in my WinMain.xaml:
<Classes:CommandListBox x:Name="LayoutListBox"
Command="{x:Static local:WinMain.rcmd}"
<!-- These lines doesn't work I explain it following
Executed="CommandBinding_Executed"
CanExecute="CommandBinding_CanExecute"
-->
... >
<...>
</Classes:CommandListBox>
and window code behind:
public WinMain()
{
InitializeComponent();
// Command binding. If I don't do this Executed and CanExecute are not executed
CommandBindings.Add(new CommandBinding(rcmd,
CommandBinding_Executed, CommandBinding_CanExecute));
}
public static RoutedCommand rcmd = new RoutedCommand();
// ExecutedRoutedEventHandler
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
// Do stuff
}
// CanExecuteRoutedEventHandler
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = !cBgWorkers.isRunning;
//if (LayoutListBox != null) LayoutListBox.IsEnabled = !cBgWorkers.isRunning;
}
but I have the same problem as the another solution. If I don't place the last line (here appears commented in CommandBinding_CanExecute) the listbox doesn't enable automatically by wpf when background worker finishes. If I put this line it works. What's happens?
Another thing, as you can see in my code snippet I would like to do the same as I do with a button where you can indicate command, executed and canexecute. I have registered them in the class, and in listbox I checked to pass the methods but it didn't work. How can I do this?
Thanks very much.
Take a look at attached behaviors.
According to the first question I posted, using CommandBindings in listbox it doesn't work. The implementation of CanExecute was:
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = !cBgWorkers.isRunning;
}
By doing WPF doesn't enable/disabled the listbox control automatically depending on the background worker state (Running or not) and I don't understand why because I have other controls like buttons with commands binded and WPF automatically enable/disable them.
So I have done the following modification:
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = !cBgWorkers.isRunning;
if (LayoutListBox != null) LayoutListBox.IsEnabled = !cBgWorkers.isRunning;
}
Now, it works. Listbox is enable when no background worker is running and disabled otherwise bu what I don't like is the last line placed into the method in where I enable/disable manually the property isEnabled of the listbox. It is inefficient so I would like to change isEnabled property of the listbox only when CanExecute changes its value. As far as I know there is a event to do this, it is CanExecuteChanged but I don't know how to implement it. Any ideas?
Now, after trying several solutions, I am implementing the Mike's solution because I think it is easier and clearer and it can be re-used for other controls with only a few changes.
I haven't been able the whole thread. It's quite long. Anyway, I thought you want to put a command on a ListBoxItem? From what I see, you inherited from ListBox. You do not need to specify the Executed and CanExecute properties of the ICommandSource. This should be specified in your RoutedCommand, not in your custom control. To get your command executed, you need to provide an event handler in your custom control. As an example, if an item gets selected, then you execute the command. Here's an example.
protected override void OnSelected(RoutedEventArgs e)
{
base.OnSelected(e);
if (this.Command != null)
{
RoutedCommand command = Command as RoutedCommand;
if (command != null)
{
command.Execute(CommandParameter, CommandTarget);
}
else
{
((ICommand)Command).Execute(CommandParameter);
}
}
}

Resources