I am using Expander in WPF to display my data. The default style for the Expander control contains a toggle button which shows/hides my content when I click on it.
How can I modify the style so that it expands when I hovers the mouse over the header and collapse when I move away?
Barebone setup should be this:
<Style TargetType="{x:Type Expander}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsExpanded" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
(Applies to the whole expander, not just the header. That would probably require messing with the template.)
It is possible to use databinding between isExpanded property an ismouseover:
IsExpanded="{Binding IsMouseOver, Mode=OneWay, RelativeSource={RelativeSource Self}}"
Related
I've searched quite a bit but most of the solutions I found were from people asking on how to do it in C#. I wanted both to practice my XAML and reduce my already messy C# code so I decided to try it on XAML.
What I've Tried:
I've created a template for the Context Menu and here's my code:
<ControlTemplate TargetType="ContextMenu">
<Grid>
<!-- Some Content -->
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Parent.IsMouseOver, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
<Setter Property="IsOpen" Value="True"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
My understanding of the code:
I imagined the hierarchy to be like this:
Parent UIControl (Can be a button, textbox, etc)
|---> Context Menu
|---> Template
So with my code Binding Parent.IsMouseOver, RelativeSource={RelativeSource TemplatedParent}, I expected it to work like this:
I've set my source to the TemplatedParent first (which I expected to be the Context Menu)
Now I'm trying to bind to the Parent (which is a UIControl of whoever uses the Context Menu) of my source (which at the moment I expect to be the TemplatedParent)
Here's the full code of everything involved with this:
Parent:
<Button Content="Button" ContextMenu="{DynamicResource ErrorPopup}"/>
Context Menu w/ Control Template (They're stored on a ResourceDictionary since they'll be reused by other controls to display each of their own Errors):
-
<ContextMenu x:Key="ErrorPopup" x:Shared="False">
<ContextMenu.Style>
<Style TargetType="ContextMenu">
<Setter Property="IsOpen" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContextMenu">
<Grid>
<!-- Some Content -->
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Parent.IsMouseOver, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
<Setter Property="IsOpen" Value="True"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ContextMenu.Style>
</ContextMenu>
What I expect:
I expected the Context Menu to popup when I place my cursor on top of the Button.
UPDATE:
I've managed to make some progress, I tried changing my binding to:
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType=Button,Mode=FindAncestor}}" Value="True">
<Setter Property="IsOpen" Value="True"/>
</DataTrigger>
Unfortunately it's displaying some weird behavior wherein the MouseOver would show the context menu ONLY if I forcibly open a Context Menu beforehand by using my mouse's right click.
This doesn't work:
I hover over the Button
Context Menu doesn't show up
This works:
I right click the Button
Context Menu shows up
Closes quickly
Shows a Context Menu from the Mouse Over
I move the cursor away = Context Menu disappears
I move the cursor inside = Context Menu appears
Could this be because the context menu doesn't actually exist yet up until I explicitly open it through a mouse's right click? And after initializing it, only then will the triggers work?
I am relatively new to WPF, but I would like to know how can I enable a listbox to select an item based on a mouseover event instead of the button click. I would like the item to be selected when the mouse is over the selected item, without having to press click first.
Thank you
You may write a simple ListBoxItem Style with a Trigger on the IsMouseOver property that sets the IsSelected property:
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsSelected" Value="True"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
So the following does the first part:
<Expander>
<Expander.Style>
<Style TargetType="Expander">
<Setter Property="IsExpanded" Value="False" />
<Setter Property="Header" Value="See More" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsExpanded,RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Header" Value="See Less" />
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
</Expander>
But what if I want the header size to be 16pt too? Can't think of the correct syntax.
There is no direct way of modifying header. You need to create custom template to change property of header only.
But there is a easy workaround which I used. You can change the font size in the trigger for the full expander like <Setter Property="FontSize" Value="16"/>. And have the fontsize of children explicitly set to 12(or the default value) or also can bind the children fontsize to the expander's parent fontsize. This will make expander children to remain as 12 or to expander's parent fontsize and trigger will not have any affect on them, so only header will be changing.
I have a UserControl which contains a ContentControl. When the user clicks this ContentControl I want to change its ContentTemplate, to make it "editable" (instead of labels display textboxes for example).
What I have is this:
<StackPanel>
<ContentControl Style="{DynamicResource ContainerStyleEditable}" GotFocus="ContentControl_GotFocus"></ContentControl>
</StackPanel>
and in userControl resources i have
<Style TargetType="{x:Type ContentControl}" x:Key="ContainerStyleEditable">
<Setter Property="ContentTemplate" Value="{DynamicResource ItemTemplateReadOnly}" />
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="ContentTemplate" Value="{DynamicResource ItemTemplateEditable}" />
</Trigger>
</Style.Triggers>
</Style>
This doe not work, it seems the GotFocus event never fires. What is the way to to this?
I usually base my triggers of IsKeyboardFocusWithin instead of IsFocused because often the focused element usually isn't the actual ContentControl, but rather a control inside it's Content.
Also, be sure that at least one control inside the ContentControl can accept focus so the control can get focus. If nothing inside the control can accept focus, your trigger will never fire.
Instead of disabling the button which happens automatically, i would like to hide (or rather collapse the visibility of) the button.
You could use a Style and Triggers, assuming that the command is in charge of setting the Button enabled/disabled:
<Button x:Name="btnMoveUp"
Command="{x:Static local:Window1.MoveItemUp}">
<Button.Style>
<Style TargetType="{x:Type Button}" >
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Note that you can define this Style at a higher scope and share it - I just put it right with the Button for a more compressed example.
The same behavior without style and trigger, if the Visibility property is not bound yet.
Command={Binding MyCommand}
Visibility="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled, Converter={StaticResource BTVC}}"
Where BTVC is a BooleanToVisibilityConverter (that is a must have).
Use the BooleanToVisibilityConverter and bind to a bool as described here.