Pages

Showing posts with label Event Handlers. Show all posts
Showing posts with label Event Handlers. Show all posts

Saturday, 3 March 2012

Firing up the default Browser

This simple snippet shows how to display a URL in a WPF window and fire up the default browser when the link is clicked.
Starting with a TextBlock in the XAML:
      <TextBlock>
         <Hyperlink Click="Hyperlink_Click"
                    NavigateUri="http://mikestedman.blogspot.com/2012/03/wpf-string-formatting.html">Link to original WPF Waltz blog entry</Hyperlink>
      </TextBlock>
And a simple event handler in the code-behind:
      private void Hyperlink_Click(object sender, RoutedEventArgs e)
      {
         Process.Start((sender as Hyperlink).NavigateUri.ToString());
      }

Tuesday, 18 January 2011

Moving down a cell in a datagrid when you press Enter

In Stock we have some DataGrids for things like Counts, which we want to be able to enter values for successive rows from the keyboard.. ie, 1 , 3 etc..

While Tab moves across a cell, Enter doesn’t move the cell focus (since we’re using a custom control of a textbox in there, the textbox swallows the enter).

To enable the Enter to work, you can just add a KeyDown handler for the TextBox in the template and then add this code behind :
      private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
if ((e.Key == Key.Enter) || (e.Key == Key.Return))
{
TextBox FocusedControl = Keyboard.FocusedElement as TextBox;

if (FocusedControl != null)
{
TraversalRequest Traversal = new TraversalRequest(FocusNavigationDirection.Down);

FocusedControl.MoveFocus(Traversal);
}
}
}
Nice and simple in the end --- it turns out that the TraversalRequest and FocusNavigationDirection classes/enums are very simple and powerful & not limited to DataGrids at all.

Sunday, 1 February 2009

IsVisibleChanged

I have the following code which is trying to detect that I’ve clicked on a button and my UserControl is now visible, so I want to set focus to a sensible control in that usercontrol.

void UCBBNotes_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
  if ((bool)e.NewValue == true)
  {
     bool a = txtNotes.Focus();
     // a returns false 
     txtNotes.UpdateLayout();
     bool b = txtNotes.Focus();
     // b returns true
  }
}

So, when reacting to certain events such as “IsVisibleChanged”, the event is called before the layout has updated all the child controls. So txtNotes.Focus() fails because txtNotes.IsVisible = False at that point.

This can either be fixed as above by forcing an UpdateLayout by the Dispatcher – which probably isn’t ideal. Or, instead of watching for the usercontrol to become visible, watch for the textbox we want to focus upon to become visible, like this :

void txtNotes_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
  if ((bool)e.NewValue == true)
  {
     txtNotes.Focus();
  }
}

Monday, 3 November 2008

DelegateCommand vs RoutedCommand vs EventHandler

I wanted to evaluate the difference between using the different types of Command mechanisms. The following code snippets aren't intended to be a working example, they simply highlight the code differences.


DelegateCommand
SimplePresenter.cs

public DelegateCommand<string> GetCustomerByDC { get; private set; }

GetCustomerByDC = new DelegateCommand(ExecuteGetCustomer, CanExecuteGetCustomer);

private void ExecuteGetCustomer(string parameter)
{
try
{
int customerId = int.Parse(parameter);
GetCustomer(customerId);
}
catch { }
}
}
private bool CanExecuteGetCustomer(string parameter)
{
try
{
int customerId = int.Parse(parameter);
return true;
}
catch
{
return false;
}
}

SimpleView.xaml.cs
ObjectDataProvider odpPresenter = (ObjectDataProvider)this.FindResource("MyPresenter");
Presenter = (SimplePresenter)odpPresenter.ObjectInstance;
Presenter.Model = newModel as SimpleModel;
Presenter.View = this;
private void txtCustomerId_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
Presenter.GetCustomerByDC.RaiseCanExecuteChanged();
}

SimpleView.xaml

xmlns:Presenters="clr-namespace:Sandstorm.Documents.Patterns.Presenters"
<ObjectDataProvider x:Key="MyPresenter" d:IsDataSource="True" ObjectType="{x:Type Presenters:SimplePresenter}"/>
<Button
x:Name="btnGetByDC"
Command="{Binding Source={StaticResource MyPresenter}, Path=GetCustomerByDC}"
CommandParameter="{Binding ElementName=txtCustomerId, Path=Text}"
Width="170"
>Get By DelegateCommand</Button>
<TextBox
TextChanged="txtCustomerId_TextChanged"
/>

RoutedCommand

SimpleView.xaml.cs
private void GetCustomer_Executed(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)
{
if (e.Parameter != null)
{
try
{
int customerId = int.Parse(e.Parameter as string);
Presenter.GetCustomer(customerId);
}
catch { }
}
}
private void GetCustomer_CanExecute(object sender, System.Windows.Input.CanExecuteRoutedEventArgs e)
{
try
{
int customerId = int.Parse(e.Parameter as string);
e.CanExecute = true;
}
catch
{
e.CanExecute = false;
}
}

SimpleView.xaml
<UserControl.CommandBindings>
<CommandBinding
Command="local:LeisureCommands.GetCustomerCommand"
Executed="GetCustomer_Executed"
CanExecute="GetCustomer_CanExecute"
/>
</UserControl.CommandBindings>
<Button
x:Name="btnGetByRC"
Command="local:LeisureCommands.GetCustomerCommand"
CommandParameter="{Binding ElementName=txtCustomerId, Path=Text}"
Width="170"
>Get By Routed Command</Button>

LeisureCommands.cs
public class LeisureCommands : RoutedUICommand
{
public readonly static RoutedUICommand GetCustomerCommand;
static LeisureCommands()
{
GetCustomerCommand = new RoutedUICommand("Get Customer...", "GetCustomerCommand", typeof(LeisureCommands));
GetCustomerCommand.InputGestures.Add(new KeyGesture(Key.C, ModifierKeys.Alt));
}
}



Event
SimpleView.xaml.cs
private void btnGetByClick_Click(object sender, RoutedEventArgs e)
{
try
{
int customerId = int.Parse(txtCustomerId.Text);
Presenter.GetCustomer(customerId);
}
catch { }
}

SimpleView.xaml
<Button
x:Name="btnGetByClick"
Click="btnGetByClick_Click"
CommandParameter="{Binding ElementName=txtCustomerId, Path=Text}"
Width="170"
>Get By Click Event</Button>


Lines of code
TypeRawOneOffPer CommandCan ExecuteTotal
DelegateCommand406341222
RoutedCommand457381226
Event15015n/a15


Conclusion
The RoutedCommand is a little more expensive in LOC terms than the DelegateCommand but the DelegateCommand does not support all the features of the RoutedCommand, in particular: Gestures.
If the "CanExecute" facility is not required the Event is by far the cheapest / easiest to implement.
I guess my conclusion was: "What are the DelegateCommands bringing to the party?"

Thursday, 30 October 2008

Routed Commands

Although we have opted to use the DelegateCommand<T> class in our project, this article gives a good overview of the Command pattern used in WPF.

The Command Pattern In Windows Presentation Foundation

DelegateCommand<T> class implements ICommand rather than subclassing RoutedCommand. The problem with this is that CanExecute is fired only once. RoutedCommands listen to a number of events and fire CanExecute quite frequently.
DelegateCommand<T> offers the RaiseCanExecuteChanged() method which can be fired manually when some "significant" event happens.
Alternatively a timer could be used to call RaiseCanExecuteChanged() at regular intervals. The following code sample uses a DispatcherTimer to raise the event on the UI thread.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_aTimer.Tick += new EventHandler(_aTimer_Tick);
_aTimer.Interval = new TimeSpan(0, 0, 1);
_aTimer.IsEnabled = false;
}

void _aTimer_Tick(object sender, EventArgs e)
{
_model.MyCommand.RaiseCanExecuteChanged();
}


These are the standard supplied commands:
ApplicationCommands—Close, Copy, Cut, Delete, Find, Help, New, Open, Paste, Print, PrintPreview, Properties, Redo, Replace, Save, SaveAs, SelectAll, Stop, Undo, and more

ComponentCommands—MoveDown, MoveLeft, MoveRight, MoveUp, ScrollByLine, ScrollPageDown, ScrollPageLeft, ScrollPageRight, ScrollPageUp, SelectToEnd, SelectToHome, SelectToPageDown, SelectToPageUp, and more

MediaCommands—ChannelDown, ChannelUp, DecreaseVolume, FastForward, IncreaseVolume, MuteVolume, NextTrack, Pause, Play, PreviousTrack, Record, Rewind, Select, Stop, and more

NavigationCommands—BrowseBack, BrowseForward, BrowseHome, BrowseStop, Favorites, FirstPage, GoToPage, LastPage, NextPage, PreviousPage, Refresh, Search, Zoom, and more

EditingCommands—AlignCenter, AlignJustify, AlignLeft, AlignRight, CorrectSpellingError, DecreaseFontSize, DecreaseIndentation, EnterLineBreak, EnterParagraphBreak, IgnoreSpellingError, IncreaseFontSize, IncreaseIndentation, MoveDownByLine, MoveDownByPage, MoveDownByParagraph, MoveLeftByCharacter, MoveLeftByWord, MoveRightByCharacter, MoveRightByWord, and more

Sunday, 26 October 2008

Accessing Properties from abstract class

I wanted my abstract class to hook into the PropertyChanged event for any Property in the derived class that implements INotifyPropertyChanged.

I use reflection to get all the properties of the derived class then check that they implement the INotifyPropertyChanged interface before adding the event handler.

The Property must be defined in the "traditional" way rather than using the auto-property syntax otherwise the InitializeProperties method in the abstract class has no object to add the event handlers to.
public class Model : AbstractModel
{
private Till _till = new Till();
public Till Till
{
get { return _till; }
set { _till = value; }
}
}
public abstract class AbstractModel : INotifyPropertyChanged
{
public AbstractModel()
{
InitializeProperties();
}

private void InitializeProperties()
{
PropertyInfo[] propertyInfoList = this.GetType().GetProperties();

foreach (PropertyInfo propertyInfo in propertyInfoList)
{
object observedObject = propertyInfo.GetValue(this, null);
if (observedObject is INotifyPropertyChanged)
{
(observedObject as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(BusinessPropertyChanged);
}
}
}
...
}

Tuesday, 14 October 2008

Walking the VisualTree

This isn't all my own code but I thought it might be handy to keep track of some code that walks the VisualTree recursively and also does something with event handlers.

AddHandlers(this);

public void AddHandlers(DependencyObject dependencyObject)
{
int childCount = VisualTreeHelper.GetChildrenCount(dependencyObject);
for (int childIndex = 0; childIndex < childCount; childIndex++)

DependencyObject childObject = VisualTreeHelper.GetChild(dependencyObject, childIndex);

// In this example we're only interested in TextBoxes
if (childObject is TextBox)
{
if ((childObject as TextBox).GetBindingExpression(TextBox.TextProperty).ParentBinding.UpdateSourceTrigger == UpdateSourceTrigger.PropertyChanged)
{
(childObject as TextBox).TextChanged += new TextChangedEventHandler(TextBox_TextChanged);
}
}
AddHandlers(childObject);
}
}