Assume there are tab1 and tab2 as two tab items and currently active tab is tab1. SelectedIndex Property set is only called when there is a change in SelectedIndex. I want an which executes even on currently active tab. MouseDown event is not working on tab item.
Any other solutions?
I suggest you to make a Tab HeaderTemplate to handle the click. Look at the sample code below:
<Window.Resources>
<DataTemplate x:Key="myTabHeaderTemplate">
<!-- Handle click here -->
<Grid MouseDown="TabControl_MouseDown">
<TextBlock Text="{Binding}" Margin="5" />
</Grid>
</DataTemplate>
</Window.Resources>
<TabControl
Background="WhiteSmoke"
SelectedItem="{Binding CurrentTab}">
<TabItem Header="tab 1" Background="LightPink" HeaderTemplate="{StaticResource myTabHeaderTemplate}" />
<TabItem Header="tab 2" Background="LightGreen" HeaderTemplate="{StaticResource myTabHeaderTemplate}" />
</TabControl>
TabControl_MouseDown() will be invoked even if your tab is already selected
You have to implement this method in code behind:
private void TabControl_MouseDown(object sender, MouseButtonEventArgs e){ ... }
Or you can bind it to a command in your ViewModel...
Related
I have created a couple of UserControl views and now I want to show the corresponding view when a tab item is clicked. So one tab item gets one view. I would like to do this in MVVM but don't know how.
Please take a look at the following code and give me some advice on how to achieve that:
The MainView (with the TabControl only):
...
<TabControl Name="pnlFormButtons"
Margin="25"
Background="Black"
SelectedItem="{Binding SelTab}"
>
<TabItem Name="tabInventurartikel" Header="Inventurartikel hinzufügen"
Background="BlanchedAlmond" Foreground="Black"
FontFamily="Verdana"
BorderBrush="Black"
>
</TabItem>
<TabItem Name="tabSonderartikel" Header="Sonderartikel hinzufügen"
Background="BlanchedAlmond" Foreground="Black"
FontFamily="Verdana"
BorderBrush="Black"
BorderThickness="2">
</TabItem>
<TabItem Name="tabAnlegen" Header="Lieferschein anlegen"
Background="BlanchedAlmond" Foreground="Black"
FontFamily="Verdana"
BorderBrush="Black"
BorderThickness="2"
IsEnabled="False">
</TabItem>
<TabItem Name="tabDrucken" Header="Lieferschein drucken"
Background="BlanchedAlmond" Foreground="Black"
FontFamily="Verdana"
BorderBrush="Black"
BorderThickness="2"
IsEnabled="False">
</TabItem>
<TabItem Name="tabHilfeseite" Header="Hilfeseite aufrufen"
Background="BlanchedAlmond" Foreground="Black"
FontFamily="Verdana"
BorderBrush="Black"
BorderThickness="2"
IsEnabled="False">
</TabItem>
<TabItem Name="tabFehlerMelden" Header="Fehler bzw. Bug melden"
Background="BlanchedAlmond" Foreground="Black"
FontFamily="Verdana"
BorderBrush="Black"
BorderThickness="2"
IsEnabled="False">
</TabItem>
</TabControl>
...
The MainViewModel (only relevant code):
...
//Binding Property SelTab - It binds to the selected tab item
private string _selTab;
public string SelTab
{
get { return _selTab; }
set
{
_selTab = value;
OnPropertyChanged("SelTab"); //INotifyPropertyChanged
GetSelTab(); //check which tab item is selected and display the corresponding view
}
}
public void GetSelTab()
{
UserControl usc = null; //initialize user control object
switch(SelTab) //which tab item is selected?
{
case "tabInventurartikel": // = TabControl.SelectedItem
usc = new Inventurartikel(); //Initialize (Show) Inventurartikel.xaml
SelTab.Content = usc; //Here I don't know how to actually show the view in the tab item because SelectedItem.Content does not exist...
break;
case "tabSonderartikel":
usc = new neuerArtikel(); //same problem here...
break;
default:
break;
}
}
...
NOTE:
The views for the tab items are basically just user control forms that I want to show inside the tab item when the corresponding tab item is selected.
I shouldn't post them here because I want to keep the focus on the actual problem as simple and as clear as possible. Any help is highly appreciated!
The easiest solution would be to bind the tab control's item source to a list of view models. Then, if you add/remove view models, tabs are added/removed accordingly.
Main window xaml:
<Grid>
<Grid.Resources>
<DataTemplate x:Key="CustomHeaderTemplate">
<Label Content="{Binding TabName}" />
</DataTemplate>
</Grid.Resources>
<TabControl x:Name="tbCtrl" ItemsSource="{Binding Items}" Loaded="tbCtrl_Loaded" SelectionChanged="tbCtrl_SelectionChanged" ItemTemplate="{StaticResource CustomHeaderTemplate}">
<TabControl.ContentTemplate>
<DataTemplate>
<uc:DeviceTab/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
The important thing is the binding of ItemSource.
Tab control view model:
class TabControlViewModel
{
public ObservableCollection<ItemViewModel> Items { get; } = new ObservableCollection<ItemViewModel>();
}
Tab control code behind Loaded event. Here you can add view models and the tab control sets up the tabs accordingly:
private void tbCtrl_Loaded(object sender, RoutedEventArgs e)
{
var tabControlViewModel = new TabControlViewModel();
tabControlViewModel.Items.Add(new ItemViewModel());
DataContext = tabControlViewModel;
tbCtrl.SelectedIndex = 0;
}
This only works if all tabs are the same. There's also a solution if you need different user controls for each tab. In that case, you need to specify a data template for the tab item's content. Basically you can tell it to load user controls based on the type of the view model. Unfortunately I don't know how to do that, but I've seen examples for it. I know it's not the exact answer you need, but I hope it helps!
I have a ListView and i want ListView to be selected when Mouse pressed. (Like ClickMode property of Buttons). is there any solution ?
I tried to put button in ListView template and change its ClickMode property
The SelectionChanged is triggered when mouse released which is by default. It seems like we cannot change it. So we can put button in ListView item template and change its click mode as what you thought about, or register a PointerPressed event for the container inside item template which will be triggered when mouse pressed not released.
but i couldn't access object that is clicked in the ListView
To access which item is clicked you still can use property like SelectedItem of ListView to get the selected item. For example:
XAML Code
<ListView Name="CategoryLIstView" Grid.Row="1" ItemsSource="{x:Bind categories}" HorizontalAlignment="Center" Margin="10" VerticalAlignment="Top" IsItemClickEnabled="True" SelectionChanged="CategoryLIstView_SelectionChanged" ItemClick="CategoryLIstView_ItemClick" PointerPressed="CategoryLIstView_PointerPressed">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Category">
<StackPanel Margin="0" PointerPressed="StackPanel_PointerPressed">
<StackPanel Orientation="Vertical" >
<TextBlock Text="{x:Bind Name}" Foreground="Blue" FontWeight="Bold" FontFamily="Yu Gothic" FontSize="17"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code behind:
private async void StackPanel_PointerPressed(object sender, PointerRoutedEventArgs e)
{
await new Windows.UI.Popups.MessageDialog("point press").ShowAsync();
System.Diagnostics.Debug.WriteLine(CategoryLIstView.SelectedIndex);
}
I am working on a Windows Store App and would like to show some additional information about an Item that was clicked in ListView or GridView. This information should be shown in a Popup or Flyout (hast do be definded in C#, not in XAML) next to the clicked item.
The Problem is, that the ItemClick event handler gives no information about the clicked visual item but only about the data item. Thus I have no information about where to show the Flyout or Popup on screen.
Use attached Flyout:
<DataTemplate x:Key="ListItemTemplate">
<Grid RightTapped="ListRightTapped" Tapped="ListTapped" Background="Transparent">
<Grid>
...
</Grid>
<FlyoutBase.AttachedFlyout>
<Flyout Closed="listFlyout_Closed">
<StackPanel>
...
</StackPanel>
</Flyout>
</FlyoutBase.AttachedFlyout>
</Grid>
</DataTemplate>
And the code:
private void ListRightTapped( object sender, RightTappedRoutedEventArgs e )
{
FlyoutBase.ShowAttachedFlyout( sender as FrameworkElement );
}
I've created a solution that works just like the old Windows Phone Toolkit ContextMenuService. The MenuFlyoutService. You can find the source on my blog. Using the service removes the need to subscribe to event handlers wherever you want to show the menu.
Your DataTemplate would look something like:
<StackPanel>
<local:MenuFlyoutService.MenuFlyout>
<MenuFlyout>
<!-- using the Click event -->
<MenuFlyoutItem Text="reply" Click="OnReplyClicked"/>
<!-- using commanding to DataContext of MenuItem -->
<MenuFlyoutItem Text="retweet" Command="{Binding RetweetCommand}"/>
<!-- using commanding to DataContext of parent list -->
<MenuFlyoutItem Text="favorite"
Command="{Binding DataContext.FavoriteCommand,
ElementName=TweetList}"
CommandParameter="{Binding}"/>
</MenuFlyout>
</local:MenuFlyoutService.MenuFlyout>
<!-- content for template goes here -->
</StackPanel>
All you need to do is get DataContext:
If You have list with items:
MyList.ItemSource = new List<Item>();
And in XAML:
<ListView x:Name="MyList">
<ListView.ItemTemplate>
<DataTemplate>
<Stackpanel>
<TextBox Text="{Binding Name}" />
<Button Content="Add sth" Click="AddClick" />
</Stackpanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And in CodeBehind to access Item while click on the button on the list:
private void AddClick(sender, args){
var senderButton= (Button) sender;
var item = (Item) sender.DataContext; //Item form the list
}
var item is whar you are looking for
I'm trying to find a good way of calling a method of the page being selected in a TabControl. Here's what I'm working with:
<TabControl x:Name="TabC" SelectionChanged="TabC_SelectionChanged">
<TabItem Header="Home" x:Name="HomeTab" IsSelected="True">
<TabItem.Content>
<Frame Source="HomePage.xaml"/>
</TabItem.Content>
</TabItem>
<TabItem Header="Test" x:Name="TestTab">
<TabItem.Content>
<Frame Source="TestPage.xaml"/>
</TabItem.Content>
</TabItem>
<TabItem Header="Test1" x:Name="Test1Tab">
<TabItem.Content>
<Frame Source="Test1Page.xaml"/>
</TabItem.Content>
</TabItem>
</TabControl>
So on my Homepage.xaml.cs, for example, I want a method to be called when I click the tabitem corresponding to it's page. How would you do this?
Any ideas are welcome!
You could subscribe to the OnLoaded event in each of your user controls.
The OnLoaded event fires each time you switch tabs.
XAML
<UserControl x:Class="WpfApplication.HomePage" Loaded="HomePage_OnLoaded" ... >
Code-behind:
private void HomePage_OnLoaded(object sender, RoutedEventArgs e)
{
// Something to do each time the tab is clicked and the page is "loaded"
}
In my application I have used WPF TabControl I want to handle click event of the TabItem.
How do i achieve it?
You can do this by adding labels to the header property for each tabitem in the tabcontrol. Then you can set an event for the label.
xaml
<TabControl Height="100" HorizontalAlignment="Left" Name="tabControl1">
<TabItem Name="tabItem1">
<TabItem.Header>
<Label Content="tabItem1"
MouseLeftButtonDown="tabItem1_Clicked"
HorizontalAlignment="Stretch"/>
</TabItem.Header>
<Grid />
</TabItem>
<TabItem Name="tabItem2">
<TabItem.Header>
<Label Content="tabItem2"
MouseLeftButtonDown="tabItem2_Clicked"
HorizontalAlignment="Stretch"/>
</TabItem.Header>
<Grid />
</TabItem>
</TabControl>
C# / Code Behind
private void tabItem1_Clicked(object sender, MouseButtonEventArgs e)
{
//DO SOMETHING
}
private void tabItem2_Clicked(object sender, MouseButtonEventArgs e)
{
//DO SOMETHING
}
Hope this helps.
This is an old question but I find an answer after being in the same situation.
I use SelectionChanged event on the TabControl (XAML)
<TabControl SelectionChanged="TabControl_SelectionChanged">
Code behind (C#):
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//Stuff
}
This is not the click HimSelf but its working for refreshing stuff..
You can use SelectionChanged event in TabControl and use switch case to do anything you like.
// XAML Code
<TabControl SelectionChanged="TabControl_SelectionChanged">
<TabItem Header="Item1"></TabItem>
<TabItem Header="Item2"></TabItem>
<TabItem Header="Item3"></TabItem>
</TabControl>
// Behind Code
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string tabItem = ((sender as TabControl).SelectedItem as TabItem).Header as string;
switch(tabItem)
{
case "Item1":
break;
case "Item2":
break;
case "Item3":
break;
default:
return;
}
}
Note that, although the answer provided by d.moncada and others addresses the question, the question itself might not be what is intended. Knowing when the user clicks on a tab is different from knowing when the user makes a tab frontmost - it can be done by clicking on a tab, but it can also be achieved by other means. For example, if you click in the tab that is already frontmost, then use the left/right arrows, you can bring another tab to the front without mouse clicking - the mouse-left-button-down event does not get called in this case (as you would expect).
Wrap the header in a no-template button.
If you use the ItemsSource:
<TabControl ItemsSource="{Binding Data}">
<TabControl.ItemTemplate>
<DataTemplate>
<Button Click="Tab_Click">
<Button.Template>
<ControlTemplate>
<ContentPresenter />
</ControlTemplate>
</Button.Template>
<Button.Content>
<!-- Actual header goes here -->
</Button.Content>
</Button>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
If you have static content you can insert it into the header right away:
<TabControl>
<TabItem>
<TabItem.Header>
<Button Click="Tab_Click">
<Button.Template>
<ControlTemplate>
<ContentPresenter />
</ControlTemplate>
</Button.Template>
<Button.Content>
<!-- Actual header goes here -->
</Button.Content>
</Button>
</TabItem.Header>
</TabItem>
</TabControl>
You can do this by adding labels to the header property for each
tabitem in the tabcontrol. Then you can set an event for the label.
The solution works pretty well; however, the "label" has margin properties which can prevent the "MouseLeftButtonDown" handler from being fired unless the user clicks the label dead on. Additionally, it looks like the styling for the rest of the tabs are affected due to label padding.
You could alleviate this by overriding the default margin/padding properties of the label...or even more simply, using TextBlock.
<TabItem x:Name="tabItem1" >
<TabItem.Header>
<TextBlock MouseLeftButtonDown="tabItem1_Click">
Click Me
</TextBlock>
</TabItem.Header>
...
</TabItem>
try to find solution with GotFocus event.
private void addTabPage_GotFocus(object sender, RoutedEventArgs e)
{
addTabPage(); //method for adding page
TabControlPages.SelectedIndex = TabControlPages.Items.Count - 1; //select added page
TabControlPages.Focus(); //change forcus to selected page
}
also method for adding page (just example)
private void addTabPage()
{
TabItem tc = new TabItem();
tc.Header = "New page";
TabControlPages.Items.Insert(TabControlPages.Items.Count - 1, tc); //insert new page
}
hope this will be helpfull