Disable minimize or maximize when double clicked on ribbon - wpf

I use the Ribbon for WPF (2010 - Microsoft.Windows.Controls.Ribbon).
How can I disable the minimize or maximize effect from the red range, when I do a double click on the tab (header)

Use this event on the SizeChanged property of the ribbon to suppress minimizing.
/// <summary>
/// Disable the minimize functionality of the ribbon.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void RibbonSizeChanged(object sender, SizeChangedEventArgs e)
{
var ribbon = sender as Ribbon;
if (ribbon != null)
{
ribbon.IsMinimized = false;
}
// Handled
e.Handled = true;
}

Related

How to handle arbitrary events during a drag and drop operation in WPF?

I want to handle events such as OnMouseMove or MouseWheel during a drag/drop operation.
However, as far as I can tell from this MSDN topic on Drag/Drop, the only events that fire during a drag/drop operation are GiveFeedback, QueryContinueDrag, Drag Enter/Leave/Over, and their Preview* counterparts. Essentially, handling these events allows me to get the mouse position, or see if the user presses Ctrl, Shift, Alt, Esc, or presses or releases one of the mouse buttons.
What I'd like, though, is to handle other events during a drag/drop operation, such as MouseWheel. Specifically what I want to do is to let the user scroll the contents of a window (using the mouse wheel) while dragging something over it. I've tried writing handlers for these other events, both bubbling and tunneling versions, as well as attaching them to various levels of the control hierarchy, but as far as I can tell, none of them are firing.
I'm aware there's a partial solution (described here, for example) where you use DragOver to scroll the contents of a window when the mouse position is near the top or bottom of the window. But that's not what I want to do.
I came across an article that implies it is possible to handle (for example) the OnMouseMove event during a drag operation. I say that because the code in the article is a variant of the approach described above, but it handles OnMouseMove instead of DragOver. However, I tried adapting this approach and still cannot get the OnMouseMove event to fire while dragging. I've added my code below. It's in F#, so I used the F# XAML type provider from FSharpx.
MainWindow.xaml:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="500" Width="900">
<DockPanel Name="panel1">
<StatusBar Name="status1" DockPanel.Dock="Bottom">
<TextBlock Name="statustext1" />
</StatusBar>
</DockPanel>
</Window>
Program.fs:
(*
Added references: PresentationCore, PresentationFramework, System.Xaml, UIAutomationTypes, WindowsBase.
*)
// STAThread, DateTime
open System
// Application
open System.Windows
// TextBox
open System.Windows.Controls
// XAML type provider
open FSharpx
type MainWindow = XAML<"MainWindow.xaml">
type TextBox2 (status : TextBlock) as this =
inherit TextBox () with
member private this.preview_mouse_left_button_down (args : Input.MouseButtonEventArgs) = do
this.CaptureMouse () |> ignore
base.OnPreviewMouseLeftButtonDown args
// Fires while selecting text with the mouse, but not while dragging.
member private this.preview_mouse_move (args : Input.MouseEventArgs) =
if this.IsMouseCaptured then do status.Text <- sprintf "mouse move: %d" <| DateTime.Now.Ticks
do base.OnPreviewMouseMove args
member private this.preview_mouse_left_button_up (args : Input.MouseButtonEventArgs) = do
if this.IsMouseCaptured then do this.ReleaseMouseCapture ()
base.OnPreviewMouseLeftButtonUp args
do
this.PreviewMouseLeftButtonDown.Add this.preview_mouse_left_button_down
this.PreviewMouseMove.Add this.preview_mouse_move
this.PreviewMouseLeftButtonUp.Add this.preview_mouse_left_button_up
let load_window () =
let win = MainWindow ()
let t = new TextBox2 (win.statustext1)
do
t.TextWrapping <- TextWrapping.Wrap
t.AcceptsReturn <- true
t.Height <- Double.NaN
win.panel1.Children.Add t |> ignore
win.Root
[<STAThread>]
(new Application () ).Run(load_window () ) |> ignore
I think you can do this more effectively with PreviewDragEnter, PreviewDragOver, and Drop. I wrote a blog topic on writing your own Drag-and-Drop Textbox that should help get you started. You can add the scrolling functionality from there:
http://xcalibur37.wordpress.com/2011/12/10/wpf-drag-and-drop-textbox-for-windows-explorer-files/
The code:
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
// Initialize UI
InitializeComponent();
// Loaded event
this.Loaded += delegate
{
TextBox1.AllowDrop = true;
TextBox1.PreviewDragEnter += TextBox1PreviewDragEnter;
TextBox1.PreviewDragOver += TextBox1PreviewDragOver;
TextBox1.Drop += TextBox1DragDrop;
};
}
/// <summary>
/// We have to override this to allow drop functionality.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void TextBox1PreviewDragOver(object sender, DragEventArgs e)
{
e.Handled = true;
}
/// <summary>
/// Evaluates the Data and performs the DragDropEffect
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TextBox1PreviewDragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effects = DragDropEffects.Copy;
}
else
{
e.Effects = DragDropEffects.None;
}
}
/// <summary>
/// The drop activity on the textbox.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TextBox1DragDrop(object sender, DragEventArgs e)
{
// Get data object
var dataObject = e.Data as DataObject;
// Check for file list
if (dataObject.ContainsFileDropList())
{
// Clear values
TextBox1.Text = string.Empty;
// Process file names
StringCollection fileNames = dataObject.GetFileDropList();
StringBuilder bd = new StringBuilder();
foreach (var fileName in fileNames)
{
bd.Append(fileName + "\n");
}
// Set text
TextBox1.Text = bd.ToString();
}
}
}
The blog topic gives you a broken-down analysis of each section.
I know this is an old question, but I had to do something similar and my solution also works for this problem. I figure I might as well link it here just in case. It's not the simplest solution but it works perfectly.
I ended up a using hooks via p/invoke to get at the native window messages before they were consumed by the drag and drop operation. By using the WH_MOUSE hook I was able to intercept the WM_MOUSEMOVE message and track the mouse without WPF's Mouse and DragDrop events. This should work for all mouse messages including WM_MOUSEWHEEL.
You can check out my question where I ended up posting my own answer. I included most of the source code with it:
WPF - Track mouse during Drag & Drop while AllowDrop = False

WPF Best way of displaying a busy indicator when dynamically creating a page

I have a WPF application that runs as an XBAP in a browser. On a few pages all the controls are dynamically created depending on what the user selects. Because of this it can look like the application is not doing anything until all the controls are loaded. I'd like to have some sort of busy indicator displayed before hand to show the user that the controls are loading, it doesn't have to be animated although would be nice if it did. I've looked into the telerik busy indicator but this doesn't work as it's really for getting data for a single control and doesn't show until the controls are loaded which defeats the purpose.
I was thinking of displaying an overlay, or something similar, first, containing a loading logo, then load the page behind this and hide the overlay when the controls have loaded. I was wondering if this was the best way of going about this or if there's a better way?
Note: I haven't tried this in a XBAP browser app, but it works in WPF Apps without any problems!
I use a DispatcherTimer to show an hourglass when necessary, and abstract this code to a static class.
public static class UiServices
{
/// <summary>
/// A value indicating whether the UI is currently busy
/// </summary>
private static bool IsBusy;
/// <summary>
/// Sets the busystate as busy.
/// </summary>
public static void SetBusyState()
{
SetBusyState(true);
}
/// <summary>
/// Sets the busystate to busy or not busy.
/// </summary>
/// <param name="busy">if set to <c>true</c> the application is now busy.</param>
private static void SetBusyState(bool busy)
{
if (busy != IsBusy)
{
IsBusy = busy;
Mouse.OverrideCursor = busy ? Cursors.Wait : null;
if (IsBusy)
{
new DispatcherTimer(TimeSpan.FromSeconds(0), DispatcherPriority.ApplicationIdle, dispatcherTimer_Tick, Application.Current.Dispatcher);
}
}
}
/// <summary>
/// Handles the Tick event of the dispatcherTimer control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
private static void dispatcherTimer_Tick(object sender, EventArgs e)
{
var dispatcherTimer = sender as DispatcherTimer;
if (dispatcherTimer != null)
{
SetBusyState(false);
dispatcherTimer.Stop();
}
}
}
You would use it like this:
void DoSomething()
{
UiServices.SetBusyState();
// Do your thing
}
Hope this helps!

User-friendly way to display a Visual in a WPF application?

Looking for a simple, elegant way to display any given Visual to the user. The only way I can think of off my head is to slap it in a brush and paint it on a Rectangle that's in a ScrollViewer. Not exactly the best option.
You could create a wrapper that inherits from FrameworkElement that would either host your Visual or a generic wrapper that will host any object deriving from Visual.
Take a look at the example in Visual.AddVisual or, if you want to host more than one visual, take a look at the (partial) example in Using DrawingVisual Objects
I don't see a way how you could do that since a Visual has neither a position nor a size. Perhaps stick to FrameworkElement and create a style for it?
My (current) answer is to slap it in an XpsDocument and display it in a DocumentViewer. I could, I suppose, do it a little less complex, but I already have the infrastructure to do it this way. Its not 100%, but it works.
First, a behavior so that I can bind to DocumentViewer.Document (its a friggen POCO, urgh):
public sealed class XpsDocumentBinding
{
#region Document
/// <summary>
/// The <see cref="DependencyProperty"/> for <see cref="Document"/>.
/// </summary>
public static readonly DependencyProperty DocumentProperty =
DependencyProperty.RegisterAttached(
"Document",
typeof(XpsDocument), //
typeof(XpsDocumentBinding),
new UIPropertyMetadata(null, OnDocumentChanged));
/// <summary>
/// Gets the value of the <see cref="DocumentProperty">Document attached property</see> on the given <paramref name="target"/>.
/// </summary>
/// <param name="target">The <see cref="DependencyObject">target</see> on which the property is set.</param>
public static XpsDocument GetDocument(DependencyObject target)
{
return (XpsDocument)target.GetValue(DocumentProperty);
}
/// <summary>
/// Sets the <paramref name="value"/> of the <see cref="DocumentProperty">Document attached property</see> on the given <paramref name="target"/>.
/// </summary>
/// <param name="dependencyObject">The <see cref="DependencyObject">target</see> on which the property is to be set.</param>
/// <param name="value">The value to set.</param>
public static void SetDocument(DependencyObject target, XpsDocument value)
{
target.SetValue(DocumentProperty, value);
}
/// <summary>
/// Called when Document changes.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
private static void OnDocumentChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var viewer = sender as DocumentViewer;
if (viewer == null)
throw new InvalidOperationException(
"This behavior is only valid on DocumetViewers.");
var doc = e.NewValue as XpsDocument;
if (doc == null)
return;
viewer.Document = doc.GetFixedDocumentSequence();
}
#endregion
}
Then in my model I expose my visual as an XpsDocument
var pack = PackageStore.GetPackage(_uri);
if (pack != null)
return new XpsDocument(pack, CompressionOption.SuperFast, _uri.AbsoluteUri);
MemoryStream ms = new MemoryStream(2048);
Package p = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);
PackageStore.AddPackage(_uri, p);
XpsDocument doc = new XpsDocument(p, CompressionOption.SuperFast, _uri.AbsoluteUri);
var writer = XpsDocument.CreateXpsDocumentWriter(doc);
var collator = writer.CreateVisualsCollator();
// write the visuals using our collator
collator.BeginBatchWrite();
collator.Write(Visual);
collator.EndBatchWrite();
p.Flush();
return doc;
Just add a DocumentViewer, bind the result of the conversion method to it via the behavior, and there it is. I'm sure there's a shortcut in here somewhere...

How does the WPF Button.IsCancel property work?

The basic idea behind a Cancel button is to enable closing your window with an Escape Keypress.
You can set the IsCancel property on
the Cancel button to true, causing the
Cancel button to automatically close
the dialog without handling the Click
event.
Source: Programming WPF (Griffith, Sells)
So this should work
<Window>
<Button Name="btnCancel" IsCancel="True">_Close</Button>
</Window>
However the behavior I expect isn't working out for me. The parent window is the main application window specified by the Application.StartupUri property. What works is
<Button Name="btnCancel" IsCancel=True" Click="CloseWindow">_Close</Button>
private void CloseWindow(object sender, RoutedEventArgs)
{
this.Close();
}
Is the behavior of IsCancel different based on whether the Window is a normal window or a Dialog? Does IsCancel work as advertised only if ShowDialog has been called?
Is an explicit Click handler required for the button (with IsCancel set to true) to close a window on an Escape press?
Yes, it only works on dialogs as a normal window has no concept of "cancelling", it's the same as DialogResult.Cancel returning from ShowDialog in WinForms.
If you wanted to close a Window with escape you could add a handler to PreviewKeyDown on the window, pickup on whether it is Key.Escape and close the form:
public MainWindow()
{
InitializeComponent();
this.PreviewKeyDown += new KeyEventHandler(CloseOnEscape);
}
private void CloseOnEscape(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
Close();
}
We can take Steve's answer one step further and create an attached property that provides the "escape on close" functionality for any window. Write the property once and use it in any window. Just add the following to the window XAML:
yournamespace:WindowService.EscapeClosesWindow="True"
Here's the code for the property:
using System.Windows;
using System.Windows.Input;
/// <summary>
/// Attached behavior that keeps the window on the screen
/// </summary>
public static class WindowService
{
/// <summary>
/// KeepOnScreen Attached Dependency Property
/// </summary>
public static readonly DependencyProperty EscapeClosesWindowProperty = DependencyProperty.RegisterAttached(
"EscapeClosesWindow",
typeof(bool),
typeof(WindowService),
new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnEscapeClosesWindowChanged)));
/// <summary>
/// Gets the EscapeClosesWindow property. This dependency property
/// indicates whether or not the escape key closes the window.
/// </summary>
/// <param name="d"><see cref="DependencyObject"/> to get the property from</param>
/// <returns>The value of the EscapeClosesWindow property</returns>
public static bool GetEscapeClosesWindow(DependencyObject d)
{
return (bool)d.GetValue(EscapeClosesWindowProperty);
}
/// <summary>
/// Sets the EscapeClosesWindow property. This dependency property
/// indicates whether or not the escape key closes the window.
/// </summary>
/// <param name="d"><see cref="DependencyObject"/> to set the property on</param>
/// <param name="value">value of the property</param>
public static void SetEscapeClosesWindow(DependencyObject d, bool value)
{
d.SetValue(EscapeClosesWindowProperty, value);
}
/// <summary>
/// Handles changes to the EscapeClosesWindow property.
/// </summary>
/// <param name="d"><see cref="DependencyObject"/> that fired the event</param>
/// <param name="e">A <see cref="DependencyPropertyChangedEventArgs"/> that contains the event data.</param>
private static void OnEscapeClosesWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Window target = (Window)d;
if (target != null)
{
target.PreviewKeyDown += new System.Windows.Input.KeyEventHandler(Window_PreviewKeyDown);
}
}
/// <summary>
/// Handle the PreviewKeyDown event on the window
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">A <see cref="KeyEventArgs"/> that contains the event data.</param>
private static void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
Window target = (Window)sender;
// If this is the escape key, close the window
if (e.Key == Key.Escape)
target.Close();
}
}
This isn't quite right is it...
MSDN says this: When you set the IsCancel property of a button to true, you create a Button that is registered with the AccessKeyManager. The button is then activated when a user presses the ESC key.
So you do need a handler in your code behind
And you don't need any attached properties or anything like that
Yes this is right.In windows Application in WPF AcceptButton and Cancel Button is there. But one thing is that if you are setting your control visibility as false, then it won't work as expected.For that you need to make as visibility as true in WPF. For example: (it is not working for Cancel button because here visibility is false)
<Button x:Name="btnClose" Content="Close" IsCancel="True" Click="btnClose_Click" Visibility="Hidden"></Button>
So, you need make it:
<Button x:Name="btnClose" Content="Close" IsCancel="True" Click="btnClose_Click"></Button>
Then you have write btnClose_Click in code behind file:
private void btnClose_Click (object sender, RoutedEventArgs e)
{ this.Close(); }

Keyboard events in a WPF MVVM application?

How can I handle the Keyboard.KeyDown event without using code-behind? We are trying to use the MVVM pattern and avoid writing an event handler in code-behind file.
To bring an updated answer, the .net 4.0 framework enables you to do this nicely by letting you bind a KeyBinding Command to a command in a viewmodel.
So... If you wanted to listen for the Enter key, you'd do something like this:
<TextBox AcceptsReturn="False">
<TextBox.InputBindings>
<KeyBinding
Key="Enter"
Command="{Binding SearchCommand}"
CommandParameter="{Binding Path=Text, RelativeSource={RelativeSource AncestorType={x:Type TextBox}}}" />
</TextBox.InputBindings>
</TextBox>
WOW - there's like a thousand answers and here I'm going to add another one..
The really obvious thing in a 'why-didn't-I-realise-this-forehead-slap' kind of way is that the code-behind and the ViewModel sit in the same room so-to-speak, so there is no reason why they're not allowed to have a conversation.
If you think about it, the XAML is already intimately coupled to the ViewModel's API, so you might just as well go and make a dependency on it from the code behind.
The other obvious rules to obey or ignore still applies (interfaces, null checks <-- especially if you use Blend...)
I always make a property in the code-behind like this:
private ViewModelClass ViewModel { get { return DataContext as ViewModelClass; } }
This is the client-code. The null check is for helping control hosting as like in blend.
void someEventHandler(object sender, KeyDownEventArgs e)
{
if (ViewModel == null) return;
/* ... */
ViewModel.HandleKeyDown(e);
}
Handle your event in the code behind like you want to (UI events are UI-centric so it's OK) and then have a method on the ViewModelClass that can respond to that event. The concerns are still seperated.
ViewModelClass
{
public void HandleKeyDown(KeyEventArgs e) { /* ... */ }
}
All these other attached properties and voodoo is very cool and the techniques are really useful for some other things, but here you might get away with something simpler...
A little late, but here goes.
Microsoft's WPF Team recently released an early version of their WPF MVVM Toolkit
. In it, you'll find a class called CommandReference that can handle things like keybindings. Look at their WPF MVVM template to see how it works.
I do this by using an attached behaviour with 3 dependency properties; one is the command to execute, one is the parameter to pass to the command and the other is the key which will cause the command to execute. Here's the code:
public static class CreateKeyDownCommandBinding
{
/// <summary>
/// Command to execute.
/// </summary>
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command",
typeof(CommandModelBase),
typeof(CreateKeyDownCommandBinding),
new PropertyMetadata(new PropertyChangedCallback(OnCommandInvalidated)));
/// <summary>
/// Parameter to be passed to the command.
/// </summary>
public static readonly DependencyProperty ParameterProperty =
DependencyProperty.RegisterAttached("Parameter",
typeof(object),
typeof(CreateKeyDownCommandBinding),
new PropertyMetadata(new PropertyChangedCallback(OnParameterInvalidated)));
/// <summary>
/// The key to be used as a trigger to execute the command.
/// </summary>
public static readonly DependencyProperty KeyProperty =
DependencyProperty.RegisterAttached("Key",
typeof(Key),
typeof(CreateKeyDownCommandBinding));
/// <summary>
/// Get the command to execute.
/// </summary>
/// <param name="sender"></param>
/// <returns></returns>
public static CommandModelBase GetCommand(DependencyObject sender)
{
return (CommandModelBase)sender.GetValue(CommandProperty);
}
/// <summary>
/// Set the command to execute.
/// </summary>
/// <param name="sender"></param>
/// <param name="command"></param>
public static void SetCommand(DependencyObject sender, CommandModelBase command)
{
sender.SetValue(CommandProperty, command);
}
/// <summary>
/// Get the parameter to pass to the command.
/// </summary>
/// <param name="sender"></param>
/// <returns></returns>
public static object GetParameter(DependencyObject sender)
{
return sender.GetValue(ParameterProperty);
}
/// <summary>
/// Set the parameter to pass to the command.
/// </summary>
/// <param name="sender"></param>
/// <param name="parameter"></param>
public static void SetParameter(DependencyObject sender, object parameter)
{
sender.SetValue(ParameterProperty, parameter);
}
/// <summary>
/// Get the key to trigger the command.
/// </summary>
/// <param name="sender"></param>
/// <returns></returns>
public static Key GetKey(DependencyObject sender)
{
return (Key)sender.GetValue(KeyProperty);
}
/// <summary>
/// Set the key which triggers the command.
/// </summary>
/// <param name="sender"></param>
/// <param name="key"></param>
public static void SetKey(DependencyObject sender, Key key)
{
sender.SetValue(KeyProperty, key);
}
/// <summary>
/// When the command property is being set attach a listener for the
/// key down event. When the command is being unset (when the
/// UIElement is unloaded for instance) remove the listener.
/// </summary>
/// <param name="dependencyObject"></param>
/// <param name="e"></param>
static void OnCommandInvalidated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
UIElement element = (UIElement)dependencyObject;
if (e.OldValue == null && e.NewValue != null)
{
element.AddHandler(UIElement.KeyDownEvent,
new KeyEventHandler(OnKeyDown), true);
}
if (e.OldValue != null && e.NewValue == null)
{
element.RemoveHandler(UIElement.KeyDownEvent,
new KeyEventHandler(OnKeyDown));
}
}
/// <summary>
/// When the parameter property is set update the command binding to
/// include it.
/// </summary>
/// <param name="dependencyObject"></param>
/// <param name="e"></param>
static void OnParameterInvalidated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
UIElement element = (UIElement)dependencyObject;
element.CommandBindings.Clear();
// Setup the binding
CommandModelBase commandModel = e.NewValue as CommandModelBase;
if (commandModel != null)
{
element.CommandBindings.Add(new CommandBinding(commandModel.Command,
commandModel.OnExecute, commandModel.OnQueryEnabled));
}
}
/// <summary>
/// When the trigger key is pressed on the element, check whether
/// the command should execute and then execute it.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
static void OnKeyDown(object sender, KeyEventArgs e)
{
UIElement element = sender as UIElement;
Key triggerKey = (Key)element.GetValue(KeyProperty);
if (e.Key != triggerKey)
{
return;
}
CommandModelBase cmdModel = (CommandModelBase)element.GetValue(CommandProperty);
object parameter = element.GetValue(ParameterProperty);
if (cmdModel.CanExecute(parameter))
{
cmdModel.Execute(parameter);
}
e.Handled = true;
}
}
To use this from xaml you can do something like this:
<TextBox framework:CreateKeyDownCommandBinding.Command="{Binding MyCommand}">
<framework:CreateKeyDownCommandBinding.Key>Enter</framework:CreateKeyDownCommandBinding.Key>
</TextBox>
Edit: CommandModelBase is a base class I use for all commands. It's based on the CommandModel class from Dan Crevier's article on MVVM (here). Here's the source for the slightly modified version I use with CreateKeyDownCommandBinding:
public abstract class CommandModelBase : ICommand
{
RoutedCommand routedCommand_;
/// <summary>
/// Expose a command that can be bound to from XAML.
/// </summary>
public RoutedCommand Command
{
get { return routedCommand_; }
}
/// <summary>
/// Initialise the command.
/// </summary>
public CommandModelBase()
{
routedCommand_ = new RoutedCommand();
}
/// <summary>
/// Default implementation always allows the command to execute.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void OnQueryEnabled(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = CanExecute(e.Parameter);
e.Handled = true;
}
/// <summary>
/// Subclasses must provide the execution logic.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void OnExecute(object sender, ExecutedRoutedEventArgs e)
{
Execute(e.Parameter);
}
#region ICommand Members
public virtual bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public abstract void Execute(object parameter);
#endregion
}
Comments and suggestions for improvements would be very welcome.
Similar to karlipoppins answer, but I found it didn't work without the following additions/changes:
<TextBox Text="{Binding UploadNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding FindUploadCommand}" />
</TextBox.InputBindings>
</TextBox>
I looked into that issue a few months ago, and I wrote a markup extension that does the trick. It can be used like a regular binding :
<Window.InputBindings>
<KeyBinding Key="E" Modifiers="Control" Command="{input:CommandBinding EditCommand}"/>
</Window.InputBindings>
The full source code for this extension can be found here :
http://www.thomaslevesque.com/2009/03/17/wpf-using-inputbindings-with-the-mvvm-pattern/
Please be aware that this workaround is probably not very "clean", because it uses some private classes and fields through reflection...
Short answer is you can't handle straight keyboard input events without code-behind, but you can handle InputBindings with MVVM (I can show you a relevant example if this is what you need).
Can you provide more information on what you want to do in the handler?
Code-behind isn't to be avoided entirely with MVVM. It's simply to be used for strictly UI-related tasks. A cardinal example would be having some type of 'data entry form' that, when loaded, needs to set focus to the first input element (text box, combobox, whatever). You would commonly assign that element an x:Name attribute, then hook up the Window/Page/UserControl's 'Loaded' event to set focus to that element. This is perfectly ok by the pattern because the task is UI-centric and has nothing to do with the data it represents.
I know this question is very old, but I came by this because this type of functionality was just made easier to implement in Silverlight (5). So maybe others will come by here too.
I wrote this simple solution after I could not find what I was looking for. Turned out it was rather simple. It should work in both Silverlight 5 and WPF.
public class KeyToCommandExtension : IMarkupExtension<Delegate>
{
public string Command { get; set; }
public Key Key { get; set; }
private void KeyEvent(object sender, KeyEventArgs e)
{
if (Key != Key.None && e.Key != Key) return;
var target = (FrameworkElement)sender;
if (target.DataContext == null) return;
var property = target.DataContext.GetType().GetProperty(Command, BindingFlags.Public | BindingFlags.Instance, null, typeof(ICommand), new Type[0], null);
if (property == null) return;
var command = (ICommand)property.GetValue(target.DataContext, null);
if (command != null && command.CanExecute(Key))
command.Execute(Key);
}
public Delegate ProvideValue(IServiceProvider serviceProvider)
{
if (string.IsNullOrEmpty(Command))
throw new InvalidOperationException("Command not set");
var targetProvider = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
if (!(targetProvider.TargetObject is FrameworkElement))
throw new InvalidOperationException("Target object must be FrameworkElement");
if (!(targetProvider.TargetProperty is EventInfo))
throw new InvalidOperationException("Target property must be event");
return Delegate.CreateDelegate(typeof(KeyEventHandler), this, "KeyEvent");
}
Usage:
<TextBox KeyUp="{MarkupExtensions:KeyToCommand Command=LoginCommand, Key=Enter}"/>
Notice that Command is a string and not an bindable ICommand. I know this is not as flexible, but it is cleaner when used, and what you need 99% of the time. Though it should not be a problem to change.

Resources