The official Fatica Labs Blog! RSS 2.0
# Monday, 16 May 2011

By extending the generic helper class proposed for a generic CoRoutine in Caliburn Micro it is easy to create an helper that we can use this way:

public IEnumerable<IResult> SourceChange()
       {
           yield return new CoMethod(() => { PriceDS = CreateDataSource(SelectedSource); });
           NotifyOfPropertyChange(() => this.PriceDS);
           yield return new CoMethod(() => { VolumeDS = CreateDataSource(SelectedSource); });
           NotifyOfPropertyChange(() => this.VolumeDS);
           yield return new CoMethod(() => { Mavg5DS = CalculateMAverage(SelectedSource,5); });
           NotifyOfPropertyChange(() => this.Mavg5DS);
           yield return new CoMethod(() => { Mavg10DS = CalculateMAverage(SelectedSource, 10); });
           NotifyOfPropertyChange(() => this.Mavg10DS);
       }

In a single line we invoke asynchronously a method without having to crate a class implementing IResult. By the way this code is the one that creates the sources for the charts in this blog post.

The helper class is pretty easy:

public class CoMethod:AbstractBackgroundAction
    {
        Action toRun;
        public CoMethod(Action toRun)
        {
            this.toRun = toRun;
        }

        protected override void OnExecute(Caliburn.Micro.ActionExecutionContext context)
        {
            toRun();
        }
    }
It just invoke the action in the BackgroundWorker.
Monday, 16 May 2011 20:24:07 (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
Caliburn | WPF

# Sunday, 15 May 2011

I was looking for a good open source charting library and I noticed that is a little difficult to find something really useful and easy to use. I had a look at the WPF Toolkit charting library, a little old for sure, but look promising at a first glance. Unfortunately it is not so easy to use, not brilliant in term of speed and with some discutable behavior,  as for example the absence of a way to remove the chart animation, or removing the fancy bullet in the line chart. By digging a little deeper I found the WPF Dynamic Data Display

imageEven if it seems not recently updated in term of source code, it has a professional level functionality, easy to customize and use, and with some effort MVVM compatible. Make sure to download the unreleased latest source changeset because it is dramatically different from the released one. Here below we show hoe to use this charting library for a very common task, creating multiple chart with the same X Axis. The goal is to have the classical view of a stock chart: Candlestick+Volume some indicators. As a surprise we can see that the latest changeset does not have out of the box any candlestick chart, neither is possible to display a proper bar chart ( there is an OldBarGraph in the code, but it does not seems to work anymore ). Well this is not generally a problem, since a good charting library should be extensible in some way, so we try to create our chart by extending the existing ones. Before to go on let’s have a look on the sample application:

image

The application, even if simple, uses Caliburn Micro, have a look here if you need some notes about that. Data are embedded resources obtained fro YAHOO! Finance for the sole purpose of writing this example application. So lets start with the candles. We note in the source code bounch that exists a MarkerPointsGraph, a graph that display a Marker at each “Y” coordinate, so couldn’t be the candlestick a marker ? Yes, by just deriving from PointMarker. Let see how “difficult” this can be:

 

public class CandleStickPointMarker:ShapePointMarker,ITransformAware
   {
       
       
       public override void Render(System.Windows.Media.DrawingContext dc, Point screenPoint)
       {
           Point screenOpen = GetScreenPoint(Open,screenPoint.X);
           Point screenHigh = GetScreenPoint(High,screenPoint.X);
           Point screenLow = GetScreenPoint(Low, screenPoint.X);
           //screenPoint is the CLOSE by gentleman agreement.
           var close = screenPoint.ScreenToData(Transform).Y;
           Pen strokePen;
           if (Open >= close) // black
           {
               strokePen = new Pen(BlackCandleStroke, CandelstickStrokeWidth);
               var h = -screenOpen.Y + screenPoint.Y;
               dc.DrawRectangle(BlackCandleFill,strokePen 
                   , new Rect(screenPoint.X - CandelstickWidth / 2, screenOpen.Y, CandelstickWidth, h)
                   );
               dc.DrawLine(strokePen, screenLow, screenPoint);
               dc.DrawLine(strokePen, screenHigh, screenOpen);
           }
           else // white
           {
               strokePen=new Pen(WhiteCandleStroke, CandelstickStrokeWidth);
               var h = screenOpen.Y - screenPoint.Y;
               dc.DrawRectangle(WhiteCandleFill, strokePen
                   , new Rect(screenPoint.X - CandelstickWidth / 2, screenPoint.Y, CandelstickWidth, h)
                   );
               dc.DrawLine(strokePen, screenLow, screenOpen);
               dc.DrawLine(strokePen, screenHigh, screenPoint);
           }
       }

       private Point GetScreenPoint(double Open,double screenX)
       {
           Point screen = new Point(0, Open);
           return new Point(screenX,screen.DataToScreen(Transform).Y);
       }
   }

Really easy, we just need a trick: since the marker currently works with a pre-transformed coordinate for the single point the marker usually represent, and we need instead other three value ( Open/Min/Max ) we need to transform these value recovered directly from the data source. This is the reason I had to create the interface ITransformAware , so we can pass the transform to the PointMarker, let see how:

using (IPointEnumerator enumerator = DataSource.GetEnumerator(GetContext()))
            {
                Point point = new Point();
                while (enumerator.MoveNext())
                {
                    enumerator.GetCurrent(ref point);
                    enumerator.ApplyMappings(Marker);

                    //Point screenPoint = point.Transform(state.Visible, state.Output);
                    Point screenPoint = point.DataToScreen(transform);

                    bounds = DataRect.Union(bounds, point);
                    var ta = Marker as ITransformAware;
                    if( null != ta )
                        ta.Transform = transform;
                    Marker.Render(dc, screenPoint);
                }
            }

This is the only trick. DataSOurce side what we have to do is to add the mapping for the missing coordinates:

 

               value.SetYMapping(k => double.Parse(k[4], CultureInfo.InvariantCulture));
               value.AddMapping(CandleStickPointMarker.OpenProperty, k => double.Parse(k[1], CultureInfo.InvariantCulture));
               value.AddMapping(CandleStickPointMarker.HighProperty, k => double.Parse(k[2], CultureInfo.InvariantCulture));
               value.AddMapping(CandleStickPointMarker.LowProperty, k => double.Parse(k[3], CultureInfo.InvariantCulture));

Xaml Side:

<ddd:ChartPlotter x:Name="price"    LegendVisibility="Hidden" NewLegendVisible="False" Grid.Row="1">
            <ddd:VerticalAxisTitle>Price</ddd:VerticalAxisTitle>
            <ddd:WidthSpring SourcePanel="{Binding LeftPanel, ElementName=volume}"/>
            <ddd:MarkerPointsGraph DataSource="{Binding PriceDS}"  >
                <ddd:MarkerPointsGraph.Marker>
                    <ddd:CandleStickPointMarker WhiteCandleFill="Azure" BlackCandleFill="DarkBlue">
                        
                    </ddd:CandleStickPointMarker>
                </ddd:MarkerPointsGraph.Marker>
            </ddd:MarkerPointsGraph>
            <ddd:ChartPlotter.MainHorizontalAxis>
                <ddd:NumericAxis LabelProvider="{StaticResource tickToDate}"/>
            </ddd:ChartPlotter.MainHorizontalAxis>
            
        </ddd:ChartPlotter>

 

Really easy and strightforward. Notice than choosing the candlestick theme does not involve changing a style, bust just setting a brush.  The green line shown one interesting trick, by specifying the WidthSpring, we spring all the chart with the left part aligned. Very important since we need to compare the charts all together. Frankly speaking I did not manage any way to achieve that with WPF Toolkit charts.

imageWidthSpring keeps the left part of the chart aligned.

Bar chart is done by specializing the PointsGraphBase chart. Data are passed as a regular LineChart:

 

public EnumerableDataSource<string[]> VolumeDS
        {
            get
            {
                return volumeDS;
            }
            set
            {
                value.SetXMapping(k => DateTime.ParseExact(k[0], "yyyy-MM-dd", CultureInfo.InvariantCulture).Ticks);
                value.SetYMapping(k => double.Parse(k[5], CultureInfo.InvariantCulture));
                volumeDS = value;
            }
        }

 

An interesting part is what we show as labels on the XAxis ? We can customize that too:

<ddd:NumericAxis LabelProvider="{StaticResource tickToDate}"/>

As we can see, we provide as LabelProvider that produce the label for each tick. If we are not satidfied by the tick, we can provide our TickProvider.

Here below you can find my DynamicDataDisplay version ( sorry for providing that way, I’m tryng to contact the development team to send the patches )

and here the sample app:

Sunday, 15 May 2011 20:31:57 (GMT Daylight Time, UTC+01:00)  #    Comments [1] - Trackback
Charting | D3 | WPF

# Monday, 09 May 2011

 

As you can see in this discussion, it is not possible to pass a “dotted” expression in an ActionMessage parameter with CM. This is due to the fact that supporting this in a complete and consistent way will force caliburn micro to grow over the micro size. Let’s have a concrete example: we want to invoke an action on the StrokeCollected event of an InkCanvas, and we want to pass the Stroke property of the EventArgs.Here below the wanted syntax:

 <InkCanvas>
        <i:Interaction.Triggers>
            <i:EventTrigger  EventName="StrokeCollected">
                <cl:ActionMessage  MethodName="StrokeCollected" >
                    <cl:Parameter Value="$eventArgs.Stroke">
                        
                    </cl:Parameter>
                </cl:ActionMessage>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </InkCanvas>

 

If we use the standard behavior, only the $eventArgs portion of the expression is resolved, adding the dot forces CM to just emit the whole string as a parameter. Since we can deal in an application with a simplified strategy, that not necessary cover all scenarios, but is good enough for our purpose, we can redefine the MessageBinder.EvaluateParameter strategy:

var microEvaluator = MessageBinder.EvaluateParameter;
           MessageBinder.EvaluateParameter = (s, t, c) => 
           {
               string[] dotted = s.Split('.');
               if (dotted.Length == 1)
               {
                   // use default CM strategy
                   return microEvaluator(s, t, c);
               }
               else
               {
                   // let's CM happy with any type
                   var first = microEvaluator(dotted[0], typeof(object), c);
                   var dw = Dig(first,dotted.Skip(1));
                   return dw;
               }
                
           };

 

As you can see, we leverage the inner evaluator in the case we have a non dotted separated argument, or for the first chunk of the expression if the dot exists. The Dig function, by the old plain reflection work recursively to return the proper value:

 

        private object Dig(object first, IEnumerable<string> iEnumerable)
        {
            if (iEnumerable.Count() == 0)
                return first;
            else
            {
                PropertyInfo pi = first.GetType().GetProperty(iEnumerable.First());
                if( null == pi )
                {
                    Exception e = new Exception("Property not found:"+iEnumerable.First());
                    LogManager.GetLog(GetType()).Error(e);
                    throw e;
                }
                return Dig(pi.GetValue(first, null),iEnumerable.Skip(1));
            }
        }
As you can see it is pretty simple, despites some fault intolerance, that we can accept since this code will not be part of the library, but is under our control.
Monday, 09 May 2011 21:43:04 (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
Caliburn | WPF

# Monday, 02 May 2011

Sometimes we want to use some shortcut key for special commands in our application, but the KeyBinding objects works with just routed commands, and so it is not directly usable with Caliburn Micro ( or with many other MVVM strategies ).
In similar situation CM rely on System.Windows.Interactivity.dll, for example when we need to map an event on a Caliburn action we can write:

 

 <Button x:Name="Save" >
           
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <cl:ActionMessage MethodName="Save" ></cl:ActionMessage>
                </i:EventTrigger>
            </i:Interaction.Triggers>
 </Button>

 

With the code above, we explicitly link the "Click" event from the button to the action calling the metod Save. We can act in a similar way by creating a custom trigger, lets see how.
First look at what we can do it in XAML:

 

<i:Interaction.Triggers>
        <local:InputBindingTrigger>
            <local:InputBindingTrigger.InputBinding>
                <KeyBinding Modifiers="Ctrl" Key="S"/>
            </local:InputBindingTrigger.InputBinding>
            <cl:ActionMessage MethodName="Save"/>
        </local:InputBindingTrigger>
    </i:Interaction.Triggers>

 

We need to declare a class, deriving from TriggerBase in System.Windows.Interactivity in order to fire the action(s) in place of executing a routed command when the user press the proper key gesture. Here the code:

class InputBindingTrigger:TriggerBase<FrameworkElement>,ICommand
    {
        public InputBindingTrigger()
        {

        }
        public InputBinding InputBinding
        {
            get { return (InputBinding)GetValue(InputBindingProperty); }
            set { SetValue(InputBindingProperty, value); }
        }
        public static readonly DependencyProperty InputBindingProperty =
            DependencyProperty.Register("InputBinding", typeof(InputBinding)
            , typeof(InputBindingTrigger)
            , new UIPropertyMetadata(null));
        protected override void OnAttached()
        {
            if (InputBinding != null)
            {
                InputBinding.Command = this;
                AssociatedObject.InputBindings.Add(InputBinding);
            }
            base.OnAttached();
        }

        #region ICommand Members
        public bool CanExecute(object parameter)
        {
            // action is anyway blocked by Caliburn at the invoke level
            return true;
        }
        public event EventHandler CanExecuteChanged = delegate { };

        public void Execute(object parameter)
        {
            InvokeActions(parameter);
        }

        #endregion
    }

 

Very easily we add the InputBinding to the bindings list on the object, and we attach the trigger as a command handler. In the execute function we fire the InvokeActions and it done. Please not the command on the KeyBinding is not required in the markup, since there is virtually any routed command.

Monday, 02 May 2011 14:16:17 (GMT Daylight Time, UTC+01:00)  #    Comments [8] - Trackback
Caliburn | Recipes | WPF

# Thursday, 28 April 2011

Since is very common to use coroutines for spawn non blocking asynchronous activities in Caliburn Micro (CM), I wrote a simple base class than executes the computation via a BackgroundWorker and ensure the result “Completed” is fired on the same thread who start the call, typically, but not necessary, the UI thread. Here the class:

public abstract class AbstractBackgroundAction:IResult
   {
       abstract protected void OnExecute(ActionExecutionContext context);
       #region IResult Members

       public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };

       public void Execute(ActionExecutionContext context)
       {
           using( BackgroundWorker bw = new BackgroundWorker() )
           {
               Exception exception=null;
               bw.DoWork+=(s,e)=>
                   {
                       try
                       {
                           OnExecute(context);
                       }
                       catch (Exception workException)
                       {
                           exception = workException;
                       }
                   };
               bw.RunWorkerCompleted+=(s,e)=>
                   {
                       Completed(this, new ResultCompletionEventArgs { Error=exception });
                   };
               bw.RunWorkerAsync();
           }
       }

       #endregion
   }
By using the RunWorkerCompleted of the BackgroundWorker we ensure to cam back to the original threads who invoked the coroutine step. Implementer has just to override the function OnExecute.
Thursday, 28 April 2011 17:01:24 (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
Caliburn | WPF

# Wednesday, 27 April 2011

In this post I will describe a – in order to me – little strange behavior in Caliburn Micro ( CM ) that I discovered in my learning by doing sessions. So the scenario is the following, I have an application with a Main model acting as a screen conductor. The conduced screen are visualized as a classical tabbed application. The exercise goal is to define a visual command on the main view and route it to the proper active item, that is I think a quite common scenario. Let me clarify what I want to achieve with an image:

clip_image001

The TabModel class is actually the model connected to the single tab screen. Lets try to do by just naming conventions:

<Button Grid.Row="0" x:Name="Save"  >
                    <Image Source="assets/disk.png"/>
                </Button>

 

Well, it does not work automatically: CM wire just the MainModel, so we need to explicitly re-target the action on the Active child:

<Button Grid.Row="0" x:Name="Save"  cl:Action.TargetWithoutContext="{Binding Path=ActiveItem}">
                    <Image Source="assets/disk.png"/>
                </Button>
Unfortunately message is not routed yet. Let’s try to define the message handler in the main model:
class MainWindowModel:Conductor<object>.Collection.OneActive
   {
       public MainWindowModel()
       {
           Items.Add(new TabModel("Tab 1"));
           Items.Add(new TabModel("Tab 2"));
           Items.Add(new TabModel("Tab 3"));

       }
      
       public void Save()
       { 
       }
   }
Well, it works !
image 

This is because CM creates the poper handler in the main model, so it can route it when we re-target the handler. Since this is probably not the desired behavior, it is probably better to use this strategy instead:

 

<Button Grid.Row="0" x:Name="Save"  
cl:Message.Attach="[Event Click] = [Action Save()]"  
cl:Action.TargetWithoutContext="{Binding Path=ActiveItem}">
                    <Image Source="assets/disk.png"/>
</Button>
By doing this we leave the naming convention strategy, and we explictly declare what we want to do, is better to avoid unpredictable behavior :)
If you are interested in the code for reproducing this check this issue.
Wednesday, 27 April 2011 16:59:28 (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
Caliburn | WPF

My Stack Overflow
Contacts

Send mail to the author(s) E-mail

Tags
profile for Felice Pollano at Stack Overflow, Q&A for professional and enthusiast programmers
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2019
Felice Pollano
Sign In
Statistics
Total Posts: 157
This Year: 0
This Month: 0
This Week: 0
Comments: 127
This blog visits
All Content © 2019, Felice Pollano
DasBlog theme 'Business' created by Christoph De Baene (delarou) and modified by Felice Pollano
Nike Winkels Nederland Outlet Nike Nederland Store Outlet Nike Nederland 2015 Outlet Nike Outlet Online Nike Sneakers Outlet