Saturday, April 24, 2010

ESRI DevSummit tech sessions. Developing .NET Applications for ArcGIS Engine

Kollat på tech-session-videos som ESRI lagt ut.

I presentationen "Developing .NET Applications for ArcGIS Engine" så går man igenom nyheterna i ArcGIS Engine. Några nyheter är:
  • VS2008, .Net 3.5 SP1.
  • Engine och Desktop är uppdelade som två runtimes.
  • Nytt att man måste aanvända RuntimeManager för att bind mot rätt runtime.
  • Ikonerna skickas med som PNG bilder.
  • GrahicsTracker, ett objekt som hjälper till med realtidsuppdateringar av objekt i kartan.
  • Background GeoProcessing, GeoProcesing kan köras som en separat process.
  • För licenser så har "Concurrent use" och "Borrow/Return" tillkommit.

Saturday, April 17, 2010

Public Resource.resx

Lade till en Resource.resx fil i ett av mina projekt och försökte komma åt ResoureManager objektet från en annat projekt, men fick ett kompileringsfel. :( Det visade sig att VS standardmässigt skapar resursfiler som Internal/Friend isf Public, vilket gör att klasserna bara går att komma åt internt i samma assembly. Detta går att lösa genom att hacka i den automatgenererade koden men det är ajjabajja , det vill man inte göra. Visar sig att det går att byta custom tool som skapar koden, vilket är en bättre lösning:

Byt från ResXCodeFileGenerator till PublicResXFileCodeGenerator så får man en resurs klass som är public.

Hantera ohanterade fel i .Net och CAB.

Hittade en bra artikel om hur man ska hantera ohanterade fel:

Tanken är att man i sin egen kod bara hanterar fel som man vet ska inträffa:

Try
Throw New InvalidAttributeException("Fel på in argumentet!!!")
Catch ex As InvalidAttributeException
'Hanterar felet
End Try


Alla andra fel som man inte vet vad det är låter man propagera hela vägen upp till applikationen som hanterar dom ohanterade felen:

<STAThread()> _
Public Shared Sub Main()
Dim currentDomain As AppDomain = AppDomain.CurrentDomain
AddHandler currentDomain.UnhandledException, AddressOf AppDomainUnhandledException
AddHandler Application.ThreadException, AddressOf ThreadException
app = New Program()
app.Run()
End Sub

Private Shared Sub AppDomainUnhandledException(ByVal sender As Object, ByVal e As UnhandledExceptionEventArgs)
HandleException(CType(e.ExceptionObject, Exception))
End Sub

Private Shared Sub ThreadException(ByVal sender As Object, ByVal ex As System.Threading.ThreadExceptionEventArgs)
HandleException(ex.Exception)
End Sub


Private Shared Sub HandleException(ByVal e As Exception)
'MessageBox.Show("Ohanterat fel har inträffat!!")
End Sub


Fördelarna som jag ser med detta är att man slipper risken att någon att fångar och sväljer fel bara för att dom inte vet vad man ska göra med felet. Samtidigt tycker jag att man alltid ska fånga alla fel som inträffar i sin kod för att kunna logga felen där dom inträffar. Detta står inte i konflikt med varandra eftersom man alltid kan kasta felet vidare efter man fångat ett exception. Dock bör man ha veta hur man gör för att behålla den fulla stacktracen när man gör det se t.ex:

VB.Net och Shared Sub Main

Som standard så startas VB.Net applikatioenr via en Main Formulär men ibland vill man lägga in loggning eller liknande direkt när en appliation startar isf att lägga det i Form_Load. Hade problem med att få en VB.Net applikation att starta via Sub Main:

<STAThread()> _
Public Shared Sub Main()

End Sub


Förväntade mig att se den som ett val under properties på appliaktionen men icke:


Visade sig att det krävs att man klickar ur "Enable application framework" för att Sub Main ska komma upp som val i VB.Net.

Saturday, April 10, 2010

The ArcGIS API for Microsoft Silverlight™/WPF™ hostad i CAB.

Suttit och testat ifall det går att lägga in ESRIs ArcGIS API for Microsoft Silverlight™/WPF™ i en CAB applikation. Skulle vara en grym kombination för kartvisning i CAB baserade applikationer. Har gjort en relativt enkel appliaktion en shell appliaktion som innehåller meny och verktygsfält samt ett workspace för kartan. Gjort en Modul som innehåller en WPF-vy som hostar kart kontrollen samt ett kommando för att sätta om kartan till full utbredning.


Detta visar på att man kan integrera en WPF-vy i ett befintligt system och att det inte blir någon stor skillnad mot att bygga WinForms vyer.

Databinding mot ITable i ArcGIS Engine

Har jobbat med databinding i CAB mot objektstrukturer för att testa hur CAB och MVC patternet fungerar tillsammans med EventBrokern, då frågan kom upp hur gör vi om vi vill kunna göra databinding direkt mot en ITable i ArcObjects? Hittade ett bra exempel http://edndoc.esri.com/arcobjects/9.2/NET/a6eb84fb-93db-4bc3-82a9-874d8890a8ca.htm på ESRIs EDN site som jag modifierat lite och byggt in i ett CAB projekt. Lösningen som dom gjort bygger på att man wrappar ITable i en BindingList.


Applikationen läser in en shapefil som läggs in i kartan och samma kartlager läggs som en ITable in via databinding in i tabellen. Detta gör att förändringar i tabellen slår igenom i kartan.


Bugg i WPF implementationen av CAB ElementHostWorkspace

Hjälpte en kollega igår med ett problem som han brottats med i nästan en vecka. När WPF smartparten stängdes och en Winform smartpart skulle laddas så fick han ett exception InvalidCastException. Eftersom två par ögon ser mer en ett par så gick vi igenom felmeddelandet och stegade fram oss i koden till vi hittade raden som spökade. Vi hittade ett fel i klassen Microsoft.Practices.CompositeUI.WPF.ElementHostWorkspace:

///
/// Raises the event.
///

/// The smart part that is being closed.
protected WorkspaceCancelEventArgs RaiseSmartPartClosing(object smartPart)
{
if (smartPart is ElementHost)
{
smartPart = elementHosts.Unwrap((ElementHost)activeSmartPart);
}
WorkspaceCancelEventArgs cancelArgs = new WorkspaceCancelEventArgs(smartPart);
RaiseSmartPartClosing(cancelArgs);

return cancelArgs;
}



Felet var att variablen activeSmartPart skulle vara smartPart. Såg det genom att man kontrollerar smartPart innan man gör cast och eftersom activeSmartPart är WinForm SmartParten så smäller koden ur vid casten. Vilket innebär att koden ska se ut så här för att fungera:


///
/// Raises the event.
///

/// The smart part that is being closed.
protected WorkspaceCancelEventArgs RaiseSmartPartClosing(object smartPart)
{
if (smartPart is ElementHost)
{
smartPart = elementHosts.Unwrap((ElementHost)smartPart);
}
WorkspaceCancelEventArgs cancelArgs = new WorkspaceCancelEventArgs(smartPart);
RaiseSmartPartClosing(cancelArgs);

return cancelArgs;
}