Reputation: 6547
I have a button and want to change the click handler every time I change tabs. I was hoping to perform this with Binding.
<Window x:Class="BWCRenameUtility.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vpan="clr-namespace:BWCRenameUtility.View.VersionPanels"
Title="MainWindow" Height="526" Width="525">
<Grid>
<DockPanel>
<TextBlock Text="Foo" DockPanel.Dock="Top" TextWrapping="Wrap" Padding="10" />
<Grid DockPanel.Dock="Bottom">
<!-- This is not correct, how do I perform this binding correct? -->
<Button Content="Export..." HorizontalAlignment="Right" Margin="10" Click="{Binding SelectedItem.Content.PerformExport,ElementName=tabcontrol}" />
</Grid>
<TabControl Name="tabcontrol">
<TabItem Header="1.2.5">
<vpan:VersionPanel1_2_5/>
</TabItem>
<TabItem Header="1.2.8">
<vpan:VersionPanel1_2_8/> <!-- These can be of the same Type by inheritance -->
</TabItem>
</TabControl>
</DockPanel>
</Grid>
</Window>
As you can see, the Button.Click is not bound correctly and I want to know how this works in WPF.
Upvotes: 2
Views: 1274
Reputation: 43596
You can achieve this with Commands, you will create a ICommand
for each of toy TabItem
ViewModels
and bind the Buttons
Command
property to that Command
The RelayCommand
is a very common way to handle stuff like this and can be used throughout your application
Relay command:
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="RelayCommand"/> class.
/// </summary>
/// <param name="execute">The execute.</param>
public RelayCommand(Action<object> execute) : this(execute, null) { }
/// <summary>
/// Initializes a new instance of the <see cref="RelayCommand"/> class.
/// </summary>
/// <param name="execute">The action to execute.</param>
/// <param name="canExecute">The can execute.</param>
/// <exception cref="System.ArgumentNullException">execute</exception>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand Members
/// <summary>
/// Defines the method that determines whether the command can execute in its current state.
/// </summary>
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
/// <returns>
/// true if this command can be executed; otherwise, false.
/// </returns>
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
/// <summary>
/// Occurs when changes occur that affect whether or not the command should execute.
/// </summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
/// <summary>
/// Defines the method to be called when the command is invoked.
/// </summary>
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion
}
And you would use in the following fashion in your application
ViewModel or Control:
public class VersionPanel1_2_8 : VersionPanel
{
public ICommand MyCommand { get; internal set; }
public VersionPanel1_2_8()
{
MyCommand = new RelayCommand(x => MethodToExecute());
}
private void MethodToExecute()
{
}
}
Xaml:
<Window x:Class="BWCRenameUtility.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vpan="clr-namespace:BWCRenameUtility.View.VersionPanels"
Title="MainWindow" Height="526" Width="525">
<Grid>
<DockPanel>
<TextBlock Text="Foo" DockPanel.Dock="Top" TextWrapping="Wrap" Padding="10" />
<Grid DockPanel.Dock="Bottom">
<!-- This is not correct, how do I perform this binding correct? -->
<Button Content="Export..." HorizontalAlignment="Right" Margin="10" Command="{Binding SelectedItem.Content.MyCommand,ElementName=tabcontrol}" />
</Grid>
<TabControl Name="tabcontrol">
<TabItem Header="1.2.5">
<vpan:VersionPanel1_2_5/>
</TabItem>
<TabItem Header="1.2.8">
<vpan:VersionPanel1_2_8/> <!-- These can be of the same Type by inheritance -->
</TabItem>
</TabControl>
</DockPanel>
</Grid>
</Window>
Upvotes: 4
Reputation: 1743
You need to bind Button's Command property to your command in WPF like,
Command="{Binding SelectedItem.Content.PerformExport, ElementName=tabcontrol}"
Click is an event, if you want you can also do event to command binding (binding any event to command in your viewmodel) however that is not necessary in your case
Upvotes: 3