Target Only the Tab of TabItem - c#

The Problem:
I am creating a drag/drop interface that allows for moving items within a tab as well as from one tab to another. Right now I have the following Style that allows me to target the Label within a TabItem. Because of a conflict with a ResourceDictionary, I want to add the Event through the code behind. The problem is if I add the Event to the TabItem then it triggers not only on the tab itself but the contents of the tab.
The Question:
How would I go about wiring up the event in the code behind for the following?
<Style
x:Key="DragDropTi"
BasedOn="{StaticResource {x:Type TabItem}}"
TargetType="TabItem">
<Setter
Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Label
Foreground="White"
Content="{Binding}">
<Label.Style>
<Style
TargetType="Label">
<EventSetter
Event="Drop"
Handler="TabItemDrop" />
<Setter
Property="AllowDrop"
Value="True" />
</Style>
</Label.Style>
</Label>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>

The answer ended up being easier than anticipated. I just had to set the MenuItem.Headeras a Label instead of a string of the name and attach the Event to the Label
Label header = new Label();
header.Content = "Tab Name";
header.AllowDrop = true;
header.Drop += new DragEventHandler(TabItemDrop);
TabItem tabItem = new TabItem();
tabItem.Header = header;

Related

Force focus on control via xaml style

I have a treeview and a listbox.
I want to specify on the style trigger-setter option that, when the listbox visibility is Hidden the focus have to return on the treeview.
Is it possibile to condition an user control focus on the state of another user control?
something like
<Style TargetType="{x:Type TreeView}">
<Style.Triggers>
<Trigger Property="Visibility" Value="Hidden">
<Setter Property="IsFocus" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
Yes it is, see the example here
FOR CHILDREN IN CONTAINERS
<StackPanel FocusManager.FocusedElement="{Binding ElementName=lol}">
<TextBox x:Name="lol"/>
<TextBox x:Name="lul"/>
</StackPanel>
FOR SELF
<TextBox FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"/>

How to avoid childrens of groupbox taking there default styles which are defined in resource or resourcedictionary in wpf

Style defined in Resource
<Setter Property="Background" Value="Red"/>
</Style>enter code here
</Window.Resources>
In window i am adding a groupbox with child label .
<Grid>
<GroupBox Header="Header">
<GroupBox.Resources>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="Background" Value="white"/>
</Style>
</GroupBox.Resources>
<Label Content="dsfdsfdsf" Foreground="Black" />
</GroupBox>
</Grid>
My Expected Result was Label taking background of white . But actually it is taking Red Background (that is defined in style of Resource )
If i set the style of the Label to explicitly null it works fine
Label Content="dsfdsfdsf" Foreground="Black" Style={x:Null}
But Controls to GroupBox are dynamically added so i want to set
Style={x:Null} to all childrens that are being added to Group box
if i set OverrideDefalutStyle to True in Label the content of label is not comming ......................
Label Content="dsfdsfdsf" Foreground="Black" OverridesDefaultStyle="True"
That style in GroupBox.Resources has no effect on the GroupBox itself. The implicit GroupBox's style is the one of its closest ancestor on VisualTree. You put that style in the wrong place.
Or use Style property instead
<Grid>
<GroupBox Header="Header">
<GroupBox.Style>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="Background" Value="white"/>
</Style>
</GroupBox.Style>
<Label Content="dsfdsfdsf" Foreground="Black" />
</GroupBox>
</Grid>
By setting
<Style TargetType="{x:Type GroupBox}">
<Setter Property="Background" Value="White"/>
</Style>
you will set the background of all GroupBox controls within your GroupBox and the GroupBox itself to white.
So if you want to set/override the Background of all Labels within your GroupBox just add an additional Style to your GroupBox targeting Label
<Style TargetType="{x:Type Label}">
<Setter Property="Background" Value="White"/>
</Style>
If you want to reset the style property of your Label just add an empty style definition to your GroupBox
<Style TargetType="{x:Type Label}"/>
The next approach is used on your on risk :)
If you only want to reset the background color, you can do this trick/hack to reset:
<Style TargetType="{x:Type Label}">
<Setter Property="Background" Value="{Binding Background.DefaultValue, RelativeSource={RelativeSource Self}}" />
<Setter Property="Foreground" Value="Black" />
</Style>
Hint: Instead of Background.DefaultValue you can also write Background.ABC the main thing here is that the binding goes wrong.

MouseDown on TabItem

I know many people asked same question, but after searching I couldn't find my answer yet.
Here is problem, I just want to touch TabItem of TabControl.
So for this I can use MouseDown/MouseLeftButtonDown as I know.
I have adding MouseDown/MouseLeftButtonDown for each TabItem,
Even I have adding MouseDown/MouseLeftButtonDown on TabControl(On this case, it's just work on area, not tabs)
Problem is tabItem isn't opens event after left clicking.
I have adding this, it's just works when user touch label of tabitem, so when user click on tabItem(Not label) this isn't works too
<Style TargetType="TabItem">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Label Content="{Binding}">
<Label.Style>
<Style TargetType="Label">
<EventSetter Event="MouseDown" Handler="TabItemMouseDown"/>
</Style>
</Label.Style>
</Label>
</DataTemplate>
</Setter.Value>
</Setter>

C# WPF Style TreeViewItem

I made a custom resource dictionary style for a TreeViewItem, but I am having difficulties with it.
<Style x:Key="StageTreeViewItem" TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
<Setter Property="Foreground" Value="Gold"/>
<Setter Property="FontFamily" Value="ArialN"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem">
<Grid>
<Image Name="PrimaryButtonImage" Source="pack://application:,,,/Images/TreeViewItem/TreeViewItem_Normal.png"/>
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The content/header of the TreeViewItem does not exist. I put "Stage One" as Header of the TreeViewItem, but it doesn't show up. Also, if I add multiple tree view items on another, it does not expand at all.
Another thing:
How can I remove the highlights when I select the tree view item? I want it to be transparent even when I hover over it and even when I click it. I don't want anything to happen, but I just don't know how, I tried everything.
Your provided code is not making it clear how you're setting header of TreeViewItem.
For other part of the question, you can use Triggers for events happening in WPF forms. Also have a look at this link, as you'll have to define a template for changing background color on mouse hover.
IsMouseOver Trigger not working in WPF

How to give my custom control an overridable default margin?

Problem
I've created a custom control (OmniBox), which has its base style set with:
<Style x:Key="GridStyle" TargetType="Grid" BasedOn="{StaticResource BaseElement}">
<Setter Property="Margin" Value="0,2" />
</Style>
But when I'm using my control, I want to be able to do something like:
<UserControl.Resources>
<Style TargetType="{x:Type ui:OmniBox}">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="Margin" Value="0,10"/> <!--Not Working?-->
</Style>
</UserControl.Resources>
<Grid>
<StackPanel>
<ui:OmniBox x:Name="One"... />
<ui:OmniBox x:Name="Two"... />
...
And have all instances of my control take on that default margin. Unfortunately, my controls are not responding to the style set in the resources. They are just keeping their default margin of "0,2".
Strangely, if I explicitly set the margin on my controls like so:
<ui:OmniBox x:Name="One" Margin="0,10" Style="OBDefaultStyle" ... />
<ui:OmniBox x:Name="Two" Margin="0,10" ... />
...
They DO use the margin of "0,10" rather than "0,2". How come the template type isn't working?
If it's relevant, my OmniBox control templates all look like this:
<Style TargetType="{x:Type local:OmniBox}" x:Key="OBDefaultStyle">
<Setter Property="Template" Value="{StaticResource OBDefaultTemplate}" />
</Style>
<ControlTemplate TargetType="{x:Type local:OmniBox}" x:Key="OBDefaultTemplate">
<Grid x:Name="PART_Grid" Style="{StaticResource GridStyle}">
... (Content)
</Grid>
</ControlTemplate>
First Attempt
In my grid style, I've tried setting Margin to
<Setter Property="Margin"
Value="{Binding Path=Margin, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:OmniBox}}}" />
But it didn't help in sucking down the templated margin.
Second Attempt
I tried creating a custom margin dependency property and binding the grid to that:
<Style x:Key="GridStyle" TargetType="Grid" BasedOn="{StaticResource BaseElement}">
<Setter Property="Margin" Value="{Binding Path=MyMargin, RelativeSource={RelativeSource TemplatedParent}}" />
</Style>
My custom property was defined as:
public static readonly DependencyProperty MarginProperty = DependencyProperty.Register("Margin", typeof(Thickness), typeof(OmniBox), new FrameworkPropertyMetadata(new Thickness(0,2,0,2), new PropertyChangedCallback(OnMarginChanged)));
Anyways it didn't work. The default margin set in the dependency property above is still overriding the margin I'm trying to set in the style template.
You can add a default style for a custom control by overriding the metadata for the DefaultStyleKey:
public class MyButton : Button
{
static MyButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));
}
}
You then create a resource dictionary called Generic.xaml that is located in a directory called Themes in the root of the project (so the path will be "/Themes/Generic.xaml"). In that resource dictionary you create a default style for your control:
<!-- Base the style on the default style of the base class, if you don't want to completely
replace that style. If you do, remember to specify a new control template in your style as well -->
<Style TargetType="SomeNamespace:MyButton" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Margin" Value="10" />
</Style>
If you just add a MyButton control it will get the default style, but you can override properties set in the default style by applying a new style:
<Window x:Class="SomeNamespace.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:SomeNamespace="clr-namespace:SomeNamespace"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="SomeNamespace:MyButton">
<Setter Property="Margin" Value="20" />
</Style>
</Window.Resources>
<Grid>
<SomeNamespace:MyButton />
</Grid>
</Window>
GridStyle specifies TargetType="Grid", so the setter <Setter Property="Margin" Value="0,2" /> applies to the Grid at the root of the control template. Setting the Margin property of the containing OmniBox has no effect of the margin of that grid.
Try specifying this in the template:
<Grid x:Name="PART_Grid" Margin="{TemplateBinding Margin}">
Notice I did not set the Style property as you did in the template. This is because the grid's Margin property will always reflect the Margin property of the OmniBox containing it, negating the effect of the Margin property in GridStyle. Instead you will want to default the OmniBox.Margin property and remove GridStyle entirely:
<Style TargetType="{x:Type local:OmniBox}" x:Key="OBDefaultStyle">
<Setter Property="Margin" Value="0 2" />
<Setter Property="Template" Value="{StaticResource OBDefaultTemplate}" />
</Style>
Have you overridden the DefaultStyleKey property in your OmniBox control?
After happening on this question, I figured out what I needed to do. In the control's class, I need to override the margin property's default value:
static OmniBox()
{
MarginProperty.OverrideMetadata(typeof(OmniBox), new FrameworkPropertyMetadata(new Thickness(0,2,0,2)));
}
After that, I get rid of the margin on the "Grid" component of the omnibox completely, since the control itself carries a margin. Now when the user sets the "Margin" property on the OmniBox, it accepts it, if they don't, it uses the default value.
Thank you all so much for your suggestions and effort.

Categories

Resources