Berichten met label c#

Howto use MvcContrib.Pagination with a ViewModel

Howto use MvcContrib.Pagination with a ViewModel

I was looking for a simple solution for paging in a ASP.MVC2 project. Though we already use MVCContrib.Grid this was the first place I searched.

The solution MVCContrib offers is elegant in the way that they separated the concept of paging, a ui element to show paging (next , previous, …) and a grid to show the content. This separation allows us to using paging on a custom table based page as well.

Because we are using ViewModels a little extra effort was needed to retain the paging information from the domain layer in the view layer.

Step by step:

* Get a Querable from repository using Domain Objects

IQueryable<DomainObject> domainObjects = rep.GetAll()

* Filter and Sort using Linq

domainObjects = domainObjects.Where(...).OrderBy(...)

* Get the data

IPagination<DomainObject> pageOfData domainObjects.AsPagination( page, pageSize)

* Map to the ViewModel

IPagination<DomainObjectViewModel> model = DomainObjectViewModel.Map( pageOfData )

* Mapping needs to retain the page information from the domain

var list = new List<DomainObjectViewModel>();
foreach (var domainObject in domainObjects)
{
list.Add(Map(domainObject));
}
new CustomPagination<DomainObjectViewModel>(list.AsEnumerable(),
    pageOfData.PageNumber, 
    pageOfData.PageSize, 
    pageOfData.TotalItems);

* Show the information on a page in a grid

<%= Html.Grid(Model).AutoGenerateColumns() %>

* Show the pager

<%= Html.Pager(Model).First( "<<").Last(">>").Next(">").Previous("<")
.Format( "Item {0} - {1} van {2} ") %>

Step by step:The ====# HowTo====
* Get a Querable from repository using Domain Objects
@@IQueryable<DomainObject> domainObjects = rep.GetAll()@@
* Filter and Sort using Linq
@@domainObjects = domainObjects.Where(…).OrderBy(…)@@
* Get the data
@@IPagination<DomainObject> pageOfData domainObjects.AsPagination( page, pageSize)@@
* Map to the ViewModel
@@IPagination<DomainObjectViewModel> model = DomainObjectViewModel.Map( pageOfData )@@
* Mapping needs to retain the page information from the domain
@@var list = new List<DomainObjectViewModel>();
foreach (var domainObject in domainObjects)
{
list.Add(Map(domainObject));
}
new CustomPagination<DomainObjectViewModel>(list.AsEnumerable(), pageOfData.PageNumber, pageOfData.PageSize, pageOfData.TotalItems);
@@
* Show the information on a page in a grid
* Show the pager

, , ,

Nog geen reacties

Building iPad applications using MonoTouch: the UISplitView

First of all, I bow deeply to the people that bring us MonoTouch. It was less than 2 days after the introduction of the iPad and the release of a beta of the iPhone/iPad SDK that a version of MonoTouch (and MonoDevelop) was available that covers the new API.

To build iPad apps, you need a couple of things that are all listed on the MonoTouch iPad page.

I couldn’t wait to build something that used the way bigger UI-surface that the iPad has. The first thing that attracted my attention when I fired up the Interface Builder was the UISplitViewController.
The idea behind the SplitView is that you have some navigation on the left (like a NavigationController, or just a TableViewController) and a data view on the right. That is, only when the display is in landscape mode. As soon as you turn the iPad (the iPad SImulator, of course) to portrait, the left side disappears and all the screen is available to the data view.
That behaviour is entirely taken care of by the UISplitViewController, at least if you stick to the conventions!

I decided to make a simple app with a list of places on the left side, and a map-view on the right:

LandscapePortait version of the UI

The obvious start

When you start a new iPad application from the New Project menu, you get the well-known set-up of files in your project. Double-click the MainWindow.xib to fire up Interface Builder. Then drag the Split View Controller from the Library Window and drop it below the Window object in de MainWindow:
MainWindow

As you can see, you get a lot for free, including stuff you don’t want. Now it gets less obvious. After clicking Cmd-Backspace a thousand times and positioning my cursor everywhere, I had an epiphany. Since the SplitViewController won’t work without two other controllers I had to add something new before I could remove the old!

No kidding, that was really the solution. So I added a UITableViewController, Interface Builder magically removed the default NavigationController, and I added a MKMapView to the view-controller on the right.

This is the result:

SplitView I then added outlets to the AppDelegate for the map, the tableview and the splitview:

Outlets

The less obvious code

To make the controllers react properly when the orientation of the UI changes, you need to override the ShouldAutorotateToInterfaceOrientation() method in each of your controllers. How do you do that?
The first step is to add a class to your project, make it inherit from your controller (a UITableViewController in my case) and override the ShouldAutorotateToInterfaceOrientation() method as below:

public class PlacesController : UITableViewController
{
	public PlacesController ()
	{
	}
 
	public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
	{
		return true;
	}
}

Repeat the step for the second controller:

public class Map : UIViewController
{
	public Map ()
	{
	}
 
	public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
	{
		return true;
	}
}

This should still compile. But it doesn’t work yet.

The even less obvious link from the code to the UI

The objects in the Interface Builder are standard objects. They need to be of the types that we just defined, to make the overridden methods work. See we need to make our own classes known to Interface Builder. That’s done by adding a Register-atribute and overriding the constructor with one that accepts an IntPtr.
The Map class changed in something like this:

[Register("Map")]
public class Map : UIViewController
{
	public Map ()
	{
	}
 
	public Map(IntPtr p) : base(p)
	{
	}
 
	public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
	{
		return true;
	}
}

The final step is setting the right class on the controller. Go to Interface Builder, select the UIViewController (e.g.) in the MainWindow, then go to the Inspector Window and type your classname over the default one:

Inspector

And then it works! The map will re-orientate itself when the iPad is turned, and the Table View appears and disappears.
Of course you want some location data in the table and the map to show the locations when clicked on, but that’s all in the code you can download.

Enjoy making software for a device that makes you need to rethink the way you always made software…!!!

Mmmmh. re-reading that last line, I realize it’s a little hard to read. What I meant was something like Joe Hewitt wrote.

, , , , ,

4 reacties

ASP.NET MVC: Editor Templates

Last week I sat with a colleague who is building an ASP.NET MVC application. Since I’m currently on a not-so-interesting application, I was really jealous and decided to out-smart him, showing off with some hard-core MVC code.

Here we go.

What’s your problem, dude?

Well, we are all very Web 2.0 and so, using Ajax and jQuery and maybe even single-page-applications, but on almost any site I fill in a form, a textbox is just a plain textbox. You can type text, like digits and characters, even if they need only my age. Come-on guys, an age is expressed as a number, so why allow me to type in anything else but digits?
Sure, you validate at the server and maybe even at the client, but still I can make errors that I have to fix later. Please, help me by preventing the error up-front.

The solution, part 1: jQuery-plugin

The solution starts with a nice jQuery-plugin by Paulo P. Marinas called jQuery AlphaNumeric. There is also a nice MaskedInput-plugin, but I found that too limiting.
It is simple to hook it up to my textbox:

$("#mytextboxid").numeric();

And voila, nothing but digits allowed!

Cool, I want that on all the fields that I know are numbers, but I surely don’t want to repeat the above Javascript.

The solution, part 2: EditorFor

Starting with MVC 2 there is an Html-helper called Html.EditorFor(). It uses a lambda as a parameter and derives a lot of interesting information from that. If you type

        <%= Html.EditorFor(model => model.Length) %>

You get code generated like this:

<div class="editor-field">
<input id="Length" name="Length" type="text" value="7" /></div>

De ViewEngine determines that you have a Integer field, generates a textbox with the name/id of the field and sets the value. If you have client-side data-validation on, you get the extra span-tag for the validation message. More on that in a minute. Maybe this doesn’t look like much, but you get different output for different field types; like radio-buttons for a Boolean field and appropriate formatting for a Decimal field.
The EditorForModel() method even generates code for all the fields on your class.

The solution, part 3: Turning validation on

I was hoping that the EditorFor() method would be all I needed. It supports validation, both client-side and server-side, and (as argued before) what better client-side validation then preventing false input to begin with!
Alas, it doesn’t do that. But in combination with DataAnnotations (Scott Guthrie has a nice blog about that) it adds range-checks to your Integer-field. So if I can limit the characters that can be typed into my textbox with a line of jQueury and can check for the upper- and lower-limit of the value with client-side validation, then I’m happy!

But that means that I have to change the behavior of the EditorFor() method. Can that be done? Well……, sort of.

The solution, part 4: Convention over configuration

The nice thing about the MVC framework is that it takes convention over configuration, meaning you do not have to configure anything to get a working application, as long as you adhere to the rules/conventions. Nothing new for Ruby on Rails programmers maybe, but for me as a long-time Microsoft-ee it is close to revolutionary.

In this case, the interesting convention is that there can be a EditorTemplates sub-directory in my View directory. If it is in a normal View directory it works for only those Views, but if you put it in the Shared directory it works for all your views:
SharedViews

If you have a user-control in there named Decimal.ascx it will be used everywhere the EditorFor() encounters a Decimal property. There is a bunch of default user-controls that are described by Brad Wilson.

What I would have liked to be “The solution, part 5: Overloading the decimal template”

Since I like the server-side formatting of the default template, and only want to add some jQuery, I would have liked to do the following:

<%@ Control Language="C#" AutoEventWireup="true" Inherits="System.Web.Mvc.ViewUserControl" %>
<%= Html.EditorFor(Model) %>
<script type="text/javascript">
    $("#mytextboxid").numeric();
</script>

I simply delegate to the original implementation, passing in the data I have available. But that doesn’t work since the EditorFor() expects a lambda as a first parameter. And I don’t know any way to convert the data I have at that point in time to a lambda. If you know, please tell me and you’ll be my hero (hmmmm, I hope it’s not going to be that colleague coming up with the solution, that would really ruin my post…).

The actual “The solution, part 5: Overloading the decimal template”

The best I could do was copying the default template for the Decimal from the blogpost of Brad Wilson. Yes that’s a shame, copying code, having to maintain code that isn’t even mine, not profiting of the improvements Microsoft makes in the default template. Nevertheless, here it is:

<%@ Control Language="C#" AutoEventWireup="true" Inherits="System.Web.Mvc.ViewUserControl" %>
<script runat="server">
    private object ModelValue {
        get {
            if (ViewData.TemplateInfo.FormattedModelValue == ViewData.ModelMetadata.Model) {
                return String.Format(System.Globalization.CultureInfo.CurrentCulture,
                                     "{0:0.00}", ViewData.ModelMetadata.Model);
            }
 
            return ViewData.TemplateInfo.FormattedModelValue;
        }
    }
</script>
<%= Html.TextBox("", ModelValue, new { @class = "text-box single-line" }) %>
<script type="text/javascript">
    $('#<%= ViewData.ModelMetadata.PropertyName %>').numeric({ allow: '<%= System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator %>'});
</script>

So, there is some server-side code that I copied, and then some client-side code I added myself.
There are two interesting things to mention about my own single line of code:

  • The jQuery selector references the name of the property, thus guaranteeing that the javascript is coupled to the right text-box. Other solutions make you use a fixed class or prefix or postfix, but that only opens the possibility of name clashes. The name-property is available in the model-metadata. See the Bradd Wilson series mentioned above for more info
  • The allowed character (the decimal separator) for entering money is retrieved from the CurrentCulture and not hard-coded. Of course.
  • As ScottGu would say: hope this helps.

, ,

4 reacties

Building iPhone applications using MonoTouch, howto: using a view without a controller

Of course, a view without a controller is not very useful in itself, but in this post I want to show you how I solved a small re-usability problem.

I’m working on a small open-source project on Codeplex that aims to build a player for the Hanselminutes podcasts. It is nothing very special, but it gives me a nice playground to find out new stuff.

So there is a “Loading playlist” message and a “Buffering audio” message displayed at the appropriate moments. You can do that in a lot of ways, but in this application, a semi-transparent view was chosen that is overlaying the current view. It has a text (of course) and a UIActivityIndicatorView (who comes up with these names????).

I try to follow three rules when building the UI:

  1. All the UI is done with the Interface Builder. That allows me to leave the actual design to someone who knows designing.
  2. Every view is in a separate NIB. That way not all the UI has to be loaded at startup, which improves user-perceived performance
  3. Loosely couple the view, to make reuse easier. That means a simple interface (as in ‘programming interface’) to the rest of the world, and all the view-related code inside the NIB

In this case I want a view that can be called from different controllers (re-usability), so when I add a file to my MonoDevelop project I choose “View Interface Definition”:

Screen shot 2010-01-25 at 8.34.03 PM

It’s no so different form what you do (at least, what I do) most of the time when you choose View Interface Definition with Controller. You add your UI-elements, define some outlets, but then  you want to activate this view from some controller, any controller.

What I came up with, is the following.

public class UIHelper
{
  UIViewController _controller;
  BusyView _busyView;
  public UIHelper (UIViewController controller)
  {
    _controller = controller;
    NSArray views = NSBundle.MainBundle.LoadNib("BusyView", _controller, null);
 
    _busyView = new BusyView(views.ValueAt(0));
    _controller.View.AddSubview(views);
    _controller.View.SendSubviewToBack(_busyView);
  }
}

It is a helper class that loads the view at construction time. It gets passed in the controller that will display the view. Then I load the NIB where the view is in. This gives me back an array. Of what? Well as the documentation says:

An array containing the top-level objects in the nib file. The array does not contain references to the File’s Owner or any proxy objects; it contains only those objects that were instantiated when the nib file was unarchived. You should retain either the returned array or the objects it contains manually to prevent the nib file objects from being released prematurely.

So you get the top-elements (actually: the IntPtr’s of them) from the NIB. In a file with only one view the first one is probably (…fingers crossed) the right one.
I add the view to the SubViews of the controller and make sure it does not show before it was meant to.

Showing the view

Whenever I need the view to display I call:

	_busyView.Show(message);
	_controller.View.BringSubviewToFront(_busyView);

The first line calls a method on the partial class in the NIB to set the text of a label. The second line makes the view visible.

What’s not to like about this solution

Well, the magical string with the name of the NIB, “BusyView”. And the magical number 0 the denotes the right object in the list of objects in the NIB.

Any ideas for improvement? Please react!

Download the code

, , , , , ,

5 reacties

Java .Net interoperability

Java .Net interoperability

Have you ever felt the urge and need to connect your Java program to a particular .Net assembly? And more specifically without the hassle of COM bridges, web services, .Net remoting or other service type components. I came across a project in which a simple Java program needed to be connected to an existing .Net assembly (btw written in C#). Everything had to be as simple as possible.
On the Internet a couple of articles were helpful: Espresso, C# method calls within Java Program and Calling a .NET Method from Java via JNI. However it didn’t quite work the way we liked so the ulimate solution came (it so often happens) from Jelle Hissink (http://www.codewise.nl)

The solution is based on:

  • Use JNI for the communication between the Java VM and the .Net CLR
  • Intercept the call to the name resolver and resolve the call to the C# class with your own method

Graphically this looks like:

Let’s work our way from the initial Java call to the final C# implementation.

Java

In Java we have the simple program:

class HelloWorld {
   public static void main(String[] args)
  {
      DotNetBridge dotNetBridge = new DotNetBridge();
      String getString = dotNetBridge.GetString();
      System.out.println("GetString() returned:   " + getString);

      String newString = "Java2.Net world";
      dotNetBridge.SetString(newString);
	getString = dotNetBridge.GetString();
      System.out.println("GetString() returned:   " + getString);
   }
}

Nothing special, just straightforward java code.
However in addition to this code we define an extra class with the DotNetBridge code on the java side. This is needed to kick start the bridging.

public class DotNetBridge
{
  private native void Initialize(String localPath);
  public native String GetString();
  public native void SetString(String newString);

  static
  {
    String path = DotNetBridge.class.getProtectionDomain().getCodeSource().getLocation().getPath();
    int idx = path.lastIndexOf("/");
    if (idx >= 0) {
      path = path.substring(0, idx);
    }
    if (path.startsWith("/")) {
      path = path.substring(1);
    }

    System.load(path + "/DotNetBridge.dll");
    DotNetBridge dotNetBridge = new DotNetBridge();
    dotNetBridge.Initialize(path);
  }
}

In a few words what does it do? It is a class with native methods telling the java compiler that it can find the interface of the methods in this class but the implementation is to be found in a native Windows dll file. On top of that when to class is instantiated for the first time the static part will ensure that the Initialize method is called in which the full path of the dll file with the implementation is passed. Be a little more patient, later on we’ll see why we need this.

DotNetBridge

We now need a simple interface from the Java to the .Net world in which strings can be passed in and out. For this purpose we create a managed C++ project in Visual Studio of the name DotNetBridge. The project consists of:

  • A C++ header file with the definition of the bridge interface
  • A C++ file with the implementation of the bridge
  • A reference to the .Net component with the implementation of the actual HelloWorld code

The header file DotNetBridge.h makes use of JNI (ofcourse) to define the interface of the bridge:

#include "jni.h"

JNIEXPORT void JNICALL Java_DotNetBridge_Initialize(JNIEnv *env, jobject thisobject, jstring localPath);
JNIEXPORT jstring JNICALL Java_DotNetBridge_GetString(JNIEnv *env, jobject thisobject);
JNIEXPORT void JNICALL Java_DotNetBridge_SetString(JNIEnv *env, jobject thisobject, jstring newString);

I’ll not dive into the details of JNI too much (see JNI Primer) but this is the most minimal definition. There are tools to generate this type of definitions (javah –jni) but we leave those out of the equation today. For now watch the prefix Java_DotNetBridge_ which are needed in case of JNI. Also the env and thisobject parameters are specific for each JNI call.

The implementation in C++ has become much more easily with the new .Net framework primitives for managed C++. The two main methods on the interface are the get and set string methods, their implementation looks like:

using namespace System;
using namespace System::Runtime::InteropServices;
using namespace HelloWorldDotNet;

#include 

JNIEXPORT jstring JNICALL
Java_DotNetBridge_GetString (JNIEnv *env, jobject thisobject)
{
    IHelloWorld ^support = gcnew HelloWorld();

    // Get a managed string.
    String ^managedString = support->GetString();

    std::string str = managedToString(managedString);

    // Create the java string...
    jstring result = env->NewStringUTF(str.c_str());

    return result;
}

JNIEXPORT void JNICALL
Java_DotNetBridge_SetString (JNIEnv *env, jobject thisobject,
								jstring newString)
{
    IHelloWorld ^support = gcnew HelloWorld();

    std::wstring newWString = jstringToWString(env, newString);

    String ^ managedString = gcnew String(newWString.c_str());

    support->SetString(managedString);
}

To enable all this we do need some extra string management functions which can translate the java formatted strings to .Net strings and vice versa. Also the transition from the managed to unmanaged environment has its effect on the string management as can be seen from:

std::wstring jstringToWString(JNIEnv *env, jstring jstr)
{
  jboolean iscopy;
  const jchar *strPtr = env->GetStringChars(jstr, &iscopy);

  const jchar *p = strPtr;
  std::wstring result;
  while (*p)
  {
    result += *(p++);
  }

  env->ReleaseStringChars(jstr, strPtr);

  return result;
}

std::string managedToString(String ^mstr)
{
  // Marshal the managed string to unmanaged memory.
  IntPtr hGlobal = Marshal::StringToHGlobalAnsi(mstr);

  char *stringPointer = static_cast(hGlobal.ToPointer());

  // Create the java string...
  std::string result = stringPointer;

  // Always free the unmanaged string.
  Marshal::FreeHGlobal(hGlobal);

  return result;
}

Finally, as said earlier, we need to kick start the whole mechanism. Hence the managed C++ code has currently no idea where to find an implementation of the HelloWorld class in the call to: IHelloWorld ^support = gcnew HelloWorld();
By the way, the import of the namespace has sneaked into the C++ code quite silently with: using namespace HelloWorldDotNet; Without setting a reference to the .Net assembly in the projects’ properties the compiler will not be able to compile this C++ class. Setting such a reference can be done with:

In the Java implementation we have seen that each instantiation of the java bridge class results in a call to the initialize function of the DotNetBridge component. Finally it is time to dive into the details of its implementation. We could have done without it if we deploy all dlls to the java executable directories. From a administration perspective this is not very neat. System administrators normally require that a solution is delivered to one location and the software should take care of its own path settings.

In essence the initialize function of the DotNetBridge is always called once and exactly once with the full path specification of the actual executable directory. So put all dlls into this directory and intercept the name resolver. Because if the runtime tries to load the assembly with the implementation of the HelloWorld class it should look into one specific dll to find this implementation. So this will happen:

  • On the initialize the directory path of the HelloWorld.dll is stored in a static variable
  • The AssemblyResolve event is augmented with its own handler
  • In the handler the directory path is used to load the HelloWorld class from the correct dll
std::wstring assemblyLoadPath;

System::Reflection::Assembly ^ MyResolveEventHandler( Object^ sender, ResolveEventArgs^ args )
{
  String ^name = args->Name;
  int idx = name->IndexOf(L',');
  if (idx >= 0) {
    name = name->Substring(0, idx);
  }
  name = String::Concat(name, gcnew String(L".dll"));

  String ^basePath = gcnew String(assemblyLoadPath.c_str());
  name = System::IO::Path::Combine(basePath, name);

  System::Reflection::Assembly ^ result = System::Reflection::Assembly::LoadFile(name);

  return result;
}

JNIEXPORT void JNICALL Java_DotNetBridge_Initialize (JNIEnv *env, jobject thisobject, jstring localPath)
{
    assemblyLoadPath = jstringToWString(env, localPath);

    AppDomain ^currentDomain = AppDomain::CurrentDomain;
    currentDomain->AssemblyResolve += gcnew ResolveEventHandler( MyResolveEventHandler );
}

This will do the trick on the .Net bridge side. The final implementation of the C# code is straightforward.

C# code

It is a C# class library project. It consists of two classes: the interface and its implementation. The code of the interface definition looks like:

using System;

namespace HelloWorldDotNet
{
    public interface IHelloWorld
    {
        void SetString(string stringValue);
        string GetString();
    }
}

Finally its implementation can be anything. In this case it is simple as:

using System;

namespace HelloWorldDotNet
{
    public class HelloWorld : IHelloWorld
    {
        private static string lastString = "brave new world";
        public void SetString(string stringValue)
        {
            lastString = stringValue;
        }
        public string GetString()
        {
            return String.Format("Hello {0}", lastString);
        }
    }
}

Finally

On purpose, in the code examples details such as exception handling and comments were left out. If you’re interested you can download all the code (see below). On the java side DOS command scripts are used to compile and run the example. You’ll find them easy and straightforward. The C++ and C# code are organized in two separate .Net projects. They were made with Visual Studio 2008. Either migrate to Studio 2008 or use the source code files to build a solution yourself.
If you can’t find your way through all the source files, this is the rough organization:

These are the main steps, with their correct order, to get it to work:

  • Compile the HelloWorld C# project
  • From the DotNetBridge project set the reference to the HelloWorld.dll created in the previous step
  • (possibly) in the DotNetBridge project set the include directories to include the path to the correct JVM include directories (otherwise the jni.h can not be found)
  • Compile the DotNetBridge project
  • Change the compile.cmd and run.cmd scripts in the Java directory to reflect the correct paths.
  • Run compile.cmd
  • Run run.cmd
  • If unchanged you should see something like:





    When you want a full download of all the code in this sample, click here.

    And last but not least: have fun!

, , , , , , , ,

5 reacties