PlexityHide

Home 

Products 

Downloads 

Our Shop 

Support 

Contact 


Saturday, October 2, 2010

How to create alternate rows in Gantt for Silverlight and WPF

image
   1: <local:BackgroundConverter x:Key="myConverter"/>
 
   1: <l:GanttRow Grid.Row="1"  ItemTemplate="{StaticResource TimeItemPres_blue_schedule}"  
   2:    ItemsSource="{Binding Path=Items}" 
   3:    Background="{Binding  Converter={StaticResource myConverter}}" ></l:GanttRow>

The Background is bound to “DataContext” that will be whatever the GanttRow represents – I add a Converter that can take my – in this case – DemoDataRow and turn it into a Brush:

   1: public sealed class BackgroundConverter : IValueConverter
   2: {
   3:  
   4:     #region IValueConverter Members
   5:  
   6:     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   7:     {
   8:         if (value is DemoDataRow)
   9:         {
  10:             LinearGradientBrush b=new LinearGradientBrush();
  11:             GradientStop gs1 = new GradientStop();
  12:             GradientStop gs2 = new GradientStop();
  13:             gs1.Color = Colors.Orange;
  14:             gs1.Offset = 0;
  15:             gs2.Color = Colors.Magenta;
  16:             gs2.Offset = 1;
  17:             
  18:             if ((value as DemoDataRow).Index%2==0)
  19:             {
  20:                 b.GradientStops.Add(gs1);
  21:                 b.GradientStops.Add(gs2);
  22:              
  23:                 return b;
  24:             }
  25:             else
  26:             {
  27:                 gs1.Offset=1;
  28:                 gs2.Offset=0;
  29:                 b.GradientStops.Add(gs1);
  30:                 b.GradientStops.Add(gs2);
  31:                 return b;
  32:             }
  33:                 
  34:         }
  35:         return new SolidColorBrush(Colors.Red);
  36:         
  37:     
  38:     }
  39:  
  40:     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  41:     {
  42:         throw new NotImplementedException();
  43:     }
  44:  
  45:     #endregion
  46: }

Gantt for Silverlight and WPF

The GTP.NET.SL enables you to easily add time dependant stuff in the background or foreground of your TimeItemArea.

As our Gantt is flexible enough to integrate with any grid or treeview we need a generic way to help you do draw things in the area that belongs to the Grid or Tree but resides under the DateScaler:

Silverligth and WPF Gantt chart

We did this by exposing two events:

   1: /// <summary>
   2: /// Overridable for advanced use, public for technical reasons
   3: /// </summary>
   4: public virtual void UpdateBackAndForegroundContent()
   5: {
   6:     if (VerticalDayStripesUse != VerticalDayStripesUse.none)
   7:         DrawVerticalDayStripes();
   8:     if (TodayLineUse)
   9:         TodayLine();
  10:     if (OnDrawBackground != null)
  11:         OnDrawBackground(this, new GanttUserDrawArgs() { Canvas = _userBackgroundCanvas });
  12:     if (OnDrawForeground != null)
  13:         OnDrawForeground(this, new GanttUserDrawArgs() { Canvas = _userForegroundCanvas });
  14: }

You can from the internal code above see that the exact same way that we implement the TodayLine and the VerticalDayStripes we also call the OnDrawBackground and OnDrawForeground events.

This is how we implement the today line:

   1: Line l = new Line();
   2: _todayLineCanvas.Children.Clear();
   3: _todayLineCanvas.Children.Add(l);
   4: l.Fill = _todayLineStroke;
   5: l.Stroke = _todayLineStroke;
   6: l.StrokeThickness = TodayLineStrokeThickness;
   7: double pos = DateScaler.TimeToPixel(DateTime.Now);
   8: if (ScheduleMode)
   9: {
  10:     l.Y1 = pos;
  11:     l.Y2 = pos;
  12:     l.X1 = 0;
  13:     l.X2 = ActualWidth;
  14: }
  15: else
  16: {
  17:     l.X1 = pos;
  18:     l.X2 = pos;
  19:     l.Y1 = 0;
  20:     l.Y2 = ActualHeight;
  21: }

Notice that the call to DateScaler.TimeToPixel easily helps anyone to convert between time and position – this call – that is very effective and the heart of our Gantt implementation – ensures that the TodayLine is positioned on the exact spot where the user perceives NOW to be.

Also notice that we check the ScheduleMode setting to decide in what direction to draw the todayline.

This is the sample implementation of the OnDrawForeground event:

   1: void gantt1_OnDrawForeground(object sender, GanttUserDrawArgs e)
   2: {
   3:     e.Canvas.Children.Clear();
   4:     Canvas c = new Canvas();
   5:     e.Canvas.Children.Add(c);
   6:     Canvas.SetLeft(c, gantt10.DateScaler.TimeToPixel(DateTime.Now));
   7:     Canvas.SetTop(c, 440);
   8:  
   9:     Ellipse ellipse = new Ellipse();
  10:     c.Children.Add(ellipse);
  11:     ellipse.Stroke = new SolidColorBrush(Colors.Blue);
  12:     ellipse.StrokeThickness = 3;
  13:     ellipse.Width = 100;
  14:     ellipse.Height = 20;
  15:  
  16:     TextBlock text = new TextBlock();
  17:     c.Children.Add(text);
  18:     text.Text = "Easily add your own time dependant stuff\n in the foreground";
  19:  
  20: }

The difference between Foreground and Background is achieved with Canvas.ZIndex settings and enables you to get effects like this:

Gantt Time items ZIndex

Where the the blue ellipse goes above the TimeItem and the green ellipse goes below the TimeItem.


Size override and User draw of Gantt Time Items

One feature that may come in handy from time to time is the size override behavior that you can get by implement the event OnTimeItem_UserDrawBounds in the GTP.NET.

It is most commonly used with UserDraw – since most of the standard time items have a standard square form that does not get any real benefit from overriding the perceived size – since the standard square that is defined by Start and Stop in one axis and GanttRow Height (with consideration to Sub columns) in the other direction.

   1: gantt1.OnTimeItem_UserDraw += new TimeItemEvent(gantt1_OnTimeItem_UserDraw);
   2: gantt1.OnTimeItem_UserDrawBounds += new TimeItemEvent(gantt1_OnTimeItem_UserDrawBounds);

And the implementations:

   1: /// <summary>
   2: /// This event can help you override how a time item is perceived in the TimeItemFromXY (the active clickable area )
   3: /// </summary>
   4: void gantt1_OnTimeItem_UserDrawBounds(Gantt aGantt, TimeItemEventArgs e)
   5: {
   6:     GraphicsPath gp = new GraphicsPath();
   7:     gp.AddEllipse(e.Rect);
   8:     e.BoundingRegion = new Region(gp);
   9: }
   1: /// <summary>
   2: /// ...and this event helps you draw something in that area. 
   3: /// Note that the two areas can differ, its up to you, but it will a bit strange...
   4: /// </summary>
   5: void gantt1_OnTimeItem_UserDraw(Gantt aGantt, TimeItemEventArgs e)
   6: {
   7:     GraphicsPath gp = new GraphicsPath();
   8:     gp.AddEllipse(e.Rect);
   9:     e.G.FillPath(new SolidBrush(Color.White), gp);
  10:     e.G.DrawPath(new Pen(Color.Blue), gp);
  11:     string s = "Notice how\r\nclicks in the corners\r\nare ignored";
  12:     SizeF mess=e.G.MeasureString(s, this.gantt1.Font);
  13:     Point pointToPlaceText = new Point((int)(e.Rect.Left + Math.Round((double)e.Rect.Width / 2) - Math.Round(mess.Width / 2)), 
  14:                                        (int)(e.Rect.Top + Math.Round((double)e.Rect.Height / 2) - Math.Round(mess.Height / 2)));
  15:     e.G.DrawString(s, this.gantt1.Font, new SolidBrush(Color.Red), pointToPlaceText);
  16:  
  17: }

This will render this way:

image

Now the cool thing is that when you click in the white area the TimeItem will be selected/moved/resized etc, but when you click in the corners, where the Time Item Square should have been drawn if this was a standard time item, this is just like clicking on the GanttRow alone.

I also added some code in the userdraw to center a text – you need to measure the text then consider the available space – then place the text.


This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]

Support

Support intro

Knowledgebase

FAQ phGantTimePackage

FAQ GTP.NET

FAQ general

History