I have a ListBox with an ItemTemplate (shown below) that when the mouse is over an item, a button is displayed that will fire a Delete Command.
This works, but what I'd like is for the button to "fade in" after the mouse has been over the listitem for a couple of seconds. How can I achieve this?
<ListBox.ItemTemplate>
<DataTemplate d:DesignSource="{d:DesignInstance quizCompanion:Question}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"></ColumnDefinition>
<ColumnDefinition Width="16"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Number}"></TextBlock>
<Button
Content="x" Grid.Column="1"
Command=MyDeleteCommand>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Visibility" Value="Hidden"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsMouseOver}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
Try using a DataTrigger with a RelativeSource for the Binding.
Here's a sample ... mouse over anywhere on the StackPanel for 2 seconds or more and the hidden button will fade in. It'll disappear when the mouse is moved off. Hopefully it'll work within your ListBox ItemTemplate:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<StackPanel Height="100" Background="Yellow">
<TextBlock Text="Mouse over the yellow area to see the button"/>
<Button Width="250" Height="50" HorizontalAlignment="Left" Opacity="0">
<Button.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type StackPanel}}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="Fade">
<Storyboard>
<DoubleAnimationUsingKeyFrames Duration="0:0:3" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="0:0:2" Value="0"/>
<LinearDoubleKeyFrame KeyTime="0:0:3" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="Fade"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</Grid>
</Page>
Related
I have a storyboard for a canvas and I want to stop it as soon as the ShowError property has changed.
<UserControl.Resources>
<Storyboard x:Key="LoaderAnimation" Name="LoaderAnimation" >
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
Storyboard.TargetName="canvas"
RepeatBehavior="Forever">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:3" Value="360"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<Viewbox x:Name="LayoutRoot" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Row="0" Height="150" Width="250">
<Canvas Height="323" Width="308" RenderTransformOrigin="0.5,0.5" x:Name="canvas">
<Canvas.RenderTransform>
<RotateTransform/>
</Canvas.RenderTransform>
<Ellipse Fill="{Binding Foreground, ElementName=userControl}" Height="71" Canvas.Left="121" Canvas.Top="21" Width="69" Opacity="0.3"/>
<Ellipse Fill="{Binding Foreground, ElementName=userControl}" Height="71" Width="69" Canvas.Left="194" Canvas.Top="52" Opacity="0.4"/>
<Ellipse Fill="{Binding Foreground, ElementName=userControl}" Width="69" Height="71"
</Canvas>
</Viewbox>
<TextBlock Grid.Row="1" TextWrapping="Wrap" FontSize="20" Margin="0 20 0 0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding ShowError}" Value="false">
<Setter Property="Text" Value="{loc:Translate LogIn.TestSpsConnection}" />
<Setter Property="Foreground" Value="Black" />
</DataTrigger>
<DataTrigger Binding="{Binding ShowError}" Value="true">
<Setter Property="Text" Value="{loc:Translate LogIn.FailSpsConnection}" />
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
I've tried every idea but I can't access the storyboard from the style of the TextBlock.
Is there any way I can stop the animation when ShowError goes true ?
thank you for your help
Try applying a style trigger onto your Canvas that stops the storyboard when ShowError goes true, instead of doing it from your TextBlock.
Example:
<UserControl.Resources>
<Storyboard x:Key="LoaderAnimation" Name="LoaderAnimation" >
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
RepeatBehavior="Forever">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:3" Value="360"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
...
<Canvas Height="323" Width="308" RenderTransformOrigin="0.5,0.5" x:Name="canvas">
...
<Canvas.Style>
<Style TargetType="Canvas">
<Style.Triggers>
<EventTrigger RoutedEvent="Loaded">
<EventTrigger.Actions>
<BeginStoryboard x:Name="beginStoryboard" Storyboard="{StaticResource LoaderAnimation}"/>
</EventTrigger.Actions>
</EventTrigger>
<DataTrigger Binding="{Binding ShowError}" Value="True">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="beginStoryboard"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Canvas.Style>
</Canvas>
Also, notice that I removed the Storyboard.TargetName from your resource, or else it violates some XAML rules when used the way that I did it. You'll get runtime errors if you keep it there.
I'm pretty much new to XAML and I'm trying to mimic following => menu
example menu (menu items I'm talking about google, facebook etc.)
Expected Behaviour:
Hoover on below Button
Should look like:
My code gives me only:
How do I achieve the expected output - make my TextBlock to appear and be part of the button?
My first approach was to use a grid and create two columns and have the second one always hidden and show only on hoover. Then I came up with belows button approach finally I found out about Expander class... Not sure whats the correct approach, below it's what I have so far, obviously far away from expected output.
<Button Name="button1" Width="170" Height="170" Cursor="Hand">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<Image Width="48" Height="48" Source="https://pbs.twimg.com/profile_images/638750728354430976/HnTYCHzN_400x400.png" />
<TextBlock Visibility="Hidden" Width="100" Height="70" VerticalAlignment="Center" HorizontalAlignment="Center" Background="pink">
MenuItem1
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, ElementName=button1}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Green"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="Margin" Value="20,0,0,0" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
You can use animation to achieve this. Below is the Template for Button which uses animation to give Slide-In and Slide-Out effect on MouseEnter and MouseLeave events
<Button Name="button1" Cursor="Hand">
<Button.Template>
<ControlTemplate>
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image Width="48" Height="48" Source="https://pbs.twimg.com/profile_images/638750728354430976/HnTYCHzN_400x400.png" />
<TextBlock Grid.Column="1" x:Name="myTextBlock" Width="0" Height="48" VerticalAlignment="Center" HorizontalAlignment="Left" Background="pink">
MenuItem1
</TextBlock>
<TextBlock Grid.Column="1" Visibility="Hidden" Width="100" Height="48" x:Name="dummyBlock" />
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation
Storyboard.TargetName="myTextBlock"
Storyboard.TargetProperty="Width"
From="0.0"
To="100"
Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard >
<DoubleAnimation
Storyboard.TargetName="myTextBlock"
Storyboard.TargetProperty="Width"
From="100.0"
To="0"
Duration="0:0:0.3" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
Here is a fair start for implementing your requirements:
1.The Style uses render transform to stretch your button.
2.The button content changes cording to a bound bool
<UserControl ...>
<UserControl.Resources>
<!--*********** Templates ***********-->
<ControlTemplate x:Key="VIEWALLTemplate">
</ControlTemplate>
<ControlTemplate x:Key="DefultTemplate">
<StackPanel Background="White" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<Image Width="48" Height="48" Source="https://pbs.twimg.com/profile_images/638750728354430976/HnTYCHzN_400x400.png" />
<TextBlock Text="MenuItem1" Visibility="Hidden" Width="100" Height="70" VerticalAlignment="Center" HorizontalAlignment="Center" Background="pink"/>
</StackPanel>
</ControlTemplate>
<!--*********** Styles ***********-->
<Style TargetType="Button">
<Setter Property="Background" Value="Green"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform ScaleX="2" ScaleY="1"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<Button Width="100" Height="100" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button.Content>
<ContentControl DataContext="{Binding}" Grid.Row="1">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Template" Value="{StaticResource DefultTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=SomeBool}" Value="true">
<Setter Property="Template" Value="{StaticResource VIEWALLTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Button.Content>
</Button>
</Grid>
</UserControl>
I have the following template defined. The TextBlock PART_TextBlock binds correctly if outside of the StackPanel but when placed inside the StackPanel I get a binding error. The StackPanel datacontext is bound to a converter and is applying the storyboard (flashing tab) as required. I need the tab to flash and also the text to display in the tab header with the flashing in the background of the text.
<dashboard:EditableTabHeaderControl.Template>
<ControlTemplate TargetType="{x:Type dashboard:EditableTabHeaderControl}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel DataContext="{Binding Path=., Mode=OneWay, Converter={StaticResource DependencyObjectToFilterConverter}}" Grid.Row="1" Background="Transparent" >
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=HasError}" Value="True" >
<DataTrigger.EnterActions>
<BeginStoryboard Name="StartBlinking" >
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="Background.Color"
To="Red"
Duration="00:00:00.4"
RepeatBehavior="Forever"
AutoReverse="True" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding Path=HasError}" Value="False" >
<DataTrigger.EnterActions>
<RemoveStoryboard BeginStoryboardName="StartBlinking" />
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<TextBlock Text=" " VerticalAlignment="Top">
</TextBlock>
<TextBox x:Name="PART_TabHeader" Text="{Binding Path=Title,
Mode=TwoWay, diag:PresentationTraceSources.TraceLevel=High}" Visibility="Collapsed">
</TextBox>
<TextBlock x:Name="PART_TextBlock" Text="{Binding Path=Title,
Mode=TwoWay, diag:PresentationTraceSources.TraceLevel=High}" >
</TextBlock>
</StackPanel>
<!-- IF THE TEXBOX/TEXTBLOCK ARE PLACED HERE TITLE BINDS CORRECTLY-->
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsInEditMode" Value="True">
<Trigger.Setters>
<Setter TargetName="PART_TabHeader" Property="Visibility" Value="Visible"/>
<Setter TargetName="PART_TextBlock" Property="Visibility" Value="Collapsed"/>
</Trigger.Setters>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</dashboard:EditableTabHeaderControl.Template>
</dashboard:EditableTabHeaderControl>
I finally figured out the Binding expression, the following worked
Text="{Binding DataContext.Title, RelativeSource={RelativeSource AncestorType=dashboard:EditableTabHeaderControl}}"
I am trying to set the selected value of a combobox from a style trigger.It works as long as we dont manually change any value in the combobox.But it stops working altogether after manually changing the selection.How can i solve this.A sample code is attached.Please do help
<Window x:Class="InputGesture.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:InputGesture"
Title="Window2" Height="300" Width="300" Name="Sample">
<Window.Resources>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ComboBox.SelectedValue" Value="1"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=chk,Path=IsChecked}" Value="True">
<Setter Property="ComboBox.IsEnabled" Value="False"/>
<Setter Property="ComboBox.SelectedValue" Value="2"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<CheckBox Name="chk" Height="23"/>
<ComboBox Name="cmb" Height="23" DisplayMemberPath="Name"
SelectedValuePath="Id" ItemsSource="{Binding ElementName=Sample,Path=DT}">
</ComboBox>
<Button Height="23" Click="Button_Click"/>
</StackPanel>
</Window>
I have found a Quick but Dirty Solutuin i guess..If anyone has a better Idea Please..
<Window x:Class="InputGesture.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:InputGesture"
Title="Window2" Height="300" Width="300" Name="Sample">
<Window.Resources>
<Style TargetType="{x:Type ComboBox}">
<Style.Resources>
<Storyboard x:Key="valueStoryBoard" >
<ObjectAnimationUsingKeyFrames Duration="00:00:00"
FillBehavior="HoldEnd"
Storyboard.TargetProperty="SelectedValue">
<DiscreteObjectKeyFrame KeyTime="00:00:00"
Value="{x:Null}" />
<!--<DiscreteObjectKeyFrame KeyTime="00:00:00"
Value="2" />-->
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Style.Resources>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=chk}"
Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="stb" Storyboard="{StaticResource valueStoryBoard}" />
</DataTrigger.EnterActions>
<Setter Property="ComboBox.IsEnabled" Value="False"/>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="stb" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<CheckBox Name="chk" Height="23"/>
<ComboBox Name="cmb" Height="23" DisplayMemberPath="Name"
SelectedValuePath="Id" ItemsSource="{Binding ElementName=Sample,Path=DT}">
</ComboBox>
<Button Height="23" Click="Button_Click"/>
</StackPanel>
</Window>
I have added a DataTemplate to a ListBox class to bind my collection to:
<ListBox x:Name="lstEmails" Height="259" Margin="12,0,12,41" Width="276"
SelectionChanged="lstEmails_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Visibility="Hidden" Content="{Binding ID}"></Label>
<TextBox Width="200" Text="{Binding EmailAddress}"></TextBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This does exactly what I want it to do. Although when I click on the TextBox, the ListBox does not automatically set the associated ListItem as Selected. I could do this in code, but I would prefer to use this as a component (no surprises there then).
Any ideas on how to achieve this?
That doesn't seem to work, it won't let me click on anything. Have I missed something. Here is my new XAML.
<UserControl.Resources>
<!--<TextBox x:Key="TB" x:Name="TextBoxInsideListBoxItemTemplate">
<TextBox.Style>-->
<Style TargetType="{x:Type TextBox}">
<Setter Property="IsHitTestVisible" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListBoxItem}, AncestorLevel=1}}"
Value="True">
<Setter Property="IsHitTestVisible" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
<!--</TextBox.Style>
</TextBox>-->
</UserControl.Resources>
<Grid>
<ListBox x:Name="lstEmails" Height="259" Margin="12,0,12,41" Width="276" SelectionChanged="lstEmails_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!--<Label Visibility="Hidden" Content="{Binding ID}"></Label>-->
<TextBox Width="220" Text="{Binding EmailAddress}" >
</TextBox>
<!--<TextBox Width="220" Text="{Binding EmailAddress}" GotFocus="TextBox_GotFocus"></TextBox>-->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Width="20" Margin="12,0,0,12" Name="btnAdd" VerticalAlignment="Bottom" Click="btnAdd_Click" Height="23" HorizontalAlignment="Left">+</Button>
<Button Width="20" HorizontalAlignment="Left" Margin="30,0,0,12" Name="btnRemove" VerticalAlignment="Bottom" Click="btnRemove_Click" Height="23">-</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,12,12" Name="btnApply" VerticalAlignment="Bottom" Width="49" Click="btnApply_Click">Apply</Button>
</Grid>
I think the click twice bit is good functionality.
You can trigger on the property IsKeyboardFocusWithin in the ItemContainerStyle and set IsSelected to true.
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Self}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="(ListBoxItem.IsSelected)">
<DiscreteBooleanKeyFrame KeyTime="0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
You could also use a Setter instead of a single frame animation but then the selection will be lost again once the focus leaves the ListBox:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="IsSelected" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
If you have multiple instance of ListBox then you may consider using your custom listbox (by deriving it from ListBox). See the explanation here.
Or, use this hack if you have only 1 (or only small number of) such ListBox and don't want to create a separate class for that:
<TextBox x:Name="TextBoxInsideListBoxItemTemplate" ... >
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="IsHitTestVisible" Value="False" />
<Style.Triggers>
<DataTrigger
Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListBoxItem}, AncestorLevel=1}}"
Value="True">
<Setter Property="IsHitTestVisible" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Note that you'll have to click once again to edit text in the TextBox (which is actually cool according to me).
I had a situation where the selection of a listbox item would change its layout, so the control might have moved away from the cursor before the mouse button is released. I have found no better solution than to use a slight delay in the Storyboard if I want to keep everything in xaml.
More importantly, GotKeyboardFocus seems to work better than IsKeyboardFocusWithin for repeated selections.
<EventTrigger RoutedEvent="GotKeyboardFocus">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsSelected">
<DiscreteBooleanKeyFrame KeyTime="00:00:00.3" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>