I have a TabItem and was previously setting the Header within the object like so,
<TabItem x:Name="Checked_Out_Items" Header="Clients In Use" Height="40" LostFocus="Checked_Out_Items_LostFocus" GotFocus="Checked_Out_Items_GotFocus" BorderThickness="0" >
However, I've run into the problem where there is not a Click event for this Tab. I found a solution where we can insert a label as the header specified here,
how to handle TabItem single click event in WPF?
But, the Label looks nothing like what I need. Here is the Tab Header defined inside the object.
Here's what it looks like with the label
<TabItem x:Name="Checked_Out_Items" Height="40" LostFocus="Checked_Out_Items_LostFocus" GotFocus="Checked_Out_Items_GotFocus" BorderThickness="0" >
<TabItem.Header>
<Label Content="Clients In Use" Height="40" MouseLeftButtonDown="Checked_Out_Items_Clicked" Width="171" />
</TabItem.Header>
Lets separate the concerns a bit.
In order to handle a mouse click event, a control needs to be prepared for receiving this event, it needs to implement a handler and the handler must actually receive the event. In case of TabItem the mouse click event is consumed by the control, without releasing the event to user defined listeners.
On the level of TabItem, the best option would be to handle the PreviewMouseLeftButtonDown event, but this is not an option if event handling shouldn't occur when child controls have their own handling functionality.
So the other option is to handle the MouseLeftButtonDown event before it reaches the TabItem, which means to handle it in a child control of the tab item.
As said, in order to receive the event, the control needs to be ready to receive the event. This means, it needs a Background not null (can be Transparent) and IsHitTestEnabled="True" (which is default in most cases) and it must actually handle the event.
For the showcase, I use a Red instead of Transparent background color. The red area is the place where mouse clicks are captured and handled.
<TabItem Padding="0">
<TabItem.Header>
<Border Height="30" Width="50"
Background="Red" MouseLeftButtonDown="Item_MouseLeftButtonDown">
<ContentPresenter
VerticalAlignment="Center" HorizontalAlignment="Center"
Content="T2"/>
</Border>
</TabItem.Header>
Test Content 2
</TabItem>
Or, in order to have a better separation between header content and click handling, a HeaderTemplate can be used:
<TabItem Header="T3" Padding="0">
<TabItem.HeaderTemplate>
<DataTemplate>
<Border MinHeight="30" MinWidth="50"
Background="Red" MouseLeftButtonDown="Item_MouseLeftButtonDown">
<ContentPresenter
VerticalAlignment="Center" HorizontalAlignment="Center"
Content="{Binding}"/>
</Border>
</DataTemplate>
</TabItem.HeaderTemplate>
Test Content 3
</TabItem>
The issue with any approach that relies on child controls is, that there is still a border of the TabItem and if the user clicks that border, the click will be outside of the child control and the tab will be selected without executing the click handler.
So a different way to handle tab changes (not clicks!) would be to handle the TabControl.SelectionChanged event and filter for events that actually originate from the TabControl and not from some inner content elements.
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.Source == sender)
{
// this selection change is actually issued because of a tab change
}
}
Another thing I just realized: The same condition could be used in TabItem.PreviewMouseLeftButtonDown in order to filter clicks to the tabitem header vs click events originating from the content area.
Edit:
The reason why Label is looking different is, that a font style is active for TabItem and Label is using some of its internal styles, ignoring the TabItem style.
Related
I got a button inside a grid that contains many other buttons and controls such as this
<Grid IsEnabled="false">
<Grid.ColumnsDefinition>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnsDefinition>
<Button Content="Run"/>
<Button Grid.Column="1" Content="Test"/>
<Button Grid.Column="2" Content="Cancel" IsEnabled="true"/>
</Grid>
As you can see the grid is disabled, but the cancel button inside it is supposed to be enabled.
The problem I'm having is that even though I set the inside button to be enabled, it stays disabled, probably because its parent is disabled.
Is there any way to override this behavior and force the button to be enabled?
I'm using it for a case where there's a long process running in the background, so all the UI actions except for cancelling the process should be disabled.
Thanks!
No. Setting IsEnabled property to false leads to disabling all the nested visual elements. One should think of element's contents as parts of its being. Disabling the element means disabling all of its parts.
The easiest workaround is to change the markup to meet your needs. I would rather bring the Cancel button out of this Grid so it's never affected by IsEnabled property of the Grid
I am using WPF split button which is inherited from
xmlns:extToolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit/extended"
The issue is I want to disable , the button ' the one below(Right side of Button 'Conf' in below 'downarrow present in the below fig) , If user clicks on Left side of the button the rightside should be disabled and the button(leftside) background should change to yellow.please find below the xaml , I am using the wpf split button , dropdown content in this case .please let me know if you have any idea
<extToolkit:SplitButton x:Name="ABCbutton"
VerticalAlignment="Center"
Command="{Binding ACommand}"
FontSize="16>
<TextBlock HorizontalAlignment="Center"
IsEnabled="{Binding IsEnabled, ElementName=AButton}"
Text="A"/>
<extToolkit:SplitButton.DropDownContent>
<StackPanel>
<Button Command="{Binding BCommand}"
Padding="3"
Style="{DynamicResource
DropDownButtonMenuButton}">
<TextBlock Margin="0,3,6,3"
Text="B"/>
</Button>
<Button Command="{Binding BCommand}"
Padding="3"
Style="{DynamicResource
DropDownButtonMenuButton}">
<TextBlock Margin="0,3,6,3"
HorizontalAlignment="Stretch"
Text="C"/>
</Button>
</StackPanel>
</extToolkit:SplitButton.DropDownContent>
</extToolkit:SplitButton>
In a case like this, you will likely be better off creating your own control. The split button can't really handle what you are talking about without a good deal of modification.
Essentially your new control will consist of two buttons, visually styled so that they look like they blend together. Each will have it's own background and enabled property. Add a ViewModel to help control behaviors and set properties, and I think you would be in business. Keep in mind that all of the controls that are supplied in any of the toolkits, frameworks, control packs, etc are made with the primitive types of drawing and framework elements (line, rectangle, border, content presenter, panel, etc) with specialized behavior code.
I end up making a lot of custom controls just because there is not one that perfectly replicates what I want.
I'm creating a WPF application containing a "Main-Content" - Layer containing a TabControl and a "Dialog" - Layer containing an ItemsControl.
The XAML looks like this:
<Grid>
<TabControl>
..Some Tabs
</TabControl>
<ItemsControl>
<ContentControl Content={Binding Dialog1Property} />
<ContentControl Content={Binding Dialog2Property} />
</ItemsControl>
</Grid>
Usually "Dialog1Property" and "Dialog2Property" are null which means the ItemsControl is invisible. Whenever I assign a Control to one of them, it is shown in front of the TabControl which is exactly what I want. If I assign a gray Rectangle with an opacity of 0.7 to one of the Dialog - Properties it creates a Gray overlay.
If I click on the Tab, which is slightly visible through the overlay, nothing happens - the Rectangle blocks Mouse Events. It is, however, still possible to focus the TabControl behind the overlay using the Tab-Key and therefore it is also possible to switch tabs even though a Dialog is shown.
Is there an easy way to tell the rectangle to somehow block key events as it allready does with Mouseclicks?
Regards
BBRain
Yes, on your Rectangle, subscribe to the event PreviewKeyDown.
<Rectangle Opacity="0.7" Fill="Green" PreviewKeyDown="Rectangle_PreviewKeyDown" />
In its handler, simply set e.Handled = true;
private void Rectangle_PreviewKeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
}
Since routed events prefixed with "Preview..." are tunneling, the elements under your rectangle won't recieve the input.
I have the following piece of code, which is part of a WPF 4 UserControl:
<Popup x:Name="CantoPopup" IsOpen="False" PlacementRectangle="50,-100,500,120"
AllowsTransparency="True" PopupAnimation="Fade"
StaysOpen="True" Width="500" Height="120">
<Border BorderBrush="#FF120403" BorderThickness="1" CornerRadius="10" Background="#FF9350">
<s:SurfaceScrollViewer x:Name="IndexScroller" Width="500" Height="120" Margin="10" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible">
<DockPanel x:Name="InnerIndexPanel" />
</s:SurfaceScrollViewer>
</Border>
</Popup>
The DockPanel is then populated in the code-behind with a collection of TextBlocks. Basically, I am trying to build a scrollable horizontal list of touchable items.
Now, I would like to detect which textblock was touched by the user. However, neither adding a TouchDown event handler to the TextBlocks nor using TouchExtensions to handle tap gestures worked. Can someone please point me in the right direction?
Under the covers, Popup creates another hwnd to render its content into. This is different from all other WPF controls. You need to register this hwnd with the Surface SDK so it will start sending touch events to it. Use this to do that: http://msdn.microsoft.com/en-us/library/microsoft.surface.presentation.input.touchextensions.enablesurfaceinput.aspx
I found out that the point is that the Popup component has some peculiarities :) In this case, it seems that it did not detect neither TouchDown events nor PreviewTouchDown ones. Therefore, I resorted to creating a UserControl made of a Canvas containing the code above and then making such control visible on top of the rest whenever I needed the popup to open. I do not know whether this is the best solution, but now it reacts as expected.
I'm trying to implement a piece of functionality that will let the user to drag files into an application to be opened in the FlowDocumentReader.
My problem is that is though I have AllowDrop=true on the FlowDocumentReader, the cursor does not change to the "drop here" icon but changes instead to "drop is not allowed" icon.
This happens only to the FlowDocumentReader, all other parts og the UI (window itself, other controls) work as expected. The FlowDocumentReader actually receives the events, and it is possible to handle the drop, but the user does not have a visual indication that he can release the mouse here.
I also cannot hide the "drop is not allowed" cursor by setting Cursor=Cursors.None
Need to handle DragOver event in FlowDocument to allow dropping here.
xaml:
<!--
<FlowDocumentReader x:Name="fdr" Background="White">
<FlowDocument x:Name="doc" AllowDrop="True" DragEnter="doc_DragOver" Drop="doc_Drop" Background="White"/>
</FlowDocumentReader>
-->
<FlowDocumentReader x:Name="fdr" Background="White">
<FlowDocument x:Name="doc" AllowDrop="True" DragOver="doc_DragOver" Drop="doc_Drop" Background="White"/>
</FlowDocumentReader>
code behind:
private void doc_DragOver(object sender, DragEventArgs e)
{
e.Effects = DragDropEffects.All;
e.Handled = true;
}
private void doc_Drop(object sender, DragEventArgs e)
{
}
I couldn't find any direct way to solve this, so here is what I have ended up with:
I placed a grid on top of the FlowDocumentReader. This grid has a sold color, opacity of 0 (transparent) and Visibility=Collapsed. The purpose of this grid is to serve as a drop target.
When FlowDocument within the FlowDocumentReader received the DragEnter event, I switch the grid's visibility to Visible. The grid starts receiving drag events and the cursor stays in the "drop here" form.
When grid receives Drop or DragLeave events, its visibility is turned back to Collapsed to allow the FlowDocument receive mouse events
<FlowDocumentReader x:Name="fdr" Grid.Row="1" Background="White">
<FlowDocument x:Name="doc" DragEnter="doc_DragEnter" Background="White"/>
</FlowDocumentReader>
<Grid x:Name="dtg" Grid.Row="1" Background="White" Opacity="0"
Drop="dtg_Drop" DragLeave="dtg_DragLeave" Visibility="Collapsed"/>