I am trying to animate a label in a WPF application. The label gets created programatically (and dynamically) so it is not defined in XAML, but is created in the C# code.
Animation Story
The label appears in the bottom of the window. The label should be positioned lower than the window, so the user can not see it initially. Then a the label moves up (like sliding) and fades out before it reaches the top of the window.
What I have done
I have implemented this behavior myself in an other project. This time I want to use WPF which should perform better.
So far I have seen there should be multiple ways of doing this. Starting with a DoubleAnimation, going by a PathAnimation and VectorAnimation (the last of which I have not tested successfully).
Encountered problems
The animation works nice with a DoubleAnimation, but there is a problem: When I resize the window, the label gets resized too (similar to an anchor in Winforms). When I make the window smaller the label gets smaller too, until it disappears completely. This effect occurs only in the height of the label. I added the code snippet adding the label. Maybe you find some error. Also there should be a better way to implement this (I personally find it very ugly).
Label lbl = new Label()
{
Content = "Test",
FontSize = 36,
Foreground = new SolidColorBrush(Colors.Red),
Background = new SolidColorBrush(Colors.Black),
HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center,
VerticalAlignment = System.Windows.VerticalAlignment.Top
};
lbl.Margin = new Thickness(0, this.MainGrid.ActualHeight + lbl.ActualHeight, 0, 0);
this.MainGrid.Children.Add(lbl);
UpdateLayout();
Transform myTransform = new TranslateTransform();
lbl.RenderTransform = myTransform;
DoubleAnimation AnimationY = new DoubleAnimation((this.MainGrid.ActualHeight + 20) * -1, TimeSpan.FromSeconds(4));
myTransform.BeginAnimation(TranslateTransform.YProperty, AnimationY);
Questions
As I said, I have found multiple ways that seem to achieve the same behavior. Which one could I use to do this. I still have to do the fade-out on the top of the window, but this animation is easier to do compared to the movement.
The animation is fine. The reason your label is resizing is because you are adding it to a Grid. If you want your label to have a fixed height, then set its Height or MinHeight property.
Related
for some reason I'm not able to add a TextBlock to my InkCanvas. In my program I have 3 RadioButtons: FreeHand, Eraser and Text. If I select Text RadioButton it's supposed to add TextBlock wherever I click with my mouse (I should be able to add as many TextBlocks as I want). The problem is that nothing happens and if I worked with Eraser before it stays on Eraser even though I selected Text RadioButton. It's like an annotation program. This is the code I tried:
TextBlock tbx = new TextBlock();
tbx.Height = 30;
tbx.Width = 50;
tbx.TextWrapping = TextWrapping.Wrap;
tbx.Margin = new Thickness(5, 10, 0, 0);
c.Children.Clear();
c.Children.Add(tbx);
InkCanvas.SetLeft(tbx, x);
InkCanvas.SetTop(tbx, y);
Well first of all you're not setting the TextBlock's Text field, so you won't see anything. And secondly you're calling SetLeft twice, so it won't be positioned correctly.
I am using following code for animation(right to left marquee):-
private void RightToLeftMarquee(TextBlock tb)
{
doubleAnimation = new DoubleAnimation();
doubleAnimation.From = -tb.Width;
doubleAnimation.To = TickerCanvas.Width;
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(100));
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(Canvas.Right)"));
sb.Children.Add(doubleAnimation);
sb.Begin(tb,true);
}
This code moves the textblock fine when width of textblock is less then the canvas but when the textblock width is greater then canvas width the marquee flickers.
The flickering you're seeing is probably due to ClearType sub-pixel positioning. You have a few options, but the animation will not look as smooth after applying them:
TextOptions.TextFormattingMode="Display"
This turns on the newer WPF 4.0 ClearType algorithm, which will make the text look crisper.
UseLayoutRounding="True"
Ensures that WPF aligns everything to the device pixels (no more blurry borders, images, etc.)
I always use both of these settings at the root elements of any app (i.e. all Windows) because it generally improves the way the application looks.
I'm trying to dynamically place content with one of the items being an image. I can get the image to load to the grid, but while the labels all align nicely, the image appears in the middle of the screen. I don't believe I'm doing this right, I'm wondering if I should be using a list? But, I'm open for suggestions. Currently I'm writing the labels with enough left margin space to separate them, but when the image renders it appears in the middle of the window.
...
Uri imguri = new Uri("/MyName;Component/Resources/myimage.png", UriKind.RelativeOrAbsolute);
BitmapImage ni = new BitmapImage(imguri);
gridEvents.Children.Add(new Label { Content = "Travel:", Margin = new Thickness(300, 0, 0, 0), FontSize = 18 });
gridEvents.Children.Add(new Image() { Source = ni, Height = 15, Width = 15 });
...
I believe the problem is similar to how I'm forcing the labels position with a hard coded margin. I'm new to wpf, so if you know of a better way - I'm ready to learn.
Image appears in the middle of the grid because you didn't set any positioning properties, like margin or align. Position in the center of the grid is just default behavior.
Actually you'd better use ItemsControl or ListView. To better understand ItemsControl read this series of articles.
I create TextBox on the Canvas like this:
TextBlock t = new TextBlock();
t.Foreground = new SolidColorBrush(...);
t.FontSize = 10;
t.HorizontalAlignment = HorizontalAlignment.Left;
t.VerticalAlignment = VerticalAlignment.Top;
t.Text = ...;
Canvas.SetLeft(t, "f(width)");
Canvas.SetTop(t, ...);
canvas.Children.Add(t);
I want to know width of this TextBlock, because Left coordinate depends on this.
Can I do it? ActualWidth is 0.
Thanks.
Before you add it, call Measure on it, then use the DesiredSize.
Edit: This is OK to do because Canvas does not affect the size of the element once placed. If you added it to, say, a Grid with a fixed-size row, this wouldn't give you the real Height once added since the adding to the Grid would change it.
As Mario Vernari points out, if you have real complex positioning needs it's pretty easy to override ArrangeOverride (and sometimes MeasureOverride) and make a custom panel. Canvas is actually written this way, as is StackPanel, etc. They are all just specific-measuring and arranging panels, and you can make your own, too.
I am working on an application that is using Drag and Drop functionality. When I drag certain items over other items, I would like to show if they are towards the top, or the bottom of the item by setting the border property of the item they are over dynamically(as oppose to in the xaml).
I have looked into this, and used examples, but none of them are working. Here is the code I have that is called when a drag operation is performed over the Grid Item.
private void Grid_DragEnter(object sender, DragEventArgs e)
{
Grid grid = (Grid)sender;
grid.Background = Brushes.Cornsilk;
Border border = new Border();
border.BorderBrush = Brushes.Black;
border.BorderThickness = new Thickness(5, 10, 15, 20);
border.Background = Brushes.Black;
border.Padding = new Thickness(10);
border.Child = grid;
}
The code above is only test code so that I can see the border is showing. Once I can get this, then I will set the top or bottom border at separate times, depending on if they are above or below the center of the grid item.
You're setting the border's child, but the border itself needs to be added to some container in order for it to be visible.
That being said, you might want to look into Adorners. They are designed for exactly this scenario, and don't require changing the visual hierarchy of your UI at runtime.