Posted by: Zeeshan Amjad | February 19, 2010

Use Radial Panel in List Box for Nested Data


We have already seen an example of using Radial Panel use as a item panel template here. Now we are going to apply the radial panel to not only item panel template but also in data template. For this example we are going to apply nested data structure because we are going to make nested list. Because every item of list box itself is a list box but we are  using item radial panel as a item panel template.

Here is our class to store nested data structure.

  1: public class ColorsList
  2: {
  3:     public ColorsList()
  4:     {
  5:         Colors = new List<string>();
  6:     }
  7: 
  8:     public void AddColor(String color)
  9:     {
 10:         Colors.Add(color);
 11:     }
 12: 
 13:     public List<String> Colors
 14:     { get; set; }
 15: }
 16: 

Here is our complete XAML file that define nested list box and use radial panel.

  1: <Window x:Class="WpfRadialList.Window1"
  2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4:     xmlns:local="clr-namespace:WpfRadialList"
  5:     Title="Radial Panel List" Height="400" Width="400">
  6:     <ListBox Margin="5" ItemsSource="{Binding}" HorizontalContentAlignment="Stretch">
  7:         <ListBox.ItemTemplate>
  8:             <DataTemplate>
  9:                 <ListBox ItemsSource="{Binding Colors}">
 10:                     <ListBox.ItemsPanel>
 11:                         <ItemsPanelTemplate>
 12:                             <local:RadialPanel Margin="15"/>
 13:                         </ItemsPanelTemplate>
 14:                     </ListBox.ItemsPanel>
 15:                     <ListBox.ItemTemplate>
 16:                         <DataTemplate>
 17:                             <Ellipse Width="20" Height="10" Fill="{Binding}"/>
 18:                         </DataTemplate>
 19:                     </ListBox.ItemTemplate>
 20:                 </ListBox>
 21:             </DataTemplate>
 22:         </ListBox.ItemTemplate>
 23:     </ListBox>
 24: </Window>
 25: 

Here is our complete C# code of the program. Again we are using the Radial Panel class from Microsoft Sample.

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: using System.Windows;
  6: using System.Windows.Controls;
  7: using System.Windows.Data;
  8: using System.Windows.Documents;
  9: using System.Windows.Input;
 10: using System.Windows.Media;
 11: using System.Windows.Media.Imaging;
 12: using System.Windows.Navigation;
 13: using System.Windows.Shapes;
 14: 
 15: namespace WpfRadialList
 16: {
 17:     /// <summary>
 18:     /// Interaction logic for Window1.xaml
 19:     /// </summary>
 20:     public partial class Window1 : Window
 21:     {
 22:         public Window1()
 23:         {
 24:             InitializeComponent();
 25: 
 26:             List<ColorsList> colorLists = new List<ColorsList>();
 27: 
 28:             ColorsList list1 = new ColorsList();
 29:             list1.AddColor("Blue");
 30:             list1.AddColor("Green");
 31:             list1.AddColor("Red");
 32:             list1.AddColor("Yellow");
 33:             list1.AddColor("Black");
 34:             list1.AddColor("Violet");           
 35: 
 36:             colorLists.Add(list1);
 37: 
 38:             ColorsList list2 = new ColorsList();
 39:             list2.AddColor("DarkOrange");
 40:             list2.AddColor("Wheat");
 41:             list2.AddColor("DarkKhaki");
 42:             
 43:             colorLists.Add(list2);
 44: 
 45:             ColorsList list3 = new ColorsList();
 46:             list3.AddColor("DarkMagenta");
 47:             list3.AddColor("DeepPink");
 48:             list3.AddColor("Purple");
 49:             list3.AddColor("DarkOliveGreen");
 50:             list3.AddColor("Brown");
 51: 
 52:             colorLists.Add(list3);
 53: 
 54:             DataContext = colorLists;
 55:         }
 56:     }
 57: 
 58:     public class ColorsList
 59:     {
 60:         public ColorsList()
 61:         {
 62:             Colors = new List<string>();
 63:         }
 64: 
 65:         public void AddColor(String color)
 66:         {
 67:             Colors.Add(color);
 68:         }
 69: 
 70:         public List<String> Colors
 71:         { get; set; }
 72:     }
 73: 
 74:     // Class from Microsoft Sample
 75:     public class RadialPanel : Panel
 76:     {
 77:         // This Panel lays its children out in a circle
 78:         // keeping the angular distance from each child
 79:         // equal; MeasureOverride is called before ArrangeOverride.
 80: 
 81:         double _maxChildHeight, _perimeter, _radius, _adjustFactor;
 82: 
 83:         protected override Size MeasureOverride(Size availableSize)
 84:         {
 85:             _perimeter = 0;
 86:             _maxChildHeight = 0;
 87: 
 88:             // Find the tallest child and determine the perimeter
 89:             // based on the width of all of the children after
 90:             // measuring all of the them and letting them size
 91:             // to content by passing Double.PositiveInfinity as
 92:             // the available size.
 93: 
 94:             foreach (UIElement uie in Children)
 95:             {
 96:                 uie.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
 97:                 _perimeter += uie.DesiredSize.Width;
 98:                 _maxChildHeight = Math.Max(_maxChildHeight, uie.DesiredSize.Height);
 99:             }
100: 
101:             // If the marginal angle is not 0, 90 or 180
102:             // then the adjustFactor is needed.
103: 
104:             if (Children.Count > 2 && Children.Count != 4)
105:                 _adjustFactor = 10;
106: 
107:             // Determine the radius of the circle layout and determine
108:             // the RadialPanel's DesiredSize.
109: 
110:             _radius = _perimeter / (2 * Math.PI) + _adjustFactor;
111:             double _squareSize = 2 * (_radius + _maxChildHeight);
112:             return new Size(_squareSize, _squareSize);
113:         }
114: 
115:         // Perform arranging of children based on 
116:         // the final size.
117: 
118:         protected override Size ArrangeOverride(Size finalSize)
119:         {
120:             // Necessary variables.
121:             double _currentOriginX = 0,
122:                     _currentOriginY = 0,
123:                     _currentAngle = 0,
124:                     _centerX = 0,
125:                     _centerY = 0,
126:                     _marginalAngle = 0;
127: 
128:             // During measure, an adjustFactor was added to the radius
129:             // to account for rotated children that might fall outside
130:             // of the desired size.  Now, during arrange, that extra
131:             // space isn't needed
132: 
133:             _radius -= _adjustFactor;
134: 
135:             // Find center of the circle based on arrange size.
136:             // DesiredSize is not used because the Panel
137:             // is potentially being arranged across a larger
138:             // area from the default alignment values.
139: 
140:             _centerX = finalSize.Width / 2;
141:             _centerY = finalSize.Height / 2;
142: 
143:             // Determine the marginal angle, the angle between
144:             // each child on the circle.
145: 
146:             if (Children.Count != 0)
147:                 _marginalAngle = 360 / Children.Count;
148: 
149:             foreach (UIElement uie in Children)
150:             {
151:                 // Find origin from which to arrange 
152:                 // each child of the RadialPanel (its top
153:                 // left corner.)
154: 
155:                 _currentOriginX = _centerX - uie.DesiredSize.Width / 2;
156:                 _currentOriginY = _centerY - _radius - uie.DesiredSize.Height;
157: 
158:                 // Apply a rotation on each child around the center of the
159:                 // RadialPanel.
160: 
161:                 uie.RenderTransform = new RotateTransform(_currentAngle);
162:                 uie.Arrange(new Rect(new Point(_currentOriginX, _currentOriginY), new Size(uie.DesiredSize.Width, uie.DesiredSize.Height)));
163: 
164:                 // Increment the _currentAngle by the _marginalAngle
165:                 // to advance the next child to the appropriate position.
166: 
167:                 _currentAngle += _marginalAngle;
168:             }
169: 
170:             // In this case, the Panel is sizing to the space
171:             // given, so, return the finalSize which will be used
172:             // to set the ActualHeight & ActualWidth and for rendering.
173: 
174:             return finalSize;
175:         }
176:     }
177: }
178: 

The output of this program is quite interesting. Here is the output of this program.

RadialPanelListBoxOutput_02

Advertisements

Responses

  1. […] creating horizontal list box here. We also saw couple of examples of using Radial Panel here and here.  Now we are going to use the Canvas as a panel. Here is simple piece of XAML code to define […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: