Try it
here.
See a picture below: :)
I ran into one odd issue when using Silverlight 2.0 Beta 2….
void Page_Loaded(object sender, RoutedEventArgs e)
{
// if you don't invoke this asynchronously, you can't add at load time
// (seems to be a silverlight 2.0 issue)
Dispatcher.BeginInvoke(delegate()
{
consoleCanvas.AnimateNewChild(
string.Format("Welcome!\nThe time right now is {0}.",
DateTime.Now.ToLocalTime()));
consoleCanvas.AnimateNewChild("\n\nThanks for stopping by WiredPrairie.us. "
+ "This code may be used for only for good, not evil.");
});
}
The code above for example — if the ConsoleCanvas control (the simple base
control for the console output-like functionality) performs any UpdateLayout calls
within the context of the Load event, the entire Silverlight control fails to load,
silently. The only work-around I could discover was to delay what I wanted to occur
by using the asynchronous invoke method on the Dispatcher object.
The easiest way to force a UIElement to measure itself is to use a little trick:
_holder.Width = this.ActualWidth;
child.Width = this.ActualWidth;
_holder.Children.Add(child);
_holder.UpdateLayout();
child.Width = child.DesiredSize.Width;
child.Height = child.DesiredSize.Height;
The console control maintains a visible (yet opacity is set to 0.0) StackPanel. Each
time a new line of output is added via the AnimateNewChild method, it’s placed
in the StackPanel. The StackPanel (_holder) is resized to fit the current width of
the entire ConsoleCavnas control. Next, the UpdateLayout method of the StackPanel is
called — which forces an immediate measure of all of the children (and thus
forces any children of the TextPanel to potentially re-layout). The width and height
are grabbed and permanently stored as the new size for the child.
Instead of using Storyboards and various animations, I found it more convenient to
simply use a DispatchTimer and do the animations manually.
List<FrameworkElement> remove = new List<FrameworkElement>();
for(int childIndex = 0; childIndex < this.Children.Count; childIndex++)
{
FrameworkElement child = this.Children[childIndex] as FrameworkElement;
if (!child.Equals(_holder))
{
child.Arrange(new Rect(0, Canvas.GetTop(child), 0, 0));
double top = Canvas.GetTop(child);
top -= 2.0;
Canvas.SetTop(child, top);
if (top + child.Height < 0.0)
{
remove.Add(child);
}
}
}
// remove them all
remove.ForEach(fe => this.Children.Remove(fe as UIElement));
If an element is no longer visible on the screen, it is removed using a Lambda
expression and the ForEach method on the List object instance named
remove (after the repositioning loop has completed).
Download source, etc.
here.