I was given the following exception:
An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationFramework.dll
Additional information: Cannot resolve all property references in the property path 'ContextMenu.IsOpen'. Verify that applicable objects support the properties.
I guess the exception is quite self-explanatory, however I have no idea on how to fix it.
Here is my code:
XAML
<Button
x:Name="btnNotifications"
Height="50px"
Width="auto"
Padding="15 0"
Click="btnNotifications_Click"
ToolTip="Notifications & Agenda"
HorizontalAlignment="Right"
DockPanel.Dock="Right"
BorderThickness="0">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource AccentColorBrush}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="Transparent"/>
</Trigger>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Button.Style>
<Button.Content>
<StackPanel
Orientation="Horizontal">
<Image
Source="/Resources/Icons/Notifications.ico"
Width="25px"
Height="25px"/>
<Label
x:Name="lblNotifications"
FontFamily="Century Gothic"
FontSize="25px"
Foreground="Maroon"
Visibility="Collapsed"/>
</StackPanel>
</Button.Content>
<Button.ContextMenu>
<ContextMenu
x:Name="btnNotificationsMenu">
<MenuItem
x:Name="btnNotificationsNoNew"
Header="No New Notifications."/>
<MenuItem
x:Name="btnNotificationsSeperator"
Background="{DynamicResource AccentColorBrush}"
Height="2px"
Focusable="False"
IsHitTestVisible="False"/>
<MenuItem
x:Name="btnNotificationsNoAgenda"
Header="Your Agenda is Empty."/>
</ContextMenu>
</Button.ContextMenu>
</Button>
Code Behind
public static void NewAppointmentForm()
{
MainWindow appointment = new MainWindow(new AppointmentForm(true));
appointment.btnNotificationsMenu.IsOpen = false;
appointment.ShowDialog();
}
Obviously wrapping the above code in a try catch and calling Close() on appointment fixes the issue. However, it is more of a workaround than a clean solution.
This issue occurs whenever I try to close the window through another Button. I tried closing the window using Close() method within an EventHandler and also as a command through XAML - Command="{Binding CloseCommand}".
I would be really grateful if someone could shed some light upon this issue.
May I point out that the Button containing the ContextMenu is wrapped inside a Border which is placed directly in the MainWindow.
If more detail is needed, please do ask. Thanks :)
Try surrounding the property with parenthesis:
Storyboard.TargetProperty="(ContextMenu.IsOpen)"
See PropertyPath XAML Syntax. The XAML parser doesn't know how to resolve the property because it can be attached to any DependencyObject.
This was a typical Isaac silly mistake.
Basically, I copied the Button which had the ContextMenu and pasted the code to create two ContextMenu-less buttons. Having the following applied to the ContextMenu-less buttons caused the program to crash:
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
Related
So I have a StackPanel menu which has a lot of buttons, each button must have a grid and inside 2 labels, the first for the icon, and the second for a small rectangle which indicates if this button is active or no. In addition, each button is linked to a page, and when the user clicks, the program displays the appropriate page.
When the program wants to get the user's attention to a specific page (for example, a notification page), an animation is started, in which we will flash the icon label (linked to that specific page) 2 times in red color for a short time, and it will be repeated every 10 seconds until the user clicks this button to see the notification.
Problem N: 1
It may happen that multiple notifications arrive at the same time from different pages, in this scenario we need to sync the StoryBoards so that the buttons will flash together every 10 seconds, otherwise you will see an unhappy result as each button will flash separately on others. My first thought was to bind something to the BeginTime of the StoryBoard, and make the StoryBoard wait for the running animations before starting. So, I jumped to the code, and as soon as I write this binding, an awesome exception pops up: Could not freeze this Storyboard timeline tree for use in feeds, I google it and I have found that I am not allowed to use any binding or dynamic resource inside the StoryBoard ControlTemplate, so, I implement a small DependencyProperty in order to synchronize the animation, and this is the reason for which you'll notice this little line here:
<Condition Binding="{Binding Synchronizer}" Value="1"/>
C# Code
public partial class Layout : Window {
public double Synchronizer { get; set; } = 0;
public static readonly DependencyProperty DependencyProperty = DependencyProperty.Register("Synchronizer", typeof(double), typeof(Layout), new PropertyMetadata());
public Layout(){
{
InitializeComponent(); DataContext = this;
}
}
}
This Synchronizer is triggered due to this XAML Code:
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever" Duration="0:0:10">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="DataContext.Synchronizer" Duration="0:0:0.6">
<DiscreteDoubleKeyFrame Value="1" KeyTime="0:0:0.0"/>
<DiscreteDoubleKeyFrame Value="0" KeyTime="0:0:0.6"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
Question N: 1 In yes / no answer, is there is any work around for this exception?
Question N: 2 Is there a better solution?
Problem N: 2
The application has several styles, mainly Dark.Xaml and Light.Xaml, as we already saw in the first issue, animation is used to indicate to the user that a specific page needs some attention. in dark mode we are going to flash the icon with a red color, and in light mode we are going to flash with a blue color, so let me focus on this part of the code:
<ColorAnimationUsingKeyFrames Duration="0:0:0.6" Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)">
<LinearColorKeyFrame Value="#8B0000" KeyTime="0:0:0.2"/>
<LinearColorKeyFrame Value="#272725" KeyTime="0:0:0.3"/>
<LinearColorKeyFrame Value="#8B0000" KeyTime="0:0:0.4"/>
<LinearColorKeyFrame Value="#272725" KeyTime="0:0:0.6"/>
</ColorAnimationUsingKeyFrames>
In general, I change the theme of the app using this C # code:
Resources.MergedDictionaries.Clear();
Resources.MergedDictionaries.Add(Global.Themes[i]);
It works fine with elements that have a DynamicResource binding, but for StaticResource No !!
Question: How can I change the app theme for this StoryBoard ControlTemplate, especially when there is no chance to use the Binding or the Dynamic Resource.
<ControlTemplate x:Key="Menu.Button" TargetType="Button">
<Grid>
<Label Content="{TemplateBinding Content}">
<Label.Style>
<Style TargetType="Label">
<Setter Property="Width" Value="35"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}, Path=Tag, Converter={StaticResource Check}, ConverterParameter=1|1}" Value="True"/>
<Condition Binding="{Binding Synchronizer}" Value="1"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard Name="Storyboard">
<Storyboard>
<ColorAnimationUsingKeyFrames Duration="0:0:0.6" Storyboard.TargetProperty="(Label.Foreground).(SolidColorBrush.Color)">
<LinearColorKeyFrame Value="#8B0000" KeyTime="0:0:0.2"/>
<LinearColorKeyFrame Value="#272725" KeyTime="0:0:0.3"/>
<LinearColorKeyFrame Value="#8B0000" KeyTime="0:0:0.4"/>
<LinearColorKeyFrame Value="#272725" KeyTime="0:0:0.6"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<RemoveStoryboard BeginStoryboardName="Storyboard"/>
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
<Label>
<Label.Style>
<Style TargetType="Label">
<Setter Property="Width" Value="2"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}, Path=Tag, Converter={StaticResource Check}, ConverterParameter=0|0}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" Value="Collapsed"></Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
</Grid>
</ControlTemplate>
<StackPanel Name="Menu" DockPanel.Dock="Left" Width="35" Orientation="Vertical" VerticalAlignment="Bottom">
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
<Button Template="{StaticResource Menu.Button}"/>
</StackPanel>
You cannot get around the problems you're facing using XAML alone. This is because Storyboards in XAML are frozen and you cannot alter them in any way.
The way I handle this is that I move any animations that need dynamic capabilities such as databinding or theme switching into code and I make them available as XAML/attached behaviors.
I have a grid in my application and I need that grid to work like a pop up while checking a togglebutton it should appear and while unchecking it should disappear and for that I wrote a code like this.
<Grid x:Name="popup" Visibility="{Binding IsChecked,ElementName=button,Converter={StaticResource BooleanToVisibility}}" >
<Grid.Resources><Storyboard x:Key="ResetButton1">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(ToggleButton.IsChecked)"
Storyboard.TargetName="button">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<System:Boolean>False</System:Boolean>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard></Grid.Resources>
<i:Interaction.Triggers>
<i:EventTrigger EventName="TouchDown">
<ei:ControlStoryboardAction Storyboard="{StaticResource ResetButton1}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBlock >this is a popup</TextBlock> </Grid>
<ToggleButton x:Name="button"></ToggleButton>
My problem occurs when I uncheck the togglebutton after I checked it. The pop up stays there with an animation.It works fine when i click out of the togglebutton.How I can Handle it?
Ok, so the way you have it currently doesn't make much sense amigo. Subscribing to the TouchDown event to fire off a storyboard that just unchecks the ToggleButton is a cyclic loop of negating itself.
Instead, just throw a couple .Triggers in there to toggle the visibility of the Grid and get rid of that Storyboard and TouchDown EventTrigger.
So just throw something like this in as triggers.
<DataTrigger Binding="{Binding IsChecked, ElementName=button}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsChecked, ElementName=button}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
Or you could also use ChangePropertyAction from the Blend SDK for wpf.
Hope this helps.
I would like to alter my program so that when an image is clicked it reveals a sidebar on the far right side of the application.
I have currently been trying to achieve this using an Expander. This is what it looks like so far:
<Expander>
<Expander.Header>
<Image Width="200" Height="300" Source="{Binding image}"/>
</Expander.Header>
<i:Interaction.Behaviors>
<local:UniqueNameBehavior ID="{Binding id}"/>
</i:Interaction.Behaviors>
<StackPanel Margin="10,4,0,0">
<ToggleButton Margin="4" Content="Option 1" Template="{StaticResource SimpleExpanderButtonTemp}"/>
<ListView>
<TextBox Text="Search" />
</ListView>
</StackPanel>
</Expander>
The idea is that whenever any movie is clicked, a sidebar on the far right side of the app is revealed containing info about the movie. If another movie is subsequently clicked, the sidebar will now contain info about the new movie.
I know that it is possible to change the ExpandDirection, but this only results in the content appearing beside the image as opposed to the far right of the application.
I've also tried adjusting the Margin of StackPanel but this results in the surrounding movies being pushed aside.
Could someone please help me out with how I can achieve this?
Thank you for your help!
I don't believe this kind of behaviour can be achieved using expanders the way you are using.
Why don't you create a grid on the far right side of your app with its width set to 0 and when you click/select a movie it sets the grid width to a new value and change its content based on the movie?
<Grid HorizontalAlignment="Right">
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="Width" Value="0"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ShowMovieForm}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.1" Storyboard.TargetProperty="Width" To="400" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.1" Storyboard.TargetProperty="Width" To="0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>
I wrote this code and got an exception:
Background property does not point to a dependencyobject in path '(0).(1)'
I saw this problem in other posts in the forum but didn't founded a solution.
<WrapPanel.Style>
<Style>
<Style.Triggers>
<Trigger Property "WrapPanel.Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard HandoffBehavior="Compose">
<Storyboard RepeatBehavior="Forever" AutoReverse="True">
<ColorAnimation
Storyboard.TargetProperty="(WrapPanel.Background).(SolidColorBrush.Color)"
Duration="00:00:01" To="Red"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</WrapPanel.Style>
Any help with this?
You most likely failed to set a value for the initial background brush. You can either do so with a style setter, or else just set a value on the panel directly. The style setter is probably better:
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Blue"/>
</Setter.Value>
</Setter>
Note that you can also specify the TargetType property on your style, so that you don't have to prefix all property reference with WrapPanel:
<Style TargetType="WrapPanel">
You must set the Background property of the WrapPanel! Otherwise the WPF subsystem doesn't recognize it as a SolidColorBrush (could be another brush as well).
<WrapPanel Background="White">
...
</WrapPanel>
is sufficient.
I have a problem with color animation. This is my source:
<Window.Resources>
<hedit:BrushToColorConverter x:Key="BrushToColorConverter" />
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ControlTemplate.Resources>
<Storyboard x:Key="buttonAnimIn">
<!-- Problem line -->
<ColorAnimation Storyboard.TargetName="bntBack" Storyboard.TargetProperty="Color" To="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Converter={StaticResource BrushToColorConverter}}" />
</Storyboard>
<Storyboard x:Key="buttonAnimOut">
<ColorAnimation Storyboard.TargetName="bntBack" Storyboard.TargetProperty="Color" To="Blue" />
</Storyboard>
<Storyboard x:Key="buttonAnimForegroundIn">
<ColorAnimation Storyboard.TargetName="btnFore" Storyboard.TargetProperty="Color" To="Blue" />
</Storyboard>
<Storyboard x:Key="buttonAnimForegroundOut">
<ColorAnimation Storyboard.TargetName="btnFore" Storyboard.TargetProperty="Color" To="Red" />
</Storyboard>
</ControlTemplate.Resources>
<Border Name="border"
BorderThickness="1"
Padding="4,2"
BorderBrush="DarkGray"
CornerRadius="3">
<Border.Background>
<SolidColorBrush Color="Blue" x:Name="bntBack" />
</Border.Background>
<ContentControl HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}">
<ContentControl.Foreground>
<SolidColorBrush Color="Red" x:Name="btnFore" />
</ContentControl.Foreground>
</ContentControl >
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<BeginStoryboard Storyboard="{StaticResource buttonAnimIn}" />
<BeginStoryboard Storyboard="{StaticResource buttonAnimForegroundIn}" />
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<BeginStoryboard Storyboard="{StaticResource buttonAnimOut}" />
<BeginStoryboard Storyboard="{StaticResource buttonAnimForegroundOut}" />
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
The problem is:
Cannot convert the value in attribute 'Style' to object of type 'System.Windows.Style'. Cannot freeze this Storyboard timeline tree for use across threads. Error at object 'System.Windows.Controls.Button' in markup file 'HLSLEditor;component/mainwindow.xaml' Line 223 Position 25.
When using fixed colors it worked, but it cannot work with the Foreground color of the parent...
How do I do an animation to the foreground or background color?
Thanks!
You cannot freeze Bindings, you probably can get around this issue by declaring a color as a resource and then bind your Control's Background to it while using StaticResource in the animation.
e.g.
<Window.Background>
<SolidColorBrush Color="{DynamicResource Background}"/>
</Window.Background>
<Window.Resources>
<Color x:Key="Background">Green</Color>
</Window.Resources>
<ColorAnimation Storyboard.TargetProperty="Foreground.Color"
Duration="0:0:1"
To="{StaticResource Background}"/>
Alternative using a resource class:
public static class MyColors
{
public static Color MyHighlightColor = Color.FromArgb(255, 0, 88, 0);
}
<ColorAnimation Storyboard.TargetProperty="Foreground.Color"
Duration="0:0:1"
To="{x:Static local:MyColors.MyHighlightColor}"/>
I think that understanding the error might give you a way of fixing the problem.
Animation requires the use of threads besides the UI thread. So storyboards have to be freezable, which means that all the animations in the storyboard must be freezable, and everything those animations use must also be freezable.
Bindings aren't freezable - pretty much by definition, as they are a mechanism whereby a dependency property can be changed. You can't use a dynamic binding in a color animation - there's the possibility that the property could change while the animation was running. The same thing happens whether you're binding to an object or you're using DynamicResource.
The thing is, this is protecting you from something that you don't really want anyway. You don't really want the colors to change while the animation is running. That's not what you're trying to accomplish. You want the color resources that the animation is using to change if the user selects a different skin.
So instead of binding storyboards to skinnable resources, add the storyboards to the dictionary of resources that get set when the skin changes (using static bindings to set the colors), and use dynamic binding in your event triggers. That should work.
When I came across this problem I worked around it by modifying my style to contain two identical elements on top of each other - one for the 'normal' state and one for the 'pressed' state. The 'pressed' one had its Opacity set to 0 by default and the other one had an Opacity of 1. My animation changed the opacities from 0 to 1 and vice versa.
This approach avoided actually animating the Color property but produced the same effect whilst keeping everything in XAML. As the colours were set in the style definition rather than the animation they could be bound as required. This will probably not be suitable for all situations but for my fairly simple style it was a very quick way to achieve the desired effect.