ASP.NET Adventure. My new project using SignalR.

image

I’m currently working on a set of applications to handle the main tasks of my family’s restaurant. This is a snapshot of the client for the kitchen. It’s on a very early state, but you can mark product orders as “Done”. It uses Entity Framework and some concepts of Domain-Driven Design. It’s also using Windows 8.1 and Windows Phone 8 for the clients (the waiters will have another kind of client to request orders to the kitchen.

SignalR is needed to notify waiters when an order is ready (or even when a product is ready). I wanted to share the progress on this! Smile For the moment, I think Windows 8 is a bit limiting in terms of layout. WPF is far more complete. But it doesn’t feel bad at all. I think the lack of Triggers for Styles will be a big headache, but some people are working on a MVVM-friendly way to face this using Visual States.

I also feel the asynchrony will be a major let down in a later stage of the solution, but with a bit of help, it can be done. I want to start it simple!

I hope you like it. The background is a bit lame, but I like blue hues! haha Open-mouthed smile

Hey, my picture appears in each order, but a picture of each waiter will appear in a few iterations, of course Smile with tongue out

Otra de ViewModels (con Cinch)

Señores, la peña está aburrida de escucharme insistir en cosas como SOLID, DDD, Separation Of Concerns, MVVM, XAML y demás.

Pero copón bendito, ¡si es que llevo razón! Dejad de hacer ñapas y programad como hombres, ¡joder!

Pues después de este arrebato para aquellos que más que programan “tirar líneas” y no aspiran a hacerlo mejor, os digo: el modelo es el camino , la verdad y la vida..

Para ello os propongo el siguiente caso extravagante. Queremos construir una instancia de nuestro modelo mediante un “asistente”. La interfaz da una serie de opciones para controlar sus propiedades. Hasta aquí todo es normal, pero ahora llega lo novedoso: nuestro modelo es un control visual. ¡Imaginad un botón! Queremos establecer sus propiedades con el asistente y el usuario puede ir controlando, por ejemplo, el tamaño del borde, el color de fondo, su texto…

Bien, nosotros queremos que cuando el usuario vaya introduciendo modificaciones en el control, se vaya actualizando su apariencia.

La cosa seguramente más de alguno todo esto lo haría a base de eventos y “sin complicarse” la vida, pero si quieres ser un maestro de la abstracción puedes optar por hacerlo como yo, un dopao de MVVM con 0% de materia grasa.

¿Qué he hecho? He creado la ventanita y un ViewModel que se hacer cargo de todas las propiedades del modelo (un Botón hecho a medida). Pero ahora viene lo divertido. Como no me gusta andar descalzo, voy armado con el Framework MVVM del maestro Sacha Barber, un tipo prático donde los haya, pero con un gusto por la elegancia y por la pureza.

Ese peaso de framework tiene durezas a chorros, pero una de las que más encandilan son las relacionadas con las validaciones. Te recomiendo que te pongas a mirarte Cinch si quieres hacer algo decente con MVVM y que prestes atención a los DataWrappers.

Básicamente un DataWrapper (envoltorio de datos) es eso, un envoltorio que se ocupa de encapsular una propiedad del ViewModel y proporcionarle soporte para validación y/o edición.

El tema es que esos DataWrappers contienen un DataValue con el dato encapsulado. Es posible agregar reglas al DataWrapper para que el ViewModel padre se entere de si se encuentran en un estado válido o no. La vista reaccionara a las validaciones sin tener que realizar actualizaciones. Todo perfectamente controlado y muy declarativo.

Bueno, para enteraros del tema no hay nada mejor que los tutoriales que pone Sacha en The Code Project. Por ejemplo: http://www.codeproject.com/Articles/38672/WPF-If-Carlsberg-did-MVVM-Frameworks-Part-4-of-n

¿Y para qué quiero Cinch y los DataWrappers del demonio?

Pues la verdad es que es muy jodido de explicar, pero en esencia resulta que el usuario puede meter cualquier dato y puede que ese dato no sea correcto. Imaginad el borde del botón. Le ponemos 1.000.000 de píxeles de ancho y la previsualización, evidentemente, pegaría un flete enorme al renderizar semejante barbarie.

La idea es que cuando el dato no sea válido, la previsualización PASA OLÍMPICAMENTE del dato.

¿Cómo? Con disparadores en el XAML, concretamente un estilo con DataTriggers 😉

Y ahora, para quien quiera saber la solución final, aquí está la pregunta que hice en Stack Overflow al respecto, que detalla todo el lío en inglés, que incluye la solución, con un trocete de XAML por si queda alguna duda.

http://stackoverflow.com/questions/17675285/mvvm-make-binding-update-viewmodel-only-when-data-is-valid/17695186?noredirect=1#17695186

Finalmente, si has llegado a leer hasta aquí y no te ha dado una embolia cerebral, o no te has dormido de aburrimiento, o si aún no piensas que se me va muchísimo la olla, quiero felicitarte sinceramente. ¡OLÉ TUS HUEVOS!

ViewModels: make them right!

It’s not so simple to just make a class implement the INotifyPropertyChanged and create some properties.

Normally you have to REPRESENT a model. But how? Replicating the properties in the model that you want? Exposing the model itself using a property?

That is a good question that every MVVM lover should have asked himself when writhing a ViewModel.

You can take a look at this article. It really hits the nail on the head.

http://msdn.microsoft.com/en-us/magazine/ff798279.aspx

I normally expose the model directly and make UI classes that implement INotifyPropertyChanged. But I see the property mapping far more elegant and pure MVVMish 😉

What do you prefer?

¿Objetos dinámicos en una DataGrid?

¿Qué broma es esta? ¡Enlazar una lista de elementos con un número indeterminado de propiedades es un fucking inferno!

Pero por otra parte, nadie dijo que representar cosas con un número variable de propiedades fuese a representarse fácilmente. Más bien es todo un reto.

Estoy investigando cómo hacerlo y parece ser que hay gente que lo ha conseguido haciendo uso del DynamicObject de .NET 4.0. Al parecer hay que lidiar con algún problema morrocotudo, ya que el DataGrid con “AutoGenerateColumns” obtiene las propiedades mediante el Type no mediante cada instancia. Golpe bajo.

A ver cómo me las apaño, que me he puesto en contacto con algunos lobos de mar que controlan del tema, pero parece que casi se esconden bajo las setas.

¡Cada problema es un mundo, chavalis!

Indicar el contexto de tus Bindings con DesignInstance

Pues resulta que hay una extensión de marcado (Markup Extension) en Blend que facilita enormemente el diseño cuando tienes Bindings y quieres indicar, por ejemplo, qué tipo de DataContext tendrás en tiempo de ejecución. Con ReSharper se agradece y mucho.

Aquí está un recorte que hará que no tengas que estar comiéndote la olla demasiado, porque no queda muy obvio eso de {d:DataContext=”…”}.

Estos son los espacios de nombres a definir (con Ignorable).

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"

Y ésta es la propiedad a establecer donde quieras indicar el DataContext

d:DataContext="{d:DesignInstance designer:MainWindowViewModel}"

Sobre todo, usando Cinch (MEFedMVVM), debido a que los ViewModels se inyectan en ejecución, es bastante útil.

Patrón Messenger para hacer golferías

¡Esto es casi un hack, casi una trampa!

Observa y caga blandito con este ejemplo de un árbol generado en el ViewModel y representado en la vista. Al pulsar sobre un nodo ¡el ViewModel se entera de todo! ¡Es un topo! Te empaqueto el ejemplo porque sé que un día de estos se te va a olvidar y lo querrás todo mascadito. Golfo, que eres un golfo.

image

Así queda el temario, para que identifiques claramente qué cojones vamos a hacer.

https://skydrive.live.com/redir?resid=C8B0DBB75540E8D5!25872&authkey=!AAmYXeD4O0cUpyA

Y sobre todo, atento a esta parte:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using GalaSoft.MvvmLight;
using System.Linq;
using GalaSoft.MvvmLight.Messaging;

namespace Tree.ViewModel
{
    /// <summary>
    /// This class contains properties that the main View can data bind to.
    /// 
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// 
    /// 
    /// You can also use Blend to data bind with the tool's support.
    /// 
    /// 
    /// See http://www.galasoft.ch/mvvm
    /// 
    /// </summary>
    public class MainViewModel : ViewModelBase
    {
        private ObservableCollection _form;
        private Form _selectedForm;


        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel()
        {
            ////if (IsInDesignMode)
            ////{
            ////    // Code runs in Blend --> create design time data.
            ////}
            ////else
            ////{
            ////    // Code runs "for real"
            ////}

            var modeloForms = new ObservableCollection
                        {
                            new Form{ 
                                Name = "Form1",
                                Children = new Collection
                                               {
                                                   new Form{ 
                                                       Name = "Hijo 1",
                                                       Children = new Collection
                                                                      {
                                                                          
                                                                          new Form {Name = "Hijillo pequeño 1"},
                                                                      }
                                                   },
                                                   new Form{ Name = "Hijo 2"},
                                               },


                            }
                        };
          
            Forms = new ObservableCollection(modeloForms.Select(form => new FormViewModel(form)));

            Messenger.Default.Register<PropertyChangedMessage>(
              this,
              OnIsSelectedChanged);
        }

        private void OnIsSelectedChanged(PropertyChangedMessage obj)
        {
            var viewModel = obj.Sender as FormViewModel;
            if (viewModel != null && viewModel.Children == null)
            {
                SelectedForm = viewModel.Form;
            }
        }

        public ObservableCollection Forms
        {
            get { return _form; }
            set
            {
                _form = value;
                RaisePropertyChanged(() => Forms);
            }
        }

        public Form SelectedForm
        {
            get { return _selectedForm; }
            set
            {
                _selectedForm = value;
                RaisePropertyChanged(() => SelectedForm);
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GalaSoft.MvvmLight;

namespace Tree
{
    public class FormViewModel : ViewModelBase
    {
        private Form _form;
        private bool _isSelected;
        private IList _children;

        public FormViewModel(Form form)
        {
            _form = form;

            if (form.Children != null)
            {
                Children = form.Children.Select(form1 => new FormViewModel(form1)).ToList();
            }
        }


        public Form Form
        {
            get { return _form; }
            set
            {
                _form = value;
                RaisePropertyChanged(() => Form);
            }
        }

        public IList Children
        {
            get { return _children; }
            set
            {
                _children = value;
                RaisePropertyChanged(() => Children);
            }
        }

        public bool IsSelected
        {
            get
            {
                return _isSelected;
            }
            set
            {
                var old = _isSelected;
                _isSelected = value;
                RaisePropertyChanged(() => IsSelected, old, value, true);
            }
        }



    }
}

Pego el codiguejo para que además tengas ese apoyo visual que tanto nos gusta. Y qué pongo aquí? Pues el RaisePropertyChanged con 4 parámetros. Surprising! Bueno, ¡pruébalo y saborea su miel YA!

¡Menús dinámicos! Harás cacota si no sabes esto

Imagina lo siguiente: Tienes un menú que se compone mediante un binding, pero resulta que es una combinación de varias colecciones. Por ejemplo, un menú que presenta una serie de opciones fijas (o variables), y entre medias, una colección enlazada con Binding. Pues colleiga, ¡se hace así!

<MenuItem.ItemsSource>

    <CompositeCollection>

        <!--<MenuItem Header="Menú de coña1" />

        <MenuItem Header="Menú de coña2" />

        <Separator/>-->

        <CollectionContainer Collection="{Binding Source={StaticResource EditorsCollectionViewSource}}" />

        <!--<Separator/>

        <MenuItem Header="Menú de coña3" />-->

    </CompositeCollection>

</MenuItem.ItemsSource>

Con la ayuda de un lobo de mar que dejó su info en Internet, ¡como los buenos samaritanos de Dios!

http://wilberbeast.com/2011/05/31/compositecollection-binding-problem/#comment-2337

En referencia a este error guarrero que da si no enlazas con la CollectionViewSource:

Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=FilterOptions; DataItem=null; target element is ‘CollectionContainer’ (HashCode=23627591); target property is ‘Collection’ (type ‘IEnumerable’)

¡Buen provecho, y una patada en el pecho!