2010-08-06 10 views
5

Tengo que crear un XamDataGrid que muestre una cantidad dinámica de columnas para un marco de tiempo de xay. Por lo tanto, no sé cuántos años un usuario seleccionaría para tener estas columnas creadas por adelantado.MVVM - ¿Cómo crear columnas en tiempo de ejecución para una xamdatagrid?

Ahora, por lo general dentro de MVVM, simplemente rellene los datos a través de tantas Propiedades como necesite Columnas dentro de su XamDataGrid, y la última simplemente las generaría automáticamente.

Obviamente no pude simplemente crear Propiedades dentro de mi ViewModel en tiempo de ejecución a menos que hiciera algo loco con Reflection.

¿De qué otro modo podría lograrlo?

¿Debo simplemente crear campos no vinculados para la cuadrícula de datos y rellenarlos a través del código? Estoy de acuerdo en que no necesitaré un enlace bidireccional en esta etapa, ya que la cuadrícula es solo de solo lectura ... solo pienso en voz alta.

¿Este enfoque es correcto sin violar el patrón de MVVM? Gracias

Respuesta

4

Puede utilizar controladores paso a paso:

En su modelo de vista:

public MyVariableCollection RowData 
{ 
    get { return new MyVariableCollection(this); } 
} 

En MyVariableCollection: protegida SomeRowViewModel modelo de vista;

public MyVariableCollection(SomeRowViewModel viewmodel) 
{ 
    this.viewModel = viewmodel; 
} 

public object this[string name] 
{ 
    get { return viewModel.GetRowColumnValue(name); } 
} 

He tratado de ser breve, pero la idea es que tienes una nueva clase con un indexador definido, entonces se puede unir de esta manera:

{Binding Path=SomeRowViewModelInstance.RowData["ColumnName"]} 

La colección de columnas en el el control de la cuadrícula de datos estaría vinculado, y podría establecer una plantilla de columna para cada columna para vincularla a la columna en cuestión; no necesita usar una cadena literal en el indexador así.

Espero que le de algo de reflexión - cualquier pregunta en esta ruta por favor deje un comentario.


Editar para un pensamiento adicional: he utilizado el contenido ComponentModel espacio de nombres para producir una costumbre TypeDescriptor. Es bastante profundo, pero puede hacer que un objeto 'aparezca' tenga propiedades adicionales o personalizadas. Es mucho más complejo que el método del indexador que publiqué anteriormente, pero si te quedas atascado, vale la pena echarle un vistazo.

+0

Gracias por su gran respuesta Kieren. Aunque encontré tres problemas con tu modelo. Primero está la propiedad RowData de ViewModel, que está pasando en su propio código un 'esto'. Sin embargo, el ctor real acepta un tipo de SomeRowViewModel que no es compatible con el tipo de 'this' anterior. – Houman

+0

El segundo problema es la forma en que se vincula una sola columna. Dentro de XamDataGrid normalmente vincularía toda la xamdatagrid simplemente a una colección BindingList y una dit generaría automáticamente esas filas. A menos que cree las columnas manualmente, no podrá vincularlas a cada columna por separado. – Houman

+0

El tercer problema es el siguiente: podría autogenerar los columnNames dinámicamente para timeperiod x a y, para poder usarlos en el indexador como sugirió. Pero el enlace no puede estar todavía en el código xaml estático. Más tiene que estar en el código detrás de la vista xaml para usar los nombres de las columnas de una manera variable. A menos que me falta algo aquí ... Gracias – Houman

1

Tuve un problema similar porque el usuario pudo definir las columnas de la cuadrícula en tiempo de ejecución.

Escribí un control que contiene la cuadrícula de datos xam y expongo una propiedad de dependencia de DataSource para vincular el modelo a la grilla (es decir, una tabla de datos).

Cada vez que cambia la fuente (se puede añadir detectores de eventos para PropertyChanged y las rejillas de eventos FieldLayoutInitializing) que la red se dinámicamente volver a representar en la limpieza de su fuente de datos y ponerlo a cero:

private void ReRenderGrid() 
{ 
    XamDataGrid.FieldLayouts.Clear(); 
    XamDataGrid.ClearValue(DataPresenterBase.DataSourceProperty); 
    XamDataGrid.DataSource = DataSource.Data.DefaultView; 
} 

Las columnas se vuelven a configurar por un controlador de eventos en el siguiente suceso que se eleva por xamdatagrid después de la fuente de datos rejillas se restablece:

XamDataGrid.FieldLayoutInitializing += LayoutInitializing; 

Handler:

private void LayoutInitializing(object sender, FieldLayoutInitializingEventArgs e) 
{ 
    const string deletebuttonstyle = "DeleteButtonStyle"; 
    const string requiredinputvalue = "RequiredInputValue"; 
    const string optionalinputvalue = "OptionalInputValue"; 
    const string outputvalue = "OutputValue"; 

    var fieldLayout = e.FieldLayout; 
    fieldLayout.Fields.Clear(); 

    AddFields(DataSource.InColumns, requiredinputvalue, fieldLayout); 
    AddSplitter(fieldLayout); 
    AddFields(DataSource.OptionalInColumns, optionalinputvalue, fieldLayout); 
    AddSplitter(fieldLayout); 
    AddFields(DataSource.OutColumns, outputvalue, fieldLayout); 

    AddUnboundField(fieldLayout, string.Empty, GetStyle(deletebuttonstyle)); 
} 

En mi caso, el origen de datos contenía todas las columnas configuradas por el usuario. AddFields llama a este método para cada entrada de la lista:

private void AddField(string name, Style style, FieldLayout fieldLayout) 
{ 
    var field = new Field {Name = name}; 
    field.Settings.LabelPresenterStyle = style; 
    field.Settings.CellValuePresenterStyle = GetStyle("StandardCellValueStyle"); 
    fieldLayout.Fields.Add(field); 
} 

AddSplitter y AddUnboundField se implementan de una manera similar.

+0

Zebi, muchas gracias por estos fragmentos de código. Estoy seguro de que está funcionando y parece realmente prometedor. Sin embargo, estos son solo fragmentos de código. No puedo seguir los estados. XamDataGrid.DataSource = DataSource.Data.DefaultView; Lo que es Data en este caso, parece que no lo tengo. El método AddFields parece tener una firma diferente a su AddField. Todavía no tengo muy claro cómo debería funcionar esto. Un simple ejemplo de trabajo realmente sería apreciado. – Houman

+0

La propiedad DataSource en mi ejemplo se refiere a un tipo I personalizado que contiene la tabla de datos (propiedad .Data) y las columnas definidas por el usuario (puede definir 3 tipos de cols, input, input opcional y cols de salida). Debe tener alguna tabla de datos para usar como fuente de datos para su grilla. Restablece esta tabla. No puedo crear un ejemplo de trabajo en este momento porque el código es de un proyecto en funcionamiento. Veré si puedo hacer mañana. – Zebi

+0

Gracias Zebi, muy apreciado. – Houman

Cuestiones relacionadas