views:

4225

answers:

13

Hey everyone,

We work extensively in the .Net Compact Framework and Windows Mobile. I've seen plenty of questions come up regarding specifics to development of ASP.Net apps or other .Net based desktop apps but nothing CF specific.

Anyone else a mobile developer out there that can share some things to start doing, stop doing, and avoid doing when developing in the Compact Framework?

+5  A: 

This isn't specific to just Compact Framework devices, however it rears it's ugly head a lot more when developing on them due to resource contraints developing on a mobile platform.


Recently I came across a great post as part of a thread on managing memory leaks which helped me identify a leak I didn't know about in a bug when setting the DataGrid.DataSource in one of our mobile apps.

When binding a DataGrid, you should not directly use something like:

dgDataGrid.DataSource = dsDataSet;

As this creates a new CurrencyManager each time that doesn't properly get disposed of. Instead you want to bind the DataGrid to a BindingSource first in order to avoid the resource leak.

bsData.DataSource = dsDataSet;

dgDataGrid.DataSource = bsData;

Who knew? Scott Langham did in another post. Thanks Scott!

Mat Nadrofsky
+1 because it's just wrong to downvote someone's answer to their own question.
MusiGenesis
I was wondering about the downvote... is there little value in what I posted in your opinion or is it just not the right thread for me to mention it because it's not .Net CF specific.. not sure. I know it was a problem in our mobile app and accentuated by the fact it was on a mobile device.
Mat Nadrofsky
No, your post was very valuable. No clue why someone would down-vote it, unless they thought you're not supposed to answer your own questions, which isn't correct.
MusiGenesis
+75  A: 

Sure:

  • Use a physical device whenever possible (not the emulator)
  • Test with multiple devices (different vendors, different models)
  • Concentrate testing around sleep/wakeup behaviors
  • When using MSTEST unit tests, never use private accessors
  • Avoid ActiveSync like the plague - debug using CoreCon direct
  • Get familiar with RPM and start using it early
  • Reuse objects when possible
  • Avoid doing a lot of work in a Form's ctor - off load it for lazy load or in a background thread
  • Load Forms on demand when possible (not all of them at once)
  • Cache the frequently used Forms, create infrequent ones on demand
  • Keep image resolutions low
  • If a class exposes Dispose use it. Always.
  • No app is too small to benefit from MVC/MVP patterns
  • Don't use the Microsoft CAB/SCSF port for the CF (the people who ported it obviously never actually used a resource-limited device)
  • Get familiar with the concept of "occasionally connected" if you will be doing any remote data/service activity
  • Docking and Anchoring are your friend and your enemy - test run-time screen rotations and multiple resolutions (even if you think you won't target them, because you're probably wrong in that thinking)
  • Look at, but don't heavily invest in the device deployment package project type. It has major limitations that will likely bite you. A batch file works surprisingly well or a custom MSBUILD task to call CabWiz
  • Brush up on your C++ and P/Invoke skills. You will need them. It's almost impossible to write a useful CF app without P/Invoking something.
  • Code to the lowest common denominator for targets.
  • Partial classes are your friend, especially for dividing logic between target types (PPC, Phone, non-mobile CE).
  • Avoid running an app from persistent storage, especially for CE and pre-WInMo 5. Copy to RAM and run from there to prevent demand-paging from killing you, especially after a sleep/wake cycle.
  • Apps should not care about sleep/wake transitions, but that's pure theory. Sleep wake *will change your app behavior, so again test, test, test.
  • Did I mention test? Especially on every device you can get your hands on? Buy cheap hardware off of eBay for your test lab. Having more devices is more important than having the latest unless you intend to use a specific feature of a newer device.
  • Ask for divine intervention if you plan to use bluetooth programmatically. Get familiar with the Widcomm and Microsoft stacks and understand that they aren't the same.
  • Watch the MSDN webcast on memory management in the Compact Framework. Watch it again for the stuff you missed the first time.
  • Watch out for sleep/wake invalidating internal handles and causing access violations. This is more esoteric but certainly happens. For example, if you're running an application off of a storage card, the entire app isn't loaded into RAM. Pieces in use are demand-paged in for execution. This is all well and good. Now if you power the device off, the drivers all shut down. When you power back up, many devices simply re-mount the storage devices. When your app needs to demand-page in more program, it's no longer where it was and it dies. Similar behavior can happen with databases on mounted stores. If you have an open handle to the database, after a sleep/wake cycle the connection handle may no longer be valid.
  • Install the evaluation version of Platform Builder. The source code for a whole lot of things is in there (like the network UI, many drivers, etc) and when your P/Invoke code isn't doing what you expect you'll at least have a place to go look for the "why".

added 5/25/10

added 7/27/10 - If you're after a aesthetic UI, be prepared to do a lot of custom or manual drawing. - If you're doing custom or manual drawing and you need to use transparency, get ready for a load of frustrations and having to write wacky code or call native code directly to work around shortcomings in the CF.

I'm simply adding to the list as they occur to me...

ctacke
An excellent start no doubt! Thanks for the answer. What port/package do you use/recommend for the CF?
Mat Nadrofsky
Well I'm obviously going to recommend the Smart Device Framework. I may be heavily biased, but it's in use by tens of thousands so it must have a reasonable value.
ctacke
All excellent except for caching frequently-used forms. I've found that to be more trouble than it's worth.
MusiGenesis
Based on personal experience in most of these areas, I'd like to give this at least +5. And what you already know about .NET will generally prove to be almost true in CE.
le dorfier
@ctacke: I was wondering if you'd seen this question of mine: http://stackoverflow.com/questions/300607/how-do-i-set-network-management-settings-or-make-the-dialog-appear-in-c-on-wind
MusiGenesis
I assume you've run into this problem before. :)
MusiGenesis
Oh that is a genius post. LMAO @ the SCSF comment. Oh and I will also recommend the Smart Device Framework and I am not biased.
Quibblesome
What is the CoreCon object?
Chris Brandsma
CoreCon is not an object. CoreCon is the transport layer that Studio uses for 'talking' to an attached device.
ctacke
Chris, great list. Can you point to any instructions for how "Avoid ActiveSync like the plague - debug using CoreCon direct" work? My team is having plenty of ActiveSync troubles, but we don't see how CoreCon helps us without ActiveSync.
Eric Farr
@Eric Farr: See this: http://msdn.microsoft.com/en-us/library/ms228708.aspx. Of course it assumes you have some for of connectivity like ethernet.
ctacke
+1. Excellent Tips.
Mitch Wheat
+1.What is RPM ?
Sachin
RPM is the Remote Performace Monitor.
ctacke
+1 Great Tips!!
DevDemon
+5  A: 

If you have to support multiple screen sizes/resolutions, form inheritance is an excellent way to do it. Basically you design your form to fit the standard 320x240 screen. To support a different screen size, you just add a new form, inherit from your custom form (instead of just Form), and then re-arrange the controls as necessary.

Another useful trick is to wrap the ShowDialog call in a way that lets you set the parent form's caption to "" temporarily - this keeps all the open forms in your application from showing up in the running programs list. Another way to enhance the wrapper is to PInvoke SetForegroundWindow with the handle of the parent window. This ensures that the parent will always re-appear after the child is closed; without this call, it's possible for other windows to be inserted in the z-stack above the parent form.

Watch out for encryption on the SD card. SqlCE will stop working altogether. Oracle Lite's behavior under encryption is much more sinister, since parts of it work and parts of it don't.

Avoid SqlCE RDA and merge replication. These would be fantastic tools if they worked reliably, but they don't in situations where the network connection can unexpectedly be dropped during replication (quite common in the WM world). This one bit me HARD with a production app. The MS support tech we dealt with was finally forced to acknowledge that it just doesn't work 100%. Actual quote: "just keep trying to replicate - they'll merge correctly eventually".

MusiGenesis
Thanks for the tips. Some great points made in here! We were going to steer clear of RDA on this project for sure.Also, we've written our own form manager so that we can push and pull forms from our own stack which seems to be working out so far and takes into account your advice. :)
Mat Nadrofsky
I'd suggest starting with supporting 240x240 as a minimum resolution sing where are still a few wm devices that have it.
Joel
@Joel: good point. I wouldn't want to piss off *both* of those guys!
MusiGenesis
+7  A: 

OpenNETCF is a great resource.

Their Smart Device Framework is a real must have when developing with the .NET Compact Framework, as so many of the Full framework features are missing [I think someone once said the .NET Compact Framework is a wrapper around NotImplementedException!]

Mitch Wheat
In the vast majority of cases if you're developing without doing something with OpenNETCF you're probably doing it wrong! :)
Quibblesome
Ine thing I'd caution about it using v. 1.4 - it's several years old now (3 IIRC?) and we've made a *lot* of changes and bug fixes since then.
ctacke
@ctacke : cheers, I've updated (not sure how I managed to put such an old link in!)
Mitch Wheat
+3  A: 

Most out of the ordinary stuff requires direct call the Windows API through P/Invoke. I have found http://www.pinvoke.net/ to be a great resource for P/Invoke on both Win32 and Windows CE.

mliesen
+2  A: 

OpenNet CF is worth looking into - even the free edition has a few useful libs - such as FTP, datagrid additional functionality etc; which is very helpful since CF lacks a lot of .net framework features.

gnomixa
I bet ctacke agrees. :) Thanks for the answer!
Mat Nadrofsky
+1  A: 

When doing anything with OutlookSession, always

  • instantiate it on the main (application) thread
  • execute against it on the main thread (I use a Control object to Invoke against)
  • and dispose of it within a decent timeframe (if you don't you'll have strange behavior in Pocket Outlook)
ZaijiaN
+2  A: 
  • If you are planning to use Sql Server 3.5 Compact read this blog.
  • There are serious performance issues at SQL Server Compact and some code may be 100 times slower on the device compared to the desktop so always test your database code on the device.
  • Setup unit and performance / integration testing on the device. Also very few people actually do this, it's not that complicated and far overweights the costs.
  • If you deploy your code all the time use the network instead of ActiveSync. The easiest way is setting up a simple FTP server or TCP agent on the device.
ollifant
Our "solution" to using SQLCE was to use SQLite. :)
Mat Nadrofsky
+1  A: 

When using a DataGrid you can sort it's contents via the column headers by using the following code originally posted on Chris Craft's blog:

using System.Windows.Forms;
using System.Data;

public static void SortDataGrid(object sender, System.Windows.Forms.MouseEventArgs e)
{
   DataGrid.HitTestInfo hitTest;
   DataTable dataTable;
   DataView dataView;
   string columnName;
   DataGrid dataGrid;

   // Use only left mouse button clicks.
   if (e.Button == MouseButtons.Left)
   {
   // Set dataGrid equal to the object that called this event handler.
   dataGrid = (DataGrid)sender;

   // Perform a hit test to determine where the mousedown event occured.
   hitTest = dataGrid.HitTest(e.X, e.Y);

   // If the MouseDown event occured on a column header,
   // then perform the sorting operation.
   if (hitTest.Type == DataGrid.HitTestType.ColumnHeader)
   {
      // Get the DataTable associated with this datagrid.
      dataTable = (DataTable)dataGrid.DataSource;

      // Get the DataView associated with the DataTable.
      dataView = dataTable.DefaultView;

      // Get the name of the column that was clicked.
      if(dataGrid.TableStyles.Count != 0)
         columnName = dataGrid.TableStyles[0].GridColumnStyles[hitTest.Column].MappingName;
      else
         columnName = dataTable.Columns[hitTest.Column].ColumnName;

      // If the sort property of the DataView is already the current
      // column name, sort that column in descending order.
      // Otherwise, sort on the column name.
      if (dataView.Sort == columnName)
         dataView.Sort = columnName + " DESC";
      else
         dataView.Sort = columnName;
      }
   }
}

private void dgDataGrid_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
   if(dgDataGrid.VisibleRowCount == 0) return;
   SortDataGrid(sender, e);
   dgDataGrid.Select(dgDataGrid.CurrentRowIndex);
}
Mat Nadrofsky
Actually the original original is from Alex Feinman: http://www.alexfeinman.com/download.asp?doc=GridDemo.zip
ctacke
+2  A: 

Unit Testing (TDD) is possible on .net cf. But there are issues.

You will be using MSTest. Not NUnit, MBUnit, XUnit.net, etc. MSTest.

You will need Visual Studio Professional (as near as I can tell). The easiest way to get started is to right-click on a method you would like to test, then select "Create Unit Test". This sets up the test project for you. Only create one test project. It doesn't like having multiple. Just do this to create the project and get all of the dependencies setup for you. Then create your own test classes.

Mock objects could be an issue. RhinoMocks, Moq, and TypeMock all depend on things that are not available in .net cf. Pex has a project calls Stubs that I'm still looking into. Pex is a Microsoft Research project. You you will end up creating custom fake objects instead.

Test are run on the device emulator. That means they have to be deployed. If you get a strange error when you first start up the test runner, you probably do not have .net 3.5 on the device emulator yet. First deploy your project, then run the tests again.

On the non-testing side: You do get LINQ to Objects and LINQ to XML. Both are a godsend. You can talk to a server via WCF, but you don't get all of the endpoints.

Chris Brandsma
+1 - Hey thanks for the Q/A slant. We're getting to the Q/A phase on a major new mobile offering and links like this will help on this, our first time through the gauntlet on shipping a Windows Mobile product.
Mat Nadrofsky
You can put a normal unit test project to unit test a compact framework (Smart Device) project. VS gives you a scary warning, but it is smooth sailing after that.
Vaccano
+1  A: 
  • You will encounter a lot of Bugs and Limitations in .net cf. You will have to monkey patch them. its ugly but you will have no choice.

  • You will end up writing a lot of custom controls. As most of the controls in the framework don't support features that are commonly requested by clients. So its a good practice to create custom controls for each and every control you use from the start. Even though you might not have anything in them when you begin. You can add custom logic later on. Without having to modify a lot of existing code.

  • If you need validation you could use .net validation framework

  • Its a good idea to sperate your code everywhere in your App. You could use the MVC pattern. And if you choose to use it you can get a head start by using MobileMVC
  • If you need a rich UI tool kit you can look at Resco (google it).
  • VS Designer will be your arch enemy.

This is all that i can think of right now.

thekindofme
A: 

When working with Windows Mobile, if you don't want your form to be full screen you need to set the FormBorderStyle to None. If you don't then you will spend hours pulling out your hair wondering why it is resizing automatically to the full screen size (which is in fact a feature of Windows Mobile)

James Hulse
Yep. Waaaay back from 2004: http://blog.opennetcf.com/ctacke/2004/02/02/NonfullscreenFormsOnThePocketPC.aspx
ctacke
Is this only relevant for CF 2.0 or Windows Mobile 6? I can edit my answer to reflect this.
James Hulse
It's relevant to all WinMo platforms, regardless of language (you get the same behavior with a C++ app).
ctacke
+3  A: 

Just as an FYI, if you are upset about not having Compact Framework support in Visual Studio 2010 then go here and vote for it to be added in. (And spread the word)

Vaccano
+1 - Yikes. Not a bad tip, "stick with VS2008 if you're into .Net CF"
Mat Nadrofsky