How to get previous selected TabItem Index from TabControl? - wpf

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" > ..

Related

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();
}

Call UserControl's listview's button click event from UserControl's Parent

I have three user controls.
User control 1
<UserControl
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"
xmlns:local="clr-namespace:Gramercy"
mc:Ignorable="d"
x:Class="wpfapplication.UCManageQALibrary"
x:Name="UserControl"
d:DesignWidth="774" d:DesignHeight="529.723">
<Grid x:Name="LayoutRoot">
<Grid>
<Button Content="List QA" x:Name="btnSearchQAStructure" Click="Button_Click_1" />
<Button Content="Add New QA" x:Name="btnAddNewQAStructure" Click="Button_Click" />
<local:UCSearchQALibrary x:Name="searchQALibrary" Visibility="Visible"/>
<local:AddNewQA x:Name="addQALibrary" Visibility="Hidden"/>
</Grid>
</Grid>
</UserControl>
User Control 2
<UserControl
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="wpfapplication.AddNewQA"
x:Name="UserControl"
d:DesignWidth="1280" d:DesignHeight="1024">
<Grid x:Name="LayoutRoot">
<Grid>
<Label x:name="Label1" Content="" />
</Grid>
</Grid>
</UserControl>
and User Control 3
<UserControl
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="wpfapplication.UCSearchQALibrary"
x:Name="UserControl"
d:DesignWidth="758" d:DesignHeight="486.905">
<Grid x:Name="LayoutRoot" >
<GroupBox Header="Question and Answer Master Library" >
<Grid Margin="8">
<WrapPanel Margin="4,0,0,0" VerticalAlignment="Stretch">
<ListView Margin="4,10,0,10" x:Name="lvQA" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" AlternationCount="2" VerticalAlignment="Stretch" Height="420">
<ListView.View>
<GridView>
<GridViewColumn >
<GridViewColumn.HeaderTemplate>
<DataTemplate>
<Label Content="Q & A Search Result : " FontSize="12" FontWeight="Bold" Margin="0,4,0,4"/>
</DataTemplate>
</GridViewColumn.HeaderTemplate>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<Button Content="{Binding Path=QuestionText}" Margin="4,10,8,4" Style="{StaticResource HyperlinkLikeButton}" VerticalAlignment="Top" Click="Button_Click" CommandParameter="{Binding Path=QuestionID}" />
<TextBlock TextWrapping="Wrap" Margin="4,0,4,4" HorizontalAlignment="Stretch"><Run Text="{Binding Path=AnswerText}"/></TextBlock>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</WrapPanel>
</Grid>
</GroupBox>
</Grid>
</UserControl>
User control 2 is used to add a new question answer, user control 3 is provide list of already created question answer. User control 1 has both user control 2 and 3. At a time either user control 2 or 3 is visible.In User control 1, on click of the List QA button user control 3 is visible and user control 2 is invisible. on click of the Add New QA button user control 2 is visible and user control 3 is invisible.
Now, In user control 3, I have a button associates with each row of the listview. On tapping/click of that button, I need a functionality to make user control 2 visible and bind the label inside user control 2 with the specific content.
I had tried with routed events.
In user control 3 I had added...
public static readonly RoutedEvent AddClickEvent = EventManager.RegisterRoutedEvent("AddClick", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(Button));
public event RoutedEventHandler AddClick
{
add { AddHandler(AddClickEvent, value); }
remove { RemoveHandler(AddClickEvent, value); }
}
void RaiseAddClickEvent()
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(UCSearchQALibrary.AddClickEvent);
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
// TODO: Add event handler implementation here.
//Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
//newWindowThread.SetApartmentState(ApartmentState.STA);
//newWindowThread.IsBackground = true;
//newWindowThread.Start();
RaiseEvent(new RoutedEventArgs(AddClickEvent));
}
and in User control 1 I added...
local:UCSearchQALibrary.AddClick="dCB_Props_AddClick"
private void dCB_Props_AddClick(object sender, System.Windows.RoutedEventArgs e)
{
MessageBox.Show("This Works");
}
Any help will be highly appreciated.
Thanks.
You may create a event the is routed to the usercontrol1.
But the better way would be to create a viewmodel (you can also use one for all 3 usercontrols).
So you create a 2 Properties in the Viewmodel with type the type Visibility and bind usercontrol1 and 2 to them. (binding is in usercontrol1).

TabControl doesn't show the tab collection

I'm trying to build a very simple and basic application that adds tab items to tab control using the MVVM pattern.
So i created:
a simple view with one button - "CustomerView.xaml"
an empty ViewModel class - it is empty cause the view doesn't save or extract any information from the Viewmodal (have only one button) - "CustomerViewModel.cs"
The MainWindow class code holds an observable collection of the CustomerViewModel
and have one "Add customer" button - to add a customer tab item to the tabcontrol and the tabcontrol itself.
i don't use commands cause it is not relevant at this time , i just was the new tabitem to appear when i add a new CustomerViewModel to the collection.
the result is that , although i can see that CustomerViewModels are added to the Observable collection, i still don't see tabitems added to the tabcontrol - The collection is not updating the the tabcontrol.
This is the MainWindow XAML:
<Window x:Class="MyViewModalTabControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:MyViewModalTabControl.ViewModal"
xmlns:vw="clr-namespace:MyViewModalTabControl.Views"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type vm:CustomerViewModel}">
<vw:CustTabView />
</DataTemplate>
<DataTemplate x:Key="ClosableTabItemTemplate">
<DockPanel Width="120">
<Button
Content="X"
Cursor="Hand"
DockPanel.Dock="Right"
Focusable="False"
FontFamily="Courier"
FontSize="9"
FontWeight="Bold"
Margin="0,1,0,0"
Padding="0"
VerticalContentAlignment="Bottom"
Width="16" Height="16"
/>
<ContentPresenter
Content="Sample"
VerticalAlignment="Center"
/>
</DockPanel>
</DataTemplate>
</Window.Resources>
<Grid Margin="4" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Name="CustTabButton" Content="New Customer" Height="30" Margin="12,136,9,136" Click="CustTabButton_Click"></Button>
<TabControl Grid.Column="1" Grid.Row="0" Background="Red"
ItemsSource="{Binding CustomerTabs}"
ItemTemplate="{StaticResource ClosableTabItemTemplate}"
>
</TabControl>
</Grid>
This is the code behind of the MainWindow:
public partial class MainWindow : Window
{
private ObservableCollection<CustomerViewModel> _customertabs;
public ObservableCollection<CustomerViewModel> CustomerTabs
{
get
{
if (_customertabs == null)
{
_customertabs = new ObservableCollection<CustomerViewModel>();
// _workspaces.CollectionChanged += this.OnWorkspacesChanged;
}
return _customertabs;
}
}
public MainWindow()
{
InitializeComponent();
}
private void CustTabButton_Click(object sender, RoutedEventArgs e)
{
CustomerViewModel CustomerWorkSpace = new CustomerViewModel();
this.CustomerTabs.Add(CustomerWorkSpace);
}
}
This is the Viewmodel class:
public class CustomerViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
}
This is the View :
UserControl x:Class="MyViewModalTabControl.Views.CustTabView"
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">
<Grid>
<Button Name="CustTabButton" Content="New Customer" Height="30" Margin="12,136,9,136"></Button>
</Grid>
What am i missing ?
where do you set the datacontext for your mainwindow? Your bindings will just work with the right Datacontext.
and wouldn't it be better to create a mainviewmodel too, which handles the stuff you put in the mainwindow.cs at the moment?
EDIT: pls look at this msdn post from josh smith. there you can find a closable tab too.
Try any of the following
the ClosableTabItemTemplate should "return" TabItem that will be displayed in the Tab control not the DockPanel
create template for the TabItem control
do it in code
This is the fix:
public MainWindow()
{
InitializeComponent();
this.DataContext=this;
}

WPF Routed Command with Bindings per-Tab

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.

Resources