Nice MultiValueConverter

If you have a MultiBinding and you want to get true when every binding evaluates to the same value, then this is four you, little pollo:

 public class AllEqualConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (!values.Any())
            {
                return true;
            }

            var first = values.First();

            var allAreTheSame = values.All(other => Equals(first, other));
            return allAreTheSame;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException("This is only mean to support conversions in One Way");
        }
    }
Anuncios

Un ComboBox con los elementos formateados que lo flipas

EDITADO: Lo de tener un combo editable con sufijos es un temario en el que no he tenido huevos para sacarlo. La pregunta en StackOverflow  aquí.

<ComboBox
                        IsEditable="True"
                        Width="70"
                        ItemsSource="{StaticResource ZoomValues}"
                        ItemStringFormat="{}{0:0.## %}"
                        Text="{Binding ActiveEditor.ZoomFactor, ElementName=Root, Converter={StaticResource PercentageConverter}, StringFormat={}{0:0.## %}}" />

Attention al Binding y al ItemStringFormat. Tócate la pera, chaval. ¡Cómo no se te va a olvidar esto?

Recurso estático en XAML a partir de un Singleton

No he encontrado manera mejor de hacerlo que esta:

<x:Static Member="common:ResourcesUIService.Instance" x:Key="ResourcesUIService"  />

Con esta sencilla nomenclatura y si has diseñado bien tu singleton, la extensión Static lo dará todísimo y tendrás acceso desde tu XAML favorito a la instancia con cosas tales como Bindings (que es de lo que se trata, ¡jojojo!).

Ponlo a prueba y nota su aroma.

¿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!

Don’t leave my this way!

UPDATE. My Glass library contains an improved version of this behavior. Take a look at it!

Aha! So you just discovered that users tend to break your applications typing everything you could imagine. Validation in Hell!

Imagine you have some information that has to be filled in. For example, this Window tell you to enter a value between 1 and 5.image

It may be not obvious to the user that information is extremely important. So you cannot leave it in an invalid state.

Boy, those mandatory fields must be valid before you go away!

But, how do you keep they into the TextBox? The user types “2000” and suddenly, they change the focus to the Dummy text box.

The required TextBox will show its value is invalid, but maybe the user is happy with that red TextBox and starts to touching here and there with something that is wrong. This can be, of course, perfectly acceptable, but sometimes the information you request just cannot be left in an invalid state.

That is why I made this Interaction Behavior. KeepFocusOnErrorBehavior.

If you attach it to any TextBoxBase (like TextBox), you will notice it will not let you change the focus to another control while it doesn’t pass the validation. Example:


As you can see, this behavior is attached to the TextBox and its ErrorCommand is set to a Command (in a View Model). This command makes it even better, because you can, for example, bind a Command that shows a message indicating that you’re not allowed to go anywhere before entering correct input.

I hope you like it Sonrisa

Here is the code:

public class KeepFocusOnErrorBehavior : Behavior<TextBoxBase> {
        protected override void OnAttached() {

            AssociatedObject.PreviewLostKeyboardFocus += AssociatedObjectOnPreviewLostKeyboardFocus;
            base.OnAttached();

        }

        private void AssociatedObjectOnPreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs keyboardFocusChangedEventArgs) {

            var textBindingExpression = AssociatedObject.GetBindingExpression(TextBox.TextProperty);

            // Forces to update the binding. As we are preventing the focus to be lost, its binding never updates and never recovers from a previous error.
            textBindingExpression.UpdateSource();

            var value = Validation.GetHasError(AssociatedObject);
            if (value) {
                keyboardFocusChangedEventArgs.Handled = true;
                ExecuteErrorCommandIfCanExecute();
            }
        }

        private void ExecuteErrorCommandIfCanExecute() {
            if (ErrorCommand != null) {
                if (ErrorCommand.CanExecute(ErrorCommandParameter))
                    ErrorCommand.Execute(ErrorCommandParameter);
            }
        }

        #region ShowErrorMessageCommand
        public static readonly DependencyProperty ErrorCommandProperty =
          DependencyProperty.Register("ErrorCommand", typeof(ICommand), typeof(KeepFocusOnErrorBehavior),
            new FrameworkPropertyMetadata((ICommand)null));

        public ICommand ErrorCommand {
            get { return (ICommand)GetValue(ErrorCommandProperty); }
            set { SetValue(ErrorCommandProperty, value); }
        }

        #endregion

        #region ErrorCommandParameter
        public static readonly DependencyProperty ErrorCommandParameterProperty =
          DependencyProperty.Register("ErrorCommandParameter", typeof(object), typeof(KeepFocusOnErrorBehavior),
            new FrameworkPropertyMetadata((object)null));

        public object ErrorCommandParameter {
            get { return (object)GetValue(ErrorCommandParameterProperty); }
            set { SetValue(ErrorCommandParameterProperty, value); }
        }

        #endregion

    }

SelectedItem, SelectedValue

Los ComboBox, las ListBox y toda esa recua de controles tan útiles son unas verdaderas bestias. En realidad, todos los ItemsControl son tan bellos como complejos.

No entender qué cojopios hacen es una de las razones por la que creamos chorricode totalmente vomitivo. “ItemsControl”, quédate con el nombre. ¡Hay que estudiárselos bien!

A nivel de usuario hay básico entender este par de propiedades:

  • SelectedItem: El elemento seleccionado. Si tenemos un Binding TwoWay a esta propiedad debemos cuidar muy mucho ciertas cosas. Lo más importante:

    El elemento enlazado con el “binding” puede no existir en la lista. Si esto se produce, visualmente no se seleccionará NADA. Es decir, ningún elemento se marcará.

  • SelectedValue: Valor seleccionado. No importa si el elemento no está en la lista. Se selecciona y punto. Queda más claro si digo que en un combo box, el Popup desplegable lleva la lista de elementos, pero luego tiene un elemento especial, que es el que aparece en la cajita del combo cuando está cerrado. El SelectedValue se pondrá ahí. Lo malo es que no siempre es posible representar el elemento (puede ser un elemento no “renderizable”.

IMPORTANTE: Para que la cosa funcione es imprescindible sobreescribir los métodos Equals en los elementos que vayan a ser representados en el ItemsControl. Es lógico, puesto que, ¿cómo va a saber sino cuál elemento se selecciona de la lista si no existe una manera de comprobar cuándo son el mismo elemento?

WARNING: El método Equals por defecto compara referencias, por lo que si son la misma referencia, el SelectedItem furrula fairly good, pero cuando la instancia te la sacas tú de la manga, haces un clone y vete tú a saber qué historias, el Equals es obligatorio si quieres que todo se sincronice solito.

¡Esos Equals tan impopulares a los que nadie les hace caso son importantísimos! Úsalos o tendré que sacar el látigo de dar.