Toggle the checkbox status when double click in WPF - wpf

Created a simple checkbox in WPF.
The single click toggles the checkbox status in the UI.
I want the checkbox status to be changed when I double click on checkbox text. Please help me with code below.
The only control in the xaml:
<Grid>
<CheckBox Content="CheckBox" HorizontalAlignment="Left" Height="60" Margin="144,93,0,0" VerticalAlignment="Top" Width="392"/>
</Grid>

I could not find a solution with standart CheckBox Control. I've created my own checkBox via UserControl.
DoubleClickCheckBox.xaml (UserControl)
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" Loaded="Grid_Loaded">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<CheckBox Name="checkBox" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked"/>
<TextBlock Name="textBlock" MouseDown="TextBlock_MouseDown" TextAlignment="Center" Grid.Column="1" Margin="4,0,4,0"/>
</Grid>
DoubleClickCheckBox.xaml.cs (UserControl)
public partial class DoubleClickCheckBox : UserControl
{
public string Text { get; set; }
public bool IsChecked { get; set; }
public event EventHandler UserControlChecked;
public event EventHandler UserControlUnChecked;
public DoubleClickCheckBox()
{
InitializeComponent();
}
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
this.checkBox.IsChecked = this.IsChecked;
this.textBlock.Text = this.Text;
}
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
if(e.ClickCount == 2)
this.checkBox.IsChecked = !this.checkBox.IsChecked;
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
if (UserControlChecked != null)
UserControlChecked(this, EventArgs.Empty);
}
private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
{
if (UserControlUnChecked != null)
UserControlUnChecked(this, EventArgs.Empty);
}
}
MainWindow.xaml
<Grid>
<local:DoubleClickCheckBox VerticalAlignment="Center" HorizontalAlignment="Center" Background="Aqua" Text="Test" IsChecked="False" UserControlChecked="DoubleClickCheckBox_UserControlChecked" UserControlUnChecked="DoubleClickCheckBox_UserControlUnChecked"/>
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void DoubleClickCheckBox_UserControlChecked(object sender, EventArgs e)
{
this.Title = "Checked";
}
private void DoubleClickCheckBox_UserControlUnChecked(object sender, EventArgs e)
{
this.Title = "UnChecked";
}
}
You can customize everything with this style. I customized only checked and unchecked events. It is up to you in future.
EDIT: As post owner wanted, i enabled single click again.
Removed CheckBox_PreviewMouseButtonDown event.

If you just want to toggle the checkbox status when double clicked, then simply make an CheckBox_MouseDoubleClick Event and set the IsChecked property to true. But take care, this Solution is not within the MVVM pattern.

Related

WPF DataGrid SelectionChange event doesn't fire when ItemsSourse is being set from UserControl

I have very interesting scenario here, look:
MainWindow XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TabControl Grid.Row="0"
Grid.Column="0"
SelectionChanged="Selector_OnSelectionChanged">
<TabItem Header="First"/>
<TabItem Header="Second"/>
</TabControl>
<ContentPresenter Grid.Column="1"
Content="{Binding SelectedUserControl}">
</ContentPresenter>
</Grid>
UserControlOne XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<DataGrid Grid.Row="0"
ItemsSource="{Binding DataSource}"
SelectedItem="{Binding SelectedItem}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<Command:EventToCommand Command="{Binding SelectionChangedCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
<Button Grid.Row="1"
Content="SetSource"
Height="50"
Command="{Binding SetSourceCommand}"/>
<Button Grid.Row="2"
Content="RemoveSource"
Height="50"
Command="{Binding RemoveSourceCommand}"/>
</Grid>
UserContolTwo XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Row="0"
Content="SetSource"
Height="50"
Command="{Binding SetSourceCommand}"/>
<Button Grid.Row="1"
Content="RemoveSource"
Command="{Binding RemoveSourceCommand}"
Height="50"/>
</Grid>
CodeBehind:
public class GridItem
{
public String Name { get; set; }
public override string ToString()
{
return Name;
}
}
public partial class Window1 : Window, INotifyPropertyChanged
{
private List<GridItem> _items;
private GridItem _selectedItem;
private List<GridItem> _dataSource;
private readonly List<UserControl> _userControlList;
private UserControl _selectedUserControl;
public UserControl SelectedUserControl
{
get { return _selectedUserControl; }
set
{
_selectedUserControl = value;
RaisePropertyChanged("SelectedUserControl");
}
}
public GridItem SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
RaisePropertyChanged("SelectedItem");
}
}
public List<GridItem> DataSource
{
get { return _dataSource; }
set
{
_dataSource = value;
RaisePropertyChanged("DataSource");
}
}
public Window1()
{
InitializeComponent();
DataContext = this;
_items = new List<GridItem>
{
new GridItem { Name = "Igor" },
new GridItem { Name = "Vasya"},
new GridItem { Name = "Vladlen"}
};
_userControlList = new List<UserControl>
{
new UserControl1(),
new UserControl2()
};
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(String propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion INotifyPropertyChanged
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelectedUserControl = _userControlList[((TabControl)sender).SelectedIndex];
}
#region SetSourceCommand
private RelayCommand<Object> _setSourceCommand;
public RelayCommand<Object> SetSourceCommand
{
get
{
return _setSourceCommand ?? (_setSourceCommand =
new RelayCommand<Object>(SetSourceMethod));
}
}
private void SetSourceMethod(Object obj)
{
DataSource = _items;
SelectedItem = _items.FirstOrDefault();
}
#endregion SetSourceCommand
#region RemoveSourceCommand
private RelayCommand<Object> _removeSourceCommand;
public RelayCommand<Object> RemoveSourceCommand
{
get
{
return _removeSourceCommand ?? (_removeSourceCommand =
new RelayCommand<Object>(RemoveSourceMethod));
}
}
private void RemoveSourceMethod(Object obj)
{
DataSource = null;
}
#endregion RemoveSourceCommand
#region SelectionChangedCommand
private RelayCommand<Object> _selectionChangedCommand;
public RelayCommand<Object> SelectionChangedCommand
{
get
{
return _selectionChangedCommand ?? (_selectionChangedCommand =
new RelayCommand<Object>(SelectionChangedMethod));
}
}
private void SelectionChangedMethod(Object obj)
{
Debug.WriteLine("Event have been rised! Selected item is {0}", ((DataGrid)obj).SelectedItem ?? "NULL");
}
#endregion RemoveSourceCommand
}
I have MainWindow, that contains UserControl. UserControl is being set dinamically, so if you pick up FirstTabItem, then UserControlOne will be loaded and if you pick up SecondTabItem - UserControlTwo will be loaded into ContentPresenter of MainWindow.
If I click button SetSource on FirstTabItem (actually on UserControlOne) - then SelectionChanged event of DataGrid fires as usually. But if I click button SetSource on SecondTabItem (actually on UserControlTwo) - then SelectionChanged event of DataGrid doesn't fire at all. Despite on bouth buttons bound to the same command (SetSourceCommand).
If buttons don't placed on other controls, for example, only on different tabitems of the same TabControl - bouth buttons invokes SelectionChange event. So problem really in markup, in using UserControls.
Has anyone encoutered with that problem? How can I fix it? I don't want invoke eventhandler programmatically.
I posted all the required code here, so you can copy-paste it and try by yourself very quickly. Or I can load example project if someone interested.
Okay so here is the actual problem in your code.
The UserControl1 has a grid in which you have used the SelectedItem Dependency Property. On this specific DP you have a Command SelectionChangedCommand.
In you commands SetSourceCommand and RemoveSourceCommand you are updating SelectedItem of the data grid which fires the SelectionChangedCommand because of the event SelectionChanged.
In your UserControl2 there is no data grid nor any control which fires SelectionChanged event to call SelectionChangedCommand. Hence it is never executed.

Input gesture doesn't work wpf

Why doesn't my input gesture work in the following?
public class CustomRoutedUICommand : RoutedUICommand
{
private static RoutedUICommand _doSomethingCommand = null;
static CustomRoutedUICommand()
{
InputGestureCollection myInputs = new InputGestureCollection();
myInputs.Add(new KeyGesture(Key.G, ModifierKeys.Control | ModifierKeys.Shift));
_doSomethingCommand = new RoutedUICommand("DoSomething", "DoSomething", typeof(CustomRoutedUICommand), myInputs);
}
public static RoutedUICommand DoSomethingCommand { get { return _doSomethingCommand; } }
}
<Button Height="23" HorizontalAlignment="Left"
Command="{x:Static Control:CustomRoutedUICommand.DoSomethingCommand}"
CommandManager.CanExecute="Command_CanExecute" CommandManager.Executed="Command_Executed"
Content="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Command.Text}"
Margin="12,54,0,0" Name="Command" VerticalAlignment="Top" Width="Auto" Padding="2"/>
private void Command_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Hii");
}
In this case, the Command to work, need to have been an element logical focus, otherwise it will not work. You can specify KeyGesture a XAML way:
<Button Height="23" Content="Test" Name="Command" VerticalAlignment="Top"
Command="{x:Static Control:CustomRoutedUICommand.DoSomethingCommand}"
CommandManager.Executed="Command_Executed"
CommandManager.CanExecute="Command_CanExecute">
<Button.InputBindings>
<KeyBinding Command="{x:Static Control:CustomRoutedUICommand.DoSomethingCommand}" Gesture="CTRL+G" />
</Button.InputBindings>
</Button>
It works when the focus will be, it can be specified as follows:
Command.Focus();
To make your case to work, you need to use CommandBindings like this:
XAML
<Window x:Class="InputGestureHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Control="clr-namespace:InputGestureHelp"
WindowStartupLocation="CenterScreen"
ContentRendered="Window_ContentRendered"
Title="MainWindow" Height="350" Width="525">
<Window.CommandBindings>
<CommandBinding Command="{x:Static Control:CustomRoutedUICommand.DoSomethingCommand}"
Executed="Command_Executed" CanExecute="Command_CanExecute" />
</Window.CommandBindings>
<Grid>
<Button Height="23" Content="Test" Name="TestButton"
VerticalAlignment="Top"
Command="{x:Static Control:CustomRoutedUICommand.DoSomethingCommand}" />
</Grid>
</Window>
Code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Command_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Hii");
}
private void Command_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void Window_ContentRendered(object sender, EventArgs e)
{
TestButton.Focus();
}
}
public class CustomRoutedUICommand : RoutedUICommand
{
private static RoutedUICommand _doSomethingCommand;
static CustomRoutedUICommand()
{
InputGestureCollection myInputs = new InputGestureCollection();
myInputs.Add(new KeyGesture(Key.G, ModifierKeys.Control, "Ctrl + G"));
_doSomethingCommand = new RoutedUICommand("DoSomething", "DoSomething", typeof(CustomRoutedUICommand), myInputs);
}
public static RoutedUICommand DoSomethingCommand
{
get
{
return _doSomethingCommand;
}
}
}

Forcing a tri-state checkbox to not move to indeterminate state

I'm working in WPF and i have an interesting requirement.
I need my checkboxes to be ThreeState, so if only some of the child elements are selected it shows as indeterminate. But when a use clicks it, i want it to select either true or false.
Here is a story to represent my requirements:
item - indeterminate
subItem - checked
subItem - unchecked
subItem - checked
When a user clicks item, the checkbox should alternate between checked and unchecked. The user should never be able to select 'indeterminate' as a state. Is this possible?
XAML:
<CheckBox IsThreeState="True" IsChecked="{x:Null}" Click="CheckBox_Clicked" />
Code-behind:
private void CheckBox_Clicked(object sender, RoutedEventArgs e)
{
var cb = e.Source as CheckBox;
if (!cb.IsChecked.HasValue)
cb.IsChecked = false;
}
If you don't like the code-behind solution, then you could sub-class your own control like in the solution for this question.
It's much easier if you use Binding with your CheckBox.
XAML:
<Window x:Class="WpfApplication39Checkbox.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>
<CheckBox Content="CheckBox" HorizontalAlignment="Left" Margin="128,95,0,0" VerticalAlignment="Top" IsThreeState="False" IsChecked="{Binding CheckState}"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="46,241,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="139,241,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="235,241,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_2"/>
</Grid>
</Window>
Code-behind:
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace WpfApplication39Checkbox
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private bool? checkState;
public bool? CheckState
{
get { return checkState; }
set
{
checkState = value;
OnPropertyChanged("CheckState");
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
CheckState = false;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
CheckState = true;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
CheckState = null;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You see the point? You set the CheckBox to IsThreeState="False" but set the third state from CodeBehind and the CheckBox behaves as expected.

How to close popup in silverlight?

I have ListBox. when i click on ListBox item I have to show item information in popup But it does not close after clicking out side. I am creating popup in itemsselected event. how to handle popup close?
One approach is to create a canvas with a transparent background that you make visible at the same time as opening the Popup and attaching to is Mouse down event to closed the popup. Like this:-
Xaml:-
<Grid x:Name="LayoutRoot" Background="White" >
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Popup x:Name="MyPopup" Closed="MyPopup_Closed" HorizontalOffset="100" VerticalOffset="100" Opened="Popup_Opened">
<ListBox x:Name="PopupChild" MaxHeight="300" LostFocus="PopupChild_LostFocus">
<sys:String>Hello World</sys:String>
</ListBox>
</Popup>
<Button Content="Open Popup" Grid.Row="1" Click="Button_Click" />
<Canvas x:Name="PopupOpen" Visibility="Collapsed" Background="Transparent" Grid.RowSpan="2" MouseLeftButtonDown="PopupOpen_MouseLeftButtonDown" />
</Grid>
Code:-
private void Button_Click(object sender, RoutedEventArgs e)
{
MyPopup.IsOpen = true;
}
private void Popup_Opened(object sender, EventArgs e)
{
PopupOpen.Visibility = Visibility.Visible;
}
private void PopupChild_LostFocus(object sender, RoutedEventArgs e)
{
MyPopup.IsOpen = false;
}
private void PopupOpen_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MyPopup.IsOpen = false;
}
private void MyPopup_Closed(object sender, EventArgs e)
{
PopupOpen.Visibility = Visibility.Collapsed;
}
Note that its important that if your popup contains a control that can receive the focus that you also handle LostFocus.
This is similar to a question that I had. Take a look at How to dismiss a popup in Silverlight when clicking outside of the control?. I posted in my solution an extension method that's been very helpful in making popups close when clicking outside of them.
I'm not quite sure what you mean by "clicking out side" because popups act in a modal way.
You should set up your popup window as a ChildWindow. Then you can handle the Closed event.
Here's a very simple sample that shows a selected string from a listbox in a main window.
First the main window:
<UserControl x:Class="PopupTest.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Vertical">
<ListBox x:Name="SomeList" Width="100" Height="100" />
<TextBlock x:Name="DialogResult" Width="100" />
</StackPanel>
</Grid>
In the codebehind, the popup is triggered when the list selection changes. Simply set up a Closed handler. In this example, I simply put the chosen list item into a textblock, then upon closing the popup, I just put the dialog result in a textblock on the main window (to show if the user pushed ok or cancel).
public MainPage()
{
InitializeComponent();
SomeList.SelectionChanged += new SelectionChangedEventHandler(SomeList_SelectionChanged);
SomeList.Items.Add("one");
SomeList.Items.Add("two");
SomeList.Items.Add("three");
}
void SomeList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var popup = new SomePopup();
popup.Closed += new EventHandler(popup_Closed);
popup.ChosenItem.Text = (string)SomeList.SelectedItem;
DialogResult.Text = "";
popup.Show();
}
void popup_Closed(object sender, EventArgs e)
{
var popup = sender as SomePopup;
if (popup.DialogResult == true)
DialogResult.Text = "Ok";
else
DialogResult.Text = "Cancel";
}
The popup closes when the user pushes Ok or Cancel, because the DialogResult value is set in the popup's code-behind:
private void OKButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}

WPF Drag n drop doesn't fire CommanBinding.CanExecute

Yes, I know it sounds weird, but it doesn't, the question is why, and if there's a work around. It works with everything, even when you hit PrintScreen or Pause keys, CanExecute fires. So after doing a drag drop, in order to make it fire, you have to do "something" else, like a mouse click, focus, hit a key, anything. That'll make the event fire, and allow Execute to happen. Anyway, here's my code, I know it's long, but it'll help you help me.
I found this bug in our large main project, so I simplified it to this little app to isolate the problem.
XAML:
<Window x:Class="DragNDropCommands.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="485" SizeToContent="Width" Loaded="Window_Loaded">
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.New" CanExecute="NewCanExecute" Executed="NewExecuted" />
<CommandBinding Command="ApplicationCommands.Save" CanExecute="SaveCanExecute" Executed="SaveExecuted" />
<CommandBinding Command="ApplicationCommands.Undo" CanExecute="UndoCanExecute" Executed="UndoExecuted" />
<CommandBinding Command="ApplicationCommands.Redo" CanExecute="RedoCanExecute" Executed="RedoExecuted" />
</Window.CommandBindings>
<Grid Margin="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Command="ApplicationCommands.New" Grid.Row="0" Grid.Column="0" FontWeight="Bold" Content="New" Width="80" Margin="8"></Button>
<Button Command="ApplicationCommands.Save" Grid.Row="0" Grid.Column="1" FontWeight="Bold" Content="Save" Width="80" Margin="8"></Button>
<Button Command="ApplicationCommands.Undo" Grid.Row="0" Grid.Column="2" FontWeight="Bold" Content="Undo" Width="80" Margin="8"></Button>
<Button Command="ApplicationCommands.Redo" Grid.Row="0" Grid.Column="3" FontWeight="Bold" Content="Redo" Width="80" Margin="8"></Button>
<CheckBox Grid.Row="1" Grid.Column="0" Margin="8" IsChecked="{Binding Path=AllowNew, Mode=TwoWay}">Allow New</CheckBox>
<CheckBox Grid.Row="1" Grid.Column="1" Margin="8" IsChecked="{Binding Path=AllowSave}">Allow Save</CheckBox>
<CheckBox Grid.Row="1" Grid.Column="2" Margin="8" IsChecked="{Binding Path=AllowUndo}">Allow Undo</CheckBox>
<CheckBox Grid.Row="1" Grid.Column="3" Margin="8" IsChecked="{Binding Path=AllowRedo}">Allow Redo</CheckBox>
<Label x:Name="labelDrag" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" BorderBrush="Black" BorderThickness="1" MouseDown="Label_MouseDown"
Background="LightBlue" HorizontalContentAlignment="Center" Margin="8">Drag this label...</Label>
<Label x:Name="labelDropNew" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" BorderBrush="Black" BorderThickness="1" Drop="labelDropNew_Drop"
Background="LightGray" HorizontalContentAlignment="Center" Margin="8" AllowDrop="True">...here to toggle AllowNew</Label>
<Label x:Name="labelDropSave" Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="2" BorderBrush="Black" BorderThickness="1" Drop="labelDropSave_Drop"
Background="LightGray" HorizontalContentAlignment="Center" Margin="8" AllowDrop="True">...here to toggle AllowSave</Label>
<ListBox x:Name="listViewLog" Grid.Row="4" Grid.ColumnSpan="4" Margin="8" Width="500">
</ListBox>
<Button Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" Margin="8" Click="Button_Click">Clear list</Button>
</Grid>
</Window>
C#:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace DragNDropCommands
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
private CommandControl commandControl = new CommandControl();
private int canExecuteCount = 1;
public Window1()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = commandControl;
}
private void NewCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
if (this.commandControl == null || listViewLog == null)
return;
e.CanExecute = this.commandControl.AllowNew;
listViewLog.Items.Add
(
String.Format
(
"{0} - NewCanExecute: {1} - commandControl.AllowNew: {2}",
canExecuteCount++, e.CanExecute, commandControl.AllowNew
)
);
}
private void NewExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("New executed");
}
private void SaveCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
if (this.commandControl == null || listViewLog == null)
return;
e.CanExecute = this.commandControl.AllowSave;
listViewLog.Items.Add
(
String.Format
(
"{0} - SaveCanExecute: {1} - commandControl.AllowSave: {2}",
canExecuteCount++, e.CanExecute, commandControl.AllowSave
)
);
}
private void SaveExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Save executed");
}
private void UndoCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
if (this.commandControl == null || listViewLog == null)
return;
e.CanExecute = this.commandControl.AllowUndo;
listViewLog.Items.Add
(
String.Format
(
"{0} - UndoCanExecute: {1} - commandControl.AllowUndo: {2}",
canExecuteCount++, e.CanExecute, commandControl.AllowUndo
)
);
}
private void UndoExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Undo executed");
}
private void RedoCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
if (this.commandControl == null || listViewLog == null)
return;
e.CanExecute = this.commandControl.AllowRedo;
listViewLog.Items.Add
(
String.Format
(
"{0} - RedoCanExecute: {1} - commandControl.AllowRedo: {2}",
canExecuteCount++, e.CanExecute, commandControl.AllowRedo
)
);
}
private void RedoExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Redo executed");
}
private void Button_Click(object sender, RoutedEventArgs e)
{
listViewLog.Items.Clear();
}
private void Label_MouseDown(object sender, MouseButtonEventArgs e)
{
Label label = (Label)sender;
if(e.LeftButton == MouseButtonState.Pressed)
DragDrop.DoDragDrop(label, label, DragDropEffects.Move);
}
private void labelDropNew_Drop(object sender, DragEventArgs e)
{
this.commandControl.AllowNew = !this.commandControl.AllowNew;
}
private void labelDropSave_Drop(object sender, DragEventArgs e)
{
this.commandControl.AllowSave = !this.commandControl.AllowSave;
}
}
public class CommandControl : DependencyObject
{
public bool AllowNew
{
get { return (bool)GetValue(AllowNewProperty); }
set { SetValue(AllowNewProperty, value); }
}
// Using a DependencyProperty as the backing store for AllowNew. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AllowNewProperty =
DependencyProperty.Register("AllowNew", typeof(bool), typeof(CommandControl), new UIPropertyMetadata(false));
public bool AllowSave
{
get { return (bool)GetValue(AllowSaveProperty); }
set { SetValue(AllowSaveProperty, value); }
}
// Using a DependencyProperty as the backing store for AllowSave. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AllowSaveProperty =
DependencyProperty.Register("AllowSave", typeof(bool), typeof(CommandControl), new UIPropertyMetadata(false));
public bool AllowUndo
{
get { return (bool)GetValue(AllowUndoProperty); }
set { SetValue(AllowUndoProperty, value); }
}
// Using a DependencyProperty as the backing store for AllowUndo. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AllowUndoProperty =
DependencyProperty.Register("AllowUndo", typeof(bool), typeof(CommandControl), new UIPropertyMetadata(false));
public bool AllowRedo
{
get { return (bool)GetValue(AllowRedoProperty); }
set { SetValue(AllowRedoProperty, value); }
}
// Using a DependencyProperty as the backing store for AllowRedo. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AllowRedoProperty =
DependencyProperty.Register("AllowRedo", typeof(bool), typeof(CommandControl), new UIPropertyMetadata(false));
}
}
You should be able to just copy paste and do a few name changes (files, namespaces) to get it running. I'd really love your help since this has been driving me nuts, and now that I finally discover the reason for the bug, I don't know what to do about it.
Any suggestion is really apreciatted.
Thanks in advance.
Just a quick suggestion:
You could use CommandManager.InvalidateRequerySuggested() in the drag and drop event handler to force the reexecution of CanExecute(). (Link)

Resources