WPF allows attaching of Application commands to user controls so that your control can respond to a command without any additional code.
You have to use the System.Windows.Input.CommandManager to register an instance of the System.Windows.Input.CommandBinding class for each member of System.Windows.Input.ApplicationCommands you need to support in your user control. The CommandBinding specifies the type of command you want to receive notification of, specifies an event handler to determine when the command can be executed, and specifies another event handler to be called when the command is executed. These event handlers are called the CanExecute and Executed event handlers.
For example if you want to launch the Print dialog from your user control when the user presses Ctrl+P. Then you have to register the ApplicationCommands.Print member in your user control. The below given sample code shows how to do that.
CommandManager.RegisterClassCommandBinding(
typeof(FileUploader),
new CommandBinding(
ApplicationCommands.Print,
(x, y) => new PrintDialog().ShowDialog(),
(x, y) => y.CanExecute = true));
Webscale architecture, Actors, CQRS, PowerShell, DevOps, Infrastructure as Code, Continuous Delivery
Thursday, February 26, 2009
Wednesday, February 18, 2009
WPF - Validating a dependency property
Validation business rules can be implemented in WPF dependency property by adding a ValidationCallbackHandler when specifying PropertyMetadata options for a DependencyProperty.
The validation method returns a Boolean value mentioning the validation of the property value that is set. The PropertyChangedCallback method is only invoked if the validation rules are passed. This way makes sure that the business rule is validated when using WPF properties.
In the example given below I have used a ValidationCallbackHandler to check whether the user input in the textbox is a positive number or not. If the validation rule fails the ForeColor of the textbox is changed to Red, otherwise the message box is displayed showing that the property was changed successfully.
public static readonly DependencyProperty PositiveNumberProperty = DependencyProperty.Register("PositiveNumber", typeof(int), typeof(Window1),
new PropertyMetadata(0, (x, y) =>
{
MessageBox.Show("Property changed");
Window1 mainWindow = x as Window1;
if (mainWindow != null)
{
mainWindow.PositiveNumberTextBox.Foreground = Brushes.Black;
mainWindow.PositiveNumberTextBox.FontWeight = FontWeights.Normal;
}
}), (x) =>
{
int positiveValue;
if (int.TryParse(x.ToString(), out positiveValue))
{
if (positiveValue >= 0)
return true;
}
return false;
});
public int PositiveValue
{
get { return (int)GetValue(PositiveNumberProperty); }
set { SetValue(PositiveNumberProperty, value); }
}
private void OnValueChanged(object sender, KeyEventArgs e)
{
TextBox textBox = sender as TextBox;
if (sender != null)
{
textBox.Foreground = Brushes.Red;
textBox.FontWeight = FontWeights.Bold;
}
}
The XAML for the sample is
<Window x:Class="MyWPFSamples.Validation.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Validating DependencyProperty" Height="300" Width="500"> <StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="16" Margin="6" FontWeight="Bold"> Enter a positive number </TextBlock>
<TextBox x:Name="PositiveNumberTextBox" Margin="6" FontSize="12" Width="150" Text="{Binding Path=PositiveNumber, UpdateSourceTrigger=PropertyChanged}" PreviewKeyDown="OnValueChanged"></TextBox>
</StackPanel>
</StackPanel>
</Window>
Output
The validation method returns a Boolean value mentioning the validation of the property value that is set. The PropertyChangedCallback method is only invoked if the validation rules are passed. This way makes sure that the business rule is validated when using WPF properties.
In the example given below I have used a ValidationCallbackHandler to check whether the user input in the textbox is a positive number or not. If the validation rule fails the ForeColor of the textbox is changed to Red, otherwise the message box is displayed showing that the property was changed successfully.
public static readonly DependencyProperty PositiveNumberProperty = DependencyProperty.Register("PositiveNumber", typeof(int), typeof(Window1),
new PropertyMetadata(0, (x, y) =>
{
MessageBox.Show("Property changed");
Window1 mainWindow = x as Window1;
if (mainWindow != null)
{
mainWindow.PositiveNumberTextBox.Foreground = Brushes.Black;
mainWindow.PositiveNumberTextBox.FontWeight = FontWeights.Normal;
}
}), (x) =>
{
int positiveValue;
if (int.TryParse(x.ToString(), out positiveValue))
{
if (positiveValue >= 0)
return true;
}
return false;
});
public int PositiveValue
{
get { return (int)GetValue(PositiveNumberProperty); }
set { SetValue(PositiveNumberProperty, value); }
}
private void OnValueChanged(object sender, KeyEventArgs e)
{
TextBox textBox = sender as TextBox;
if (sender != null)
{
textBox.Foreground = Brushes.Red;
textBox.FontWeight = FontWeights.Bold;
}
}
The XAML for the sample is
<Window x:Class="MyWPFSamples.Validation.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Validating DependencyProperty" Height="300" Width="500"> <StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="16" Margin="6" FontWeight="Bold"> Enter a positive number </TextBlock>
<TextBox x:Name="PositiveNumberTextBox" Margin="6" FontSize="12" Width="150" Text="{Binding Path=PositiveNumber, UpdateSourceTrigger=PropertyChanged}" PreviewKeyDown="OnValueChanged"></TextBox>
</StackPanel>
</StackPanel>
</Window>
Thursday, February 12, 2009
Unit testing CAB applications
Creating unit tests is a quite challenging thing to do when creating a CAB application. Especially with the dependencies built during runtime by dependency injection that the CAB depends on. The main requirement for creating a unit test project for CAB is a Testable workitem. The TestableWorkItem class holds all the items required by the Dependency Injection framework while running the tests.
public class TestableRootWorkItem : WorkItem
{
public TestableRootWorkItem()
{
InitializeRootWorkItem(CreateBuilder());
Services.AddNew();
Services.AddNew();
Services.AddNew();
}
public Builder Builder
{
get { return InnerBuilder; }
}
public IReadWriteLocator Locator
{
get { return InnerLocator; }
}
private Builder CreateBuilder()
{
Builder builder = new Builder(); builder.Strategies.AddNew(BuilderStage.Initialization); builder.Strategies.AddNew(BuilderStage.Initialization); builder.Strategies.AddNew(BuilderStage.PostInitialization);
builder.Policies.SetDefault(new ObjectBuiltNotificationPolicy());
return builder;
}
}
Mocks can be created using any Mocking Framework. In this example I have used Rhino Mocks. The dependencies can be added to the TesttableWorkItem class during the TestInitialize stage and then get it resolved in the TestMethods
[TestInitialize()]
public void MyTestInitialize()
{
IEmployeeService _employeeService = mocks.StrictMock();
IListEmployeesView view = mocks.StrictMock();
using (mocks.Record())
{
Expect.Call(_employeeService.GetCount()).Return(4);
}
workItem = new TestableRootWorkItem();
workItem.Services.Add(_employeeService);
eventPublisher = workItem.Items.AddNew();
eventSubscriber = workItem.Items.AddNew();
presenter = workItem.Items.AddNew();
presenter.View = view;
}
[TestMethod()]
public void GetCountTest()
{
int expected = 4;
int actual;
actual = presenter.GetCount();
Assert.AreEqual(expected, actual, "Count returned did not match the expected value");
}
[TestMethod]
public void EventPublicationSubscriptionTest()
{
eventPublisher.OnInsertEmployee(new EventArgs("Prajeesh"));
Assert.AreEqual(true, eventPublisher.NewEmployeeEventRaised, "Failed to raise event publication");
Assert.AreEqual(true, eventSubscriber.NewEmployeeEventHandled, "Failed to handle event publication");
}
public class TestableRootWorkItem : WorkItem
{
public TestableRootWorkItem()
{
InitializeRootWorkItem(CreateBuilder());
Services.AddNew
Services.AddNew
Services.AddNew
}
public Builder Builder
{
get { return InnerBuilder; }
}
public IReadWriteLocator Locator
{
get { return InnerLocator; }
}
private Builder CreateBuilder()
{
Builder builder = new Builder(); builder.Strategies.AddNew
builder.Policies.SetDefault
return builder;
}
}
Mocks can be created using any Mocking Framework. In this example I have used Rhino Mocks. The dependencies can be added to the TesttableWorkItem class during the TestInitialize stage and then get it resolved in the TestMethods
[TestInitialize()]
public void MyTestInitialize()
{
IEmployeeService _employeeService = mocks.StrictMock
IListEmployeesView view = mocks.StrictMock
using (mocks.Record())
{
Expect.Call(_employeeService.GetCount()).Return(4);
}
workItem = new TestableRootWorkItem();
workItem.Services.Add
eventPublisher = workItem.Items.AddNew
eventSubscriber = workItem.Items.AddNew
presenter = workItem.Items.AddNew
presenter.View = view;
}
[TestMethod()]
public void GetCountTest()
{
int expected = 4;
int actual;
actual = presenter.GetCount();
Assert.AreEqual
}
[TestMethod]
public void EventPublicationSubscriptionTest()
{
eventPublisher.OnInsertEmployee(new EventArgs
Assert.AreEqual
Assert.AreEqual
}
Subscribe to:
Posts (Atom)