2010-02-18 29 views
13

Todavía estoy tratando de poner los pies en la tierra con Silverlight y RIA Services, y por supuesto comenzando con algunas de las cosas más "divertidas" como las cuadrículas y la paginación inteligente. Puedo conectarme a los servicios de RIA (usando un ORM de cosecha propia, no L2S o EF), obtener datos en la grilla y conectarme a un DataPager. El servicio de dominio funciona bien con el ORM de cosecha propia, al menos para consultas. (Sigue trabajando en completa ABM). Sin embargo, todavía hay problemas:Silverlight, DataPager, RIA Services y paginación inteligente

  1. para apoyar la aplicación de usuario, necesito clasificación controlado por el usuario y filtrado, además de paginación inteligente (sólo ejecutar la consulta para las filas necesario para mostrar) y agrupación.

  2. Hasta ahora, no he visto nada en DataGrid o DataPager para externalizar estas capacidades de modo que los parámetros de filtrado, clasificación y paginación se puedan pasar al servidor para generar la consulta adecuada.

  3. Los conjuntos de datos son potencialmente bastante grandes; Mi mesa que he elegido para el trabajo de prototipos puede tener hasta 35,000 entradas en algunos clientes, y estoy seguro de que hay otras tablas mucho más grandes con las que tendré que lidiar en algún momento. Entonces, el aspecto de "paginación inteligente" es esencial.

Ideas, sugerencias, orientación y ladrillos nerf son bienvenidos.

Respuesta

11

OK, he pasado unos días en las malas hierbas con esta, y creo que tengo un control sobre ella.

Primero, una pieza importante de magia. Para que la paginación funcione correctamente, el buscapersonas debe conocer el recuento total de elementos, sin importar cuántos elementos devolvió la consulta actual. Si la consulta devuelve todo, el recuento de elementos es, obviamente, la cantidad de elementos devueltos. Para la paginación inteligente, el recuento de elementos sigue siendo el total de artículos disponibles, aunque la consulta solo devuelve lo que se muestra. Con el filtrado, incluso el total de elementos disponibles cambia cada vez que cambia el filtro.

El control Silverlight Datapager tiene una propiedad llamada ItemCount. Es de solo lectura y no se puede unir a datos en XAML, o establecer directamente en el código. Sin embargo, si el control de usuario que contiene el buscapersonas tiene un DataContext que implementa IPagedCollectionView, entonces el objeto de contexto de datos debe implementar una propiedad ItemCount con notificación PropertyChanged, y el DataPager parece recoger esto automágicamente.

En segundo lugar, recomiendo la excelente series of blog posts on RIA Services de Brad Abrams, especialmente esta en ViewModel. Contiene la mayor parte de lo que necesita para realizar el trabajo de paginación y filtrado, aunque le falta la pieza crítica para administrar el recuento de elementos. Su muestra descargable también contiene un muy buen marco básico para implementar ModelViewViewModel (MVVM). ¡Gracias, Brad!

Así que aquí está cómo hacer que el recuento de elementos funcione. (Este código hace referencia a un ORM personalizado, mientras que el código de Brad utiliza Entity Framework; entre los dos puede calcular lo que necesita en su entorno)

Primero, su ORM necesita admitir el recuento de registros, con y sin su filtrar. Aquí está mi código de servicio de dominio que hace que los recuentos a los Servicios RIA:

[Invoke] 
public int GetExamCount() 
{ 
    return Context.Exams.Count(); 
} 

[Invoke] 
public int GetFilteredExamCount(string descriptionFilter) 
{ 
    return Context.Exams.GetFilteredCount(descriptionFilter); 
} 

Nota del [invocación] atributo. Lo necesita para cualquier método DomainService que no devuelva una entidad o una colección Entity.

Ahora para el código de ViewModel. Necesitas un ItemCount, por supuesto. (Esto es del ejemplo de Brad.)

int itemCount; 
    public int ItemCount 
    { 
     get { return itemCount; } 
     set 
     { 
      if (itemCount != value) 
      { 
       itemCount = value; 
       RaisePropertyChanged(ItemCountChangedEventArgs); 
      } 
     } 
    } 

Su método LoadData se ejecute la consulta para obtener el conjunto actual de filas para mostrar en la cuadrícula de datos. (Esto no aplica la costumbre de clasificación todavía, pero eso es una adición fácil.)

EntityQuery<ExamEntity> query = 
     DomainContext.GetPagedExamsQuery(PageSize * PageIndex, PageSize, DescriptionFilterText); 
    DomainContext.Load(query, OnExamsLoaded, null); 

El método de devolución de llamada a continuación, ejecuta la consulta para obtener los conteos. Si no se utiliza ningún filtro, obtenemos el recuento de todas las filas; si hay un filtro, obtenemos el recuento de las filas filtradas.

private void OnExamsLoaded(LoadOperation<ExamEntity> loadOperation) 
{ 
    if (loadOperation.Error != null) 
    { 
     //raise an event... 
     ErrorRaising(this, new ErrorEventArgs(loadOperation.Error)); 
    } 
    else 
    { 
     Exams.MoveCurrentToFirst(); 
     if (string.IsNullOrEmpty(DescriptionFilterText)) 
     { 
      DomainContext.GetExamCount(OnCountCompleted, null); 
     } 
     else 
     { 
      DomainContext.GetFilteredExamCount(DescriptionFilterText, OnCountCompleted, null); 
     } 
     IsLoading = false; 
    } 
} 

También hay un método de devolución de llamada para el recuento:

void OnCountCompleted(InvokeOperation<int> op) 
{ 
    ItemCount = op.Value; 
    TotalItemCount = op.Value; 
} 

Con el conjunto ItemCount, el control DataPager lo recoge, y tenemos paginación con el filtrado y una consulta inteligente que devuelve sólo los registros de ¡se mostrará!

LINQ facilita la consulta con .Skip() y .Take(). Hacer esto con raw ADO.NET es más difícil. Aprendí cómo hacer esto desmontando una consulta generada por LINQ.

SELECT * FROM 
    (select ROW_NUMBER() OVER (ORDER BY Description) as rownum, * 
    FROM Exams as T0 WHERE T0.Description LIKE @description) as T1 
WHERE T1.rownum between @first AND @last ORDER BY rownum 

La cláusula de "seleccionar ROW_NUMBER() OVER (ORDER BY Descripción) como rownum" es la parte interesante, porque no muchas personas usan "OVER" todavía. Esta cláusula clasifica la tabla en Descripción antes de asignar números de fila, y el filtro también se aplica antes de asignar números de fila. Esto permite que SELECT externo filtre los números de fila, después de ordenar y filtrar.

¡Así que ahí está, paginación inteligente con filtrado, en RIA Services y Silverlight!

+3

Cuando encuentro problemas como este con frameworks que se supone que hacen tareas comunes, en este caso paginación, es más fácil que te preocupes. Para usar RIA o no usar RIA esa es la pregunta ... – sipwiz

+0

Bueno, esa es una pregunta abierta por ahora. RIA Services for Silverlight 3 y VS 2008 está prácticamente muerto; lo que está disponible ahora es la versión beta pública, que no se mejorará y se admitirá solo hasta diciembre. Entonces, los servicios de RIA para Silverlight 4 y VS 2010 son opciones. Está en el estado RC2 ahora; Lo verificaré tan pronto como llegue al estado de lanzamiento. FWIW, Brad Abrams dice que permita que la cuadrícula de datos de Silverlight haga la búsqueda, pero todavía existe el problema del filtrado personalizado, y eso es lo que realmente me mató inicialmente a los Servicios de RIA. Tenemos que ser capaces de filtrar en el servidor. –

4

Aquí está la solución rápida y sucia (que fui a):

Basta con mover el DomainDataSource a su modelo de vista! ¡Hecho!

Es posible que no exactamente ser grande para la capacidad de prueba y probablemente algunas otras limitaciones que no he descubierto todavía, pero personalmente no me importa acerca de que hastasomething better comes along.

dentro de su modelo de vista simplemente una instancia de la fuente de datos:

// Feedback DataSource 
_dsFeedback = new DomainDataSource(); 
_dsFeedback.DomainContext = _razorSiteDomainContext; 
_dsFeedback.QueryName = "GetOrderedFeedbacks"; 
_dsFeedback.PageSize = 10; 
_dsFeedback.Load(); 

y proporcionar una propiedad enlazable:

private DomainDataSource _dsFeedback { get; set; } 
public DomainDataSource Feedback 
{ 
    get 
    { 
     return _dsFeedback; 
    } 
} 

Y añadir su DataPager a su XAML:

<data:DataPager Grid.Row="1" 
        HorizontalAlignment="Stretch" 
        Source="{Binding Feedback.Data}" 
        Margin="0,0,0,5" /> 

    <data:DataGrid ItemsSource="{Binding Feedback.Data}"> 


PS. Gracias a 'Francois' de la página enlazada anterior. ¡Ni siquiera me di cuenta de que podía sacar DomainDataSource del XAML hasta que vi su comentario!

Cuestiones relacionadas