Trouble with simple C# WPF custom controls - c#

I'm having some difficulty finding simple examples while using WPF when it comes to control bindings and I'm hoping you can help me get my head around it with this simple example.
Can you please explain why this doesn't work and also a simple way to get it running?
I've looked at numerous tutorials but they are all still a little advanced for me at this stage I think so any help is greatly appreciated.
Thanks!
XAML:
<Window
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" x:Class="DemoProject.MainWindow"
xmlns:custom="clr-namespace:DemoProject"
Title="DemoProject" >
<TextBox x:Name="MyTextBox">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{x:Static custom:MainWindow.CommandEnterKeyPressed}"
CommandParameter="{Binding Path=Text, RelativeSource={RelativeSource AncestorType={x:Type TextBox}}}" />
</TextBox.InputBindings>
</TextBox>
<Window.CommandBindings>
<CommandBinding Command="{x:Static custom:MainWindow.CommandEnterKeyPressed}"
Executed="CommandEnterKeyPressedExecuted" />
</Window.CommandBindings>
</Window>
C#:
namespace DemoProject
{
public partial class MainWindow : Window
{
private static RoutedUICommand CommandEnterKeyPressed;
public MainWindow()
{
InitializeComponent();
}
public static RoutedUICommand CommandEnterKeyPressed = new RoutedUICommand();
private void CommandEnterKeyPressedExecuted(object sender, CanExecuteRoutedEventArgs e)
{
MessageBox.Show("Enter key was pressed");
}
}
}
When I run this, I get the errors
"The member "CommandEnterKeyPressed" is not recognised or is not
accessible" and "No overload for "'ommandEnterKeyPressed' matches
delegate 'System.Windows.Input.ExecutedRoutedEventHandler'".
Is there something simple I'm missing?
Thanks.

Change CanExecuteRoutedEventArgs to ExecutedRoutedEventArgs
private void CommandEnterKeyPressedExecuted(object sender, CanExecuteRoutedEventArgs e)
Should be
private void CommandEnterKeyPressedExecuted(object sender, ExecutedRoutedEventArgs e)
CanExecuteRoutedEventArgs is used for CanExecute event. You should also remove this line
private static RoutedUICommand CommandEnterKeyPressed;
and leave only public declaration of your RoutedUICommand

Related

WPF RoutedCommand CanExecute event is not fired

I have created a UserControl that has a command (DeleteCommand) inside:
public partial class TestControl : UserControl
{
public static RoutedCommand DeleteCommand = new RoutedCommand();
private void DeleteCommandExecute(object sender, ExecutedRoutedEventArgs e)
{
}
private void DeleteCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
public TestControl()
{
InitializeComponent();
CommandBinding deleteCommandBinding = new CommandBinding(DeleteCommand, DeleteCommandExecute, DeleteCommandCanExecute);
this.CommandBindings.Add(deleteCommandBinding);
}
}
I have put this UserControl inside a Window:
<Window x:Class="TestRoutedCommand.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestRoutedCommand"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Fire event" Margin="156,29,205,254" Command="{x:Static local:TestControl.DeleteCommand}" />
<local:TestControl Margin="126,135,135,46"/>
</Grid>
</Window>
There is also a Button which is using the DeleteCommand. My problem is that this button is always disabled and the DeleteCommandCanExecute handler is never called, although e.CanExecute is always set to true.
I have tried to call:
CommandManager.InvalidateRequerySuggested();
but nothing happens. The event is never fired. Maybe I am doing the CommandBinding wrong.
What I want to achieve is that when the user clicks on the button that the DeleteCommandExecute handler is fired. My goal is to create commands for my MenuButtons which will trigger some methods in my UserControls which can be deep in the Visual Tree.
Slightly change your XAML:
<Grid>
<Button Content="Fire event" Margin="156,29,205,254" Command="{x:Static local:TestControl.DeleteCommand}" CommandTarget="{Binding ElementName=Control1}" />
<local:TestControl x:Name="Control1" Margin="126,135,135,46"/>
</Grid>
CommandTarget says where to find needed handlers.

Triggering events from View to ViewModel in WPF

working in WPF with C# I am generating an event from a view MyView and what I need to do is to handle it in the associated view model class MyViewModel.
I am using caliburn.micro to solve and this is the code in synthesis:
<UserControl x:Class="MyView"
xmlns:cal="http://www.caliburnproject.org"
DataContext="MyViewModelInstance"
cal:Message.Attach="[Event CancelEvent]=[Action CancelButton_Click_MyViewModelHandler($source,$eventArgs)]">
<Grid>
<Button Click="CancelButton_Click"> </Button>
</Grid>
</UserControl>
In the code behind I handle the click event generating a CancelEvent:
public partial class MyView : UserControl
{
public event EventHandler CancelEvent;
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
if(CancelEvent!=null)
{
CancelEvent(sender,e);
}
}
}
In the class MyViewModel I defined the function
public void MyViewMOdelHandler(Object sender, EventArgs arg)
What I need to do is to handle the CancelEvent in MyViewModelInstance, using the code above results as no one is subscribed to the CancelEvent (CancelEvent == null) so that the CancelEvent handler in MyViewModelInstance is not invoked.
Does anybody know a solution to the problem? (caliburn is not mandatory)
Thanks in advance.
-Z-
I think the solution is easy. In your view:
<UserControl x:Class="MyView"
xmlns:cal="http://www.caliburnproject.org"
DataContext="YourViewModel"
<Grid>
<Button Click="CancelButton_Click" cal:Message.Attach="[Event Click]=[Action MyViewModelHandler($source,$eventArgs)]">> </Button>
</Grid>
CancelButton_Click in code behind can be removed.
In your viewmodel:
public class YourViewModel : PropertyChangedBase
{
public void MyViewModelHandler(Object sender, EventArgs arg)
{
}
}
Is there any reason you're not directly attaching the click event of the button? as that would be the simplest solution.
Looking at your example it would seem the Message.Attach is specifiing a method that doesn't exist.
If the method on the view model is
public void MyViewModelHandler(Object sender, EventArgs arg)
then the attach syntax would be
cal:Message.Attach="[Event CancelEvent]=[Action MyViewModelHandler($source,$eventArgs)]"

Catch custom event by Interactivity.EventTrigger

I have a simple user-control with an event:
using System.Windows;
namespace TriggersTest
{
public partial class MyControl
{
public MyControl()
{
InitializeComponent();
}
public static readonly RoutedEvent ButtonPressedEvent =
EventManager.RegisterRoutedEvent("ButtonPressed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyControl));
public event RoutedEventHandler ButtonPressed
{
add { AddHandler(ButtonPressedEvent, value); }
remove { RemoveHandler(ButtonPressedEvent, value); }
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs { RoutedEvent = ButtonPressedEvent });
}
}
}
And I want to catch this event in the other view:
<Window x:Class="TriggersTest.MainWindow"
Name="Root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:TriggersTest"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:MyControl>
<i:Interaction.Triggers>
<i:EventTrigger EventName="ButtonPressed">
<i:InvokeCommandAction Command="{Binding MyCommand, ElementName=Root}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</local:MyControl>
</Grid>
</Window>
The event has been raised, but i:EventTrigger doesn't invoke a command.
How can I fix this?
Its all fine with your code. The binding is not working. I can tell just by looking at this.
Do not use ElementName inside InvokeCommandAction because InvokeCommandAction is not part of LogicalTree in WPF.
Just change your Binding or use x:Reference and everything should be fine.

When to clean up a command-binded control?

I have a user control which has a CheckBox, a Button, and a CommandBinding. If the CheckBox is checked, the Button is enabled. The MainWindow uses the UserControl. When the Button in the main window is pressed, the UserControl is removed from UI, and GC.Collect() is called, but CanExecute method still runs.
I find that if I click the button in main window twice, CanExecute will no longer run. It seems that I don't call GC.Collect() at the right time.
I want to know what is the good timing to call GC to clean the unused user control, so that CanExecute will not be called.
XAML
<UserControl x:Class="WpfApplication1.UserControl1"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<RoutedUICommand x:Key="okCommand" Text="OK"/>
</UserControl.Resources>
<UserControl.CommandBindings>
<CommandBinding Command="{StaticResource okCommand}" CanExecute="CommandBinding_CanExecute_1"/>
</UserControl.CommandBindings>
<StackPanel>
<CheckBox Name="checkBox" Content="CheckBox"/>
<Button Command="{StaticResource okCommand}" Content="{Binding Path=Text, Source={StaticResource okCommand}}"/>
</StackPanel>
</UserControl>
Code behind
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void CommandBinding_CanExecute_1(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = checkBox.IsChecked.GetValueOrDefault(false);
System.Media.SystemSounds.Beep.Play();
}
}
MainWindow
<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" Loaded="Window_Loaded_1">
<StackPanel>
<Border Name="container"/>
<Button Content="Set Null" Click="Button_Click_1"/>
</StackPanel>
</Window>
Code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
container.Child = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
UserControl1 uc = new UserControl1();
container.Child = uc;
}
}
Use grid as container and Container.Clear() method and forget about GC.
I find another solution. That is to call CommandBindings.Clear() in UserControl1 when it unloads.
I believe this is a neat way, since the caller of UserControl1 doesn't take care of the cleaning job of UserControl1.

button1.PerformClick() in wpf

Why this code in WPF does not work ?
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("yes");
}
private void Form1_Load(object sender, EventArgs e)
{
button1.PerformClick();
}
I need to command.
To use the windows form application's style, you need to write the following extension method:
namespace System.Windows.Controls
{
public static class MyExt
{
public static void PerformClick(this Button btn)
{
btn.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
}
}
}
now you can use it for any button, assuming a button called "btnOK":
btnOK.PerformClick();
Wait.. there is simple way. if your button name is button1 and button1 click event already subscribed,you will just call that event like
button1_Click(this,null);
Instead of PerformClick() use RaiseEvent()
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("yes");
}
private void Form1_Load(object sender, EventArgs e)
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(Button.ClickEvent);
button1.RaiseEvent(newEventArgs);
}
I think the shortest and most efficient solution to your problem would be simply done in one line.
button1.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
That should work for WPF C#
Good practice in WPF is using commands. It improves testability and separates UI and business logic.
First you may try RoutedUICommand.
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self ="clr-namespace:Test"
Title="MainWindow"
Height="350" Width="525">
<Window.CommandBindings>
<CommandBinding Command="{x:Static self:MainWindow.RoutedClickCommand}"
CanExecute="CommandBinding_CanExecute"
Executed="CommandBinding_Executed"/>
</Window.CommandBindings>
<Grid>
<Button Content="Test" Name="Btn1" Command="{x:Static self:MainWindow.RoutedClickCommand}"/>
</Grid>
In code behind file we have to define RoutedClickCommand and Execute|CanExecute handlers:
public static ICommand RoutedClickCommand = new RoutedUICommand("ClickCommand", "ClickCommand", typeof(MainWindow));
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("ololo");
}
So, when you need button logic ("button1.PerformClick();" in your sample), just put next line:
MainWindow.RoutedClickCommand.Execute(null);
As for me, I preffer another way which supposes carry command into presentation model. Composite Application Library (Prism) helps me with its DelegateCommand class. Then command definition in presentation model looks like:
private DelegateCommand<object> _clickCommand;
public ICommand ClickCommand
{
get
{
if (this._clickCommand == null)
{
this._clickCommand = new DelegateCommand<object>(p =>
{
//command logic
},
p =>
{
// can execute command logic
});
}
return this._clickCommand;
}
}
And view XAML and code behind:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self ="clr-namespace:Test"
Title="MainWindow"
Height="350" Width="525">
<Grid>
<Button Content="Test" Name="Btn1" Command="{Binding ClickCommand}"/>
</Grid>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Model = new SampleModel();
}
protected SampleModel Model
{
get
{
if (this.Model.ClickCommand.CanExecute())
{
this.Model.ClickCommand.Execute();
}
return (SampleModel)this.DataContext;
}
set
{
this.DataContext = value;
}
}
}
Next code calls command in view bypassing clicking on button:
if (this.Model.ClickCommand.CanExecute())
{
this.Model.ClickCommand.Execute();
}
An excerpt from Adam Nathans WPF Unleashed, recommended by this blog.
Imho one of the best, if not the best WPF references around.
var bap = new System.Windows.Automation.Peers.ButtonAutomationPeer(someButton);
var iip = bap.GetPattern(System.Windows.Automation.Peers.PatternInterface.Invoke)
as System.Windows.Automation.Provider.IInvokeProvider;
iip.Invoke();
Because PerformClick is a method on WindowsForms Button control:
http://msdn.microsoft.com/en-us/library/system.windows.forms.button.performclick.aspx
Not on the WPF Button control:
http://msdn.microsoft.com/en-us/library/system.windows.controls.button_methods.aspx
To automate a button click, you might like to take a look at the UI automation framework:
http://msdn.microsoft.com/en-us/library/ms747327.aspx

Categories

Resources