Calculator Application Using IronJS and WPF by invoking an external JavaScript file

Rajnilari2015
Posted by in WPF category on for Beginner level | Points: 250 | Views : 3467 red flag
Rating: 5 out of 5  
 1 vote(s)

In this article, we will build a simple calculator by using WPF and will use IronJS for writing the various calculator operations.We are using an external JavaScript as our dynamic scripting language.This Java Script file will have all the functions that the Calculator will use.


 Download source code for Calculator Application Using IronJS and WPF by invoking an external JavaScript file

Recommendation
Read Calculator Application Using IronJS and WPF before this article.

Introduction

In the previous article , we have seen how to invoke a dynamic scripting language (e.g. Java Script) using Iron Python.But in that article, we were building the functions programatically.In this article, we will extend our same example to demonstrate the power of IronJS of invoking an external Java Script file.The development environment is Microsoft Visual Studio Community 2015.

Environment Setup

Let's create a solution file and add two project, one WPF(CalciPL) and another Class Library(CalciBL) projects.Choose the Class Library(CalciBL) project, click on Managed Nuget Packages.

In the Search box Type "IronJS" and click "Search"

Click on the Install button to install "IronJS". We are using version 0.2.0.1

Once installed, we will get the below screen

Now we are good to go for writing our Business Logic(s)

Using the code

Let us first create a javascript file say CaliOperations.js which will have the below functions

/*
  Function Name: Add
  Purpose: For Addition of two numbers
*/

function Add(a,b)
{    
    return a+b;
}



/*
  Function Name: Sub
  Purpose: For Subtraction of two numbers
*/

function Sub(a,b)
{    
    return a-b;
}

/*
  Function Name: Mul
  Purpose: For Multiplication of two numbers
*/
function Mul(a,b)
{    
    return a*b;
}


/*
  Function Name: Div
  Purpose: For Division of two numbers
*/
function Div(a,b)
{    
    return a/b;
}

Let us write the below code in the CaliOperation.cs file

using IronJS;
using System;


namespace CalciBL
{
    public class CaliOperation
    {
        public int CaliOperations(int a, int b, string @operator)
        {
            const string FILEPATH = @"D:\CaliOperations.js";

            string operation = string.Empty;

            // Instantiate the IronJS Engine
            var context = new IronJS.Hosting.CSharp.Context();

            //Reads Javascript Source Code
            context.ExecuteFile(FILEPATH);

            //Set the operation mode as per the operator choosen
            switch (@operator)
            {
                case "+":
                    operation = "Add";
                    break;

                case "-":
                    operation = "Sub";
                    break;

                case "*":
                    operation = "Mul";
                    break;

                case "/":
                    operation = "Div";
                    break;
            }

            //fo holds the needed JS function  
            FunctionObject fo = context.Globals.GetT<FunctionObject>(operation);

            //invoke the JS dynamic method
            BoxedValue bv = fo.Call(context.Globals, Convert.ToDouble(a), Convert.ToDouble(b));

            //unboxing the unknown values to a known value
            double result = bv.Unbox<double>();

            //Execute method runs the dynamic code
            return Convert.ToInt32(result);
        }
    }
}

Code Explanation

The very first thing we need to perform is to instantiate the IronJS Engine which can be achieve by the below code

new IronJS.Hosting.CSharp.Context()

Next we are invoking the ExecuteFile method of the on the context object. The ExecuteFile caches the AST tree for the parsed "CaliOperations.js" file and uses the cache.

Next, based on the operator choosen at runtime, we are setting the operation that is defined in the "CaliOperations.js" JavaScript file.

IronJS automatically sends the function being called into the FunctionObject parameter.The FunctionObject class is derived from CommonObject.

 //fo holds the needed JS function  
FunctionObject fo = context.Globals.GetT<FunctionObject>(operation);

The FunctionObject has a call method that invokes the dynamic methods

 //invoke the JS dynamic method
BoxedValue bv = fo.Call(context.Globals, Convert.ToDouble(a), Convert.ToDouble(b));

As can be figure out that, the Call method returns a BoxedValue type. This is a NaN-tagged struct that is used for representing values that don't have a known type at runtime.IronJS passes integers as doubles, so we need to cast them.

Convert.ToDouble(a)

Finally, we are unboxing the unknown values to a known value by invoking the Unbox function

To test our function, we can write a simple Unit Test project as under

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CalciBL.Tests
{
    [TestClass()]
    public class CaliOperationTest
    {
        [TestMethod()]
        public void CaliOperationAdditionSuccessTest()
        {
            CaliOperation objCalciOp = new CaliOperation();
            var expected = 60;
            var actual = objCalciOp.CaliOperations(20, 40, "+");
            Assert.AreEqual(expected, actual);
           
        }

        [TestMethod()]
        public void CaliOperationAdditionFaliureTest()
        {
            CaliOperation objCalciOp = new CaliOperation();
            var expected = 35;
            var actual = objCalciOp.CaliOperations(-20, 40, "+");
            Assert.AreNotEqual(expected, actual);

        }

        [TestMethod()]
        public void CaliOperationSubtractionSuccessTest()
        {
            CaliOperation objCalciOp = new CaliOperation();
            var expected = -20;
            var actual = objCalciOp.CaliOperations(20, 40, "-");
            Assert.AreEqual(expected, actual);

        }

        [TestMethod()]
        public void CaliOperationSubtractionFaliureTest()
        {
            CaliOperation objCalciOp = new CaliOperation();
            var expected = 35;
            var actual = objCalciOp.CaliOperations(-20, 40, "-");
            Assert.AreNotEqual(expected, actual);

        }

        [TestMethod()]
        public void CaliOperationMultiplicationSuccessTest()
        {
            CaliOperation objCalciOp = new CaliOperation();
            var expected = -800;
            var actual = objCalciOp.CaliOperations(-20, 40, "*");
            Assert.AreEqual(expected, actual);

        }

        [TestMethod()]
        public void CaliOperationMultiplicationFaliureTest()
        {
            CaliOperation objCalciOp = new CaliOperation();
            var expected = 35;
            var actual = objCalciOp.CaliOperations(20, 40, "*");
            Assert.AreNotEqual(expected, actual);

        }

        [TestMethod()]
        public void CaliOperationDivisionSuccessTest()
        {
            CaliOperation objCalciOp = new CaliOperation();
            var expected = 10;
            var actual = objCalciOp.CaliOperations(400, 40, "/");
            Assert.AreEqual(expected, actual);

        }

        [TestMethod()]
        public void CaliOperationDivisionFaliureTest()
        {
            CaliOperation objCalciOp = new CaliOperation();
            var expected = 35;
            var actual = objCalciOp.CaliOperations(56, 40, "/");
            Assert.AreNotEqual(expected, actual);

        }
    }
}

Now let us make our UI design in WPF which will be as under

And the code is as under

using CalciBL;
using System;
using System.Windows;

namespace CalciPL
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        CaliOperation objCalciOp;
        public MainWindow()
        {
            InitializeComponent();
            objCalciOp = new CaliOperation();
        }

        private void btnAdd_Click(object sender, RoutedEventArgs e)
        {
            var nums = InputValues();
            txtResult.Text = Convert.ToString(objCalciOp.CaliOperations(nums.Item1, nums.Item2, "+"));
        }

        private void btnSub_Click(object sender, RoutedEventArgs e)
        {
            var nums = InputValues();
            txtResult.Text = Convert.ToString(objCalciOp.CaliOperations(nums.Item1, nums.Item2, "-"));
        }

        private void btnMul_Click(object sender, RoutedEventArgs e)
        {
            var nums = InputValues();
            txtResult.Text = Convert.ToString(objCalciOp.CaliOperations(nums.Item1, nums.Item2, "*"));
        }

        private void btnDiv_Click(object sender, RoutedEventArgs e)
        {
            var nums = InputValues();
            txtResult.Text = Convert.ToString(objCalciOp.CaliOperations(nums.Item1, nums.Item2, "/"));
        }

       private Tuple<int, int> InputValues()
        {
            var num1 = Convert.ToInt32(txtNum1.Text);
            var num2 = Convert.ToInt32(txtNum2.Text);
            return Tuple.Create(num1, num2);
        }
    }    
}

Now run the application and we can feel the taste of our simple calculator.

Conclusion

So in this article we have seen how to invoke an external dynamic language like Java Script file functions using IronPython.Hope this will be helpful.Attached is the zipped file.Thanks for reading.

Page copy protected against web site content infringement by Copyscape

About the Author

Rajnilari2015
Full Name: Niladri Biswas (RNA Team)
Member Level: Platinum
Member Status: Member,Microsoft_MVP,MVP
Member Since: 3/17/2015 2:41:06 AM
Country: India
-- Thanks & Regards, RNA Team


Login to vote for this post.

Comments or Responses

Login to post response

Comment using Facebook(Author doesn't get notification)