Id. de artículo: 326145 - Última revisión: jueves, 22 de mayo de 2003 - Versión: 1.2

Cómo: Implementar un GROUP DataSet BY Helper Class en C# .NET

En esta página

Expandir todo | Contraer todo

Resumen

En este artículo paso a paso se describe cómo implementar y cómo utilizar una clase DataSetHelper que incluye código de ejemplo para crear un objeto DataTable que contiene datos agregados de otro objeto DataTable .

Para ello, utilice los métodos públicos siguientes:
  • CreateGroupByTable
  • InsertGroupByInto
  • SelectGroupByInto
El método SelectGroupByInto llama a la CreateGroupByTable y los métodos InsertGroupByInto . También puede utilizar a los miembros de datos y métodos de auxiliar privado para almacenar la lista campo analizada y para tratar correctamente los valores NULL cuando se calculan los valores de agregado.

La clase DataSetHelper incluye una variable de miembro de DataSet . Opcionalmente, puede asignar un DataSet existente. Si la variable miembro apunta a un DataSet válido, los objetos DataTable que crea el CreateGroupByTable o el método SelectGroupByInto se agregan al DataSet . En cualquier caso, la llamada al método devuelve una referencia al objeto DataTable . El método InsertGroupByInto requiere un destino existente DataTable y no devuelve nada. Para obtener información adicional acerca de los objetos DataSet, haga clic en el número de artículo siguiente para verlo en Microsoft Knowledge Base:
313485  (http://support.microsoft.com/kb/313485/EN-US/ ) INFO: Guía para DataSet, DataView y DataViewManager

Requisitos

En la lista siguiente se describe el hardware, el software, la infraestructura de red y los service pack recomendados que se necesitarán:
  • Microsoft Windows XP, Windows 2000 o Windows NT 4.0 Service Pack 6a
  • Microsoft Visual Studio .NET
En este artículo se supone que está familiarizado con los temas siguientes:
  • Sintaxis de Visual C# .NET
  • Fundamentos y sintaxis de ADO.NET

Clase DataSetHelper Shell

El código en esta sección declara la clase de shell que todos los artículos de DataSetHelper agregar métodos y variables miembro para.
  1. Inicie Visual Studio NET..
  2. En el menú archivo , seleccione nuevo y, a continuación, haga clic en proyecto .
  3. En el cuadro de diálogo Nuevo proyecto , haga clic en Proyectos de Visual C# en Tipos de proyecto y, a continuación, haga clic en Biblioteca de clases en plantillas .
  4. En el cuadro de texto nombre , escriba DataSetHelper . Haga clic en Aceptar .
  5. En el código en la parte superior de la ventana código, agregue la línea siguiente:
    using System.Data;
  6. Reemplace el código de la clase con el siguiente código:
    public class DataSetHelper
    {
        public DataSet ds;
        public DataSetHelper(ref DataSet DataSet)
        {
            ds = DataSet;
        }
        public DataSetHelper()
        {
            ds = null;
        }
    }
    las dos sobrecargas del constructor permiten crear una instancia de la clase con o sin una referencia a un DataSet válido. Para una clase que contiene una referencia a un DataSet válido, los objetos DataTable que devuelven los métodos también se agregan automáticamente al DataSet .

Analizadores de lista de campos

Esta sección contiene el código de dos analizadores de lista de campo: uno para la lista de campos y otro para los campos de agrupar por. La estructura analizada se utiliza para que los métodos CreateGroupByTable y InsertGroupByInto no tienen que la lista de campos de reanálisis. Estos métodos deben reanálisis la lista de campos si se llama a desde el método SelectGroupByInto o desde su propio código. La lista de campos analizada y la lista de campos sin analizar se almacenan en variables de miembro privado de la clase DataSetHelper .
  1. Agregue la siguiente definición de clase privada a la clase DataSetHelper que creó en la sección "":
    private class FieldInfo
    {
        public string RelationName;
        public string FieldName;	//source table field name
        public string FieldAlias;	//destination table field name
        public string Aggregate;
    }
    Nota esta clase es común a otros artículos DataSetHelper y contiene algunos campos que no utilice este artículo.
  2. Agregue las siguientes variables miembro privadas a la definición de clase inmediatamente después de la declaración de DataSet :
    private System.Collections.ArrayList m_FieldInfo; private string m_FieldList;
    private System.Collections.ArrayList GroupByFieldInfo; private string GroupByFieldList;
  3. Agregue el siguiente método privado a la definición de clase DataSetHelper . Este método es el mismo que el método que se utiliza en otros artículos DataSetHelper y se utiliza para analizar la lista de campos Agrupar por.
    private void ParseFieldList(string FieldList, bool AllowRelation)
    {
        /*
         * This code parses FieldList into FieldInfo objects  and then 
         * adds them to the m_FieldInfo private member
         * 
         * FieldList systax:  [relationname.]fieldname[ alias], ...
        */ 
        if (m_FieldList == FieldList) return;
        m_FieldInfo = new System.Collections.ArrayList();
        m_FieldList = FieldList;
        FieldInfo Field; string[] FieldParts; string[] Fields=FieldList.Split(',');
        int i;
        for (i=0; i<=Fields.Length-1; i++)
        {
            Field=new FieldInfo();
            //parse FieldAlias
            FieldParts = Fields[i].Trim().Split(' ');
            switch (FieldParts.Length)
            {
                case 1:
                    //to be set at the end of the loop
                    break;
                case 2:
                    Field.FieldAlias=FieldParts[1];
                    break;
                default:
                    throw new Exception("Too many spaces in field definition: '" + Fields[i] + "'.");
            }
            //parse FieldName and RelationName
            FieldParts = FieldParts[0].Split('.');
            switch (FieldParts.Length)
            {
                case 1: 
                    Field.FieldName=FieldParts[0];
                    break;
                case 2:
                    if (AllowRelation==false)
                        throw new Exception("Relation specifiers not permitted in field list: '" + Fields[i] + "'.");
                    Field.RelationName = FieldParts[0].Trim();
                    Field.FieldName=FieldParts[1].Trim();
                    break;
                default:
                    throw new Exception("Invalid field definition: " + Fields[i] + "'.");
            }
            if (Field.FieldAlias==null) 
                Field.FieldAlias = Field.FieldName;
            m_FieldInfo.Add (Field);
        }
    }
  4. Agregue el siguiente método privado a la definición de clase. Este método se utiliza para analizar la lista de campo, incluidas las funciones de agregado.
    private void ParseGroupByFieldList(string FieldList)
    {
        /*
        * Parses FieldList into FieldInfo objects and adds them to the GroupByFieldInfo private member
        * 
        * FieldList syntax: fieldname[ alias]|operatorname(fieldname)[ alias],...
        * 
        * Supported Operators: count,sum,max,min,first,last
        */ 
        if (GroupByFieldList == FieldList) return;
        GroupByFieldInfo = new System.Collections.ArrayList();
        FieldInfo Field; string[] FieldParts; string[] Fields = FieldList.Split(',');
        for (int i=0; i<=Fields.Length-1;i++)
        {
        Field = new FieldInfo();
            //Parse FieldAlias
            FieldParts = Fields[i].Trim().Split(' ');
            switch (FieldParts.Length)
            {
                case 1:
                    //to be set at the end of the loop
                    break;
                case 2:
                    Field.FieldAlias = FieldParts[1];
                    break;
                default:
                    throw new ArgumentException("Too many spaces in field definition: '" + Fields[i] + "'.");
            }
            //Parse FieldName and Aggregate
            FieldParts = FieldParts[0].Split('(');
            switch (FieldParts.Length)
            {
                case 1:
                    Field.FieldName = FieldParts[0];
                    break;
                case 2:
                    Field.Aggregate = FieldParts[0].Trim().ToLower();    //we're doing a case-sensitive comparison later
                    Field.FieldName = FieldParts[1].Trim(' ', ')');
                    break;
                default:
                    throw new ArgumentException("Invalid field definition: '" + Fields[i] + "'.");
            }
            if (Field.FieldAlias==null)
            {
                if (Field.Aggregate==null)
                    Field.FieldAlias=Field.FieldName;
                else
                    Field.FieldAlias = Field.Aggregate + "of" + Field.FieldName;
            }
            GroupByFieldInfo.Add(Field);
        }
        GroupByFieldList = FieldList;
    }

Método CreateGroupByTable

Esta sección contiene el código para el método CreateGroupByTable .

El siguiente es la convención de llamada para el método CreateGroupByTable :
dt = dsHelper.CreateGroupByTable("OrderSummary", ds.Tables["Orders"], "EmployeeID,sum(Amount) Total,min(Amount) Min,max(Amount) Max");
este ejemplo de llamada, crea una nueva DataTable con un TableName de OrderSummary y cuatro campos (EmployeeID, total, Min y max). Los cuatro campos tienen el mismo tipo como el EmployeeID y el importe de campos en la tabla Orders de datos.

Utilice la siguiente sintaxis para especificar campos en la lista de campos:
fieldname[ alias]|aggregatefunction(fieldname)[ alias], ...
Nota siguiente para esta sintaxis:
  • ColumnName y las propiedades DataType son las propiedades sólo a las que se copian al destino DataTable .
  • Puede cambiar el nombre un campo en el destino DataTable especificando un nombre de alias.
  • La lista de campos puede contener un subconjunto de nombres de campos que aparecen en un orden diferente en el origen de DataTable . Si la lista de campos está en blanco, se produce una excepción.
  • Especificadores de relación no se admiten como parte del nombre del campo. Todos los campos deben proceder de la DataTable del mismo.
Para llamar al método CreateGroupByTable , agregue el método siguiente a la clase DataSetHelper que creó en la sección "":
public DataTable CreateGroupByTable(string TableName, DataTable SourceTable, string FieldList)
{
    /*
     * Creates a table based on aggregates of fields of another table
     * 
     * RowFilter affects rows before GroupBy operation. No "Having" support
     * though this can be emulated by subsequent filtering of the table that results
     * 
     *  FieldList syntax: fieldname[ alias]|aggregatefunction(fieldname)[ alias], ...
    */ 
    if (FieldList == null)
    {
        throw new ArgumentException("You must specify at least one field in the field list.");
        //return CreateTable(TableName, SourceTable);
    }
    else
    {
        DataTable dt = new DataTable(TableName);
        ParseGroupByFieldList(FieldList);
        foreach (FieldInfo Field in GroupByFieldInfo)
        {
            DataColumn dc  = SourceTable.Columns[Field.FieldName];
            if (Field.Aggregate==null)
                dt.Columns.Add(Field.FieldAlias, dc.DataType, dc.Expression);
            else
                dt.Columns.Add(Field.FieldAlias, dc.DataType);
        }
        if (ds != null)	
            ds.Tables.Add(dt);
        return dt;
    }
}

Método InsertGroupByInto

Esta sección contiene código para el método InsertGroupByInto .

Los resultados se ordenan en los campos que aparecen en el argumento GroupBy . El argumento GroupBy debe cumplir con una lista de campo de orden válida (menos modificadores ASC y DESC). Si el argumento GroupBy está en blanco, el destino DataTable contiene sólo un único registro que agrega toda la entrada. Al llamar a la ParseGroupByFieldList y las propiedades ParseFieldList , se pueden analizar las listas que se han analizado anteriormente, si estas listas están disponibles. Si la lista de campos está en blanco, se produce una excepción.

Esta es la convención de llamada para el método InsertGroupByInto :
dsHelper.InsertGroupByInto(ds.Tables["OrderSummary"], ds.Tables["Orders"],
    "EmployeeID,sum(Amount) Total,min(Amount) Min,max(Amount) Max", "EmployeeID<5", "EmployeeID");
				
este ejemplo de llamada lee los registros de la DataTable que se denomina Orders y escribe registros en la DataTable que se denomina OrderSummary. OrderSummary DataTable contiene el campo IdEmpleado y tres agregados diferentes del campo Importe que se filtran en "EmployeeID < 5" y que están agrupados en y (ordenados por) EmployeeID.

Nota La expresión de filtro se aplica antes de cualquier función agregado. Para implementar funcionalidad tipo HAVING, filtrar el DataTable resultante.

To call the InsertGroupByInto method, add the following method to the DataSetHelper class that you created in the "" section:
public void InsertGroupByInto(DataTable DestTable, DataTable SourceTable, string FieldList,
    string RowFilter, string GroupBy)
{
    /*
     * Copies the selected rows and columns from SourceTable and inserts them into DestTable
     * FieldList has same format as CreateGroupByTable
    */ 
    if (FieldList == null)
        throw new ArgumentException("You must specify at least one field in the field list.");
    ParseGroupByFieldList(FieldList);	//parse field list
    ParseFieldList(GroupBy,false);			//parse field names to Group By into an arraylist
    DataRow[] Rows = SourceTable.Select(RowFilter, GroupBy);
    DataRow LastSourceRow = null, DestRow = null; bool SameRow; int RowCount=0;
    foreach(DataRow SourceRow in Rows)
    {
        SameRow=false;
        if (LastSourceRow!=null)
        {
            SameRow=true;
            foreach(FieldInfo Field in m_FieldInfo)
            {
                if (!ColumnEqual(LastSourceRow[Field.FieldName], SourceRow[Field.FieldName]))
                {
                    SameRow=false;
                    break;
                }
            }
            if (!SameRow)
                DestTable.Rows.Add(DestRow);
        }
        if (!SameRow)
        {
            DestRow = DestTable.NewRow();
            RowCount=0;
        }
        RowCount+=1;
        foreach(FieldInfo Field in GroupByFieldInfo)
        {
            switch(Field.Aggregate)    //this test is case-sensitive
            {
                case null:        //implicit last
                case "":        //implicit last
                case "last":
                    DestRow[Field.FieldAlias]=SourceRow[Field.FieldName];
                    break;
                case "first":
                    if (RowCount==1)
                        DestRow[Field.FieldAlias]=SourceRow[Field.FieldName];
                    break;
                case "count":
                    DestRow[Field.FieldAlias]=RowCount;
                    break;
                case "sum":
                    DestRow[Field.FieldAlias]=Add(DestRow[Field.FieldAlias], SourceRow[Field.FieldName]);
                    break;
                case "max":
                    DestRow[Field.FieldAlias]=Max(DestRow[Field.FieldAlias], SourceRow[Field.FieldName]);
                    break;
                case "min":
                    if (RowCount==1)
                        DestRow[Field.FieldAlias]=SourceRow[Field.FieldName];
                    else
                        DestRow[Field.FieldAlias]=Min(DestRow[Field.FieldAlias], SourceRow[Field.FieldName]);
                    break;
            }
        }
        LastSourceRow = SourceRow;
    }
    if(DestRow!=null)
        DestTable.Rows.Add(DestRow);
}


private FieldInfo LocateFieldInfoByName(System.Collections.ArrayList FieldList, string Name)
{
    //Looks up a FieldInfo record based on FieldName
    foreach (FieldInfo Field in FieldList)
    {
        if (Field.FieldName==Name)
            return Field;
    }
    return null;
}

private bool ColumnEqual(object a, object b)
{
    /*
     * Compares two values to see if they are equal. Also compares DBNULL.Value.
     * 
     * Note: If your DataTable contains object fields, you must extend this
     * function to handle them in a meaningful way if you intend to group on them.
    */ 
    if ((a is DBNull) && (b is DBNull))
        return true;    //both are null
    if ((a is DBNull) || (b is DBNull))
        return false;    //only one is null
    return (a==b);    //value type standard comparison
}   

private object Min(object a, object b)
{
    //Returns MIN of two values - DBNull is less than all others
    if ((a is DBNull) || (b is DBNull))
        return DBNull.Value;
    if (((IComparable)a).CompareTo(b)==-1)
        return a;
    else
        return b;
}   

private object Max(object a, object b)
{
    //Returns Max of two values - DBNull is less than all others
    if (a is DBNull)
        return b;
    if (b is DBNull)
        return a;
    if (((IComparable)a).CompareTo(b)==1)
        return a;
    else
        return b;
}   

private object Add(object a, object b)
{
    //Adds two values - if one is DBNull, then returns the other
    if (a is DBNull)
        return b;
    if (b is DBNull)
        return a;
    return ((decimal)a + (decimal)b);
}

Método SelectGroupByInto

Esta sección contiene el código para el método SelectGroupByInto . Este método es una combinación de la CreateGroupByTable y los métodos InsertGroupByInto . El método SelectGroupByInto crea una nueva DataTable basado en objetos DataTable existentes y copia los registros que están ordenados y filtrados a la nueva DataTable .

El siguiente es la convención de llamada para el método SelectGroupByInto :
dt = dsHelper.SelectGroupByInto("OrderSummary", ds.Tables["Employees"],
    "EmployeeID,sum(Amount) Total,min(Amount) Min,max(Amount) Max", "EmployeeID<5", "EmployeeID");
este ejemplo de llamada crea una nueva DataTable con un TableName de OrderSummary y cuatro campos (EmployeeID, total, Min y max). Estos cuatro campos tienen el mismo tipo como el valor de IdEmpleado y los campos de importe de la tabla de pedidos de datos. A continuación, en este ejemplo lee los registros de pedidos DataTable y escribe los registros a la DataTable de OrderSummary. OrderSummary DataTable contiene el campo IdEmpleado y tres agregados diferentes del campo Importe que se filtran en "EmployeeID < 5" y que están agrupados en y (ordenados por) EmployeeID. Si el GroupBy argumento está en blanco, el destino DataTable contiene sólo un único registro que agrega toda la entrada.

Nota La expresión de filtro se aplica antes de cualquier función agregado. Para implementar funcionalidad tipo HAVING, filtrar la DataTable resultante.

Para llamar al método SelectGroupByInto , agregue el método siguiente a la clase DataSetHelper que creó en la sección "":
public DataTable SelectGroupByInto(string TableName, DataTable SourceTable, string FieldList,
	string RowFilter, string GroupBy)
{
    /*
     * Selects data from one DataTable to another and performs various aggregate functions
     * along the way. See InsertGroupByInto and ParseGroupByFieldList for supported aggregate functions.
     */ 
    DataTable dt = CreateGroupByTable(TableName, SourceTable, FieldList);
    InsertGroupByInto(dt, SourceTable, FieldList, RowFilter, GroupBy);
    return dt;
}

Probar la aplicación

  1. Guardar y, a continuación, compile la clase DataSetHelper que creó en las secciones anteriores.
  2. Siga estos pasos para crear un nuevo Windows de Visual C# aplicación:
    1. Inicie Visual Studio NET..
    2. En el menú archivo , seleccione nuevo y, a continuación, haga clic en proyecto .
    3. En el cuadro de diálogo Nuevo proyecto , haga clic en Proyectos de Visual C# en Tipos de proyecto y, después, haga clic en Aplicación para Windows en plantillas .
  3. En el Explorador de soluciones, haga clic con el botón secundario en la solución y, a continuación, haga clic en Agregar proyecto existente . Agregue el proyecto DataSetHelper.
  4. En el menú proyecto , haga clic en Agregar referencia .
  5. En el cuadro de diálogo Agregar referencia , haga clic en la ficha proyectos y, a continuación, agregue una referencia al proyecto DataSetHelper a la aplicación Windows Forms.
  6. En el Diseñador de formulario, arrastre tres controles Button y un control DataGrid desde el cuadro de herramientas al formulario. Nombres de los botones btnCreateGroupBy , btnInsertGroupByInto y btnSelectGroupByInto . Mantenga el nombre predeterminado para el control DataGrid (DataGrid1).
  7. En el código de formulario, agregue la siguiente instrucción using al principio de la ventana de código:
    using System.Data;
  8. Agregue las siguientes declaraciones de variables a la definición del formulario:
    DataSet ds; DataSetHelper.DataSetHelper dsHelper;
  9. Add the following code to the Form_Load event:
    ds = new DataSet();
    dsHelper = new DataSetHelper.DataSetHelper(ref ds);
    //Create the source table
    DataTable dt = new DataTable("Orders");
    dt.Columns.Add("EmployeeID", Type.GetType("System.String"));
    dt.Columns.Add("OrderID", Type.GetType("System.Int32"));
    dt.Columns.Add("Amount", Type.GetType("System.Decimal"));
    dt.Rows.Add(new object[] {"Sam", 5, 25.00});
    dt.Rows.Add(new object[] {"Tom", 7, 50.00});
    dt.Rows.Add(new object[] {"Sue", 9, 11.00});
    dt.Rows.Add(new object[] {"Tom", 12, 7.00});
    dt.Rows.Add(new object[] {"Sam", 14, 512.00});
    dt.Rows.Add(new object[] {"Sue", 15, 17.00});
    dt.Rows.Add(new object[] {"Sue", 22, 2.50});
    dt.Rows.Add(new object[] {"Tom", 24, 3.00});
    dt.Rows.Add(new object[] {"Tom", 33, 78.75});
    ds.Tables.Add(dt);
  10. Agregue el código siguiente al evento btnCreateGroupBy.Click :
    dsHelper.CreateGroupByTable("OrderSummary", ds.Tables["Orders"], 
    	"EmployeeID,count(EmployeeID) Orders,Sum(Amount) OrderTotal,max(Amount) BestOrder,min(Amount) WorstOrder");
    dataGrid1.SetDataBinding(ds, "OrderSummary");
  11. Agregue el código siguiente al evento btnInsertGroupByInto.Click :
    dsHelper.InsertGroupByInto(ds.Tables["OrderSummary"], ds.Tables["Orders"], 
        "EmployeeID,count(EmployeeID) Orders,sum(Amount) OrderTotal,max(Amount) BestOrder,min(Amount) WorstOrder", 
        "", "EmployeeID");
    dataGrid1.SetDataBinding(ds, "OrderSummary");
  12. Agregue el código siguiente al evento btnSelectGroupByInto.Click :
    dsHelper.SelectGroupByInto("OrderSummary2", ds.Tables["Orders"], 
        "EmployeeID,count(EmployeeID) Orders,sum(Amount) OrderTotal,max(Amount) BestOrder,min(Amount) WorstOrder", 
        "OrderID>10", "EmployeeID");
    dataGrid1.SetDataBinding(ds, "OrderSummary2");
  13. Ejecutar la aplicación y, a continuación, haga clic en cada uno de los botones. Observe que el control DataGrid está relleno con las tablas y los datos desde el código.
    Nota Puede hacer clic sólo en el btnCreateGroupBy y los botones btnSelectGroupByInto una vez. Si hace clic en cualquiera de estos botones más de una vez, recibirá un mensaje de error que intenta agregar la misma tabla two times. Además, debe hacer clic en btnCreateGroupBy antes de hacer clic en btnInsertGroupByInto ; en caso contrario, el destino DataTable no se crea. Si hace clic en el botón btnInsertGroupByInto varias veces, llenar el DataGrid con registros duplicados.

Ideas de mejora

  • ColumnName y las propiedades DataType son las propiedades sólo a las que se copian al destino DataTable . Puede extender el método CreateTable para copiar propiedades adicionales, como la propiedad MaxLength , o puede crear nuevas columnas de claves.
  • Puede ampliar la funcionalidad para que pueda especificar campos de objetos DataTable relacionados.
  • Puede ampliar la funcionalidad agregando compatibilidad para funciones de agregado adicionales, tales como el promedio o la función DesvEst . Si lo hace, deben haber creado dinámicamente variables para realizar un seguimiento valores intermedios. Para realizar un seguimiento valores intermedios, puede agregar variables miembro a la clase FieldInfo y, a continuación, utilizar esas variables miembro para almacenar valores intermedios.

Solucionar problemas

  • Fieldname y las partes alias de la lista de campos deben cumplir las convenciones de nomenclatura DataColumn . El Analizador restringe también los nombres en que el nombre no debe contener un punto (.), una coma (,) o un espacio ().
  • Si hace clic en un botón de más de una vez, la misma tabla se agrega dos veces en el DataSet . Esto produce una excepción. Para evitar este problema, puede agregar código a la aplicación de prueba para comprobar si ya existe un DataTable con el mismo nombre. Como alternativa, puede crear la clase DataSetHelper sin una referencia a un DataSet y, a continuación, enlazar la propiedad de DataGrid.DataSource directamente a la variable dt en lugar de mediante la llamada de método SetDataBinding .
  • Si la tabla de origen utiliza tipos de datos personalizado (por ejemplo, una clase), debe agregar código al método InsertGroupByInto para realizar una copia profunda de los datos. En caso contrario, se copia sólo una referencia.

La información de este artículo se refiere a:
  • Microsoft ADO.NET (included with the .NET Framework)
  • Microsoft Visual C# .NET 2002 Standard Edition
Palabras clave: 
kbmt kbhowtomaster KB326145 KbMtes
Traducción automáticaTraducción automática
IMPORTANTE: Este artículo ha sido traducido por un software de traducción automática de Microsoft (http://support.microsoft.com/gp/mtdetails) en lugar de un traductor humano. Microsoft le ofrece artículos traducidos por un traductor humano y artículos traducidos automáticamente para que tenga acceso en su propio idioma a todos los artículos de nuestra base de conocimientos (Knowledge Base). Sin embargo, los artículos traducidos automáticamente pueden contener errores en el vocabulario, la sintaxis o la gramática, como los que un extranjero podría cometer al hablar el idioma. Microsoft no se hace responsable de cualquier imprecisión, error o daño ocasionado por una mala traducción del contenido o como consecuencia de su utilización por nuestros clientes. Microsoft suele actualizar el software de traducción frecuentemente.
Haga clic aquí para ver el artículo original (en inglés): 326145  (http://support.microsoft.com/kb/326145/en-us/ )
 

Seleccione idioma