Otro interesante artículo en “Karl on WPF” sobre el uso del patrón Model-View-ViewModel en las aplicaciónes de negocio realizadas en WPF ( por lo visto no elegí mal en su momento al decidir utilizarlo
)
Página de Archivo 3
XAML Power Toys
Revisando un post del blog Karl on WPF me he encontrado con las XAML Power Toys, de momento no he tenido tiempo de verlas mucho, pero parecen una gran ayuda a la hora de diseñar los formularios con WPF.
A ver si puedo echarles un ojo con detenimiento
WPF DataGrid v1 liberado
Más información aquí.
Linq to SQL, ¿muerto?
Finalmente para implementar el borrado de una “fila” de un detalle, he implementado una nueva clase MasterDetailViewModel, que deriva de la clase ViewModel que ya tenia implementada.
Las vistas en las que vayan a ser maestro-detalle deberán implementar el ViewMode derivando de esta clase.
La clase tiene dos propiedades nuevas
· CurrentDetailName. Que indica el nombre del detalle que está activo en la vista ( deberá coincidir con el nombre de una propiedad de la entidad asociada al ViewModel.
· CurrentItem. Que tiene el objeto que esta actualmente seleccionado en el detalle.
1: public string CurrentDetailName
2: {
3: get { return this.currentDetailName; }
4: set
5: {
6: if (this.currentDetailName != value)
7: {
8: this.currentDetailName = value;
9: this.UpdateAllowedUserActions();
10: }
11: }
12: }
13:
14: public object CurrentItem
15: {
16: get { return this.currentItem; }
17: set
18: {
19: if (this.currentItem != value)
20: {
21: this.currentItem = value;
22: this.UpdateAllowedUserActions();
23: }
24: }
25: }
Además sobreescribe dos métodos de ViewModel, para poder activar el botón de borrar de la barra de herramientas cuando estamos en edición y hay un detalle activo y otro para realizar el borrado.
1: protected override bool CanDelete(object obj)
2: {
3: bool canDelete = false;
4:
5: if (this.ViewModelState == ViewModelStateType.Default)
6: {
7: canDelete = base.CanAddNew(obj);
8: }
9: else
10: {
11: canDelete = (this.DeleteCommand.IsActive &&
12: !String.IsNullOrEmpty(this.CurrentDetailName) &&
13: this.CurrentItem != null);
14: }
15:
16: return canDelete;
17: }
18:
19: protected override void Delete(object obj)
20: {
21: if (this.ViewModelState == ViewModelStateType.Default)
22: {
23: base.Delete(obj);
24: }
25: else
26: {
27: // Get the detail property info
28: PropertyInfo pi = this.DataModel.GetType().GetProperty(currentDetailName);
29: Debug.Assert(pi != null, String.Format("Detail {0} not found", currentDetailName));
30:
31: // Get the detail property value
32: object detail = pi.GetValue(this.DataModel, null);
33: Debug.Assert(pi != null, String.Format("Detail {0} not found", currentDetailName));
34: Debug.Assert(detail is IBindingList, String.Format("Detail {0} doesn't implement IBindingList", currentDetailName));
35:
36: IBindingList detailList = (IBindingList)detail;
37:
38: // Add a new entity to the detail object and set it as the current item
39: detailList.Remove(this.CurrentItem);
40: }
41: }
En mi caso el detalle se va a mostrar siempre en un Grid, que, por el momento al menos, es la versión Express de el DataGrid de Xceed.
La solución es la más sencilla y posiblemente no es la ideal, pero hasta que encuentre una mejor me vale.
Por el momento sólo tiene 2 pegas.
1. Que necesita código en la vista para actualizar el nombre del detalle que está activo, por ejemplo:
1: private void DataGridCambios_IsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs e)
2: {
3: if (Convert.ToBoolean(e.NewValue))
4: {
5: this.ViewModel.CurrentDetailName = "Cambios";
6: }
7: else
8: {
9: this.ViewModel.CurrentDetailName = "";
10: }
11: }
2. Que al realizar el borrado el Grid está perdiendo el foco, cosa que resulta bastante molesta, tendré que ver si tengo alguna forma de solventarlo jejeje
WPF Datagrid CTP
Estos días estoy pensando como voy a hacer para implementar las vistas maestro-detalle con el patrón Model-View-ViewModel, no he encontrado mucha información sobre ello, y tengo un par de opciones que tengo que probar, a ver cual va mejor.
Hay que tener en cuenta que va a poder haber mas de un detalle, en el caso de la vista de Divisas, que es la que estoy haciendo a modo de prototipo ya que tiene casi todo lo necesario y no es muy complicada, habrá 2 detalles, uno para los cambios y otro para el arqueo de moneda.
Otra de las cosas a tener en cuenta es que en estado de edición ( nuevo/edición ) los botones de añadir y borrar deberían poder actuar sobre el detalle que esté activo en cada momento ( que en el caso de la vista de Divisas se visualizan/editan en un grid ), y esto es lo que mas me está costando decidir como enfocar jeje
En cuanto tenga la implementación definitiva explicaré en un post nuevo como lo haya enfocado.
Impresión de informes en WPF
Búsquedas rápidas
Las búsquedas rápidas van a servir para buscar ( raro no ?? ) datos y mostrarlos en 1 o más controles de la vista activa.
Todavia no lo tengo terminado, pero va a constar de 3 partes:
1. Un botón de búsqueda.
2. Un popup, que se visualizará al hacer el click en el botón de búsqueda.
3. Configuraciones para las búsquedas que permitirán personalizarlas un poco.
Por el momento sólo tengo implementadas búsquedas por 2 campos, pero acabaré extendiéndolo para que soporte más de 2 lógicamente.
Un par de ejemplos de como se ven:
La configuración para está búsqeda se definiría así ( por el momento irán el app.config de la aplicación, aunque posiblemente sea mejor tenerlas en archivos XML a parte ):
1: <search
2: name="Divisas"
3: type="Generic"
4: mode="WCF"
5: description="Búsqueda de divisas"
6: handler="VisualPyme.Communications.MessagingGateway, VisualPyme.Communications"
7: entityType="VisualPyme.Data.Model.DataTransferObjects.Divisa, VisualPyme.Data.Model.DataTransferObjects">
8: <parameters>
9: <parameter
10: name="IdDivisa"
11: title="Divisa"
12: type="string"
13: length="10"
14: />
15: <parameter
16: name="NombreUnidadMonetariaPlural"
17: title="Nombre"
18: type="string"
19: length="30"
20: />
21: </parameters>
22: <columns>
23: <column
24: selection="Id"
25: name="IdDivisa"
26: header="Divisa"
27: length="10"
28: />
29: <column
30: selection="Description"
31: name="NombreUnidadMonetariaPlural"
32: header="Nombre"
33: length="30"
34: />
35: </columns>
36: </search>
- name, nombre de la búsqueda ( ejerce de identificador de la misma )
- type, servirá para saber que popup mostrar al hacer click en el bóton, por el momento sólo hay uno, y posiblemente no haya más, con lo que posiblemente acabe por desaparecer.
- description, descripción de la búsqueda.
- handler, es el nombre de la clase que nos permitirá realizar la búsqueda a través de WCF.
- entityType, el nombre de la clase que representa el tipo de datos devuelto por la búsqueda.
- parameters, los datos de los campos por lo que se permite realizar la búsqueda.
- columns, los datos de las columnas que se deben mostrar en el grid en el que se muestran los resultados.
Ejemplo de como se usaría el botón en XAML:
1: <WrapPanel Grid.Column="1" Grid.Row="1" >
2: <TextBox Width="150"
3: Text="{Binding IdDivisa, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
4: HorizontalAlignment="Left" x:Name="txtDivisa" CharacterCasing="Upper" AcceptsReturn="False"
5: Margin="5"/>
6:
7: <customControls:SearchButton
8: x:Name="Searcher"
9: SearchName="Divisas"
10: SelectionIdTextBox="{Binding ElementName=txtDivisa}"
11: ImageSource="/VisualPyme.Shell.Resources;Component/Images/Icons/magnifier.png" Focusable="False" />
12: </WrapPanel>
Todavía me faltan algunas cosillas por ver y por cambiar que no me convencen del todo de como lo tengo implementado, pero cada vez tiene mejor pinta
WCF huuuuuummmmmm …
… para la próxima parte que quiero ver (más adelante escribiré para explicar que es) estoy replanteándome el cambiar lo que tenia pensado para los servicios de WCF, que era:
1. Un proyecto con un servicio de WCF por cada módulo de la aplicación, que ejercería de fachada sobre la implementación real del servicio (que estaría en otro ensamblado/proyecto ).
2. Otro proyecto con la implementación real de cada servicio de WCF
DE está forma salen bastantes servicios … con muchísimos métodos/operaciones … que además con el tiempo seguirían creciendo … no es que sea un gran problema, pero, no me gusta
Así que estoy planteándome el crear un solo servicio de WCF con un sólo método y buscando la forma de identificar, en función de los datos del mensaje que llegue al servicio WCF (request), que “servicio” real tiene que ejecutarse.
Seguramente no sea la mejor manera de enfocarlo pero …