-----------------------------------

Acquista i software ArcGIS tramite Studio A&T srl, rivenditore autorizzato dei prodotti Esri.

I migliori software GIS, il miglior supporto tecnico!

I migliori software GIS, il miglior supporto tecnico!
Azienda operante nel settore GIS dal 2001, specializzata nell’utilizzo della tecnologia ArcGIS e aderente ai programmi Esri Italia Business Network ed Esri Partner Network

-----------------------------------



Visualizzazione post con etichetta ArcEngine. Mostra tutti i post
Visualizzazione post con etichetta ArcEngine. Mostra tutti i post

domenica 13 giugno 2010

Singletons e System.__COMObject

Quando un ArcObject (basato su COM) in ambiente .NET viene istanziato via interop con la parola riservata 'new', viene preso un riferimento all'oggetto stesso tramite un wrapper .NET Framework fortemente tipizzato (runtime callable wrapper (RCW)). Un RCW è un oggetto gestito che può trattenere un oggetto COM in una applicazione .NET.

Vediamo un esempio:

IEnvelope env = new EnvelopeClass();


In questo caso, in fase di compilazione, il compilatore conosce il tipo esatto della variabile tramite Reflection e metadati ed a runtime utilizza questa informazione per sapere il tipo esatto della variabile.

Vediamo un altro esempio:

            IEnvelope a = axMapControl1.Extent;

            try
            {
                EnvelopeClass b = (EnvelopeClass)a;
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }


In questo caso, quando il codice è compilato, il compilatore sa solo che la proprietà Extent restituisce un oggetto che implementa l'interfaccia IEnvelope ma non può sapere il tipo della classe dell'oggetto. Sebbene possiamo sempre 'castare' ad interfacce che implementano Envelope, il runtime .NET 'wrappa' il riferimento all'oggetto COM tramite un RCW generico chiamato System.__ComObject.
Riprendendo l'esempio, se proviamo a 'castare' la variabile a in EnvelopeClass otterremmo un errore perchè non possiamo 'castare' da un System.__ComObject ad una classe.



Possiamo, come abbiato detto, castare mediante le interfacce che sono implementate dall'oggetto ma, come potete vedere, l'oggetto è un System.__ComObject.

Invece nel primo esempio che abbiamo visto l'rcw è fortemente tipizzato:




Vediamo ora cosa succede con gli oggetti Singleton.
Gli oggetti singleton supportano una sola istanza dell'oggetto (vedi post).
Dalla ArcGIS 9.x, gli oggetti singleton sono singletons per thread e non per processo (vedi post).

Anche qui vale quello che abbiamo detto precedentemente solo che, se dovessimo istanziare un nuovo oggetto, prenderemmo come riferimento l'istanza corrente.
Per esempio:
IWorkspaceFactory workspaceFactory = new AccessWorkspaceFactoryClass();

            IWorkspaceFactory workspaceFactory1 = new AccessWorkspaceFactoryClass();

            if (object.ReferenceEquals(workspaceFactory, workspaceFactory1))
                System.Windows.Forms.MessageBox.Show("workspaceFactory and workspaceFactory1: same reference");


            SpatialReferenceEnvironment spatialReferenceEnvironment = new SpatialReferenceEnvironmentClass();
            SpatialReferenceEnvironment spatialReferenceEnvironment1 = new SpatialReferenceEnvironmentClass();

            if (object.ReferenceEquals(spatialReferenceEnvironment, spatialReferenceEnvironment1))
                System.Windows.Forms.MessageBox.Show("spatialReferenceEnvironment and spatialReferenceEnvironment1: same reference");

AccessWorkspaceFactoryClass e SpatialReferenceEnvironment sono singleton (vedi qui l'elenco degli oggetti singleton negli arcobjects).  In questo caso, dopo aver istanziato la classe, se la dovessimo reinstanziare, otterremmo lo stesso riferimento (verifica con il metodo ReferenceEquals). Non si può dire lo stesso di una classe non singleton. Env e env1 non rappresentano la stessa istanza:

IEnvelope env = new EnvelopeClass();
            IEnvelope env1 = new EnvelopeClass();
            if (object.ReferenceEquals(env, env1))
                System.Windows.Forms.MessageBox.Show("env and env1: same reference");
            else
                System.Windows.Forms.MessageBox.Show("env and env1: Not the same reference");

Con gli oggetti singleton, a differenza di quelli non singleton, potremmo incorrere nell'errore precentemente visto ("Impossibile eseguire il cast...") anche con un semplice new

IWorkspaceFactory workspaceFactory = new AccessWorkspaceFactoryClass();


Questo perchè è possibile che sia presente già la singola istanza come RCW non fortemente tipizzato e quindi il cast fallisce anche se si fa riferimento con un'interfaccia perchè il new tenta di 'castare' da RCW non tipizzato a RCW tipizzato e l'operazione fallisce. Ad esempio tools in ArcObjects scritti .NET da terze parti potrebbero 'wrappare' un oggetto in un generico wrapper causando l'errore.

In questo esempio non fallisce perchè supponiamo di trovarci nel caso in cui non siamo in presenza di una istanza già presente (AccessWorkspaceFactoryClass) e non tipizzata ( System.__ComObject ) e quindi il cast viene eseguito:

IWorkspaceFactory workspaceFactory = new AccessWorkspaceFactoryClass();
IWorkspaceFactory workspaceFactory1 = new AccessWorkspaceFactoryClass();


Per evitare comunque il possibile errore precedentemente descritto è buona regola utilizzare la classe Activator per assicurare che l'oggetto singleton sia wrappato con un rcw fortemente tipizzato quando fai riferimento ad esso per la prima volta. Usando il metodo CreateInstance della class Activator invece di usare il new, l'Activator è abilitato a prendere le informazioni (metadato) per eseguire il cast.

Type factoryType = Type.GetTypeFromProgID(
                  "esriDataSourcesGDB.AccessWorkspaceFactory");
            IWorkspaceFactory workspaceFactory = (IWorkspaceFactory)
              Activator.CreateInstance(factoryType);

mercoledì 24 dicembre 2008

ComReleaser - gestione del ciclo di vita dei cursori

I cursori del geodatabase dovrebbero sempre venire esplicitamente distrutti in un ambiente che utilizza la garbage collection. La regola è sempre rilasciare un oggetto COM non appena l'applicazione ha finito di utilizzare il suo riferimento. Questo è particolarmente importante con i cursori del geodatabase poichè fallire il rilascio dei cursori può mettere in uno stato di lock il sistema e le risorse dbms; un sintomo comune è il blocco di una tabella per un tempo indeterminato dopo
aver finito di ciclare sulle righe con un search cursor.
Questo articolo è una lettura fondamentale per gli sviluppatori che usano il geodatabase API: dimostra l'importanza di rilasciare gli oggetti COM (e specialmente i cursori) e di utilizzare un approccio diverso.
Molti sviluppatori .NET che hanno lavorato con il COM interop conosceranno già il metodo statico Marshal.ReleaseComObject, ma c'è anche una sezione dedicata ad una classe nell'ADF chiamata ComReleaser che è veramente utile quando si lavora con i cursori.

Ecco un esempio dell'uso del ComReleaser per assicurarsi che il cursore sia propriamente rilasciato:


using (ComReleaser comReleaser = new ComReleaser())

        {

 

            // Istanzia un cursore e gestisci il ciclo di vita con il ComReleaser.

 

            IFeatureCursor featureCursor = featureClass.Search(null, true);

 

            comReleaser.ManageLifetime(featureCursor);

 

 

 

            // Cicla attraverso le features.

 

            IFeature feature = null;

 

            while ((feature = featureCursor.NextFeature()) != null)

            {

 

                // Fai qualcosa

 

            }

 

        }



Indipendentemente da come il codice lascia questo blocco using (se un valore è restituito, se viene gettata un'eccezione o esce) il
cursore comunque avrà il proprio reference count correttamente decrementato.

Vedi articolo

lunedì 15 dicembre 2008

EMAB (Logger)

I have used EMAB for simplification ( EMAB download )
for this project.

Nevertheless now it has been overcome by Enterprise Library 4.1 ( Enterprise Library 4.1 download )

For details see Best practises Microsoft


App.Config:


<?xml version="1.0"?>

<configuration>

 

 

 

 

  <configSections>

    <section name="exceptionManagement" type="Microsoft.ApplicationBlocks.ExceptionManagement.ExceptionManagerSectionHandler,Microsoft.ApplicationBlocks.ExceptionManagement" />

  </configSections>

 

 

  <exceptionManagement mode="on">

    <publisher assembly="MapControlEMAB" type="Studioat.ArcEngine.AppBase.Classes.EM" fileName="LogError.txt" sendEMail="off" operatorMail="xxxx@gmail.it" operatorFrom="xxxx@yahoo.it" subject="Logger MapControlEMAB"  host="smtp.mail.yahoo.it" user="" password=""/>

  </exceptionManagement>

 

</configuration>




mode="on|off" enable/disable log
assembly="MapControlEMAB" assembly which holds the custom class to manage log
type="Studioat.ArcEngine.AppBase.Classes.EM" custom class to manage log
fileName="LogError.txt" name of the log file created in bin

sendEMail="on|off" enable/disable log on email
operatorMail="xxxx@gmail.it" mail to
operatorFrom="xxxx@yahoo.it" mail from
subject="Logger MapControlEMAB" subject
host="smtp.mail.yahoo.it" smtp
user="" authentication user mail
password="" authentication password mail


From menu select 'Demo Log':

In this sample the error is in the log:

try

            {

                int a = 1, b = 0, c;

 

                c = a / b;

 

            }

            catch (Exception ex)

            {

 

                ExceptionManager.Publish(ex);

 

            }

            finally

            {

 

                MessageBox.Show("See new entry in LogError.txt", "Logger");

 

            }




In this sample the error is in the log plus your extra information:

try

            {

                int a = 1, b = 0, c;

 

                c = a / b;

 

            }

            catch (Exception ex)

            {

 

                NameValueCollection nvc = new NameValueCollection();

                nvc.Add("Info", "My comments bla bla bla:\n\n");

                ExceptionManager.Publish(ex, nvc);

 

 

            }

            finally

            {

 

                MessageBox.Show("See new entry in LogError.txt", "Logger");

 

            }




In this sample the error without handling Exception (remember that to see this error you can't be in debug but you must run directly exe.)


int a = 1, b = 0, c;

 

            c = a / b;





In form main we set UnhandledException for unhandling errors

/// <summary>

    /// The main entry point for the application.

    /// </summary>

    [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]

    [STAThread]

    static void Main()

    {

 

 

        #region manager error

        Application.ThreadException += new ThreadExceptionEventHandler(frmMain.UIThreadException);

        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

 

 

        AppDomain.CurrentDomain.UnhandledException +=

            new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        #endregion manager error

 

 

        Application.Run(new frmMain());

    }

    #region manager error

    private static void UIThreadException(object sender, ThreadExceptionEventArgs t)

    {

        DialogResult result = DialogResult.Cancel;

        try

        {

            result = ShowThreadExceptionDialog("Error", t.Exception);

        }

        catch (Exception ex)

        {

            try

            {

                MessageBox.Show("Error", "Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop);

                ExceptionManager.Publish(ex);

            }

            finally

            {

                Application.Exit();

            }

        }

 

 

        if (result == DialogResult.Abort)

            Application.Exit();

    }

    private static DialogResult ShowThreadExceptionDialog(string title, Exception e)

    {

        string errorMsg = "Contact admin with following info:\n\n";

        errorMsg += e.Message + "\n\nStack Trace:\n" + e.StackTrace;

        return MessageBox.Show(errorMsg, title, MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop);

    }

    private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)

    {

        try

        {

            Exception ex = (Exception)e.ExceptionObject;

 

 

            NameValueCollection nvc = new NameValueCollection();

            nvc.Add("Info", "Contact admin with these info errors:\n\n");

            ExceptionManager.Publish(ex, nvc);

 

 

        }

        catch (Exception exc)

        {

            try

            {

 

                ExceptionManager.Publish(exc);

            }

            finally

            {

                Application.Exit();

            }

        }

    }

    #endregion manager error





class EM inherits from IExceptionPublisher and is the custom class used for the logger.



Here you can download the soluzion VS2008 Logger Error

sabato 15 novembre 2008

Object initializers con AO

In .NET 3.0 è stato introdotto un nuovo approccio all'inizializzazione degli oggetti: object initializers.
Questo consente di istanziare e inizializzare il tutto in una singola riga.

Una istanza di ESRI.ArcGIS.Geometry.Point può essere creata in .NET 3.0:

IPoint point = new PointClass { X = 3.5, Y = 5.8 };




Può essere pratico nel caso in cui multiple Interface sono richieste per inizializzare un oggetto che richiederebbero nel caso del casting (per esempio utilizzando IQueryFilter and IQueryFilterDefinition per inizializzare un query filter).

IQueryFilter queryFilter = new QueryFilterClass { WhereClause = "PID > 40", PostfixClause = "ORDER BY PID" };

 

        IDatasetName datasetName = new FeatureClassNameClass { Name = "Parcels", WorkspaceName = wsName };

 

        ILine line = new LineClass { FromPoint = point1, ToPoint = point2 };



Questo approccio è comunque da evitare quando:

- una proprietà può gettare un errore perchè nel caso sarebbe difficoltoso 'debuggare'.

- il codice può diventare difficile da leggere quando siamo in presenza di diverse interfacce ereditate dalla classe (per esempio Field)

Vedi articolo

Singleton class in c#

Quando hai bisogno di creare una classe che ha una sola istanza nella tua applicazione occorre creare una singleton class.

In c# con l'inizializzazione statica è semplice:

public sealed class Singleton

    {

        private static readonly Singleton instance = new Singleton();

 

        private Singleton() { }

 

        public static Singleton Instance

        {

            get

            {

                return instance;

            }

        }

    }



Mettendo a readonly la variabile privata statica instance verrà inizializzata solo o in un costruttore statico o in una inizializzazione statica (come in questo caso).

L'istanziazione della classe avverrà solo quando verrà chiamata la proprietà pubblica instance.

La classe è sealed per evitare di creare istanze dalle classi derivate.


Lavorare in ambiente multithreaded ed assicurarti la thread safety

Con questo approccio ci assicuriamo che venga creata una sola istanza e soltanto quando necessario.
La variabile è volatile per permettere di accederci una volta completato l'assegnamento alla variable stessa.
Per evitate deadlock si utilizza una istanza di un oggetto (syncRoot) sul lock.


using System;

 

public sealed class Singleton

{

    private static volatile Singleton instance;

    private static object syncRoot = new Object();

 

    private Singleton() { }

 

    public static Singleton Instance

    {

        get

        {

            if (instance == null)

            {

                lock (syncRoot)

                {

                    if (instance == null)

                        instance = new Singleton();

                }

            }

 

            return instance;

        }

    }

}

venerdì 7 novembre 2008

Background worker

using System;

using System.ComponentModel;

using System.Windows.Forms;

using ESRI.ArcGIS.ADF;

using ESRI.ArcGIS.Geodatabase;

 

//Author: Domenico Ciavarella

//www.studioat.it

namespace Studioat.ArcEngine.Forms

{

    public partial class frmBW : Form

    {

 

        BackgroundWorker backGroundWorker = null;

        enum operation { start, stop };

        public IFeatureClass FeatureClass

        {

            get;

            set;

        }

 

 

        #region Ctor

        public frmBW()

        {

            InitializeComponent();

 

        }

 

        public frmBW(IFeatureClass featureClass):this()

        {

 

 

            FeatureClass = featureClass;

 

 

        }

        #endregion Ctor

 

        private void btnStart_Click(object sender, EventArgs e)

        {

 

            Operation(operation.start);

            RunWorker();

 

 

        }

        private void btnStop_Click(object sender, EventArgs e)

        {

 

            backGroundWorker.CancelAsync();

 

 

        }

 

        #region private method

        void Operation(operation op)

        {

 

            btnStart.Enabled = (op == operation.stop);

            btnStop.Enabled = (op == operation.start);

            InitializeProgressBar();

        }

        void InitializeProgressBar()

        {

            progressBar.Maximum = 100;

            progressBar.Minimum = 0;

            progressBar.Value = 0;

        }

        void RunWorker()

        {

 

           backGroundWorker = new BackgroundWorker();

           backGroundWorker.WorkerReportsProgress = true;

           backGroundWorker.WorkerSupportsCancellation = true;

           backGroundWorker.DoWork += new DoWorkEventHandler(doWork);

           backGroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(runWorkerCompleted);

           backGroundWorker.ProgressChanged += new ProgressChangedEventHandler(progressChanged);

           backGroundWorker.RunWorkerAsync(FeatureClass);

 

        }

        #endregion private method

 

        #region BackgroundWorker

        void doWork(object sender, DoWorkEventArgs e) {

 

                BackgroundWorker senderWorker = sender as BackgroundWorker;

 

                IFeatureClass featureClass = e.Argument as IFeatureClass;

                int featureCount = featureClass.FeatureCount(null);

 

                IFeatureCursor featureCursor = featureClass.Search(null, true);

                IFeature feature = featureCursor.NextFeature();

 

                int i = 0;

                while (feature != null)

                {

 

                    //////////////////////////////////////

                    //////////////here your work

                    //System.Threading.Thread.Sleep(1000);

                    //////////////////////////////////////

 

                    ++i;

                    int progressInPercent = (int)(((decimal)(i) / (decimal)featureCount) * 100);

 

                    backGroundWorker.ReportProgress(progressInPercent, feature.OID);

 

 

 

 

 

                    if(senderWorker.CancellationPending) {

 

                        e.Cancel = true;

 

                        break;

 

                    }

 

                    feature = featureCursor.NextFeature();

 

                }

 

                ComReleaser.ReleaseCOMObject(featureCursor);

 

            }

        void runWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

        {

 

 

 

                if (e.Cancelled)

                   lblStatus.Text = "work was cancelled.";

                else

                   lblStatus.Text = "work finished processing request.";

 

                Operation(operation.stop);

 

        }

        void progressChanged(object sender, ProgressChangedEventArgs e) {

 

            progressBar.Value = e.ProgressPercentage;

 

            lblStatus.Text = string.Format("working on OID of: {0}",e.UserState);

 

        }

        #endregion

 

 

 

    }

}





Qui puoi scaricare la soluzione in VS2008 MapControlBW

mercoledì 5 novembre 2008

Extension method

Esempio di Extension method su IFields

namespace Studioat.ArcEngine

{

    public static class Helper

    {

 

        public static IField get_Field(this IFields fields, string FieldName)

        {

            int i = fields.FindField(FieldName);

 

            return (i==-1)?null:fields.get_Field(i);

 

        }

 

    }

 

}






IField field = featureClass.Fields.get_Field("MyFieldName");

mercoledì 22 ottobre 2008

Esempio Linq utilizzato con ClassBreaks




using System;

using System.Collections.Generic;

using System.Drawing;

using System.Linq;

using ESRI.ArcGIS.ADF.BaseClasses;

using ESRI.ArcGIS.Carto;

using ESRI.ArcGIS.Controls;

using ESRI.ArcGIS.Display;

using ESRI.ArcGIS.esriSystem;

using ESRI.ArcGIS.Geodatabase;

namespace Studioat.ArcEngine

{

 

  public sealed class Classify : BaseCommand

  {

 

 

    private IHookHelper m_hookHelper = null;

    private ITOCControl2 m_tocControl = null;

    public Classify(ITOCControl2 tocControl)

    {

 

      base.m_caption = "Classify LINQ";

 

      m_tocControl = tocControl; 

 

      try

      {

        string bitmapResourceName = GetType().Name + ".bmp";

        base.m_bitmap = new Bitmap(GetType(), bitmapResourceName);

      }

      catch (Exception ex)

      {

        System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap");

      }

    }

 

    #region Overriden Class Methods

 

    /// <summary>

    /// Occurs when this command is created

    /// </summary>

    /// <param name="hook">Instance of the application</param>

    public override void OnCreate(object hook)

    {

      if (hook == null)

        return;

 

      try

      {

        m_hookHelper = new HookHelperClass();

        m_hookHelper.Hook = hook;

        if (m_hookHelper.ActiveView == null)

          m_hookHelper = null;

      }

      catch

      {

        m_hookHelper = null;

      }

 

      if (m_hookHelper == null)

        base.m_enabled = false;

      else

        base.m_enabled = true;

    }

 

    /// <summary>

    /// Occurs when this command is clicked

    /// </summary>

    public override void OnClick()

    {

      //nedd to get the layer from the custom-property of the map

      if (null == m_hookHelper)

        return;

 

      //get the mapControl hook

      object hook = null;

      if (m_hookHelper.Hook is IToolbarControl2)

      {

        hook = ((IToolbarControl2)m_hookHelper.Hook).Buddy;

      }

      else

      {

        hook = m_hookHelper.Hook;

      }

 

      //get the custom property from which is supposed to be the layer to be saved

      object customProperty = null;

      IMapControl3 mapControl = null;

      if (hook is IMapControl3)

      {

        mapControl = (IMapControl3)hook;

        customProperty = mapControl.CustomProperty;

      }

      else

        return;

 

      if ((null == customProperty) || !(customProperty is ILayer) || !(customProperty is IFeatureLayer))

        return;

 

 

      IFeatureLayer featureLayer = customProperty as IFeatureLayer;

      IGeoFeatureLayer geoFeatureLayer = featureLayer as IGeoFeatureLayer;

      IFeatureClass featureClass = geoFeatureLayer.DisplayFeatureClass;

 

      string sFieldName = "Popolazione";

      int numClasses = 5;

 

 

      IBasicHistogram basicHistogram = new BasicTableHistogram();

      ITableHistogram tableHistogram = basicHistogram as ITableHistogram;

      tableHistogram.Field = sFieldName;

      tableHistogram.Table = featureClass as ITable;

 

      object oVals =new object();

      object oFreqs =new object();

      basicHistogram.GetHistogram(out oVals, out oFreqs);

      IClassifyGEN classifyGEN = new NaturalBreaks();

 

      classifyGEN.Classify(oVals, oFreqs, ref numClasses);

 

      IClassBreaksRenderer render = new ClassBreaksRenderer();

      double[] cb = (double[])classifyGEN.ClassBreaks;

 

      double[] dVals = (double[])oVals;

      int[] iFreqs = (int[])oFreqs;

 

      var dValsL = dVals.Select((num, index) => new { Num = num, Index = index });

      var iFreqsL = iFreqs.Select((num, index) => new { Num = num, Index = index });

 

      var pairs = from a in dValsL join b in iFreqsL on a.Index equals b.Index select new { Values = a.Num, Frequency = b.Num };

 

 

      List<int> listCount = new List<int>();

 

      for (int i = 0; i < numClasses; i++)

      {

 

          var a = from p in pairs where ((i == 0) ? (p.Values >= cb[i]) : (p.Values > cb[i])) && p.Values <= cb[i + 1] select new { p.Frequency };

          int j = a.Sum(p => p.Frequency);

          listCount.Add(j);

 

      }

 

 

      render.Field = sFieldName;   

      render.BreakCount = numClasses;   

      render.MinimumBreak = cb[0];   

 

 

 

 

      IAlgorithmicColorRamp colorRamp = new AlgorithmicColorRamp();

      colorRamp.Algorithm = esriColorRampAlgorithm.esriCIELabAlgorithm;  

 

 

      IRgbColor color1 = new RgbColor();

 

      IRgbColor color2 = new RgbColor();

      color1.Red = 255 ;  

      color1.Green = 210;   

      color1.Blue = 210;   

      color2.Red = 190;   

      color2.Green = 0;   

      color2.Blue = 170;   

      colorRamp.FromColor = color1;   

      colorRamp.ToColor = color2;   

      colorRamp.Size = 5 ;

      bool ok = true;

      colorRamp.CreateRamp (out ok);

 

 

      IClassBreaksUIProperties  classBreaksUIProperties = render as IClassBreaksUIProperties;   

      classBreaksUIProperties.ColorRamp = "Custom";

      IEnumColors enumColors = colorRamp.Colors; 

      enumColors.Reset(); 

      for (int i = 0;i<numClasses;i++)

      {

        render.set_Break(i,cb[i + 1]);

 

        render.set_Label(i, string.Format("{0} - {1} - Count {2}", cb[i], cb[i + 1], listCount[i]));

        classBreaksUIProperties.set_LowBreak(i, cb[i]);       

        ISimpleFillSymbol simpleFillSymbol = new SimpleFillSymbol();       

        simpleFillSymbol.Color = enumColors.Next();       

        render.set_Symbol(i,simpleFillSymbol as ISymbol);   

      }                

 

      geoFeatureLayer.Renderer = render as IFeatureRenderer;

 

      mapControl.ActiveView.Refresh();

      m_tocControl.Update();

 

    }

 

    #endregion

  }

}



Qui puoi scaricare la soluzione in VS2008 ClassBreakLinq