I have an action Edit in my WPF application, which is bound to items in a ListView control, i.e. it is executed when an item is double clicked or the Edit button in the toolbar is clicked. This action in turn displays a modal window with the editing stuff.
Now when I select multiple items in the list, click Edit, the items stay selected in the background, also, when I close the dialog, they are still selected in the sence that their background is blue. However, they seem to be not selected in the sence that the Edit button is disabled in the toolbar (the Edit action's CanExecute method simply checks FileList.SelectedIndex != -1. What's more, the "selected" items won't get deselected when I click some other list item - they only get deselected when I explicitly click on them one by one - it's as if the blue background is stuck on them.
My code does not use any fancy ListView styles or what not, so what could be causing this ?
I can post my code upon request, but it is pretty much standard.
EDIT:
After cutting down my code I finally found what's causing this issue. After showing the dialog, I edit the items in the data bound collection, so that the ListView would get updated (i.e. replace the bound objects to new objects). The question is, why is this causing a problem and how should I resolve it ?
Something in your code must be causing this issues. Below is a sample which behaves as expected.
XAML:
<Window x:Class="TestDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<RoutedUICommand x:Key="EditItemsCommand" Text="Edit Items" />
</Window.Resources>
<Window.CommandBindings>
<CommandBinding
Command="{StaticResource EditItemsCommand}"
CanExecute="EditItems_CanExecute"
Executed="EditItems_Executed" />
</Window.CommandBindings>
<StackPanel>
<Button Name="_editButton" Content="Edit" Command="{StaticResource EditItemsCommand}" />
<Button Content="Unselect all" Click="OnUnselectAll" />
<ListView
Name="_listView"
ItemsSource="{Binding Path=Items}"
SelectionMode="Extended"
MouseDoubleClick="OnListViewMouseDoubleClick">
</ListView>
</StackPanel>
</Window>
Code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
namespace TestDemo
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public IEnumerable<string> Items
{
get
{
for (int i = 0; i < 10; i++) { yield return i.ToString(); }
}
}
private void EditItems_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = _listView != null && _listView.SelectedItems.Count > 0;
}
private void EditItems_Executed(object sender, ExecutedRoutedEventArgs e)
{
EditWindow editWindow = new EditWindow();
editWindow.EditItems = _listView.SelectedItems.Cast<string>();
editWindow.ShowDialog();
}
private void OnListViewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
_editButton.Command.Execute(null);
}
private void OnUnselectAll(object sender, RoutedEventArgs e)
{
_listView.SelectedItem = null;
}
}
}
XAML:
<Window x:Class="TestDemo.EditWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="EditWindow">
<ListBox ItemsSource="{Binding Path=EditItems}" />
</Window>
Code behind:
using System;
using System.Collections.Generic;
using System.Windows;
namespace TestDemo
{
public partial class EditWindow : Window
{
public EditWindow()
{
InitializeComponent();
DataContext = this;
}
public IEnumerable<string> EditItems { get; set; }
}
}
What do you have ListView.SelectionMode set to? It sounds like it is set to Multiple (clicking an item extends the selection), while you might want to set it to Extended (selection is extended when clicking an item and pressing Control or Shift) instead.
I'm not sure what to say about the Edit command problem, though. Maybe there is an odd behavior with SelectedIndex and multiple selection - possibly check the count of the objects in the ListView.SelectedItems collection instead?
Related
Revised: I apologize for missing some important descriptions in the first version, now the problem should be well-defined:
so I'm making a toy CAD program with following views:
MainWindow.xaml
CustomizedUserControl.xaml
CustomizedUserControl is a Tab within MainWindow, and its DataContext is defined in MainWindow.xaml as:
<Window.Resources>
<DataTemplate DataType="{x:Type local:CustomizedTabClass}">
<local:UserControl1/>
</DataTemplate>
</Window.Resources>
And CustomizedUserControl.xaml provides a canvas and a button, so when the button is pressed the user should be able to draw on the canvas. As the following code shows, the content of Canvas is prepared by the dataContext, "tabs:CustomizedTabClass".
CustomizedUserControl.xaml
<CustomizedUserControl x:Name="Views.CustomizedUserControl11"
...
>
<Button ToolTip="Lines (L)" BorderThickness="2"
Command="{Binding ElementName=CustomizedUserControl11,
Path=DrawingCommands.LinesChainCommand}"
IsEnabled="True"
Content = "{Binding ElementName=CustomizedUserControl11,
Path=DrawingCommands.Button1Name}">
</Button>
...
<canvas x:Name="CADCanvas"
Drawing="{Binding Drawing ,Mode=TwoWay}" >
</canvas>
It is also notable that I used an external library, Fody/PropertyChanged, in all classes so property notifications would be injected without further programming.
CustomizedUserControl.xaml.cs
using PropertyChanged;
using System.ComponentModel;
using System.Windows.Controls;
[AddINotifyPropertyChangedInterface]
public partial class CustomizedUserControl: Usercontrol, INotifyPropertyChanged{
public CADDrawingCommands DrawingCommands { get; set; }
public CustomizedUserControl()
{
InitializeComponent();
DrawingCommands = new CADDrawingCommands(this);
DrawingCommands.Button1Name = "yeahjojo"; //For testing data binding
}
public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
}
CADDrawingCommands.cs
using PropertyChanged;
using System.ComponentModel;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows;
[AddINotifyPropertyChangedInterface]
public class CADDrawingCommands : INotifyPropertyChanged{
UserControl _drawableTab;
public string Button1Name { get; set; } = "TestForDataBinding";
public RoutedCommand LinesChainCommand { get; set; } = new RoutedCommand();
public CADDrawingCommands(UserControl dTab){
_drawableTab = dTab;
CommandBinding lineCommandBinding = new CommandBinding(LinesChainCommand,
(object sender, ExecutedRoutedEventArgs e) =>
{
MessageBox.Show("Test");
//Draw on canvas inside CustomizedUserControl (modify Drawing property in CustomizedTabClass)
}, (object sender, CanExecuteRoutedEventArgs e) => { e.CanExecute = true; });
_drawableTab.CommandBindings.Add(lineCommandBinding);
}
public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
}
The Content of Button is set correctly, as I can read the string defined in Button1Name:
Therefore I suppose the Data Binding for Command is also ok. IsEnabled has been set to true and CanExecute of the CommandBinding would only return true.
Why is my button still greyed out and not clickable?
If I define the button inside a Window instead of UserControl (and set the datacontext of the Window to its own code behind, the button will be clickable! Why?
Thank you for your time! Hopefully would somebody help me cuz I've run out of ideas and references.
Made the simplest example.
Everything works as it should.
BaseInpc is my simple INotifyPropertyChanged implementation from here: BaseInpc
using Simplified;
using System.Windows;
using System.Windows.Input;
namespace CustomizedUserControlRoutedCommand
{
public class CADDrawingCommands : BaseInpc
{
UIElement _drawableTab;
private string _button1Name = "TestForDataBinding";
public string Button1Name { get => _button1Name; set => Set(ref _button1Name, value); }
public static RoutedCommand LinesChainCommand { get; } = new RoutedCommand();
public CADDrawingCommands(UIElement dTab)
{
_drawableTab = dTab;
CommandBinding lineCommandBinding = new CommandBinding(LinesChainCommand,
(object sender, ExecutedRoutedEventArgs e) =>
{
MessageBox.Show("Test");
//Draw on canvas inside CustomizedUserControl (modify Drawing property in CustomizedTabClass)
}, (object sender, CanExecuteRoutedEventArgs e) => { e.CanExecute = true; });
_drawableTab.CommandBindings.Add(lineCommandBinding);
}
}
}
<UserControl x:Name="CustomizedUserControl11" x:Class="CustomizedUserControlRoutedCommand.CustomizedUserControl"
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:CustomizedUserControlRoutedCommand"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Button ToolTip="Lines (L)" BorderThickness="2"
Command="{x:Static local:CADDrawingCommands.LinesChainCommand}"
IsEnabled="True"
Content = "{Binding ElementName=CustomizedUserControl11,
Path=DrawingCommands.Button1Name}">
</Button>
</Grid>
</UserControl>
using System.Windows.Controls;
namespace CustomizedUserControlRoutedCommand
{
public partial class CustomizedUserControl : UserControl
{
public CADDrawingCommands DrawingCommands { get; }
public CustomizedUserControl()
{
DrawingCommands = new CADDrawingCommands(this);
InitializeComponent();
DrawingCommands.Button1Name = "yeahjojo"; //For testing data binding
}
}
}
<Window x:Class="CustomizedUserControlRoutedCommand.TestCustomizedUserControlWindow"
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:CustomizedUserControlRoutedCommand"
mc:Ignorable="d"
Title="TestCustomizedUserControlWindow" Height="450" Width="800">
<Grid>
<local:CustomizedUserControl/>
</Grid>
</Window>
If you showed your code in full, then I see the following problems in it:
You are setting the value incorrectly for the DrawingCommands property.
In this property, you do not raise PropertyChanged.
The binding in the Button is initialized in the InitializeComponent() method. At this point, the property is empty, and when you set a value to it, the binding cannot find out.
There are two ways to fix this:
Raise PropertyChanged in the property;
If you set the property value once in the constructor, then set it immediately in the initializer. Make the property "Read Only". This way, in my opinion, is better.
public CADDrawingCommands DrawingCommands { get; }
public FileEditTabUserControl()
{
DrawingCommands = new CADDrawingCommands(this);
InitializeComponent();
DrawingCommands.Button1Name = "yeahjojo"; //For testing data binding
}
You have a button bound to a command in the DrawingCommands.LinesChainCommand property.
But to this property, you assign an empty instance of the = new RoutedCommand () routing command.
This looks pointless enough.
If you need a routable command, create it in the "Read Only" static property.
This will make it much easier to use in XAML:
public static RoutedCommand LinesChainCommand { get; } = new RoutedCommand();
<Button ToolTip="Lines (L)" BorderThickness="2"
Command="{x:Static local:DrawingCommands.LinesChainCommand}"
IsEnabled="True"
Content = "{Binding ElementName=CustomizedUserControl11,
Path=DrawingCommands.Button1Name}">
</Button>
Raising PropertyChanged in CADDrawingCommands properties is also not visible in your code.
If it really does not exist, then the binding is also unaware of changing property values.
When I tab into the WPF Datagrid it focuses the first cell (with a rectangle) but does not select it (in blue). If I press tab again it focuses and selects it.
I think the DataGridCell actually has IsSelected=true, but it is not being painted in blue. I have tried hacking around with the datagrid and visual-states but I can't make it repaint the grid correctly when you first tab in.
Has anyone seen this before and do you have a solution?
code to reproduce:
MainWindow.xaml
<Window x:Class="WpfApplication1.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">
<StackPanel>
<TextBox Width="100"/>
<DataGrid SelectionMode="Single" SelectionUnit="Cell"
ItemsSource="{Binding MyItems}" AutoGenerateColumns="True"/>
</StackPanel>
</Window>
MainWindow.xaml.cs
using System.Collections.Generic;
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MyItems.Add(new Thingy() { Name = "Frank", Age = 34 });
MyItems.Add(new Thingy() { Name = "Jim", Age = 43 });
MyItems.Add(new Thingy() { Name = "Bob", Age = 56 });
MyItems.Add(new Thingy() { Name = "Harry", Age = 23 });
DataContext = this;
}
private List<Thingy> _myItems = new List<Thingy>();
public List<Thingy> MyItems
{
get { return _myItems; }
}
}
public class Thingy
{
public string Name { get; set; }
public int Age { get; set; }
}
}
click on the TextBox, then hit tab --- cell 1 is not selected
hit tab again --- cell 2 is selected
Any help is much appreciated, thanks.
Update:
When SelectionUnit=FullRow, I have had some success along the lines shown below, if SelectedIndex is set to 0 upon creation the first row is now selected in blue. It still needs some work to cope with shift-tab etc. There is still a problem though because when I change the SelectionMode to extended and press shift-downarrow the second row gets selected but the first row gets unselected (they should both be selected). If I do it again rows 2+3 are selected which is correct and it continues to work ok after that.
protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e)
{
base.OnIsKeyboardFocusWithinChanged(e);
int oldIdx = this.SelectedIndex;
this.SelectedIndex = -1;
this.SelectedIndex = oldIdx;
}
Further Update:
Fixed that issue by setting the private _selectionAnchor field. (Thanks ILSpy)
protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e)
{
base.OnIsKeyboardFocusWithinChanged(e);
this.SelectedIndex = -1;
this.SelectedIndex = 0;
SelectionAnchor = SelectedCells[0];
}
protected DataGridCellInfo? SelectionAnchor
{
get
{
return typeof(DataGrid).GetField("_selectionAnchor", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this) as DataGridCellInfo?;
}
set
{
typeof(DataGrid).GetField("_selectionAnchor", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(this, value);
}
}
I know my answer is too late but it would help other navigating to this site.
After lot of research, I got the answer on how to select the element while tabbing.
It was really easy and was a single line of code in XAML that did the trick;
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="IsTabStop" Value="False"/>
</Style>
By setting IsTabStop to false you are telling the datagridcell's visual tree to go inside its template and find any element that is focus able. If it finds some element then it focuses that element.
You can do like this. Register for a got focus event and then set the original source as selected item.
<Window x:Class="WpfApplication1.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">
<StackPanel>
<TextBox Width="100"/>
<DataGrid SelectionMode="Single" SelectionUnit="Cell"
ItemsSource="{Binding MyItems}" AutoGenerateColumns="True"
GotFocus="WPF_DataGrid_GotFocus" />
</StackPanel>
</Window>
Then in the code behind file :
private void WPF_DataGrid_GotFocus(object sender, RoutedEventArgs e)
{
(e.OriginalSource as DataGridCell).IsSelected = true;
}
I hope it helps!
If CodeBehind is an option the following code sets the selectedItem:
private void CrashGrid_OnGotKeyboardFocus(object sender, RoutedEventArgs e)
{
(DataGrid)e.Source.SelectedItem = (DataGrid)e.Source.CurrentCell.Item;
}
I'm doing a sample with MVVM and have a problem with commands. I have an Article class (with ID, Name, Price, etc.), an ArticleViewModel that represents the view model, and a user control (ArticleControl) that allows to input the data for the article, with bindings to the properties of the ArticleViewModel. This user control has a biding for a save command.
<UserControl.CommandBindings>
<CommandBinding x:Name="saveCmd"
Command="local:Commands.Save"
CanExecute="CommandBinding_CanExecute"
Executed="CommandBinding_Executed"/>
</UserControl.CommandBindings>
This is how the command is defined:
public class Commands
{
private static RoutedUICommand _save;
public static RoutedUICommand Save
{
get { return _save; }
}
static Commands()
{
InputGestureCollection saveInputs = new InputGestureCollection();
saveInputs.Add(new KeyGesture(Key.S, ModifierKeys.Control, "Ctrl+S"));
_save = new RoutedUICommand(
"Save",
"Save",
typeof(Commands),
saveInputs);
}
}
And the command binding handlers:
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
double baseprice = 0;
double.TryParse(ArticleBasePrice.Text, out baseprice);
e.CanExecute =
!string.IsNullOrEmpty(ArticleID.Text) &&
!string.IsNullOrEmpty(ArticleName.Text) &&
!string.IsNullOrEmpty(ArticleDescription.Text) &&
baseprice > 0;
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
ArticleViewModel avm = (ArticleViewModel)DataContext;
if (avm != null && avm.Save())
{
ArticleID.Text = String.Empty;
ArticleName.Text = String.Empty;
ArticleDescription.Text = String.Empty;
ArticleBasePrice.Text = String.Empty;
}
}
Now, I put this user control on a window. When I hit Ctrl+S the command is executed. However, I also put a Save button on that window, next to this user control. When I click it I want to execute the same command (and I don't want to do another command binding in the window where the user control is hosted).
<StackPanel>
<local:ArticleControl x:Name="articleControl" />
<Button Name="btnSave"
Content="Save" Width="100"
HorizontalAlignment="Left"
Command="{???}"/> <!-- what should I put here? -->
</StackPanel>
But I do not know how to refer that saveCmd defined in the user control. I tried different things, some are completely wrong (they throw exception when running the app), some don't have any effect.
Command="{StaticResource saveCmd}"
Command="{StaticResource local:ArticleControl.saveCmd}"
Command="{x:Static local:Commands.Save}"
Any help is appreciated. Thank you.
The reason why the Save button will not cause the commandbindings of your other control to execute is because the Save button is outside the user control and therefore the command system will not look for a commandbinding in that control. The Command execution strategy is a bit like a bubbling event and will start from the focused item (the Button) and go up the visual tree until it finds the CommandBindings.
You can either implement the command binding in the parent control or set the CommandTarget property of the Save button to the user control.
Another approach is to set the FocusManager.IsFocusScope=True on the button or the container of the button. If you do this I suggest you read up on what IsFocusScope does but in a nutshell it will leave the input focus on whatever control has the focus when you press the button, instead of making the button the new input focus. This is generally used for toolbars or menu like structures.
Based on Patrick's suggestions, this is what I did:
Put the command binding in the user control and implemented the handlers in the code-behind as shown in the original message.
Used Command, CommandTarget and FocusManager properties on the button to point to the binding from the user control (ArticleUserControl is the x:Name of the user control).
This is how the XAML for the window looks:
<Window x:Class="MVVMModel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMModel"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<local:ArticleControl x:Name="articleControl" />
<Button Name="btnSave" Content="Save" Width="100" HorizontalAlignment="Left"
Command="local:Commands.Save"
CommandTarget="{Binding ElementName=ArticleUserControl}"
FocusManager.IsFocusScope="True" />
</StackPanel>
</Window>
I think you just have to move your CommandBinding to a Resource Dictionary, so that it's available outside your UserControl!
Here is what I did to work, though I'm not particularly happy with the solution. If anyone knows a better approach, please do let me know.
I moved the logic for the commands handler in a separate, static class:
static class CommandsCore
{
public static bool Save_CanExecute(ArticleControl ac)
{
double baseprice = 0;
double.TryParse(ac.ArticleBasePrice.Text, out baseprice);
return
!string.IsNullOrEmpty(ac.ArticleID.Text) &&
!string.IsNullOrEmpty(ac.ArticleName.Text) &&
!string.IsNullOrEmpty(ac.ArticleDescription.Text) &&
baseprice > 0;
}
public static void Save_Executed(ArticleControl ac)
{
ArticleViewModel avm = (ArticleViewModel)ac.DataContext;
if (avm != null && avm.Save())
{
ac.ArticleID.Text = String.Empty;
ac.ArticleName.Text = String.Empty;
ac.ArticleDescription.Text = String.Empty;
ac.ArticleBasePrice.Text = String.Empty;
}
}
}
I kept the command binding in the user control as it was
<UserControl.CommandBindings>
<CommandBinding x:Name="saveCmd"
Command="local:Commands.Save"
CanExecute="CommandBinding_CanExecute"
Executed="CommandBinding_Executed"/>
</UserControl.CommandBindings>
But in the handlers I called the two methods I just defined above.
public void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = CommandsCore.Save_CanExecute(this);
}
public void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
CommandsCore.Save_Executed(this);
}
And then I did the same from the window where the control is used.
<Window x:Class="MVVMModel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMModel"
Title="MainWindow" Height="350" Width="525">
<Window.CommandBindings>
<CommandBinding x:Name="saveCmd"
Command="local:Commands.Save"
CanExecute="CommandBinding_CanExecute"
Executed="CommandBinding_Executed"/>
</Window.CommandBindings>
<StackPanel>
<local:ArticleControl x:Name="articleControl" />
<Button Name="btnSave" Content="Save" Width="100" HorizontalAlignment="Left"
Command="local:Commands.Save"/>
</StackPanel>
</Window>
and the handlers
public void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = CommandsCore.Save_CanExecute(articleControl);
}
public void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
CommandsCore.Save_Executed(articleControl);
}
And this works, the Save button is enabled only when the fields are filled in appropriately and the command is executed correctly when clicking the button.
I have a form with TextBox and two Buttons. One button has IsDefault property set to true, and IsCancel set to true for other button. TextBox is CommandTarget for both buttons. When I'm pressing Enter or ESC keys on TextBox, it works as I'm pressing on corresponding button.
I want to remove buttons from the form. They should not be visible, but the textbox should react on Enter or ESC as before. I cannot just set button's Visible property to collapsed - in this case they does not work at all. And I prefer to avoid of tracking keyboard events.
Is it possible?
While Skeets' and Abe's methods work, they are hacks. You can simply specify that a WPF command should also be invoked by a so called InputGesture, in this case a KeyGesture ("enter", or "escape"). You can set the scope of this KeyGestures by placing the CommandBinding for the command at the appropriate level in the Visual Tree. Like this:
<Window x:Class="CommandSpike.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CommandSpike"
Title="Window1" Height="300" Width="300">
<StackPanel>
<Grid>
<Grid.CommandBindings>
<CommandBinding x:Name="EnterBinding"
Command="{x:Static local:Commands.EnterCommand}"
CanExecute="CommandBinding_CanExecute"
Executed="EnterBinding_Executed"/>
<CommandBinding x:Name="CancelBinding"
Command="{x:Static local:Commands.CancelCommand}"
CanExecute="CommandBinding_CanExecute"
Executed="CancelBinding_Executed"/>
</Grid.CommandBindings>
<TextBox>
Press Enter or Cancel when I have focus...
</TextBox>
</Grid>
<TextBox Margin="0,4">
Pressing Enter or Cancel does nothing while I have focus!
</TextBox>
</StackPanel>
</Window>
using System.Windows;
using System.Windows.Input;
namespace CommandSpike
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void EnterBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Enter");
}
private void CancelBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Cancel");
}
}
}
using System.Windows.Input;
namespace CommandSpike
{
public static class Commands
{
public static RoutedUICommand EnterCommand { get;private set; }
public static RoutedUICommand CancelCommand { get; private set; }
static Commands()
{
EnterCommand=new RoutedUICommand("Enter",
"EnterCommand",
typeof(Commands));
EnterCommand.InputGestures.Add(
new KeyGesture(Key.Enter)
);
CancelCommand=new RoutedUICommand("Cancel",
"CancelCommand",
typeof(Commands));
CancelCommand.InputGestures.Add(
new KeyGesture(Key.Escape)
);
}
}
}
Have you tried other mechanisms to make the buttons invisible? Here are some suggestions:
Set Opacity to 0
Set Width/Height to 0
Set a RenderTransform that moves the buttons off-screen
I would give them an empty ControlTemplate:
<ControlTemplate x:Key="blankButton" TargetType="{x:Type Button}" />
...
<Button IsDefault="True" ... Template="{StaticResource blankButton}" />
<Button IsCancel="True" ... Template="{StaticResource blankButton}" />
My WPF page has a RadGrid control provided by Telerik. The Grid is a nested grid which essentially means that clicking on the (+) sign on the leftmost column of the row expands the row into a Subgrid. This is being done by specifying a hierarchical grid in my XAML. Everything works just fine when you click on the row and expand the subgrid but the selectedItem of the initially selected row does not seem to change. An example would be selecting row 1 of the grid initially and then expanding row 4 to display the subgrid. The subgrid is displayed but the selectedItem is still row 1. The desired behavior is for row 4 to be the selectedItem once it is expanded to display the subgrid. Can anyone point out what exactly is going wrong over here.
Thanks
Your are right - here is the updated version:
private void RadGridView_Loaded(object sender, RoutedEventArgs e)
{
var childGrid = (RadGridView)sender;
var parentRow = childGrid.ParentRow;
if (parentRow != null)
{
RadGridView1.SelectedItem = childGrid.DataContext;
parentRow.IsExpandedChanged += new RoutedEventHandler(parentRow_IsExpandedChanged);
}
}
void parentRow_IsExpandedChanged(object sender, RoutedEventArgs e)
{
RadGridView1.SelectedItem = ((GridViewRow)sender).DataContext;
}
Here is an example:
XAML
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
Title="Window1">
<Grid>
<telerik:RadGridView x:Name="RadGridView1" ItemsSource="{Binding}">
<telerik:RadGridView.ChildTableDefinitions>
<telerik:GridViewTableDefinition />
</telerik:RadGridView.ChildTableDefinitions>
<telerik:RadGridView.HierarchyChildTemplate>
<DataTemplate>
<telerik:RadGridView ItemsSource="{Binding Items}" Loaded="RadGridView_Loaded" />
</DataTemplate>
</telerik:RadGridView.HierarchyChildTemplate>
</telerik:RadGridView>
</Grid>
C#
using System.Windows;
using System.Linq;
namespace WpfApplication1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = from i in Enumerable.Range(0, 10)
select new
{
ID = i,
Items = from j in Enumerable.Range(0, 10)
select new
{
ID = j,
}
};
}
private void RadGridView_Loaded(object sender, RoutedEventArgs e)
{
RadGridView1.SelectedItem = ((FrameworkElement)sender).DataContext;
}
}
}