Prevent automatic resize of window when content changes - wpf

I have made a picture viewer which is a Window with SizeToContent="Width". This looks just the way I want it when I open it with the first picture in a series.
When I go the next picture in the series, which happens to be wider than the previous one, the Window is resized to fit this new picture. The left edge of the Window stays in the same place, but the right edge of the Window is now outside the edge of the screen.
How can I prevent an automatic resize like this?
I do not want to use ResizeMode="NoResize" because I want the user to be able to manually change the size of the Window should he or she want to.
XAML
<Window SizeToContent="Width" WindowStartupLocation="CenterOwner">
<Grid>
<DockPanel>
<Button DockPanel.Dock="Left"
Content="Previous" />
<Button DockPanel.Dock="Right"
Content="Next" />
<Image Source="{Binding CurrentImage}"
Stretch="Uniform"
StretchDirection="DownOnly"
RenderOptions.BitmapScalingMode="Fant" />
</DockPanel>
</Grid>
</Window>

Reset the SizeToContent property in a Loaded event handler:
public MainWindow()
{
InitializeComponent();
Loaded += (o, e) => SizeToContent = SizeToContent.Manual;
}
Or if you don't like code behind:
<Window.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="SizeToContent">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{x:Static SizeToContent.Manual}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>

Related

WPF: button width cannot be changed smaller

In one of the windows of my WPF application, the button width cannot be changed to smaller size whatever I do. I tried change the property of "width" in xaml, drag the button in designer, or pragmatically change it using c#. Even if I created a new button in that window, the width could only be changed to larger size but could not be changed to smaller size. Though there was no error or warning, none of the approaches successfully change the width. The weird thing was, I could change the height of the button smaller or larger easily by dragging, and in my other window, I can change the buttons width and height smaller or larger easily. I am using the same style for all the buttons in all the windows. If I drag the button, there will be no response of it unless I unlock the one of the litlle "knot" around it, but it will look like this:
The only thing is that I use a notification template for this window and there are some animation effects. But I didn't see any major difference between it and others. Here is the XAML code:
<Window x:Class="Timebreak.NotiWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Timebreak"
mc:Ignorable="d"
Title="TimeBreak" Height="450" Width="450"
WindowStyle="None" AllowsTransparency="True" Opacity="0.7" Background="#f9f9ff"
WindowStartupLocation="Manual" Left="0" Top="0">
<Grid>
<Button x:Name="button1" Content="OK" Margin="358,341,13,72" Click="Submit_Click" FontSize="16" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<RadioButton x:Name="radioButton" Content="Yes. I want to stand up and take a break for (minutes)" HorizontalAlignment="Left" Height="26" Margin="31,105,0,0" VerticalAlignment="Top" Width="368" Checked="radioButton_Checked" FontSize="14"/>
<RadioButton x:Name="radioButton1" Content="No. I don't want to stand up and take a break because" HorizontalAlignment="Left" Margin="31,206,0,0" VerticalAlignment="Top" FontSize="14" Checked="radioButton1_Checked"/>
<Slider x:Name="slider" HorizontalAlignment="Left" Height="23" Margin="40,136,0,0" VerticalAlignment="Top" Width="374" IsSnapToTickEnabled="True" ValueChanged="slider_ValueChanged" Maximum="30" Minimum="1" Cursor="Hand" AutoToolTipPlacement="TopLeft" Interval="29" IsMoveToPointEnabled="True" TickPlacement="BottomRight"/>
<!-- Animation -->
<Grid.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
<SplineDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
<SplineDoubleKeyFrame KeyTime="0:0:4" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Grid.RenderTransform>
<ScaleTransform ScaleY="1" />
</Grid.RenderTransform>
</Grid>
Does ideas about it? Thanks in advance!
Does ideas about it?
You forgot to post the markup of the custom Style that you are obviously using but you could try to set the MinWidth property of the Button to 0:
<Button x:Name="button1" Content="OK" Margin="358,341,13,72" Click="Submit_Click" FontSize="16"
VerticalAlignment="Top" HorizontalAlignment="Left" MinWidth="0"/>
Please post your all relevants parts of your XAML markup and code if still cannot increase the width of the Button.

XAML animation of height of control with dynamic content

I have a panel that should be minimized unless the user hovers the mouse over the panel. It is implemented using a storyboard that lets the height of the panel grow when the use puts the mouse over the control. At the moment the target height is hard coded to 400 which is a bad solution as the content of the panel will be different each time the application starts (it is static during execution).
How do you create an animation that lets the panel grow to the size of the current content?
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="500" Width="525">
<Grid>
<Border Margin="10,0" Background="LightGray" HorizontalAlignment="Left" VerticalAlignment="Top" CornerRadius="0,0,8,8">
<Border.Effect>
<DropShadowEffect Opacity="0.5"/>
</Border.Effect>
<Border.Triggers>
<EventTrigger RoutedEvent="Border.MouseEnter">
<BeginStoryboard>
<BeginStoryboard.Storyboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Height"
From="25"
To="400"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard.Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Border.MouseLeave">
<BeginStoryboard>
<BeginStoryboard.Storyboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Height"
From="400"
To="25"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard.Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<StackPanel Margin="5">
<TextBlock Height="25" Text="My items panel" />
<ListBox MinWidth="150" MinHeight="100" ItemsSource="{Binding MyItems}" />
</StackPanel>
</Border>
</Grid>
Edit: I have tried with binding to the Height of the StackPanel but that didn't really help as it didn't take the margins of the stackpanel into account thus making the panel shorter than needed.
<DoubleAnimation Storyboard.TargetProperty="Height"
From="{Binding ElementName=NameOfStackPanel, Path=ActualHeight}"
To="25"
Duration="0:0:0.2" />
You could create a converter to handle adding the margins to the ActualHeight of your StackPanel. You could even use a multivalue convertor so you could bind the margin too and not have to hardcode a fudge factor. Finally, you could probably wrap your stackpanel in another panel (without margins) and bind to the height of that instead.

WPF: Show and persist ToolTip for a Textbox based on the cursor

The purpose of this tooltip is to show, the format of the string which must be entered.
The features I would like to achieve are:
The tooltip should be shown when the user places the cursor in the textbox, i.e. when the user tabs into the control.
The tooltip should update based on user input into the textbox (this can be achieved by binding).
The tooltip must persist until the user tabs out of the control.
I wanted to know if the standard tooltip as provided has configuration settings, properties, that can be used to achieve this,... in my research thus far I haven't found any. If the existing tooltip is not up to the task, which is very likely, I'd like some pointers, sample code to achieve this...
Thanks
Hasanain
Using a combination of event triggers, bindings, and minimal code-behind I managed to implement a behavior which would update the ToolTip while the user types into textbox; when the keyboard focus is lost the tooltip disappears.
Here is the xaml for the textbox:
<TextBox Grid.Column="0" x:Name="txtBxQckTkt" Margin="5,5,0,0" Width="250" ToolTipService.IsEnabled="True"
Text="{Binding QuickTicketText}">
<TextBox.Triggers>
<EventTrigger RoutedEvent="TextBox.GotKeyboardFocus">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames
Storyboard.TargetName="txtBxQckTktToolTip"
Storyboard.TargetProperty="IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False"/>
<DiscreteBooleanKeyFrame KeyTime="0:0:0.0001" Value="True" />
</BooleanAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="txtBxQckTktToolTip"
Storyboard.TargetProperty="Placement">
<DiscreteObjectKeyFrame Value="{x:Static PlacementMode.Bottom}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="TextBox.LostKeyboardFocus">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames
Storyboard.TargetName="txtBxQckTktToolTip"
Storyboard.TargetProperty="IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/>
<DiscreteBooleanKeyFrame KeyTime="0:0:0.0001" Value="False" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBox.Triggers>
<TextBox.ToolTip>
<ToolTip x:Name="txtBxQckTktToolTip" Placement="Bottom" Content="{Binding ToolTip}">
</ToolTip>
</TextBox.ToolTip>
</TextBox>
Here is the code-behind:
txtBxQckTktToolTip.PlacementTarget = txtBxQckTkt;
_handler = (s, e) =>
{
var viewModel = DataContext as SingleTradeEntryViewModel;
if (viewModel == null) return;
viewModel.OnKeyup.Execute(txtBxQckTkt.Text);
};
txtBxQckTkt.KeyUp -= _handler;
txtBxQckTkt.KeyUp += _handler;
When the command (OnKeyup) executes, it raises a change notification for the ToolTip property bound as seen in the xaml.
Thanks
Hasanain
You might have to implement your own using the Popup Control. Here is some sample XAML to get you started:
<Button Width="120" Height="30" Name="btn">
<Popup IsOpen="True" StaysOpen="True" PlacementTarget="{Binding ElementName=btn}" Placement="Bottom">
<Button Width="120" Height="30" Content="Button In ToolTip"/>
</Popup>
</Button>
And here is some example code to get you started:
http://social.msdn.microsoft.com/forums/en-US/wpf/thread/845ffad0-4abf-4830-b206-03f7fe53f74b
2. ToolTip="{Binding Text, ElementName=textBox1, UpdateSourceTrigger=PropertyChanged}"
Here textBox1 is your textbox name and I have changed UpdateSourceTrigger to PropertyChanged so it updates your tooltip as you type.
3. ToolTipService.ShowDuration="12000"
Give this property a random time which is long enough to suit your needs.
I don't fully understand your first point but I think you need the tooltip to show in your gotfocus eventhandler. This can be achieved by something like in the gotfocus event.
ToolTip toolTip = ToolTipService.GetToolTip(textBox1) as ToolTip;
toolTip.IsOpen = true;
You could create a trigger that sets the ToolTip based on if the control has focus or not

Dependency Property Value Precedence and animations

I am animating some property using DoubleAnimation. Before animation is triggered any local or Setter changes are properly reflected in the property. After animation completes nothing seems to be able to change the value of the property. I have even tried ClearValue and InvalidateProperty as well set calling SetValue but the value leftover from animation persists. If animation is repeated, the property continues to be animated as expected so it only appears to be locked for non-animation changes.
Is there a way to rectify this behavior? I want to use the animation to change the property value but still be able to change it manually or via a Setter to anything else. I know a thing or two about Dependency Property Value Precedence but the behavior I am currently experiencing is a bit strange. I'd hate to have to use "manual animations".
EDIT: Added sample XAML + code.
<Window x:Class="WpfApplication7.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
x:Name="_this"
Background="Red">
<DockPanel>
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Center" >
<Button Click="ToggleOnClick">Toggle!</Button>
<Button Click="SetHalfOnClick">Set to 0.5!</Button>
</StackPanel>
<TextBox DockPanel.Dock="Bottom" IsReadOnly="True" Text="{Binding ElementName=_viewbox,Path=Opacity}" />
<Viewbox x:Name="_viewbox">
<Viewbox.Style>
<Style TargetType="{x:Type FrameworkElement}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsToggled,ElementName=_this,Mode=OneWay}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="0.2"
Duration="0:0:0.5"
Storyboard.TargetProperty="(UIElement.Opacity)" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="1"
Duration="0:0:0.5"
Storyboard.TargetProperty="(UIElement.Opacity)" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Viewbox.Style>
<TextBlock Text="Sample!" />
</Viewbox>
</DockPanel>
</Window>
Here is the code:
using System.Windows;
namespace WpfApplication7
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1
{
public bool IsToggled
{
get { return (bool)GetValue(IsToggledProperty); }
set { SetValue(IsToggledProperty, value); }
}
public static readonly DependencyProperty IsToggledProperty = DependencyProperty.Register("IsToggled", typeof(bool), typeof(Window1), new UIPropertyMetadata(false));
public Window1()
{
InitializeComponent();
}
private void ToggleOnClick(object sender, RoutedEventArgs e)
{
IsToggled = !IsToggled;
}
private void SetHalfOnClick(object sender, RoutedEventArgs e)
{
_viewbox.Opacity = 0.5;
}
}
}
Edit 2 in response to comments:
In your example you can work around the problem by:
Setting FillBehaviour to Stop on the animation
Adding a handler in code to the Completed event:
<Storyboard Completed="FadeOut_Completed">
Finally, set the desired 'final' value in the Completed handler (either explicitly or by using the current value of the property
private void FadeOut_Completed(object sender, EventArgs e)
{
_viewbox.Opacity = _viewbox.Opacity; //this sets the DP value to the animated value
}
This works in your sample; hopefully it will work in your problem!
Original Answer
If you set the FillBehaviour property of the Storyboard to Stop (instead of the default value of HoldEnd) it will revert to the pre-animation value of the property once the animation completes. HoldEnd causes the animation to maintain its final value on the property
Update in response to comments:
As noted in the comments, the animation value will override the value set against the property when HoldEnd is specified as the FillBehaviour.
This makes it slightly tricky to set the value to something else.
I am not sure if there is a better way to achieve this, but the example below shows one way to work around it. Its hard to judge how applicable this is without a sample usage from the OP, but in this example I am animating the width of a Rectangle on load, and then resetting it to another value when a button is clicked:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Target" Storyboard.TargetProperty="Width"
From="10" To="100" Duration="0:00:01" FillBehavior="HoldEnd" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Rectangle Height="10" Width="10" Fill="Red" x:Name="Target"/>
<Button Grid.Row="1" Content="Resize">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Target" Storyboard.TargetProperty="Width">
<DiscreteDoubleKeyFrame Value="50" KeyTime="0:00:00" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</Window>
This works because the new animation overrides the value set in the original.
You can use UIElement.BeginAnimation with the animation parameter set to null. It will clear all animations attached to your property.

WPF - Animation to make an error message disappear

I have the following xaml in my window:
<Border Height="100" BorderBrush="Black" BorderThickness="2" CornerRadius="10" Background="PaleVioletRed" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Margin="10" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="17" FontWeight="Bold">Error Message Here</TextBlock>
</Border>
Which basically displays this:
alt text http://xs.to/thumb-4CB2_4B69F8E6.jpg
I plan to bind it's Visibility to an error state variable so it shows when an error occurs.
But I don't want to show it for a long time. I would like it to disappear/fade after 2 seconds. Is there a way to do this via XAML? Or a nice WPF way?
Something like this psudo code logic:
when (ErrorMessage.Visibility == Visible )
{
Wait(2000); // Wait 2 seconds
ErrorMessage.Visibility == Collapsed;
}
but preferable done with XAML.
My instincts tell me there is a way to do this with an animation, but I am not an animation expert and could use some help.
The other option is to try and setup a timer and control it with that.
use something like this....
<EventTrigger RoutedEvent="Page.Loaded">
<BeginStoryboard>
<Storyboard BeginTime="0:0:1">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="image1" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
change the routed event to match your needs, set the BeginTime on the storyboard to 2 mins ( or whatever ), set the targetname to your border element.

Resources