Reputation: 1613
I have created a custom ContentControl in WPF and applied to it the following template:
<Style TargetType="{x:Type local:BdlUserControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:BdlUserControl">
<Grid x:Name="ContentGrid">
<Grid.RowDefinitions>
<RowDefinition Height="22"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="White">
<StackPanel HorizontalAlignment="Right">
<Button Content="Close" Width="50" Name="BtClose" Click="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BtClose_Click}"/>
</StackPanel>
</Grid>
<Grid Grid.Row="1">
<ContentPresenter Content="{TemplateBinding Content}" Margin="{TemplateBinding Padding}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The problem is that the BtClose doesn't call the method BtClose_Click declared in the code-behind of the custom control as shown below:
public void BtClose_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine("Test");
}
The error is very generic:
A first chance exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll
Any hints on why is that happening?
Upvotes: 4
Views: 9075
Reputation: 43596
In WPF you can only bind to a DependencyProperty
, In WPF Bottons have a Command property that you can Bind to. Commands are the MVVM way to handle events in WPF.
Here is a quick example of a Command binding in WPF.
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="50" Width="100" >
<Grid>
<Button Content="Click" Command="{Binding MyCommand}" />
</Grid>
</Window>
Code:
public partial class MainWindow : Window
{
public MainWindow()
{
MyCommand = new MyClickCommand();
InitializeComponent();
DataContext = this;
}
public MyClickCommand MyCommand { get; set; }
}
public class MyClickCommand : ICommand
{
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
MessageBox.Show("click!");
}
}
In the above example the Execute
method in MyClickCommand
will be called when you click on the button.
Now to make this a bit more user friendly you can use a RelayCommand
implementations, this allows to pass delegates into the Command implementation which in most cases is the easiest way to use commands in WPF.
Example:
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="50" Width="100" >
<Grid>
<Button Content="Click" Command="{Binding MyCommand}" />
</Grid>
</Window>
Code:
public partial class MainWindow : Window
{
public MainWindow()
{
MyCommand = new RelayCommand(MyMethod);
InitializeComponent();
DataContext = this;
}
public RelayCommand MyCommand { get; set; }
private void MyMethod()
{
MessageBox.Show("Click!");
}
}
public class RelayCommand : ICommand
{
readonly Action<object> _execute;
readonly Func<bool> _canExecute;
public RelayCommand(Action execute) : this(execute, null) { }
public RelayCommand(Action<object> execute) : this(execute, null) { }
public RelayCommand(Action execute, Func<bool> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = p => execute();
_canExecute = canExecute;
}
public RelayCommand(Action<object> execute, Func<bool> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute();
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
Example:
Upvotes: 0