Archive

Archive for the ‘Exploring the CodeFluent Runtime’ Category

Single Instance Application in .NET

September 10, 2014 Leave a comment

Running a single instance of an application is very easy with CodeFluent Runtime. Add the following nugget package: http://www.nuget.org/packages/CodeFluentRuntimeClient and use the SingleInstance class:

 
SingleInstance _singleInstance = new SingleInstance("Unique Name"); 

public MainForm() 
{ 

  if (!_singleInstance.WaitForMutext(IntPtr.Zero, IntPtr.Zero)) 
  { 
    Close(); 
  } 

  InitializeComponent();
}

If you want to make an action when the second instance is started, you can handle the windows message “”WM_” + uniqueName”:

 
protected override void WndProc(ref Message m) 
{ 
  if (m.Msg == _singleInstance.Message) 
  { 
    // your code
  } 
  base.WndProc(ref m); 
} 

SingleInstance class provides a helper to activate a Form, so when the second instance is started, it actually display the form of the first instance:

 
public partial class MainForm : Form 
{ 
  SingleInstance _singleInstance = new SingleInstance("My App"); 

  protected override void WndProc(ref Message m) 
  { 
  // Display the window of the first instance 
    _singleInstance.OnWndProc(this, m, true); 
    base.WndProc(ref m); 
  } 
} 

You can also force the instance to run, even if one is already running, by using the command line argument “/siForce” or “-siForce”.

 
$> myapp.exe /siForce 

Happy runtime exploration,

The R&D Team

CommonMark for C# using CodeFluent Runtime

September 5, 2014 Leave a comment

Markdown is a plain text language that can be converted to HTML. This language is well adopted: GitHub, StackOverflow, Reddit, some blogging platforms, and many others.

This language had no specification, so there were many different implementations. A few days ago, Standard Markdown, quickly renamed to Common Markdown, was born. This is the first specification of Markdown. At the same time, the C and JavaScript implementation was released:

At SoftFluent we though JavaScript is great but we are mostly using C# so there is no Common Markdown implementation.

We’re not providing a C# implementation as it would take time to develop and to maintain. Here, we want to show you how to call JavaScript code from C# using the CodeFluent Script Engine from the CodeFluent Runtime.

This is just a sample/preview and not aims to be used in production.

The full (but very short) code is available on GitHub: https://github.com/SoftFluent/SoftFluent.CommonMarkdown 

Here’s the main code:

private static readonly string _language = DetermineBestEngine();
private static string DetermineBestEngine()
{
    // use IE9+'s chakra engine?
    bool useChakra = ScriptEngine.GetVersion(ScriptEngine.ChakraClsid) != null;
    return useChakra ? ScriptEngine.ChakraClsid : ScriptEngine.JavaScriptLanguage;
}
string method = @"
    function markdownToHtml(text) {
        var reader = new stmd.DocParser();
        var writer = new stmd.HtmlRenderer();
        var parsed = reader.parse(text);
        return writer.render(parsed);
    };";

using (ScriptEngine engine = new ScriptEngine(_language))
using (ParsedScript parsed = engine.Parse(File.ReadAllText("stdm.js") + method))
    return (string)parsed.CallMethod("markdownToHtml", engine.Eval(EncodeJavaScriptString(text)));

And how to use it:

Markdown.ToHtml(@"# Hello there
This is a paragraph.
- one
- two
- three
- four
1. pirate
2. ninja
3. zombie")

This code gives the following result :

<h1>Hello there</h1>
<p>This is a paragraph.</p>
<ul>
  <li>one</li>
  <li>two</li>
  <li>three</li>
  <li>four</li>
</ul>
<ol>
  <li>pirate</li>
  <li>ninja</li>
  <li>zombie</li>
</ol>

CodeFluent Runtime Client is free and available from NuGet. This package contains lots of useful class such as the ScriptEngine.

Have fun with Markdown,

The R&D Team

Template Engine and Extensibility

June 11, 2014 Leave a comment

A few time ago, we presented the CodeFluent Runtime’s Template Engine. Today we’ll see how to extend it to change a little bit its syntax and to add custom keywords.

Here is a simple template:

<% var now = new Date(); %>
Hello <%= Name %>!
It's <%= now.toDateString() %>
Cheers,
<%= CurrentUser %>

To use the standard Template Engine, we use this following code:

Template template = new Template();

template.LoadText(templateText, "Name", "CurrentUser");
string templateResult = template.Run(new Dictionary<string, object>
{
     { "Name", "Jone Doe" }, 
     { "CurrentUser", Environment.UserName }
}); 

Console.WriteLine(templateResult);

This will output:

Hello Jone Doe!
It’s Thu Mar 6 2014
Cheers,
The R&D Team

After some customization, the template will be more readable:

Hello {{Name}}!
It's {{Now:yyyy/MM/dd}}
Cheers,
{{CurrentUser}}

Before extending the template engine we have to understand how it works. The engine is composed of 4 classes:

  • Template: contains the configuration such as delimitation tokens and methods to load and run the template
  • ParsedTemplate: contains parameters and code or text blocks extracted while parsing the template
  • ParsedBlock / CodeBlock: contains block text and a method to transform it into JavaScript code
  • Output: contains methods to write into the output file

Let’s use the first sample to understand. First, it will parse the template and extract the following blocks:

  • CodeBlock: var now = new Date();
  • TextBlock: Hello
  • CodeBlock: = Name
  • TextBlock: It’s
  • CodeBlock: = now.toDateString()

Then it will transform blocks into JavaScript instructions. These Text blocks are transformed into “Output.Write(block content)”. When code block starts with “=” it will generate “Output.Write(parameterName)”, otherwise the JavaScript is written as is.

The generated JavaScript is:

ActiveXObject=null;
function __run(Output, Name, CurrentUser) {
 var now = new Date(); 
Output.WriteBlock(1);
Output.Write( Name );
Output.WriteBlock(3);
Output.Write( now.toDateString() );
Output.WriteBlock(5);
Output.Write( CurrentUser );
}

Now we understand the template engine, let’s extend it.
We would like to change to {{ and }}. To do so, we extend the Template class.

public class CustomTemplate : Template
{
    public CustomTemplate()
    {
        StartToken = "{{";
        EndToken = "}}";
    }
}

We also need to create a new CodeBlock to parse the content and write the appropriate JavaScript code:

public class CustomCodeBlock : CodeBlock
{
    public string Format { get; private set; }
    public string ArgumentName { get; private set; }

    public CustomCodeBlock(string code, int creationIndex)
        : base(code, creationIndex)
    {
        Parse(code);
    }

    private void Parse(string text)
    {
        if (text == null || text.StartsWith("="))
            return;

        string argumentName = text;
        string format = null;
        int formatIndex = text.IndexOf(":");
        if (formatIndex > 0)
        {
            argumentName = text.Substring(0, formatIndex);
            format = text.Substring(formatIndex + 1);
        }

        ArgumentName = argumentName;
        Format = format;
    }

    public override void BuildSourceCode(StringBuilder source, ParsedTemplate parsed)
    {
        if(!string.IsNullOrEmpty(ArgumentName))
        {
            source.Append(parsed.Template.OutputItemName);
            if (string.IsNullOrEmpty(Format))
            {
                source.Append(".Write(");
                source.Append(ArgumentName);
                source.Append(");");
            }
            else
            {
                source.Append(".WriteFormatted(");
                source.Append(ArgumentName);
                source.Append(", \"");
                source.Append(Format);
                source.Append("\");");
            }

            return;
        }

        base.BuildSourceCode(source, parsed);
    }
}

Now we have to create the WriteFormatted function in the Output class:

[ComVisible(true)] // Needed to be used by JavaScript code
public class CustomOutput : Output
{
    public CustomOutput(ParsedTemplate template, TextWriter writer)
        : base(template, writer)
    {

    }

    public void WriteFormatted(object value, string format)
    {
        if (string.IsNullOrWhiteSpace(format))
        {
            Write(string.Format("{0}", value));
        }
        else
        {
            string formattedValue = string.Format("{0:" + format + "}", value);
            Write(formattedValue);
        }
    }
}

Finally let’s say to the Template to use our custom classes instead of the default ones.

public class CustomTemplate : Template
    {
        public override CodeBlock CreateNewCodeBlock(string code, int creationIndex)
        {
            return new CustomCodeBlock(code, creationIndex);
        }

        public override Output CreateNewOutput(ParsedTemplate parsedTemplate, TextWriter writer)
        {
            return new CustomOutput(parsedTemplate, writer);
        }
    }

That’s it! The full sample is available on our GitHub.

Happy Templating

The R&D Team.

How to compress or extract CAB archives?

June 2, 2014 1 comment

Today, on the series “Exploring the CodeFluent Runtime” we’re going to explore how to compress or extract CAB archives.

Cabinet (or CAB) is an archive file format for Windows that supports lossless data compression and embedded digital certificates used for maintaining archive integrity. Cabinet files have .cab file name extensions.

First, we have to add a reference to “CodeFluent.Runtime.dll”. The namespace we’ll use is “CodeFluent.Runtime.Compression”, the same as for compressing or extracting ZIP file.

One of the biggest advantage compare to ZIP file, is that it can work in memory or by using the file system as it uses Stream. The second point is you don’t have to add a native DLL: it’s all managed. While it’s less efficient than a native implementation, it’s easier to deploy.

Here’s an example to compress one file and a directory:

using (MemoryStream stream = new MemoryStream())
{
    using (CabFile file = new CodeFluent.Runtime.Compression.CabFile(stream, CabFileMode.Compress))
    {
        file.CompressionLevel = CabCompressionLevel.Maximum;
        file.AddEntry("File.txt");
        file.AddDirectory("Sample");
    }
}

Extracting files is as simple as compressing.

using (CabFile file = new CodeFluent.Runtime.Compression.CabFile(stream, CabFileMode.Decompress))
{
    file.EntryExtracted += (sender, e) =>
    {
        //e.Entry.Name
        //e.Entry.OutputStream
        //e.Entry.Bytes
        //e.Entry.Size
        //e.Entry.LastWriteTime
        //e.Entry.Tag
    };
    file.ExtractEntries();
}

And there’s more…

We add a method to determine the compression method (CAB or ZIP) of a file. This method can use the file extension if available or the first four bytes of the file (i.e. magic number):

CompressionUtilities.SniffFileFormat("test.cab", useExtensionAsHint: true) == CompressionFileFormat.Cab

And that’s not all, in the previous article, we wrote about how to sign a file by using the runtime. CAB file can also be signed, so let sign it:

X509Certificate2 certificate = Authenticode.FindSuitableCertificate(); 
Authenticode.SignFile(certificate, "test.cab", null, "SoftFluent");

Cab properties

Happy compressing and signing,

The R&D Team

Exploring the CodeFluent Runtime: Authenticode

May 28, 2014 2 comments

Today, on the series “Exploring the CodeFluent Runtime” we’re going to explore how to sign an application with Authenticode method.

Microsoft Authenticode, which is based on industry standards, allows developers to include information about themselves and their code with their programs through the use of digital signatures. Authenticode allows software vendors to sign:

  • .cab files
  • .cat files
  • .ctl files
  • .dll files
  • .exe files
  • .ocx files

First we need a certificate that allows Code Signing. If you haven’t one, let’s create a self-signed one:

REM May change depending of your installed Windows SDK
cd "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin"

REM Generate the root certificate
.\makecert.exe -r -pe -n "CN=Sample.CA" -ss CA -sr CurrentUser -a sha1 -cy authority -sky signature -sv d:\Sample.CA.pvk d:\Sample.CA.cer

REM Add the Root certificate to the user store
certutil.exe -user -addstore Root d:\Sample.CA.cer

REM Create the certificate for code signing
.\makecert.exe -pe -n "CN=Sample.CodeSigning" -eku "1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13" -a sha1 -cy end -sky signature -ic d:\Sample.CA.cer -iv d:\Sample.CA.pvk -sv d:\Sample.CodeSigning.pvk d:\Sample.CodeSigning.cer

REM Convert to certificate to pfx file format
.\pvk2pfx.exe -pvk d:\Sample.CodeSigning.pvk -spc d:\Sample.CodeSigning.cer -pfx d:\Sample.CodeSigning.pfx

For convenience you can add the certificate to the personal store (“My”) by double clicking on it in the explorer.

We can now sign a file. Add the “CodeFluent.Runtime.dll” reference and use the following code:

// If you have zero more than one code signing certificate in the personal store, you have to load the certificate manually.
X509Certificate2 certificate = Authenticode.FindSuitableCertificate();
Authenticode.SignFile(certificate, "sample.exe", null, "SoftFluent");

The first line find a valid certificate for code signing in the user certificate store. If none is found, it returns null.

The second line signs the file. You have to indicate:

  • the certificate to use
  • the file to sign
  • the timestamp server
  • the display name

If you look at the file properties, you’ll find a new tab ‘Digital Signature’ which contains details about the signer.

Digital Signature

 

Please note:

  • you don’t need to provide a password, nor a path to the certificate => Generic, simple and secure
  • the method doesn’t rely on the Windows SDK, so you don’t have to bother with SDK path => much simplier :)
  • it’s a DLL so it’s very easy to integrate in your application

Additionally you’ll find two methods:

//Determines whether the specified certificate can sign code.
public static bool CanSignCode(X509Certificate2 certificate)

//Determines whether the specified file is signed using authenticode.
public static bool IsSigned(string filePath)

Starting with build 786:

When you sign a file with a timestamp server, an exception is sometimes raised. The workaround is to sign the file without using a timestamp server and then timestamp the signed file:

X509Certificate2 certificate = Authenticode.FindSuitableCertificate();
Authenticode.SignFile(certificate, "sample.exe", null, "Sample");
Authenticode.TimeStampFile("sample.exe", "http://timestamp.verisign.com/scripts/timstamp.dll");

We also introduce a new overload which allow to specify the hash algorithm to use:

Authenticode.SignFile(certificate, "sample.exe", null, "Sample", Authenticode.Sha512AlgorithmId);

Happy authenticoding,

The R&D team

Exploring the CodeFluent Runtime: Web Controls – Part 2

February 5, 2014 1 comment

In Part 1 of this series, we looked at some useful controls from the CodeFluent.Runtime.Web assembly.
On the same subject, we’ll explore in this post some other very useful controls for ASP.NET WebForms application.

The first controls are DataSource controls; They aren’t visual but very convenient as they can be bound to any DataBound controls like GridView, ListView, etc.

CountryDataSource (CodeFluent.Runtime.Web.UI.CountryDataSource) gives you a list of countries with a lot of properties, including localization information (EnglishName, NativeName, Location, Region, etc.). The type of the enumerated item is CodeFluent.Runtime.Utilities.Country. You can learn more about this type in the related article on our blog.

<cfe:CountryDataSource ID="CountryDataSource1" runat="server"/>
<asp:GridView ID="GridView2" runat="server" DataSourceID="CountryDataSource1" AllowPaging="true">

CountryDataSource

CultureDataSource (CodeFluent.Runtime.Web.UI.CultureDataSource) gives you a list of CultureInfo (System.Globalization.CultureInfo) and can be bound with any DataBoundControl (GridView, DropDownList…).

<cfe:CultureDataSource ID="CultureDataSource1" runat="server" />
<asp:GridView ID="GridView3" runat="server" DataSourceID="CultureDataSource1" AllowPaging="true">

CultureDataSource

CodeFluent Entities comes with another cool Web Control: the CultureDropDownList.

CultureDropDownList (CodeFluent.Runtime.Web.UI.WebControls.CultureDropDownList) displays automatically for you a DropDownList filled with cultures. With a single line of code, you can let the user change the UI Culture of your website.
First, add this control to your page:

<cfe:CultureDropDownList id="cultures" runat="server" CultureCookieName="culture" AutoPostBack="true" TitleMemberName="EnglishIEStyle" TextMemberName="NativeName" CultureList="en-us;fr-fr" />

The CultureList property lets you set the cultures you want to display. By default, all available cultures (on the current computer) are loaded.

Then, just add the following code in the Global.asax file.

protected void Application_AcquireRequestState(object sender, EventArgs e)
{
    CultureDropDownList.SetRequestCulture(Request, "culture"); 
}

The second parameter corresponds to the name of the cookie set in the CultureDropDownList in the page.

Because the CultureDropDownList control is set to AutoPostBack=”true”, when the user selects another culture, the website page will automatically reload with the selected culture. Of course, you need to put in place the ASP.NET globalization mechanism and provide the corresponding resources files :).

FreeForm Control
Now, another topic. Let’s imagine you have several forms to implement as pages on your site, most of them used to get simple input from your users. Let’s suppose you want to send email with the content of the forms. This can be useful for polls for example.

For this, you can use the FreeForm control (CodeFluent.Runtime.Web.UI.WebControls.FreeForm). It allows you to create an arbitrary form, add all the child controls you want to it and then add a piece of code to gather all the user input data. Here is a quick example.

We start with a simple markup:

<cfe:FreeForm ID="FF" runat="server" OnFormChanged="OnFormChanged" DecamelizeOptions="Default" >
    <ItemTemplate>
        <asp:Panel ID="Panel3" runat="server" GroupingText="Personnal Information">
            <asp:Label ID="Label1" runat="server" Text="Preferred Name:" /><br />
            <asp:TextBox ID="TextBox1" runat="server" Text='<%#Bind("PreferredName") %>' /><br />
            <asp:Label ID="Label2" runat="server" Text="City:" /><br />
            <asp:TextBox ID="TextBox3" runat="server" Text='<%#Bind("City") %>' /><br />
        </asp:Panel>
        <asp:Panel ID="Panel4" runat="server" GroupingText="Business Information">
            <asp:Label ID="Label3" runat="server" Text="Your Company:" /><br />
            <asp:TextBox ID="TextBox4" runat="server" Text='<%#Bind("YourCompany") %>' /><br />
            <asp:Label ID="Label4" runat="server" Text="Describe your primary role and function:" /><br />
            <asp:TextBox ID="TextBox5" runat="server" Text='<%#Bind("DescribeYourPrimaryRole_x0026_Function") %>' /><br />
        </asp:Panel>
        <br />
        <asp:Button ID="Button2" runat="server" Text="OK" />
    </ItemTemplate>
</cfe:FreeForm>

We have a form with 4 textboxes and their corresponding labels into 2 panels, plus a standard button to submit :

When the user submits the button, the whole input data will be transformed into a dictionary instance automatically. Each control will provide a dictionary entry in that instance. Notice that all the Text attributes of the textboxes have a standard ASP.NET bind token attached. That token will become the entry field key, and the entry value will be the data entered by the user (whatever the type of this data and the type of the control). To get this dictionary you just need to attach to the FormChanged event and read the Values property of the FormChangedEventArgs parameter, like this:

<script runat="server">
    protected void OnFormChanged(object sender, FormChangedEventArgs e)
    {
        StringBuilder sb = new StringBuilder();

        foreach (DictionaryEntry de in e.Values)
        {
            sb.AppendLine(de.Key + "=" + de.Value + "<br/>");
        }
        
        // NOTE: instead, send email here with the content of the StringBuilder
        litResult.Text = sb.ToString();
    }
</script>     

You may have noticed that we have defined the field names using camel-case and also some weird hexadecimal notation. The FreeForm control has the ability to “decamelize” these keys and unescape the Unicode characters represented by their hexadecimal values. This trick allows us to use anything for key names (although the Bind syntax is much more restrictive). You can define several options in the DecamelizeOption attribute (None, ForceFirstUpper, ForceRestLower, UnescapeUnicode, UnescapeHexadecimal, ReplaceSpacesByUnderscore, ReplaceSpacesByMinus, ReplaceSpacesByDot, KeepFirstUnderscores, DontDecamelizeNumbers, KeepFormattingIndices).

So, this simple example gives you the following result:

Of course, you will hopefully implement something more useful in your project :) You can also imagine having a form generator for power-users, letting them design simple forms and process the Key/Value Dictionary generated by the FreeForm control in a pretty much automatic way.

NumericTextBox Control
Do you need a numeric-only textbox input?. CodeFluent.Runtime.Web has a solution for you: the NumericTextBox control.

The NumericTextBox control (CodeFluent.Runtime.Web.UI.WebControls.NumericTextBox) prevents user from entering non-numeric characters. You can define the value type with the TargetTypeName attribute, define the MaximumNumbers, MaximumIntegerNumbers, MaximumDecimalNumbers or the Negative or Positive Sign. Note this control can be used inside a FreeForm control we say previously.

<cfe:NumericTextBox ID="NumericTextBox1" runat="server" Value='<%# Bind("NumberOfEmployees") %>' TargetTypeName="System.Int32" />

There is also associated DataControlField, NumericTextField CodeFluent.Runtime.Web.UI.WebControls.NumericTextField) fields controls that you can use in GridView, DetailsView, etc.

<cfe:NumericTextField DataField="Age" HeaderText="Age" TargetTypeName="System.Int32"/>

Captcha Control
The Captcha control (CodeFluent.Runtime.Web.UI.WebControls.CaptchaControl) displays an image with some simple text inside, but supposedly quite difficult to read for machines. You can define the image size, the complexity of the produced image, and a timeout duration. Notice that the image is generated by the BinaryLargeObjectHttpHandler of CodeFluent Entities (Learn more about Blob here).

The Captcha control comes with its validator, the CaptchaValidator control (CodeFluent.Runtime.Web.UI.WebControls.CaptchaValidator). As any validator, you just need to declare the ControlToValidate and the CaptchaControlID associated.

In this example, we just display a message if the text entered corresponds to what was generated by the Captcha control.

<cfe:CaptchaControl ID="CaptchaControl1" runat="server" Width="200px" Height="50px" Expiration="120"
    Options="FontWarpFactorMedium, BackgroundNoiseLevelHigh,LineNoiseLevelHigh" />
<br />
Please enter the code or press F5 to refresh the browser
<br />
<cfe:CaptchaValidator ID="CaptchaValidator1" runat="server" ControlToValidate="Verify" CaptchaControlID="CaptchaControl1"
    SetFocusOnError="True" ErrorMessage="The code doesn’t match or there was a timeout" ForeColor="Red" />
<br />
<asp:TextBox ID="Verify" runat="server" EnableViewState="False" AutoCompleteType="None" />
<asp:Button ID="btValidate" runat="server" Text="Validate" OnClick="btValidate_Click" /><br />
<asp:Label ID="lblResult" runat="server" Text="You enter the correct text! Thank you for validating." Visible="false" ForeColor="Green"/>

In the button Click event, call Page.IsValid to validate the captcha:

<script runat="server">
    protected void btValidate_Click(object sender, EventArgs e)
    {
        if (Page.IsValid)
        {
            lblResult.Visible = true;
        }
        else
        {
            lblResult.Visible = false;
        }
    }
</script> 

Have a look at the Captcha image here:

Captcha

As you’ve seen in this serie, CodeFluent.Runtime.Web can be very useful to us, web developers who are tired to write a lot of code-behind to do simple actions. With these controls you just need to drag and drop them on your page, save and enjoy.

These controls are located in the CodeFluent.Runtime.Web assembly, part of the CodeFluent Entities product ! Try them!

Happy controling!

The R&D team.

Exploring the CodeFluent Runtime: Web Controls – Part 1

January 28, 2014 1 comment

Today, on the series “Exploring the CodeFluent Runtime” we’re going to explore the ASP.Net Web Controls inside the CodeFluent.Runtime.Web namespace. This is all provided as part of CodeFluent Entities.

In the CodeFluent.Runtime.Web assembly, you’ll find several controls usable in ASP.Net WebForms applications. The first we’ll see are controls used to render UI relatively to the data (bindings).

BooleanControl (CodeFluent.Runtime.Web.UI.WebControls.BooleanControl) displays what’s defined in FalseTemplate or TrueTemplate according to a boolean value.

<cfe:BooleanControl ID="BooleanControl1" runat='server' Value='<%# Eval("MyBooleanValue") %>' AutoBind="true">
    <TrueTemplate>
        This template will be displayed if Value is evaluated as "true"
    </TrueTemplate>
    <FalseTemplate>
        This template will be displayed if Value is evaluated as "false"
    </FalseTemplate>
</cfe:BooleanControl>

CompareControl (CodeFluent.Runtime.Web.UI.WebControls.CompareControl) displays FalseTemplate or TrueTemplate according to what’s defined by the ValueToCompare attribute and an Operator (Equal, NotEqual,
GreaterThan, GreaterThanEqual, LessThan, LessThanEqual, DataTypeCheck). For the DataTypeCheck operator, the ValueToCompare will be the full name of the type to check.

<cfe:CompareControl ID="CompareControl1" runat='server' Value='<%# Eval("MyValueToCompare") %>' Operator="GreaterThan" ValueToCompare="0">
    <TrueTemplate>
        Value is greater than 0
    </TrueTemplate>
    <FalseTemplate>
        Value is less than or equal to 0
    </FalseTemplate>
</cfe:CompareControl>
 
<cfe:CompareControl ID="CompareControl2" runat='server' Value='<%# Eval("MyValueToCompare") %>' Operator="DataTypeCheck" ValueToCompare="System.Int32">
    <TrueTemplate>
        Value is a System.Int32
    </TrueTemplate>
    <FalseTemplate>
        Value is not a System.Int32
    </FalseTemplate>
</cfe:CompareControl>

MultiCompareControl (CodeFluent.Runtime.Web.UI.WebControls.MultiCompareControl) is similar to the CompareControl but is more like a switch.

<cfe:MultiCompareControl ID="MultiCompareControl1" runat="server" Value='<%#Eval("MyValueToMultiCompare") %>'>               
    <case ValueToCompare="10" Operator="GreaterThan">
            Value is greater than 10
    </case>
    <case ValueToCompare="0">
    Value is equal to 0
    </case>
    <default>
    Value is not equal to 0 and is less than or equal to 10
    </default>
</cfe:MultiCompareControl>

ExistsControl (CodeFluent.Runtime.Web.UI.WebControls.ExistsControl) displays FalseTemplate or TrueTemplate depending on a given value. The value is tested against “null”, “DBNull”, or an empty string (possibly trimmed).

<cfe:ExistsControl ID="ExistsControl1" runat='server' Value='<%# Eval("Email") %>' Trim="true">
    <TrueTemplate>
        This template is displayed only if Value is not null or empty 
    </TrueTemplate>
    <FalseTemplate>
        This template is displayed when Value is null
    </FalseTemplate>
</cfe:ExistsControl>

When you work with enumerations into your Model, you want to be able to display and edit them easily into your forms or GridView. We have a solution for you! Let me introduce the Enum Controls.

EnumCheckBoxList (CodeFluent.Runtime.Web.UI.WebControls.EnumCheckBoxList) derives from the standard CheckBoxList control but is automatically filled with the fields of the enumeration type you define EnumTypeName parameter. Note this also supports multi-valued enumerations (with a [Flags] custom attribute).

EnumRadioButtonList (CodeFluent.Runtime.Web.UI.WebControls.EnumRadioButtonList) derives from the standard RadioButtonList control. As the EnumCheckBox, you only need to define the EnumTypeName attribute

EnumDropDownList (CodeFluent.Runtime.Web.UI.WebControls.EnumDropDownList) derives from the standard DropDownList and works the same way.

Another control that allows you to quickly bind your data is the BoolControl (CodeFluent.Runtime.Web.UI.WebControls.BoolControl). The BoolControl is a visual custom control that displays a System.Boolean or Nullable<System.Boolean> bound value. Depending whether the value is nullable or not, it can display a True/False or True/False/Undefined visual. It can use a CheckBox, DropDownList, horizontal button list, ListBox or horizontal or vertical radio button list to display these 2 or 3 items. It also supports read-only rendering and custom texts, interesting for localization purposes.

Is Customer:

<cfe:BoolControl ID="BoolControl1" runat="server" Value='<%# Bind("IsCustomer") %>' TrueText="Yes" FalseText="No" UnspecifiedText="Undefined" BoolControlType="HorizontalRadioButtonList" />

Contact Method:

<cfe:EnumCheckBoxList ID="EnumCheckBoxList1" runat="server" Value='<%# Bind("MethodToContact") %>' EnumTypeName="BlogCFE.ContactManager.ContactMethod" />
Origin (RadioButton):
<cfe:EnumRadioButtonList ID="EnumRadioButtonList1" runat="server" Value='<%# Bind("Origin") %>' EnumTypeName="BlogCFE.ContactManager.ContactOrigin" />
Origin (DropDown):
<cfe:EnumDropDownList ID="EnumDropDownList1" runat="server" Value='<%# Bind("Origin") %>' EnumTypeName="BlogCFE.ContactManager.ContactOrigin" />           

Here is the result:

For each of these controls, an associated DataControlField exists so you can use them in GridView, DetailsView, etc.

<cfe:BoolField DataField="IsCustomer" HeaderText="Is Customer" TrueText="Yes" FalseText="No" BoolControlType="DropDownList" />
<cfe:EnumCheckBoxListField DataValueField="MethodToContact" HeaderText="Contact method" EnumTypeName="BlogCFE.ContactManager.ContactMethod" />
<cfe:EnumRadioButtonListField DataValueField="Origin" HeaderText="Origin (RadioButton)" EnumTypeName="BlogCFE.ContactManager.ContactOrigin" />
<cfe:EnumDropDownListField DataValueField="Origin" HeaderText="Origin (DropDown)" EnumTypeName="BlogCFE.ContactManager.ContactOrigin" />        

the result in a grid view:

List of Contacts

As you’ve seen, these controls can avoid you to write a lot of code focusing more on a declarative way of programming.

In the next article, we’ll introduce the DataSources controls and another couple of cool utilities.

The R&D team.

Follow

Get every new post delivered to your Inbox.

Join 51 other followers