Creating an easy Grouped ObservableCollection for the LongListSelector

The LongListSelector is great for long lists in Windows Phone 7, but getting your data into the right format can be tricky and confusing (certainly took me a while to work out what to do!). Especially if you want to use 'pure' binding to an ObservableCollection.

The answer that I found easiest to understand and follow was to use 'nested Observable collections'. This also ensure that things are kept up-to-date in the UI without additional coding.

To help me understand what was need I broke it down into some simple stages. I am sure it can be done with a single LINQ statement.

Let say you have a list of contacts that you would like to display with the typical A-Z short cuts as shown here. This includes showing group titles that contain no child records too!

image

Create the basic object - Contacts

We'll start with the simple Contact class that has two 3 properties. One is derived to create the key value. This can be any value, but here it's the first letter of the Name value in lower case. If your data is changing then you should implement the INotifyPropertyChanged interface. I have left it out here for simplicity.

namespace PhoneTester1.Model
{
public class Contact
{
public string Name { get; set; }
public string JobTitle { get; set; }
private string _NameKey;
/// <summary>
/// First letter of the Name. Used for grouping in the long list selector
/// </summary>
public string NameKey
{
get
{
//If not set then
if (_NameKey == null)
{
//get the first letter of the Name
char key = char.ToLower(this.Name[0]);
if (key < 'a' || key > 'z')
{
key = '#';
}
_NameKey = key.ToString();
}
return _NameKey;
}
}
}
}

Create the Group Observable Collection

Then we'll create a Group class. I have called it GroupOC for Grouping Observable Collections.

using System.Collections.ObjectModel;
namespace PhoneTester1.Model
{
public class GroupedOC<T>:ObservableCollection<T>
{
/// <summary>
/// The Group Title
/// </summary>
public string Title
{
get;
set;
}
/// <summary>
/// Constructor ensure that a Group Title is included
/// </summary>
/// <param name="name">string to be used as the Group Title</param>
public GroupedOC(string name)
{
this.Title = name;
}
/// <summary>
/// Returns true if the group has a count more than zero
/// </summary>
public bool HasItems
{
get
{
return (Count != 0);
}
private set
{
}
}
}
}

Create the Helper method to Group the Contacts

I created a static method  called CreateGroupedOC in a static Collection Helper class called CollectionHelper. This can then be called on to group everything up.

using System.Collections.ObjectModel;
using System.Linq;
using PhoneTester1.Model;
namespace PhoneTester1.Functions
{
public static class CollectionHelpers
{
/// <summary>
/// Groups a passed Contacts ObservableCollection
/// </summary>
/// <param name="InitialContactsList">Unordered collection of Contacts</param>
/// <returns>Grouped Observable Collection of Contacts suitable for the LongListSelector</returns>
public static ObservableCollection<GroupedOC<Contact>> CreateGroupedOC(ObservableCollection<Contact> InitialContactsList)
{
//Initialise the Grouped OC to populate and return
ObservableCollection<GroupedOC<Contact>> GroupedContacts = new ObservableCollection<GroupedOC<Contact>>();
//first sort our contacts collection into a temp List using LINQ
var SortedList = (from con in InitialContactsList
orderby con.Name
select con).ToList();
//Now enumerate throw the alphabet creating empty groups objects
//This ensure that the whole alphabet exists even if we never populate them
string Alpha = "#abcdefghijklmnopqrstuvwxyz";
foreach (char c in Alpha)
{
//Create GroupedOC for given letter
GroupedOC<Contact> thisGOC = new GroupedOC<Contact>(c.ToString());
//Create a temp list with the appropriate Contacts that have this NameKey
var SubsetOfCons = (from con in SortedList
where con.NameKey == c.ToString()
select con).ToList<Contact>();
//Populate the GroupedOC
foreach (Contact csm in SubsetOfCons)
{
thisGOC.Add(csm);
}
//Add this GroupedOC to the observable collection that is being returned 
// and the LongListSelector can be bound to.
GroupedContacts.Add(thisGOC);
}
return GroupedContacts;
}
}
}

Tie it together in your ViewModel

In my projects I am usually populating a collection of objects either from a database or web service. Here we'll start with a collection of Contacts that is populated in a random order. This ObservableCollection we would pass to the method shown above (CreateGroupedOC ) to group it and return a grouped ObservableCollection.. This can then be referenced in your ViewModel and bound to the LongListSelector control.

I also use the very handy MVVM Light Toolkit produced by the very excellent Laurent Bugnion of GalaSoft. This you can find at http://mvvmlight.codeplex.com/ and some info about it at http://www.galasoft.ch/mvvm/getstarted/. I strongly recommend using it.

I have included my whole ViewModel below. Hopefully the comments make it self explanatory!

using System;
using System.Collections.ObjectModel;
using System.Text;
using GalaSoft.MvvmLight;
using PhoneTester1.Functions;
using PhoneTester1.Model;
namespace PhoneTester1.ViewModel
{
/// <summary>
/// This class contains properties that the main View can data bind to.
/// You can also use Blend to data bind with the tool's support.
/// This code is provided as is by Hard Medium Soft Ltd.
/// see us at http://www.hardmediumsoft.com
/// </summary>
public class MainViewModel : ViewModelBase
{
public string ApplicationTitle
{
get
{
return "Nicholas Rogoff for Hard Medium Soft Ltd.";
}
}
public string PageName
{
get
{
return "Tester App";
}
}
/// <summary>
/// The <see cref="GroupedContacts" /> property's name.
/// </summary>
public const string GroupedContactsPropertyName = "GroupedContacts";
private ObservableCollection<GroupedOC<Contact>> _GroupedContacts = new ObservableCollection<GroupedOC<Contact>>();
/// <summary>
/// Gets the GroupedContacts property.
/// 
/// Changes to that property's value raise the PropertyChanged event. 
/// This property's value is broadcasted by the Messenger's default instance when it changes.
/// </summary>
public ObservableCollection<GroupedOC<Contact>> GroupedContacts
{
get
{
return _GroupedContacts;
}
set
{
if (_GroupedContacts == value)
{
return;
}
var oldValue = _GroupedContacts;
_GroupedContacts = value;
// Update bindings, no broadcast
RaisePropertyChanged(GroupedContactsPropertyName);
}
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
//Populate some Contacts with random strings
ObservableCollection<Contact> tempContactsOC = new ObservableCollection<Contact>();
for (int i = 0; i < 50; i++)
{
Contact tempContact=new Contact(){Name = RandomString(12,false,i) + " - " + i, JobTitle=RandomString(18,false,i)};
tempContactsOC.Add(tempContact);
}
//Create our Nested ObservableCollection
GroupedContacts = CollectionHelpers.CreateGroupedOC(tempContactsOC);
}
#region Random String generator
/// <summary>
/// Generates a random string with the given length
/// </summary>
/// <param name="size">Size of the string</param>
/// <param name="lowerCase">If true, generate lowercase string</param>
/// <returns>Random string</returns>
private string RandomString(int size, bool lowerCase, int seed)
{
StringBuilder builder = new StringBuilder();
Random random = new Random((int)DateTime.Now.Ticks * seed);
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
if (lowerCase)
return builder.ToString().ToLower();
return builder.ToString();
}
#endregion
}
}

If you think you can make this simpler or better please let me know. Thanks.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Cultures (CultureInfo and RegionInfo) Not supported on Windows Phone 7

Here is a list of cultures from the Microsoft Silverlight supported cultures listing (CultureInfo Class) that I have discovered are not currently (11/11/2010) NOT supported on the Windows Phone 7 platform.

ar-DZ

Arabic (Algeria)

ar-BH

Arabic (Bahrain)

ar-EG

Arabic (Egypt)

ar-IQ

Arabic (Iraq)

ar-JO

Arabic (Jordan)

ar-KW

Arabic (Kuwait)

ar-LB

Arabic (Lebanon)

ar-LY

Arabic (Libya)

ar-MA

Arabic (Morocco)

ar-OM

Arabic (Oman)

ar-QA

Arabic (Qatar)

ar-SA

Arabic (Saudi Arabia)

ar-SY

Arabic (Syria)

ar-TN

Arabic (Tunisia)

ar-AE

Arabic (U.A.E.)

ar-YE

Arabic (Yemen)

hy-AM

Armenian (Armenia)

zh-HK

Chinese (Hong Kong SAR, PRC)

zh-MO

Chinese (Macao SAR)

zh-SG

Chinese (Singapore)

hr-BA

Croatian (Bosnia and Herzegovina)

dv-MV

Divehi (Maldives)

fa-IR

Farsi (Iran)

gu-IN

Gujarati (India)

he-IL

Hebrew (Israel)

hi-IN

Hindi (India)

kn-IN

Kannada (India)

kk-KZ

Kazakh (Kazakhstan)

syr-SY

Syriac (Syria)

ta-IN

Tamil (India)

te-IN

Telugu (India)

th-TH

Thai (Thailand)

ur-PK

Urdu (Pakistan)

vi-VN

Vietnamese (Vietnam)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by: nrogoff
Posted on: 11/11/2010 at 11:38 AM
Tags: ,
Categories: .Net Development | Windows Phone 7
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Windows 2008 R2 Hyper-V - Guests VMs have slow performance - Change you adapter settings

If you are experiencing very slow or ‘jittery’ network performance when attempting to connect to them using remote desktop or file shares, then it may well be down to a couple of settings on your adapters.

I had this experience on two types of network cards. A Marvell Yukon 88E8056 and a Realtek RTL8187. After much head bashing I found various bits of info about the network adapter settings and made the following changes.

On the Host Hyper-V Server

On all network adapter configuration I disabled the following

  • IPv4 Checksum Offload
  • Large Send Offload (IPv4)
  • TCP Checksum Offload (IPv4)

image

This seemed to do most of the work, but just to be sure I also tackled the guests.

On the Guest VMs

On all network adapter configuration I disabled the following

  • IPv4 Checksum Offload
  • Large Send Offload Version 2(IPv4)
  • TCP Checksum Offload (IPv4)

image

If these don’t work for you then I have also heard of success switching to the legacy network adapter in the guest VM. Also ensure that your flow control is enabled on your host NICs.

To get to the Adapter configuration

settings open the 'Network and Sharing Center', click on 'Change adapter settings', then right-click on the adapter and select properties. Now click the 'Configure' button.

image

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by: nrogoff
Posted on: 9/24/2010 at 11:12 AM
Categories: Windows | Hyper-V
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Windows Server Backup–Can't handle greater than 2TB Volumes

I have just discovered that Windows Server Backup on Windows server 2008 R2 is incapable of backing up any volume 2TB or over. This, it turns out, is due to a VHD file limit. Backup essentially creates a VHD for each volume in the backup, which is great for recovery, but causes this annoying problem.

The not very helpful message you will receive if you try a full server backup when one of the volumes is too large is

"Volumes larger than 2088958 megabytes cannot be protected."

error message.png

The work-around is to not do full volume backups, but make your selection of folders. Choose 'Custom' backup configuration and then just select all the folders on the volume that is too large.

 

Technorati Tags: ,,

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by: nrogoff
Posted on: 9/21/2010 at 11:53 AM
Categories: Windows | Backup
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Easy guide to configuring Windows 2008 Firewall for SQL 2008 R2

After installing SQL Server 2008 R2 on a Windows 2008 server you will need to configure the firewall (if it’s turned on!) to allow access to the SQL server. Here is the simple method using the interface and assumes the following:

  • The SQL Instance is the default (first installed)
  • The ports have not been manually configured
  • Nothing too exotic like database mirroring is required.
  1. Open the Firewall either from the Control panel
    image
    or by running WF.msc
  2. There are 3 default firewall profiles. One or more can be active depending on what and how you have configured your NICs. You will need to ensure you are editing the correct profile. Here you can see that mine is on a domain, so my Domain Profile is Active.
    image
  3. Select ‘Inbound Rules’ in the left hand pane.
  4. Click on ‘New Rule…’ in the right actions pane.
  5. select Port Rule Type and click Next>
    image
  6. Set TCP and Specific local Ports to 1433 and click Next>
    image
  7. Leave the default of ‘Allow the connection’ and click Next>
  8. If you don’t ever want SQL to be directly accessible on a Public network (assuming you are going to ever connect your SQL server directly to the internet for some reason!!) then un-check the ‘Public’. Otherwise just click Next>
  9. Name it SQLPort and give it a description and click Finish.
    image

 

That will enable inbound connections to your SQL Server. If you are also enabling SQL Browser Service then you will need to add UDP Port 1434 too another inbound rule.

If you have more than one instance of SQL then you will need to set the port and create rules for them.

For full details on ports and setting it up go to http://msdn.microsoft.com/en-us/library/cc646023(v=SQL.105).aspx

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by: nrogoff
Posted on: 9/21/2010 at 5:37 AM
Categories: SQL | SQL Server | Windows
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

How to bulk unblock files in Windows 7 or Server 2008

In Windows 7 (actually any of the latest Windows releases) you will find that files copied to your local drives are not trusted until you right-click on them and in the properties click the ‘Unblock’ button. This is all very well for one or two files, but gets extremely tedious with more. It turns out to be related to NTFS’s ability to allow alternate data streams.

So here is a simple method of mass or bulk unblocking files.

  1. Download the Sysinternals Streams.exe from http://technet.microsoft.com/en-us/sysinternals/bb897440.aspx
  2. I find Sysinternals so useful I create a ‘SysInternals’ folder on my C: drive and then put this into my ‘path’ environment variable so that I can run them from anywhere. However, if this is too much then the easiest is to copy the streams.exe to the root folder you wish to have files unblocked.
  3. In a command windows, use ‘cd’ to navigate to your folder.
  4. Type the command ‘streams –s –d subfoldername’ and press enter.

Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by: nrogoff
Posted on: 9/1/2010 at 7:57 AM
Tags: , , , ,
Categories: .Net Development | Windows | Windows 7 | security
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

SQL script to kill all connections to a SQL Server database

I have finally perfected a nice script for killing connections to databases. Although basic, I found many of the ones I google'd, had one problem or another that stopped them working straight away, which just wastes time. This one works! I have just used it.

Just replace the database name and it's good. It is easy to alter it to work across a list of databases too.

-- =============================================
-- Author:        Nicholas Rogoff
-- Create date: 04/03/2010
-- Description:    Script that Kills all connections to a database
-- except the current one
-- =============================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
 
DECLARE    @execSql NVARCHAR(1000)
DECLARE @databaseName VARCHAR(100)
DECLARE @NoKilled INT
 
-- *** CHANGE THE NAME OF THE DATABASE *** ---
SET @databaseName = '#### Replace this with a database name here ####'   
  
PRINT 'START: Killing active connections to the "' + @databaseName + '" database'  
 
-- Count Connections
select @NoKilled = COUNT(*)  
from master.dbo.sysprocesses   
where db_name(dbid) = @databaseName   
 and  
 DBID <> 0   
 and  
 spid <> @@spid 
  
-- Create the sql to kill the active database connections   
set @execSql = ''  
select @execSql = @execSql + 'kill ' + convert(char(10), spid) + ' '  
from master.dbo.sysprocesses   
where db_name(dbid) = @databaseName   
 and  
 DBID <> 0   
 and  
 spid <> @@spid   
exec (@execSql)   
 
PRINT 'END: Killed "' + CAST(@NoKilled AS VARCHAR(4)) 
+ '" active connections to the "' + @databaseName + '" database'  
 
 
GO

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by: nrogoff
Posted on: 3/4/2010 at 4:23 AM
Tags:
Categories: SQL | SQL Server | T-SQL
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

How to fix Adobe PDF preview in 64 bit Windows

This will fix previews in both Outlook and Windows explorer on Windows 7 64 bit machines.

If you get

This file cannot be previewed because of an error with the following previewer: PDF Preview Handler for Vista

in outlook when trying to preview PDF's or just get no previews of PDF's in explorer..

..then try the following.

Caution: Changing the registry should be done with great care?so make a backup of any changes!

  1. Start the Registry editor by using Start->Run (or Windows Key + R) and type regedit and click OK
  2. Expanding the tree to locate
    HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Classes\CLSID\{DC6EFB56-9CFA-464D-8880-44885D7DC193} and select it.
  3. Now to make a backup of the previous settings just in case this does not work for you, right-click on the branch in the left pane and select export. Choose a location you can find again later (just in case! Although you should do this for any registry changes too.). You only need to export the selected branch. Windows 7 automatically takes full registry snapshot in case of major problems.
  4. Now on the right hand side double-click to edit the AppID value and change it to {534A1E02-D58F-44f0-B58B-36CBED287C7C}.
  5. I preview started working immediately even without restarting outlook! However you may need to restart?

Now, I can't take credit for this brilliant solution. I found it at http://bink.nu/news/fix-adobe-pdf-preview-handler-on-64-bit-windows.aspx and only write it again here to make it easier to find for all! Why adobe don't fix this I am not sure!

See also http://nrogoff.spaces.live.com/blog/cns!A5B6DA80CCEA9EBC!1593.entry

Technorati Tags: ,,,

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by: nrogoff
Posted on: 1/15/2010 at 2:52 AM
Tags: , , , , ,
Categories: Windows 7
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Easy Deep Zoom Panoramas with Microsoft?s ICE

Microsoft Research have produced a great panorama application that requires almost no input at all! It?s called Microsoft Image Composite Editor (ICE).

image

Now there are several programs out there that will do panoramas and you probably got one with your camera. However what is really great with this is the stitching algorithm seems very good and best of all is the very easy export to Deep Zoom Tileset!

(For more info on Deep Zoom see http://msdn.microsoft.com/en-us/library/cc645050(VS.95).aspx or for the very good Deep Zoom Composer application for creating them go to http://msdn.microsoft.com/en-us/library/dd409068.aspx)

It can also export in a new format called HD View.

(For information on this tool and plug-in see http://research.microsoft.com/en-us/um/redmond/groups/IVM/HDView/HDcreate.htm.)

You just add your images and the rest is pretty much done for you. I have quickly tried it a on a couple of panorama I took while on holiday in Spain. These are the out the box Deep Zooms and took no other intervention from me. 5 minutes and done.

This one was taken on a tripod using a Nikon D300. 15 Images.

Click to see Deep Zoom Panorama of the Villa

and this using a compact Panasonic DMC-FT1 camera hand held, but using the Panorama help function. 7 Images.

Click to see Deep Zoom Panorama of Andalucia

You can get and download ICE for free at http://research.microsoft.com/en-us/um/redmond/groups/ivm/ICE/

 

 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by: nrogoff
Posted on: 9/12/2009 at 2:40 AM
Categories: Silverlight | Deep Zoom
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Creating alternative sub-sites in a Publishing Site in SharePoint (MOSS)

It is easy to be lead into believing that you can only create another Publishing site as a sub-site of an existing Publishing site in SharePoint 2007 (MOSS). This is however only because that is the only site template on offer to you by default.

There are two things you can do. Use command line methods for adding sites or allow more templates to be used. For reasons only known to Microsoft they have made the second option a struggle to find. 

The easy way to manage which Site Templates is to simply add the following the URL of the Main publishing site

/_Layouts/AreaTemplateSettings.aspx

example:

http://www.MyPublishingSite.com/_Layouts/AreaTemplateSettings.aspx

 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by: nrogoff
Posted on: 8/6/2009 at 1:30 PM
Tags: , ,
Categories: MOSS
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed