MVC Series Part 1: Dynamically Adding Items Part 3

Collections named with same substring in a Dynamic Item

Click here to view the source code

In the second part of the series, I discussed how to include a collection inside a dynamic item. Here is one gotcha that I ran into during development. Let’s say we decide to add a Publisher for every new book and you want the ability to add a few books the publisher has distributed. Here is the PublisherViewModel class I created:

public class PublisherViewModel
    {
        public PublisherViewModel()
        {
            Books = new List<PublisherBookViewModel>();
            for ( int i = 0; i < 3; i++ )
            {
                Books.Add( new PublisherBookViewModel() );
            }
        }
        public string Name { get; set; }
        public IList<PublisherBookViewModel> Books { get; set; }
    }

Here is how the html would look for PublisherViewModel:

<dl class="dl-horizontal">
    <dt>
        @Html.DisplayNameFor( model => @Model.Name )
    </dt>
    <dd>
        @Html.EditorFor( model => @Model.Name )
    </dd>
    <br />
    <dt>
        @Html.DisplayNameFor( model => @Model.Books )
    </dt>
    <dd>
        @for ( int i = 0; i < @Model.Books.Count(); i++ )
        {
            @Html.EditorFor( model => @Model.Books[i] )
        }
    </dd>
</dl>

I went ahead and created a new class for the books collection called PublisherBookViewModel. It simply contains one property for Name. Here is how the Html looks:

@using ( Html.BeginCollectionItem( "Books" ) )
{
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor( model => @Model.Name )
        </dt>
        <dd>
            @Html.EditorFor( model => @Model.Name )
        </dd>
    </dl>
}

But when I go to create one new Book and post back, I actually end up receiving 4 items in my ‘NewBooks’ collection. How did this even happen?

Well, the reason this occurred is again thanks to our BeginCollectionItem HtmlHelper class. The extra logic that we added in the last article seems to merely grab the first occurrence of our collection name:

collectionName = htmlFieldPrefix.Substring( 0, htmlFieldPrefix.IndexOf( collectionName ) + collectionName.Length );

If we look at what the HtmlFieldPrefix string looks like coming in we can start to spot the problem:

“NewBooks[18fe8281-9b41-43ff-bcc9-a14ce3e99dc8].Publisher.Books[0]”

So, our parent dynamic item is being bounded to a collection called ‘NewBooks’, but the PublisherViewViewModel has its own collection of items called ‘Books’. Our Substring method needs to be a little bit smarter by replacing ‘IndexOf’ with ‘LastIndexOf’. And with that, we will no longer have issues with sub collection binding.

This is as far as I took with dynamically adding items in MVC, but at some point it would be nice to be able to add dynamic items to a dynamic item (i.e., instead of pre-populating our Characters collection, we let the user add as many as they need). Perhaps another day I will delve into this.

MVC Series Part 1: Dynamically Adding Items Part 2

Collections in a Dynamic Item

Click here to view the source code

In the first part of the series, I discussed how to add items dynamically. So, why don’t we expand on our idea and let’s say we want to add the ability to include another collection into our original dynamic item. We will expand our BookViewModel editor template to include a collection of 5 story Characters a user can insert:

<dl id="booksContainer">
        @foreach ( var classicBook in @Model.ClassicBooks )
        {
            <dl>
                <dt>
                    @Html.DisplayNameFor( model => classicBook.Title )
                </dt>
                <dd>
                    @Html.DisplayFor( model => classicBook.Title )
                </dd>
                <dt>
                    @Html.DisplayNameFor( model => classicBook.Author )
                </dt>
                <dd>
                    @Html.DisplayFor( model => classicBook.Author )
                </dd>
            </dl>
        }
</dl>

And we included a CharacterViewModel editor template that only includes the ability to insert first and last name. But when you attempt to add a book with a characters we run into the same problem originally where the new Characters are not binding correctly. The reason this exists is because our HtmlHelper is not able to uniquely identify sub items inside a recently dynamically added item. Makes sense?

No? Well, let’s discuss first what the BeginCollectionItem Html helper generates when injected into the Html element. Here is the BookViewModel’s partial view for the title:

<dt>
    @Html.DisplayNameFor( model => @Model.Title )
</dt>
<dd>
    @Html.EditorFor( model => @Model.Title )
</dd>

And here is the output that actually gets injected into the Html element after passing through the Html helper:

<dt>
    Title
</dt>
<dd>
    <input class="text-box single-line"
           id="NewBooks_3ad36db7-7685-4c8e-aadd-a2309f65e858__Title"
           name="NewBooks[3ad36db7-7685-4c8e-aadd-a2309f65e858].Title"
           type="text" value="" />
</dd>

Here you can see how the Html helper is inserting a Guid into the id and name fields so MVC can uniquely identify the property back to the item. But if we use the same comparison for Character, here is the partial view for name:

<dt>
    FirstName
</dt>
<dd>
    <input class="text-box single-line"
           id="Characters_dd611290-f64b-4b1a-9add-bad035f7b94f__FirstName"
           name="Characters[dd611290-f64b-4b1a-9add-bad035f7b94f].FirstName"
           type="text" value="" />
</dd>
<dt>
    LastName
</dt>
<dd>
    <input class="text-box single-line"
           id="Characters_dd611290-f64b-4b1a-9add-bad035f7b94f__LastName"
           name="Characters[dd611290-f64b-4b1a-9add-bad035f7b94f].LastName"
           type="text" value="" />
</dd>

Although the character model is correctly getting a Guid assigned, there is no way for MVC to know that CharacterViewModel belongs to a NewBooks sub item. In order to solve this, we need to delve into our BeginCollectionItem Html helper and make sure it retains the ‘NewBooks’ guid. This is quite straightforward if we do a comparison on the incoming collection name:

var htmlFieldPrefix = html.ViewData.TemplateInfo.HtmlFieldPrefix;
if ( htmlFieldPrefix.Contains( collectionName ) )
{
        collectionName = htmlFieldPrefix.Substring( 0, htmlFieldPrefix.IndexOf( collectionName ) + collectionName.Length );
}

And let’s take a look again at our injected output:

<dt>
     FirstName
</dt>
<dd>
    <input class="text-box single-line"
           id="NewBooks_1a95a483-e5c7-4696-ac91-bd9f0563b83b__Characters_e3e949f5-aae7-44cd-9aa8-419658c25e75__FirstName"
           name="NewBooks[1a95a483-e5c7-4696-ac91-bd9f0563b83b].Characters[e3e949f5-aae7-44cd-9aa8-419658c25e75].FirstName"
           type="text" value="" />
</dd>
<dt>
    LastName
</dt>
<dd>
    <input class="text-box single-line"
           id="NewBooks_1a95a483-e5c7-4696-ac91-bd9f0563b83b__Characters_e3e949f5-aae7-44cd-9aa8-419658c25e75__LastName"
           name="NewBooks[1a95a483-e5c7-4696-ac91-bd9f0563b83b].Characters[e3e949f5-aae7-44cd-9aa8-419658c25e75].LastName"
           type="text" value="" />
</dd>

Now our character items will get posted back onto our dynamic item.

Removing Dynamic Items

Click here to view the updated source code with delete button

Another problem I have run into is attempting to remove items that were dynamically created. The simplest solution I resorted to was adding a uniquely generated id on the incoming model and assigning the highest order html element of that model template the unique id.

So, if we take the current demo project and add a property to our BookViewModel.cs class called UniqueId:

public Guid UniqueId { get; set; }Then assign it inside our constructor:UniqueId = Guid.NewGuid();

We can now reference this in our Model View template. Looking inside BookViewModel.cshtml, we need to move the ‘dl’ tag outside our ‘BeginCollectionItem’ Html helper and assign its id value to our unique id:

< dl class="dl-horizontal" id="@Model.UniqueId">

We need to do this because inside we are going to add a delete button. When the click event occurs, we’re going to call a javascript function and pass into it this parent ‘dl’ html element. The only way we can uniquely identify is by referencing the html element’s id field:

< input type="button" id="Delete" name="Delete" value="Delete" onclick="javascript: deleteBook(document.getElementById('@Model.UniqueId'))" />

And so in our Index.cshtml section where we put our scripts we simply include one more function which will remove any html element from the DOM:

function deleteBook(bookDiv)
{
bookDiv.remove();
}

MVC Series Part 1: Dynamically Adding Items Part 1

Introduction

Recently, I have been exposed to working on a project using ASP.NET MVC 5. My experience working with MVC for the first time was overall positive, but it did run into quite a few hair pulling scenarios. My background up to this point primarily dealt with C# WPF applications, but with a little bit of web development on the side.  In this series, I will discuss some of the major issues that led to many sleepless nights working on this project. And although these scenarios may not seem to be the most difficult to an experienced MVC developer, these are the problems that caused major hiccups to a first timer like myself.

Dynamically Adding Items

Click here to view the source code

In one of the first major issues I needed to attempt to solve was trying to add items dynamically to a View. Representing a collection already populated is fairly straight forward using MVC’s Razor, as represented here in my collection of classical books:

<dlclass="dl-horizontal"id="booksContainer">
        @foreach ( var classicBook in @Model.ClassicBooks )
        {
            <dlclass="dl-horizontal">
                <dt>
                    @Html.DisplayNameFor( model => classicBook.Title )
                </dt>
                <dd>
                    @Html.DisplayFor( model => classicBook.Title )
                </dd>
                <dt>
                    @Html.DisplayNameFor( model => classicBook.Author )
                </dt>
                <dd>
                    @Html.DisplayFor( model => classicBook.Author )
                </dd>
            </dl>
        }
</dl>

We can even go one step further and place this inside a ‘DisplayTemplate’ and push the display content into a partial view:

dynamic-img-1

<dl class="dl-horizontal" id="booksContainer">
        @foreach ( var classicBook in @Model.ClassicBooks )
        {
            @Html.DisplayFor(model => classicBook);
        }
</dl>

But how do we add content on the fly?

Well, we could have a button that inserts javascript into our ‘booksContainer’ element and this would provide a seamless experience for the user. But what if we decide to change how the view looks? And how could we get this to post back to MVC server? What about if we decided to take in an image file as well?

Given I did not want to update the view in two places, I managed to find a solution that managed to do all of the above, linked here.

In summary, I was able to use an ajax call to retrieve my BookViewModel’s partial html view from the server and inject it into an html element:

  • Adding an editor partial view for the BookViewModel

dynamic-img2

 

  • Including the html element that will take in new books:
    <div id="newBooks">
        @for ( int i = 0; i < @Model.NewBooks.Count(); i++ )
        {
            @Html.EditorFor( model => @Model.NewBooks[i] )
        }
    </div>
  • On the server, the HomeController’s method that simply returns my partial view:
    public ActionResult CreateNewBook()
    {
        var bookViewModel = new BookViewModel();
        return PartialView( "~/Views/Shared/EditorTemplates/BookViewModel.cshtml", bookViewModel );
    }
  • The ajax call that handles the add book button click and injects the returned partial view:
    @section Scripts {
        <script type="text/javascript">
            $("#addbook").on('click', function () {
                $.ajax({
                    async: false,
                    url: '/Home/CreateNewBook'
                }).success(function (partialView) {
                    $('#newBooks').append(partialView);
                });
            });
        </script>
    }

And now we can dynamically add items on button click! The user is able to add as many books as they want, click submit, and the collection of books will get received on HttpPost. But, when we put a break post on our post method, the NewBooks collection comes back as empty. Why is this happening?

Well the reason is because MVC can only bind back a collection of items if it can uniquely identify each one. This article actually describes how you can get a collection of items to bind appropriately on post back, linked here.

Unfortunately, this does not apply when items are getting added dynamically. Luckily, the previous article also solved this problem by creating a Html Helper class, BeginCollectionItem, that adds a unique identifier to every new inserted item. All we need to do is modify our BookViewModel editor template to include it:

@using ( Html.BeginCollectionItem( "NewBooks" ) )
{
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor( model => @Model.Title )
        </dt>
        <dd>
            @Html.EditorFor( model => @Model.Title )
        </dd>
        <dt>
            @Html.DisplayNameFor( model => @Model.Author )
        </dt>
        <dd>
            @Html.EditorFor( model => @Model.Author )
        </dd>
        <dt>
            @Html.DisplayName( "Book Cover File Image" )
        </dt>
        <dd>
            @Html.TextBoxFor( m => @Model.BookCoverUrl, null, new { type = "file", @class = "input-file" } )
        </dd>
    </dl>
}

And with that we can now dynamically add items and they will uniquely get posted back onto the server.

Ajax.ActionLink

Click here to view the updated source code with the Ajax.ActionLink button

To add to this there is also a way create a new book using Ajax.ActionLink.

To demonstrate this the change involves removing the original ‘input’ button to this Razor Ajax button:

@Ajax.ActionLink( “Add Book”, “CreateNewBook”, new AjaxOptions
{
HttpMethod = “GET”,
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = “newBooks”
} )

Behind the scenes, this is how the button is represented as straight HTML:

a data-ajax=”true” data-ajax-method=”GET” data-ajax-mode=”after” data-ajax-update=”#newBooks” href=”/Home/CreateNewBook” rel=”nofollow”>Add Book

This also allows us to remove all the scripting for the Index.cshtml page, but I was still having issues clicking the button without it redirecting me to a new page. Then I stumbled upon this article (scroll down to the ‘Ajax.ActionLink’ section), which mentioned including a jquery.unobtrusive-ajax.js file. This script will interrupt the submission process for items that have the data-ajax attribute, which we have seen Razor creates such an element when it renders to the web page.

Android Development with Android Studio

Click here to download code and sample project

Currently, developing mobile applications is one of the most popular environments to program. So, I decided to go ahead and take a step back into the world of Java to create an Android app. I went ahead and decided to give Google’s IDE, Android Studio, a try during this process. The IDE, which is based on IntelliJ IDEA, is still in early access preview though, but already looks quite promising.

To get started I went ahead and downloaded the Android Studio. As a preface, Android Studio requires at least JDK 6 installed before beginning. The entire installation process may take a while if the JDK needs to be installed first. Also, I would highly recommend downloading Genymotion as an Android Emulator replacement since the one on Android Studio is extremely slow. As for learning how to develop an Android application, the tutorial on Android’s site works quite well located here.

So, during this project I decided to port my coworkers TicTacToe concept into Android. The game is similar to regular TicTacToe, except the game is expanded into a 3×3 grid of TicTacToe games. Each individual game that is won is considered a marker for the overall game. There is also a bit of strategy that was added to force the player to consider where their next move should. Needless to say, it is quite an interesting take on TicTacToe and I encourage you to try it.

Since I am coming from a C#/WPF world I am going to bring over some of the concepts of MVVM into this architecture. If you are not familiar withMVVM it is simply a way to decouple business logic from the UI. This way the UI can change however it needs to while keeping the main logic the same.

To get started, open up Android studio and create a new project. When created you can see there is already a pretty verbose folder structure created for a default project.

Project-View

 

Let us start off with adding basic information for our application by looking into the AndroidManifest.xml. In here I will simply add a title for our app by setting the  android:label property. Then to include an app icon, I must include an image into each of the res/drawable-xxxx folders with the image resized appropriately. Here is a rough break down of the dimensions:

    • drawable-ldpi (120 dpi, Low density screen) – 36px x 36px
    • drawable-mdpi (160 dpi, Medium density screen) – 48px x 48px
    • drawable-hdpi (240 dpi, High density screen) – 72px x 72px
    • drawable-xhdpi (320 dpi, Extra-high density screen) – 96px x 96px
    • drawable-xxhdpi (480 dpi, Extra-Extra-high density screen) – 144px x 144px

From <http://stackoverflow.com/questions/5350624/set-icon-for-android-application>

After that we will go back to our manifest file and set the android:icon to our new app icon. Once we compile the app successfully and attempt to run though, the studio brings up the Device Manager to choose an emulator. If you decided to install Genymotion (which I still highly recommend), run it and add a new device to emulate. Once added, select the new device and click play. You will see the device represented in a new window and back in Android Studio when you look in the Device Manager you should see your new emulator.

2014-04-16-15_16_17-Choose-Device

 

So selecting our new emulator we’re able to start running our application. Great, now let us start developing our custom View. I created a MiniBoardView class that extends View which will handle the drawing of the board, markings, and whether the board is in a playable, win, or draw state. You can download the project and view the class file to see all the logic that goes into place, but here are a few main points:

  • We will need to create a custom Paint object that handles the drawing to the screen
  • Any new action that can apply to the board needs a call to invalidate to update the UI
  • To view the control in the designer, certain logic will need to get ignored on rendering. This can be done by doing a check on isInEditMode
  • For all our rendering purposes, make sure to override the onDraw method

Once our view is ready for usage, I went ahead and started implementing the business logic. After setting up the base Model-ViewModel classes I went ahead and tried out my first hit test logic.

First-Hit-Test-Response

 

Now that the basis for our application is done, the rest is simply filling out the logic for our game.  Here is our final result:

Final-Output

 

This should go without saying, but Android Studio is not even at version 1.0. Because of that the IDE is quite unstable. This led to many different frustrations throughout the learning process. Sometimes I would have to restart Android Studio simply because it refused to successfully build anymore. Another peculiar issue I ran into was opening up my project one day, running my app, and suddenly view this:

 

2014-04-16-15_27_16-Genymotion-for-personal-use-Galaxy-S4-4.3-API-18-1080x1920-1080x1920-4

 

What happened to the sizes of my boxes? Did the logic change? No. Did I mistype something? No. Maybe restarting will help? No. I tried many different solutions and even recoded much of the design to no avail. Out of frustration I stepped away for a while and came back to find everything was back to normal. Never saw this problem again. Also, I use to update the product periodically as well until one update caused my whole project to fail. Several hours of snooping online pointed me to updating certain gradle files to get my project working again. Needless to say, I ceased doing that for the rest of my development.

Overall, I enjoyed the development process going back into Java and using Android Studio. I did not take full advantage of what the Android stack has available but I look forward to attempting another project using this IDE.

Text On A Path With Alignment

Click here to view the source code

In past WPF projects, design specifications given by artists are sometimes challenging to attempt to implement. One scenario I have ran into multiple times was trying to display custom text around a curved object. Most of the time this problem was avoided by the artist providing the content as images, but, fortunately, this was only feasible because the text was finite and static. Recently I came across this same scenario again except this time the incoming text could be dynamic. The immediate reaction was to simply read the text as images stored in a folder provided by the customer. This solution tends to create problems in the future because:

  • The user must be familiar with some image editing tool
  • If not accustomed to any, then the user has to be trained
  • The user must be aware of the exact font, weight, and color the artist intended
  • The user must also have the same eye for lining up text as the original artist intended (which many tools can aid in)

With all these issues, it would be better to assume that if a user could get something wrong then they will, which will result in an application that seems off. Not happy with this path I decided to look into creating text on a path.

Fortunately, a majority of the work had already been developed by Charles Petzold described in his article Render Text On A Path With WPF.

The article provides a comprehensive description of his algorithm for placing text on a path. It is worth a read to get an in-depth understanding of how the algorithm works. To try and sum it up though, the algorithm uses a PathFigure object to shape the path the text will render and the class comes equipped with a method to help simplify calculations. In sizing the text font onto the path, the text is scaled to fit entirely on the length of the path. For the best performance, we render the text as DrawingVisual objects so they only need to be created once when the text changed. The result comes out as this:

Result1

 

Fantastic! This worked well for what I wanted, except for one problem; the text scaling. I knew the path I wanted my text to render, but not the length of the text since that could change dynamically. When attempting to apply this algorithm to a path I had in mind, the results were less than pleasing (red curve represents the path for the text):

Result2

 

I needed the text to render the same size despite the length of the path, but the current algorithm would require me to resize the path dynamically based on the size of the text. This did not seem reasonable, especially since I would prefer the text to rest on the center of the path.

So, in order to accomplish this the first thing I needed was a Dependency Property of type HorizontalAlignment to set the content alignment. Setting the alignment to Stretch will keep the original behavior of the algorithm by resizing the text to fit the path. Then we need another Dependency Property for font size, which will only get applied if the content alignment was not Stretch. Now, when calculating the text length we need to substitute our font size over the default 100

private void OnTextPropertyChanged()
{
    _formattedChars.Clear();
    _textLength = 0;
    if (!String.IsNullOrEmpty(Text))
    {
        foreach (char ch in Text)
        {
            var fontSize = ContentAlignment == HorizontalAlignment.Stretch ? 100 : FontSize;
            var formattedText =
                new FormattedText(ch.ToString(), CultureInfo.CurrentCulture,
                    FlowDirection.LeftToRight, _typeface, fontSize, Foreground);
            _formattedChars.Add(formattedText);
            _textLength += formattedText.WidthIncludingTrailingWhitespace;
        }
        GenerateVisualChildren();
    }
}

Then we move onto our TransformVisualChildren method and make sure the scaling factor stays at 1 since we no longer want the text to rescale to the path

private void TransformVisualChildren()
{
    ...
    var scalingFactor = ContentAlignment == HorizontalAlignment.Stretch ? _pathLength / _textLength : 1;
    ...
}

Since content alignment can be set as Center, or Right aligned, the initial progress will need adjusting to push the text further along the path

private void TransformVisualChildren()
{
    ...
    double progress = 0;
    switch (ContentAlignment)
    {
        case HorizontalAlignment.Left:
        case HorizontalAlignment.Stretch:
            progress = 0;
            break;
        case HorizontalAlignment.Center:
            progress = Math.Abs(_pathLength - _textLength) / 2 / _pathLength;
            break;
        case HorizontalAlignment.Right:
            progress = Math.Abs(_pathLength - _textLength) / _pathLength;
            break;
    }
    ...
}

And that is all we have to do since the scaling factor will be set to 1 if content is not stretched. Here is the result with content alignment set to Center. Also, you can see all the various alignments applied:

Result31

 

Although I was very satisfied with the results, a change in the scope of our project made this solution obsolete. Just another day in the life of a programmer.