Showing posts with label panels. Show all posts
Showing posts with label panels. Show all posts

Wednesday, October 1, 2008

Silverlight 3D...

Karim sent me this link to this guy that did this '3d' silverlight solution. here is only a video but its pretty slick...

http://www.innoveware.com/

speacking of 3d silverlight there are also a couple of related projects on codeplex. Faisal Khan a friend sent me a mini me version that does a puesdo 3d layout based on x, y and z. I'm playin with a wrapper class that will allow more complicated 3d effects but his View3D panel works well and we'll drop it into the hackingsilverlight library for our own little mini me 3d engine for Silverlight that not only for the book but we will use it for the project george that I'll talk about at some later point after the book is finished, completely.

Thursday, June 12, 2008

Another Radial Panel

A few weeks back I did a post(s) on panels using Robby's animating panel base including a Radial panel. Jobi a friend of mine did a post on his radial panel he wrote so I thought I would share that with everyone. Jobi's post gets more into explaining the math where I just showed so I thought it would be interesting if your into Silverlight Panels.

http://jobijoy.blogspot.com/2008/04/simple-radial-panel-for-wpf-and.html

Monday, June 2, 2008

More on Panels

I was playing around and made a few more panels. Lets start with a random panel. This panel builds on what we learned about the animating panel base and allows us to layout everything out randomly on screen. This is especially interesting for doing graphics randomly placed around the UI and is more for effect then what you would use in a real business application. A logical use for this might be a portfolio or other like function or just for fun. If we start with the Animating Wrap Panel we need to redo the arrange method starting with replacing the variables at the top with the following:

double Width = 0;
double Height = 0;
Random ThisNum = new Random();

Like the Wrap Panel we still need to run through all the panel children. Our loop should have its internal code replaced with the following:

Width = element.DesiredSize.Width;
Height = element.DesiredSize.Height;

double NewX = double.Parse(ThisNum.Next(
int.Parse(this.Width.ToString())).ToString());
double NewY = double.Parse(ThisNum.Next(
int.Parse(this.Height.ToString())).ToString());

if (MyFirstTime)
{
SetElementLocation(element, new
Rect(NewX, 1500, Width, Height), false);
}
else
{
SetElementLocation(element, new Rect(NewX, NewY, Width, Height));
}

In this case we see that we are creating new Random X,Y values so that our layout is unique every single time. We then like the other panels call the SetElementLocation in like manner. Other wise this panel is much the same as the others.

This panel allows us more interesting possibilities now we will address one more common panel that you might want to use and animate

Animating Radial Panel

So starting with the radial panel we need to do a little more math then the others. Building this panel we add 3 variables to the class itself like this listing:
protected void GetListOfPoints(int pointCount, double Width)
{
double x = Width / 2;

Radius = x;

double y = 0;

double theta = (2 * Math.PI) / pointCount;

for (int i = 0; i < pointCount; i++)
{
if (i > 0)
{
x = (Radius * (Math.Cos((i) * theta)));
y = (Radius * (Math.Sin((i) * theta)));
}

XList.Add(x + Radius);
YList.Add(y + Radius);
}
}

With out getting into great detail this method basically gives the points we need to layout our children on. Now we can alter the arrange override and we are good. In the arrange we start with variables like this:

double Width = 0;
double Height = 0;

GetListOfPoints(this.Children.Count, this.Width );
int Count = 0;

Width = element.DesiredSize.Width;
Height = element.DesiredSize.Height;

if (MyFirstTime)
{
SetElementLocation(element, new
Rect(XList[Count], 1500, Width, Height), false);
}
else
{
SetElementLocation(element, new
Rect(XList[Count], YList[Count], Width, Height));
}

Count++;The rest of the method is the same once we drop out of the loop like the wrap panel. In this case the biggest difference in the loop is having to track our position so we can get the right X/Y values for the layout.

By default like the other panels we did using the animating panel base we start be animating the children from off the screen below. All of these panels are included in the panel factory download off of HackingSilverlight.net. With that you can do all the hot panels you like.

http://www.hackingsilverlight.net/samples/PanelFactory.zip

Friday, May 30, 2008

Animating Panels and the Animating Panel Base

One of the cool things that enhances UX (User Experience) with an application is to make it pleasing to look at and use. Many times people do searches and expect recordsets. Frequently these recordsets are placed in data grids of some kind. Though Silverlight does in fact support a data grid control we might also consider using a custom panel that lays out elements visually and to make it more excited we can animate children into position depending on the current state. Writing this so it animates nicely programmatically can be a lot of work not to mention a huge pain and not very reusable. But alas you are more than welcome to do all this extra work just to discover you should have used a dispatch timer and not use Silverlight animations altogether and then waste more time figuring out how to make that work. OR you can use the animating panel base that has the dispatch timer infrastructure written tested and built in. Robi wrote this control and gave it to Mike H were they both demo’d it at MIX08 in their respective presentations. Lets re do our WrapPanel to use animating Panel Base and see how cool we can make it.


If we start with the lame wrap panel from earlier we first need to change its base class so the first line should now look like this (you can download the source from the panel factory project on HackingSilverlight.net):


public class WrapPanel : AnimatingPanelBase


Now we have the dispatch timer magic infrastructure. Next we need to add a property and method to our class like this listing that gives us a completed event for animations.

private bool MyFirstTime = true;
void WrapPanel_AnimationCompleted(object sender, RoutedEventArgs e)
{
MyFirstTime = true;
}


Next we need to actually wire this event up in the object constructor. This way the event handler gets called when the first animation is complete. The code we add to a class constructor is:


AnimationCompleted += new RoutedEventHandler(WrapPanel_AnimationCompleted);


Now once complete we are done with ‘additional’ members but we still need to change the ArrangeOverride method. First where we were calling element.arrange we need to replace that code with this block:

if (MyFirstTime)
{
SetElementLocation(element,
new Rect(Left, 1500, Width, Height), false);
}
else
{
SetElementLocation(element, new Rect(Left, Top, Width, Height));
}

In this case if we are starting from the first animation we are animating from a location way off and below the screen. This would almost complete it but we need to another block to deal with the initial run of the arrange. The following listing goes right before the return at the end of the method:

if (MyFirstTime && this.Children.Count > 0)
{
MyFirstTime = false;
this.InvalidateMeasure();
}

On first run we then start at some weird location so we need to make 2 passes to be able to properly lay out elements and then get them to animate to the correct position. In this case on first time where there is more then 0 returned we set the value to false and invalidate measure. This has the effect of allowing us to animate from a starting position.

Now that we have written an animating wrap panel we can use what we have learned to create other kinds of panels that animate. Lets start with the Stack panel. Silverlight already has one but with the animating panel base and our wrap panel we can change a few things and be good to go with some hot animation. In the case of a vertical stacking panel the code change is in the Arrange where we only need one variable:

Double top = 0;

Then when we loop through our children all we need to do is this:

if (_firstArrange)
{
SetElementLocation(e, new Rect(0, 1500,
this.DesiredSize.Width, e.DesiredSize.Height), false);
}
else
{
SetElementLocation(e, new Rect(0, top,
this.DesiredSize.Width, e.DesiredSize.Height));
}
top += e.DesiredSize.Height;

so on first arrange we set everything to some location off screen and then set to the correct location and we set the next top to the current height so things are laid out horizontally. Otherwise the panel is the same as the wrap panel.

you can download the project I have for making this panels at:

http://www.hackingsilverlight.net/samples/PanelFactory.zip

and this is on Beta 1. I'll update this download as I go including new panels and more.

Creating and Using Panels

If your familiar with WPF (Windows Presentation Foundation) from the programming point of view at all you must know what a panel. A panel in its simplest form is a container like a canvas that manages the layout of the children it contains. In Silverlight, we have a panel base class and a stack panel. The Stack Panel lay’s out its children either horizontally or vertically and can be seen in chapter 3. In WPF one of the more popular ‘Panels’ is a Wrap panel. Currently Silverlight doesn’t have one but using the base class Panel we can create one. This will give us a chance to look at the anatomy of Custom panel and how they work. Lets start by creating WrapPanel class as in this example:

public class LamePanel : Panel { }

From here we need to start by overriding two base members on the Panel class ‘Measure’ and ‘Arrange’. Measure is called so that the size of everything can be calculated before things are laid out and then Arrange is called to actually do the layout. Together the methods should look like this:

protected override Size MeasureOverride(Size availableSize) { }

protected override Size ArrangeOverride(Size FinalSize) { }

These won’t compile yet as we are not returning values so lets work out what each one does to create a Wrap Panel. Lets start with the first method that gets called namely ‘MeasureOverride’. Of the two this is the simplest one. Basically we need to go through each child in the panel and ‘Measure’ it so that we know the size for sure. In the following list we can see is loop through the children calling ‘Measure’ on each child to get it as large as possible with in the size allotted it.


for (int x = 0; x < this.Children.Count; x++)
{
this.Children[x].Measure(
new Size( double.PositiveInfinity, double.PositiveInfinity));
}

return new Size();

We need to return a size so we return a new size at the end. Now once we make sure we call Measure on all the children we can then write our ArrangeOverride method. In Arrange we want to layout all the children of our Panel and in this case we want to lay them out horizontally to the end of the line or width and then wrap the children down to the next line and so forth. The first step is to declare the variables we will use like this listing:

double Top = 0;
double Left = 0;
double Width = 0;
double Height = 0;
double NextTop = 0;

All of these values are used to track the current values used to layout children elements. Next we need to run thorugh each child and do the lay out. Start that process by adding a loop like this example:

foreach (UIElement element in this.Children) { }

From here we need to start be checking each childs desired height and width. We can do that easily like this and set the Width and height values we will need:

Width = element.DesiredSize.Width;
Height = element.DesiredSize.Height;

This gives us a point to start with as we run through each child. Next we need to see if we are still on the same line and if not we need to change a few of the of the base values we are using to move us to the next line using this listing:

if ((Left + Width) > FinalSize.Width)
{
Left = 0;
Top = NextTop;
NextTop = 0;
}


At this point we have our basic values we need to layout the current child so we need to actually do that like this:

element.Arrange(new Rect(Left, Top, Width, Height));

Using the values we calculated we create a new Rectangle and pass this into the element Arrange member. Before being entirely complete with this method we do need to do a little bit more calculation. We need to get the next Left value and the next top value like this listing:

Left = Left + Width;
NextTop = Math.Max(NextTop, Top + Height);

Now we just need to return the Size value that we passed in and our panel is complete. Run it and you can see it wrap and stack the panel children that you add in xaml.

I could show you a few more panels but the key take away is how easy it is to creating layout panels like this.