DataGrid inside TabItem event handling - wpf

I have a TabControl with two TabItems, inside the one TabItem I have a DataGrid.
I'm trying to handle the TabItem click, and it works, but, when I click in one row of the "dataGrid1" the event "TabItem_MouseLeftButtonUp" of TabItem click is fired too. See the code:
<TabControl Height="211" HorizontalAlignment="Left" Margin="33,29,0,0" Name="tabControl1" VerticalAlignment="Top" Width="417" >
<TabItem Header="tabItem1" Name="tabItem1">
<Grid />
</TabItem>
<TabItem MouseLeftButtonUp="TabItem_MouseLeftButtonUp">
<DataGrid AutoGenerateColumns="True" Height="134" Name="dataGrid1" Width="307" />
</TabItem>
</TabControl>
Note: I can't use the personalize <TabItem.Header> because I'm using MahApps, if I use TabItem.Header the style os TabItem will break.

The MouseLeftButtonUp event is bubbling routed event. When you on the DataGrids row the event bubbling through its ancestors and calls the corresponding handlers, TabItem_MouseLeftButtonUp for TabItem in your case.
In your TabItem_MouseLeftButtonUp event you can check who raised the event, which control is the origin. If its not the TabItem do nothing.
private void TabItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if(sender is TabItem)
{
//do the work
}
}

You will recieve the EventArgs with MouseLeftButtonUp event. Just filter out whatever you need.

Related

WPF Button Height same as ListItem height

I have a ListBox, In it I have a custom DataTemplate set for the ListBox.ItemTemplate so the ListBox Items are Radio buttons styled as rounded buttons.
Is there any way I could bind another separate button on my View to the Height of the ListBox.ItemTemplate's RadioButton's ActualHeight, so the separate button's height would always be the same height as the Radiobuttons in the ListBox?
Here's a solution with some code behind. Handle the SizeChanged event for the RadioButton, and assign the given height to the view model's Height property. Bind the separate button's Height property to the Height property in the view model. Here's the XAML:
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton
Content="{Binding Name}"
SizeChanged="OnRadioButtonSizeChanged" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button
Content="Button"
Height="{Binding Height}"
/>
And here's the code behind:
private void OnRadioButtonSizeChanged(object sender, SizeChangedEventArgs e)
{
ViewModel.Height = e.NewSize.Height;
}
Of course, the view model's Height property should raise the PropertyChanged event.

WPF: Clicking on a DataGrid Row inside a TreeView does not trigger TreeView.SelectedItemChanged

I am new to WPF, and suffering with an existing code.
We have a tree, which has many branches/leaves. In one branch we have a DataGrid.
If we click on the empty area of the grid (where no rows are), then TreeView.SelectedItemChanged called properly. In our case, SelectedItem = 'SelectedGridBorder' (see XAML below)
But if we click on a row/cell of the grid, row gets focused, but TreeView.SelectedItemChanged is NOT called.
So TreeView.SelectedItem is still the previously selected item.
Is is possible to achieve this (according to me) logical behavior, so when clicking on a row, TreeView.SelectedItemChanged should be called automatically, and TreeView.SelectedItem should be 'SelectedGridBorder', just like clicking on the grid area where no rows are.
Why is it different for 'SelectedItemChanged' to click on a grid row, or click on a grid where no rows are?
Thanks.
XAML:
<TreeView x:Name="CalculationDataTree" .....>
<Cinch:EventCommander.Mappings>
<Cinch:CommandEvent
Command="{Binding Path=DataContext.SelectionChangeCommand ....
Event="SelectedItemChanged"
Cinch:CommandEvent.CommandParameter="{Binding ElementName=CalculationDataTree,Path=SelectedItem}"/>
...
<TreeViewItem x:Name="Params" ...>
<TreeViewItem.Header>
<TextBlock>Parameters</TextBlock>
</TreeViewItem.Header>
<TreeViewItem x:Name="Dates" Margin="0,6,0,0">
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="4,10">Date(s)</TextBlock>
<ContentControl Margin="4,6" Content="{Binding}" ContentTemplate="{StaticResource OwnEditorTemplate}" />
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
<Border Name="SelectedGridBorder" ... >
<StackPanel Orientation="Vertical">
<TextBlock Margin="4,10">Other parameters</TextBlock>
<StackPanel Orientation="Horizontal">
<DockPanel>
<dg:DataGrid Height="300" Width="600" Name="dataGrid" ....>
<dg:DataGrid.Columns>
...
</dg:DataGrid.Columns>
The answer to
Why is it different for 'SelectedItemChanged' to click on a grid row, or click on a grid where no rows are?
MouseDown is a bubbling event. What's happening is the TextBox of your DataGrid marked the event as handled so it never reached TreeViewItem (WPF creates the TreeViewItem automatically even though you didn't specifically include it in your markup). If you clicked on a Header, or RowSelector, they would not mark the event as handled.
To get the behavior you were expecting
//WPF creates the TreeViewItem automatically if you didn't include it
<TreeViewItem PreviewMouseDown="TreeviewItem_PreviewMouseDown">
<Border Name="SelectedGridBorder" ... >
<StackPanel Orientation="Vertical">
<TextBlock Margin="4,10">Other parameters</TextBlock>
<StackPanel Orientation="Horizontal">
The Handler
private void TreeviewItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var treeViewItem = sender as TreeViewItem;
treeViewItem.IsSelected = true;
}

How to prevent a DataGrid from receiving any keyboard focus?

I have a Window, containing a Grid, which contains another Grid with InputBindings (on Enter and Delete keys) and, amongst other controls, a read-only DataGrid.
When the DataGrid has the focus, the InputBindings stop firing their commands. I'm then forced to manually give the focus to another control before the InputBindings can work.
How can I bypass this behavior? I tried playing with almost every input/keyboard related DataGrid's property with no success.
Here's the XAML, even though it doesn't bring much to the table:
<Grid>
<Grid.InputBindings>
<KeyBinding Key="Enter" Command="{Binding DoStuff}"/>
<KeyBinding Key="Delete" Command="{Binding UndoStuff}"/>
</Grid.InputBindings>
<!-- stuff... -->
<Grid >
<!-- more stuff... -->
<DataGrid IsReadOnly="True" ItemsSource="{Binding SomeProperty}" SelectedItem="{Binding SomeSelectedProperty, Mode=TwoWay}">
<DataGrid.Columns>
<!-- blah -->
</DataGrid.Columns>
</DataGrid>
</Grid>
</Grid>
you can handle the PreviewGotKeyboardFocus event.
<DataGrid Name="grid" PreviewGotKeyboardFocus="grid_PreviewGotKeyboardFocus"
private void grid_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
e.Handled = true;
}

Best Way to Replace UserControl Loaded in TabControl TabItem

I currently have a TabControl loaded in MainWindow.xaml, which has three tabs. Let's name them Tab1, Tab2 and Tab3.
The individual tabs have views (usercontrols) supplied and they all work as expected. Code as follows. I am using MahApps Metro TabControl here.
<Controls:MetroAnimatedSingleRowTabControl Grid.Row="0" Grid.ColumnSpan="4" x:Name="MainTabControl">
<TabItem Header="Tab1">
<view:Tab1View DataContext="{Binding}" />
</TabItem>
<TabItem Header="Tab2">
<view:Tab2View DataContext="{Binding}" />
</TabItem>
<TabItem Header="Tab3">
<view:Tab3View DataContext="{Binding}" />
</TabItem>
</Controls:MetroAnimatedSingleRowTabControl>
What I would like to do now is to switch the view of Tab3 (which is Tab3View.xaml) to another view (let's call it subTab3View.xaml) when I click on a button on Tab3View.xaml. This will basically switch the Tab3 content from Tab3View.xaml to subTab3View.xaml.
Could anyone kindly suggest me a way to achieve this?
You can have a content control in your tab, and then change the content on button click or whatever event you want.
<TabItem Header="Tab3">
<ContentControl x:Name="contentControl"/>
</TabItem>
private void ButtonClick(object sender, RoutedEventArgs e)
{
this.contentControl.Content = new Tab3View();
}

WPF TabItem Element MouseClick Event

In WPF app inside a TabControl there is a TabItem element with one Label. I want to fire the event on MouseClick on the Tab of this TabControl, but the event MouseLeftButtonDown:
<TabItem Header="Header1" MouseLeftButtonDown="TabItem_MouseLeftButtonDown" >
<Label Height="28" Name="AdderLbl" Width="120" Background="Azure" >Label</Label>
</TabItem>
fires only on click over the label. It is not wat I want.
How I could fire the event on MouseClick over the Tab, not its content?
What are you trying to achieve? It looks like you're trying to trap when the user moves to the tab, if so you can hook a different event SelectionChanged
:-)
I did not want selectionchanged event because that would involve a switch. So i wanted an event directly on the tab clicked.
While i thought an MouseDown event was what I was looking for.... after wiring up all sorts of mouse events with break points; i found the MouseUp events worked for me.
So I used MouseLeftButtonUp or MouseUp.
For who really want to use something like MouseLeftButtonDown event, you can use the "MouseUp" event instead.
=)
While handling SelectionChanged event is the better approach to handling tab changes, here is a possible solution to your question. I don't recommend it in your case, but it illustrates an approach that may be useful in other cases
<TabControl>
<TabItem>
<TabItem.Header>
<Button Click="Button_Click">
<Button.Template>
<ControlTemplate>
<Label>Header1</Label>
</ControlTemplate>
</Button.Template>
</Button>
</TabItem.Header>
<Label Height="28" Name="AdderLbl" Width="120" Background="Azure" >Label</Label>
</TabItem>
</TabControl>
You need the event Selector.Selected
<TabControl x:Name ="TabControls" Dock="Top" DockWidth="500" DockHeight="500" TabItemShape="Rounded">
<TabControl>
TabControls.SelectionChanged += SelectionChanged;
private void SelectionChanged(object sender, SelectionChangedEventArgs selectionChangedEventArgs) {
var itemTab = (TabItem) TabControls.SelectedItem;
(...)
}

Resources