WPF Routed Command with Bindings per-Tab - wpf

I intended to disable and enable the Buttons outside the TabControl, just like those inside the TabItem when the current tab is changed. But the CommandBindings of the TabItem do not seem to impact "up" the visual tree. What is the right way to do this?
With this XAML:
<Window x:Class="WpfApplication10.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication10"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<Button Content="MyCommand1" Command="local:MainWindow.MyCommand1" />
<Button Content="MyCommand2" Command="local:MainWindow.MyCommand2" />
<TabControl>
<TabItem Header="tabItem1" Name="tabItem1">
<TabItem.CommandBindings>
<CommandBinding Command="local:MainWindow.MyCommand1"
Executed="ExecuteMyCommand" />
</TabItem.CommandBindings>
<StackPanel>
<Button Content="MyCommand1" Command="local:MainWindow.MyCommand1" />
<Button Content="MyCommand2" Command="local:MainWindow.MyCommand2" />
</StackPanel>
</TabItem>
<TabItem Header="tabItem2" Name="tabItem2">
<TabItem.CommandBindings>
<CommandBinding Command="local:MainWindow.MyCommand2"
Executed="ExecuteMyCommand"/>
</TabItem.CommandBindings>
<StackPanel>
<Button Content="MyCommand1" Command="local:MainWindow.MyCommand1" />
<Button Content="MyCommand2" Command="local:MainWindow.MyCommand2" />
</StackPanel>
</TabItem>
</TabControl>
</StackPanel>
</Window>
With this Code Behind:
public static readonly RoutedUICommand MyCommand1 = new RoutedUICommand();
public static readonly RoutedUICommand MyCommand2 = new RoutedUICommand();
public MainWindow()
{
InitializeComponent();
}
private void ExecuteMyCommand(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Hello");
}

MSFT gave me the correct answer in their WPF forum, here (http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/bb3d1eb1-96fa-4fbc-beda-799613acb9f7)
<StackPanel>
<StackPanel FocusManager.IsFocusScope="True">
<Button Content="MyCommand1" Command="local:Window8.MyCommand1" />
<Button Content="MyCommand2" Command="local:Window8.MyCommand2" />
</StackPanel>
<TabControl>
<TabItem Header="tabItem1" Name="tabItem1">
<TabItem.CommandBindings>
<CommandBinding Command="local:Window8.MyCommand1" Executed="ExecuteMyCommand" />
</TabItem.CommandBindings>
<StackPanel>
<Button Content="MyCommand1" Command="local:Window8.MyCommand1" />
<Button Content="MyCommand2" Command="local:Window8.MyCommand2" />
</StackPanel>
</TabItem>
<TabItem Header="tabItem2" Name="tabItem2">
<TabItem.CommandBindings>
<CommandBinding Command="local:Window8.MyCommand2" Executed="ExecuteMyCommand"/>
</TabItem.CommandBindings>
<StackPanel>
<Button Content="MyCommand1" Command="local:Window8.MyCommand1" />
<Button Content="MyCommand2" Command="local:Window8.MyCommand2" />
</StackPanel>
</TabItem>
</TabControl>
</StackPanel>

Your don't have any code that could disable buttons. You can do it in several ways:
1. Define CanExecute event handler.
<CommandBinding Command="local:MainWindow.MyCommand1"
Executed="ExecuteMyCommand"
CanExecute="MyCommand_CanExecute"/>
Code behind:
private void MyCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = tabItem1.IsSelected;
}
2. Bind button IsEnabled property to tab item IsSelected property
<Button IsEnabled="{Binding ElementName=tabItem1, Path=IsSelected}"
Content="MyCommand1" Command="local:MainWindow.MyCommand1" />

Is this all the code?
You have a special CanExecute defined, that disables the MyCommandsX ?
Or you have a binding on the Enabled Property of the bound buttons, and you implement INotifyPropertyChanged or something?
Or why should they be enabled/disabled in your code sample?
I you ask me, I wouldn't expect the code to disable the buttons..
Update 1:
You could enable the buttons the same way you did it, by adding the command bindings in the surrounding stackpanel for example.
<StackPanel>
<StackPanel.CommandBindings>
<CommandBinding Command="local:MainWindow.MyCommand1"
Executed="ExecuteMyCommand" />
</StackPanel.CommandBindings>
<Button Content="MyCommand1" Command="local:MainWindow.MyCommand1" />
<Button Content="MyCommand2" Command="local:MainWindow.MyCommand2" />
<TabControl>
You can use the CanExecute part of the command binding to verify the conditions under which the bound buttons enabled.
Instead you should handle the command itself I think.

Related

How to get previous selected TabItem Index from TabControl?

Following xaml code for your testing needs.
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="200" Width="350">
<DockPanel>
<TabControl x:Name="TabControl" DockPanel.Dock="top">
<TabItem x:Name="TabItem1" Header="London">
<Label Content="London" />
</TabItem>
<TabItem x:Name="TabItem2" Header="Paris">
<Label Content="Paris" />
</TabItem>
<TabItem x:Name="TabItem3" Header="Tokyo">
<Label Content="Tokyo" />
</TabItem>
<TabItem x:Name="TabItem4" Header="Istanbul">
<Label Content="Istanbul" />
</TabItem>
</TabControl>
</DockPanel>
</Window>
How to get previous TabItem Index from TabControl and show in the MessageBox?
I need vb.net code running from code behind.
RemovedItems is an IList property in the SelectionChangedEventArgs that holds the items that were unselected since the last time the SelectionChanged event occurred.
You could check it each time the SelectionChanged of the TabControl event occurred:
private void TabControl_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.RemovedItems.Count > 0)
{
var oldTabItem = e.RemovedItems[0] as TabItem;
}
}
xaml:
<DockPanel>
<TabControl x:Name="TabControl" DockPanel.Dock="top" SelectionChanged="TabControl_OnSelectionChanged" > ..

How to create hotkey for button by modifying xaml?

I am trying to learn keybinding in WPF by a simple example.
here is my XAML file:
<Window.Resources>
<RoutedUICommand x:Key="myNewCommand"></RoutedUICommand>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding Command="{StaticResource myNewCommand}" Executed="Button_Click"></CommandBinding>
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Command="{Binding myNewCommand}" Key="B" />
</Window.InputBindings>
<Grid>
<Button Command="{Binding myNewCommand}" Click="Button_Click" Content="Click Here"/>
</Grid>
And this is code behind for Button_Click :
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("hello");
}
I get the "hello" message when I click on button, but no response when I press "B" on keyboard.
I want to have this binding without changing the Button_click, can I do it just in XAML? how?
Your command bindings aren't correct. You should replace {Binding myNewCommand} with {Binding Source={StaticResource myNewCommand}}. It is also not necessary to have a Click handler on the button when you have already bound a command.
<Window.Resources>
<RoutedUICommand x:Key="myNewCommand"/>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding Command="{StaticResource myNewCommand}"
Executed="MyCommandExecuted"/>
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Command="{Binding Source={StaticResource myNewCommand}}" Key="B" />
</Window.InputBindings>
<Grid>
<Button Command="{Binding Source={StaticResource myNewCommand}}"
Content="Click Here"/>
</Grid>
The Executed handler:
private void MyCommandExecuted(object sender, RoutedEventArgs e)
{
MessageBox.Show("hello");
}

WPF Data Binding From UserControl

I want to bind 'SomeText' from my UserControl, into the Content of my Label.
I currently have a UserControl which just displays my 'SomeText'. The XAML, and Code Behind file can be seen below.
<UserControl x:Class="TabHeader.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="183" d:DesignWidth="235"
x:Name="uc">
<Grid>
<Label Height="43" HorizontalAlignment="Left" Margin="57,102,0,0" Name="textBlock1" Content="{Binding Path=SomeText, ElementName=uc}" VerticalAlignment="Top" Width="86" />
</Grid>
</UserControl>
namespace TabHeader
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
private string someText;
public UserControl1()
{
this.SomeText = "23";
InitializeComponent();
}
public string SomeText
{
get
{
return someText;
}
set
{
someText = value;
}
}
}
}
I then have my main XAML page where I have, a Tab Control within a Grid. I'm using a Style to generate two Labels within the Columns Header. I am able to pull through the Header field, but I am unable to pull through the controls field.
<Window x:Class="TabHeader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vw="clr-namespace:TabHeader"
Title="MainWindow" Height="350" Width="525" Name="Tabs">
<Grid>
<TabControl Height="262" HorizontalAlignment="Left" Margin="47,26,0,0" Name="tabControl1" VerticalAlignment="Top" Width="366">
<TabControl.Resources>
<Style TargetType="TabItem" x:Key="tabItemHeaderStyle" >
<Setter Property="HeaderTemplate" >
<Setter.Value>
<DataTemplate DataType="{x:Type TabItem}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=Header, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TabItem}}"/>
<Label Content="{Binding Path=SomeText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=vw:UserControl1}}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabItem Style="{StaticResource tabItemHeaderStyle}" Header="TI 1" Name="tabItem1" Width="100">
<vw:UserControl1 x:Name="UserControl11"></vw:UserControl1>
</TabItem>
<TabItem Style="{StaticResource tabItemHeaderStyle}" Header="TI 2" Name="tabItem2">
</TabItem>
</TabControl>
</Grid>
</Window>
Any assistance with this would be greatly appreciated.
Cheers.
Edit 1
For anyone interested added my working code below, where I have used the DependencyProperty.
MainWindow.xaml
<Grid>
<TabControl Height="262" HorizontalAlignment="Left" Margin="47,26,0,0" Name="tabControl1" VerticalAlignment="Top" Width="366">
<TabControl.Resources>
<Style TargetType="TabItem" x:Key="tab1ItemHeaderStyle">
<Setter Property="HeaderTemplate" >
<Setter.Value>
<DataTemplate DataType="{x:Type TabItem}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=Header, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TabItem}}"/>
<Label Content="{Binding Path=UC1Figure, ElementName=uc1}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabItem Style="{StaticResource tab1ItemHeaderStyle}" Header="[Tab 1]" Name="tabItem1" Width="100">
<vw:UserControl1 x:Name="uc1"></vw:UserControl1>
</TabItem>
<TabControl>
</Grid>
UserControl1.xaml
<Grid>
<Label Height="43" HorizontalAlignment="Left" Margin="69,128,0,0" Name="textBlock1" Content="{Binding Path=UC1Figure, ElementName=uc}" VerticalAlignment="Top" Width="100" />
<Button Name="updateSomeFigure" Content="Press Me" Click="updateSomeFigure_Click" Width="100" Height="100" Margin="69,12,66,71" />
</Grid>
UserControl1.xaml.cs
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public static readonly DependencyProperty SomeFigureProperty =
DependencyProperty.Register("UC1Figure", typeof(int), typeof(UserControl1));
public int UC1Figure
{
get { return (int)this.GetValue(SomeFigureProperty); }
set { this.SetValue(SomeFigureProperty, value); }
}
private void updateSomeFigure_Click(object sender, RoutedEventArgs e)
{
UC1Figure = UC1Figure + 1;
}
}
If you want to data bind a property to the UI of your UserControl, you have two options. The first is to implement the INotifyPropertyChanged Interface in your code behind. The second is to define DependencyPropertys instead of regular CLR properties. You can find out how to do that in the Dependency Properties Overview page on MSDN.
You might also want to read the Data Binding Overviewā€ˇ page on MSDN before you start data Binding.

Binding when element is instantiated in code behind

I have two properties that need to be binded. One is Value and it is the UserControl's property and the second one is property from an image element. The image element is inside Window. The Window is intestated in the code behind (UserControl).
What do I need to add to enable proper binding between image src and property Value. The code is shown below.
<UserControl x:Class="nnnn">
<UserControl.Resources>
<propSheet:BitmapConverter x:Key="bitmapConverter" />
<Window x:Key="imagePopup"
Width="640"
Height="480">
<Grid Background="LightGray">
<Image Grid.Row="0" Source="{Binding Path=Value, Converter={StaticResource bitmapConverter}}" />
<TextBlock Text="{Binding Path=Value}"></TextBlock>
<Button Grid.Row="1"
Width="25"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Click="OpenFile_Click">
...
</Button>
</Grid>
</Window>
</UserControl.Resources>
<Grid>
<Button Click="ViewImage_Click">View Image</Button>
</Grid>
You would have to set the Window's DataContext property to the UserControl instance before showing it:
private void ViewImage_Click(object sender, RoutedEventArgs e)
{
var window = Resources["imagePopup"] as Window;
window.DataContext = this; // the UserControl
window.Show();
}

UserControl with Exposable Command on WPF

I'm creating a Toolbar with some buttons, and I want each button to execute an different command according to the ViewModel attached to it's DataContext, so I created if like this:
public readonly DependencyProperty NewCommandProperty = DependencyProperty.Register(
"NewCommand", typeof(ICommand),
typeof(VirtueGridToolbar));
public ICommand NewCommand
{
get
{
return (ICommand)GetValue(NewCommandProperty);
}
set
{
SetValue(NewCommandProperty, value);
}
}
public GridToolbar()
{
InitializeComponent();
}
and the xaml of the control is this:
<UserControl x:Class="Virtue.Modules.Library.Controls.GridToolbar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ToolBar Background="Transparent">
<ToolBar.Items>
<Button x:Name="NewButton"
Width="25"
Height="25"
ToolTip="Novo"
Command="{Binding NewCommand}">
<Image Source="{DynamicResource NewLarge}" />
</Button>
<Button x:Name="EditButton"
Width="25"
Height="25"
ToolTip="Editar">
<Image Source="{DynamicResource EditLarge}" />
</Button>
<Button x:Name="DeleteButton"
Width="25"
Height="25"
ToolTip="Excluir">
<Image Source="{DynamicResource DeleteLarge}" />
</Button>
<Separator />
<Button x:Name="SaveButton"
Width="25"
Height="25"
ToolTip="Excluir">
<Image Source="{DynamicResource SaveLarge}" />
</Button>
</ToolBar.Items>
</ToolBar>
</UserControl>
But when I add the UserControl to another control and attribute the Command
<V:GridToolbar NewCommand="{Binding Path=New}" />
the command does not execute.
Any suggestions?
Tks,
Diego

Resources