Windows Platform

Windows | Problemas con Windows Hello

Hace algún tiempo, con alguna actualización Insider de Windows, dejó de funcionarme la autenticación por reconocimiento facial, conocida como Windows Hello, con lo que últimamente no he podido disfrutar de la comodidad de que se desbloquee el equipo al sentarme delante de él. Al dejar de funcionarme intenté añadir un nuevo perfil por si el problema estaba en que no había suficientes para comparar pero, al intentarlo, recibí un error que decía “It looks like you’ve already setup Windows Hello on another account” y que me imposibilitaba no sólo añadir nuevos perfiles sino usar Windows Hello en sí.

Tras varias semanas de buscar soluciones inexistentes y tratar de probar todo tipo de cosas como quitar Windows Hello y el PIN, ejecutar comandos de powershell para resetear la configuración de las Apps de Windows, etc… al final encontré la solución en un foro de Microsoft donde un usuario ha compartido una guía de pasos que ha tomado y que le han servido Solución

Mi solución

En mi caso, me ha bastado con ejecutar el paso 3 “Browse to C:\Windows\System32\WinBioDatabase\ and delete all entries, I had two for two user accounts.” para que comenzara a funcionarme de nuevo Windows Hello.

Espero que os ayude.

WPF | MVVM y Menú contextual (ContextMenu) en filas de un DataGrid y los problemas del Binding

posterEs bastante común en las aplicaciones que muestran listados de registros, disponer de un menú contextual que extienda las opciones disponibles a realizar sobre cada registro, o simplemente que contenga algunas de ellas que podamos considerar como más usadas para que el usuario no tenga que desplazarse por la pantalla en busca de la opción necesaria.

Para esto, prácticamente todos los controles de WPF disponen de menú contextual, fácilmente gestionable pero que presenta algunos retos cuando estamos trabajando con el patrón MVVM ya que, el Binding se tiene que resolver con el ViewModel que contiene las acciones para que los comandos asociados a las opciones funcionen correctamente, así que vamos a ver paso a paso cómo podemos solventarlo.

Montando el Menú Contextual en nuestro DataGrid

Montar el menú contextual es una labor muy sencilla ya que, con sólo acceder a la propiedad ContextMenu del DataGrid podríamos tenerlo pero, como lo queremos a nivel de registros, debemos asociárselo a cada una de las filas del DataGrid y no al DataGrid en sí mismo tal y como se muestra en el siguiente snippet de código.

<Window x:Class="WPFSamples.DataGridContextMenu.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPFSamples.DataGridContextMenu"
        mc:Ignorable="d"
        xmlns:viewModels="clr-namespace:WPFSamples.DataGridContextMenu.ViewModels"
        Title="MainWindow" 
        Height="350" 
        Width="525"
        WindowStartupLocation="CenterScreen">
    <Window.DataContext>
        <viewModels:FakeViewModel/>
    </Window.DataContext>
    <Grid>
        <DataGrid x:Name="MyGrid" 
                  ItemsSource="{Binding MyGridModelCollection}"
                  CanUserAddRows="False">
            <DataGrid.Resources>
                <ContextMenu x:Key="MyContextMenu">
                    <MenuItem Header="Test Option"/>
                </ContextMenu>
            </DataGrid.Resources>
            <DataGrid.RowStyle>
                <Style TargetType="{x:Type DataGridRow}">
                    <Setter Property="ContextMenu" Value="{StaticResource MyContextMenu}" />
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>
    </Grid>
</Window>

Como se puede observar en el código XAML, tendremos una colección asignada al DataGrid mediante un Binding a una colección de objetos de nuestro ViewModel. En el próximo artículo os hablaré sobre cómo establecer MVVM en WPF, así que de momento estableceremos el DataContext de nuestra vista de forma directa añadiendo el ViewModel tal y como se puede apreciar antes de comenzar el Grid con la etiqueta “<Window.DataContext>…”. Posteriormente definimos el ContextMenu como un recurso del DataGrid y le asignaremos un valor a la propiedad x:Name que debe ser único en el contexto del DataGrid y que en mi ejempo es “MyContextMenu” para después crear un estilo para las filas del DataGrid mediante la etiqueta “<DataGrid.RowStyle>…” donde establecemos mediante un “<Setter>” la propiedad ContextMenu de las filas y le asignamos el ContextMenu que definimos en los recursos del DataGrid haciendo uso de su Name.

quote-marks1NOTA: Como buena práctica, es importante asignar un valor a la propiedad x:Name de aquellos elementos más relevantes para poder acceder a ellos en Bindings y Storyboards que establezcamos en nuestro código XAML.quote-marks1

De esta forma, al ejecutar la aplicación, ya tendremos disponible un menú contextual en cada uno de los registros del DataGrid tal y como se puede ver en la siguiente imagen aunque de momento no ejecutará accíón alguna.

image

 

Añadiendo acciones a las opciones del menú contextual

En este punto es donde comienza a complicarse la situación porque debemos establecer un contexto para poder hacer un Binding con nuestro ViewModel y así poder ejecutar los comandos que contiene. Buscando información al respecto, encontré este artículo sobre ContextMenu a nivel de filas https://blog.gisspan.com/2012/11/contextmenu-for-wpf-datagrid-on-row.html que ofrece una buena explicación pero da por hecho que cada uno de los registros está asociado a un ViewModel en sí y que, por lo tanto, cada uno de ellos contiene las acciones a ejecutar. Pero en realidad, el caso es más complejo si estamos siguiendo el patrón MVVM de una forma más estricta y que, por lo tanto, disponemos de un ViewModel global para la vista que contiene toda la información que queremos mostrar en pantalla en forma de propiedades además de los comandos que se pueden ejecutar. Es decir, este ViewModel contiene una colección que no necesariamente tiene que ser también de ViewModels y que, de hecho, por rendimiento no debería serlo, además de los comandos que se pueden ejecutar tal y como muestro en el código a continuación.

    public class FakeViewModel : INotifyPropertyChanged
    {
        public List<MyGridModel> MyGridModelCollection
        {
            get; set;
        }


        private DelegateCommand<object> myCommand;
        public ICommand MyCommand => myCommand;


        public FakeViewModel()
        {
            MyGridModelCollection = InitializeCollection();

            this.myCommand = new DelegateCommand<object> (MyCommandMethod);
        }

        private void MyCommandMethod(object parameter)
        {
            var myModel = parameter as MyGridModel;
            MessageBox.Show("You selected a command");
        }

        private List<MyGridModel> InitializeCollection()
        {
            var collection = new List<MyGridModel>
            {
                new MyGridModel { Title = "Item #1", Desc="Desc for item #1 ", Created=System.DateTime.Now },
                    new MyGridModel { Title = "Item #2", Desc="Desc for item #2 ", Created=System.DateTime.Now },
                    new MyGridModel { Title = "Item #3", Desc="Desc for item #3 ", Created=System.DateTime.Now },
                    new MyGridModel { Title = "Item #4", Desc="Desc for item #4 ", Created=System.DateTime.Now },
                    new MyGridModel { Title = "Item #5", Desc="Desc for item #5 ", Created=System.DateTime.Now },
                };
            return collection;
        }

        #region PropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged([CallerMemberName]string propertyName = "")
        {
            var Handler = PropertyChanged;
            Handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion

    }

quote-marks1Es importante tener en cuenta que los ViewModels deberían implementar la interfaz INotifyPropertyChanged para poder comunicar a la vista cualquier cambio que se produzca en las propiedades que están enlazadas con Binding.quote-marks1

Una vez que tenemos nuestro ViewModel, vamos a enlazar nuestros comandos a través de la propiedad Command que tienen los elementos del ContextMenu de la siguiente forma.

<DataGrid.Resources>
  <ContextMenu x:Key="MyContextMenu">
    <MenuItem Header="Test Option"
              Command="{Binding MyCommand}"/>
  </ContextMenu>
</DataGrid.Resources>

Como se puede ver, estamos haciendo un Binding al comando definido en el ViewModel. ¿Funcionará? La respuesta es que No porque el contexto de cada una de las filas es el modelo que tiene que representar, es decir, una instancia de tipo MyGridModel que no contiene el comando, con lo que no encontrará lo que debe ejecutar.

Estableciendo el contexto adecuado

Para que sea posible encontrar el comando a ejecutar en cada una de las opciones del menú contextual, es necesario establecer su contexto real, es decir, el ViewModel global. Hay varios workarounds un poco complejos o mal pensados desde mi punto de vista, así que voy a dar mi versión óptima o la que creo que es más óptima. En primer lugar, le indicaremos al menú contextual que su contexto debe ser el ViewModel de la vista y esto lo haremos estableciendo el mismo que el del propio DataGrid. Esto implica que, al ser el contexto de cada fila el ViewModel completo, debemos pasar como parámetro del comando el elemento actual para que la acción se pueda ejecutar sobre ese elemento en cuestión. Estos cambios de contexto son los que cuesta algo más entender y establecer, pero se ven de forma clara en el código.

<DataGrid.Resources>
  <ContextMenu x:Key="MyContextMenu"
              DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}">
    <MenuItem Header="Test Option"
              Command="{Binding MyCommand}"
              CommandParameter="{Binding Path=SelectedItem,
                                        RelativeSource={RelativeSource Mode=FindAncestor,
                                        AncestorType={x:Type DataGrid}}}"/>
  </ContextMenu>
</DataGrid.Resources>

Como podéis ver, el parámetro del comando será el elemento seleccionado del DataGrid ya que, al hacer click con el botón derecho sobre el elemento, éste quedará seleccionado.

Con esta solución, ya podremos ejecutar los comandos necesarios dentro de nuestro ContextMenu y seguir trabajando con nuestro ViewModel respetando las características de MVVM.

Descarga

Si queréis ver el código completo, podéis acceder a mi repositorio de GitHub y descargároslo libremente

watch-github

 

Enjoy coding.

WPF | Eliminar barra de navegación en Frames

posterCuando estamos realizando la navegación dentro de un Frame en una aplicación WPF, de forma automática nos aparecerá la barra de navegación que ocasiones puede que no deseemos mantenerla pese a las ventajas que nos podría aportar, ya sea porque el diseño que debemos implementar no contemple esa barra de navegación o simplemente porque no queremos que el usuario la use y proveemos nosotros mismos la navegación funcional requerida.

Continue reading…

Windows Phone 8.1 | Usar el flash de la cámara ¿Torch o Flash?

posterMientras desarrollaba la aplicación Torch8 me encontré con estas dos formas de controlar el flash de la cámara pero, ¿cuál es la adecuada para qué momento y cómo debo usarla?

Si vamos a la documentación podemos observar que la ayuda para tomar esta decisión es mínima y que depende en gran medida de la interpretación que hagamos sobre la descripción.

  • TorchControl : Provides functionality for controlling the torch LED settings on a capture device.
  • FlashControl : Provides functionality for controlling the flash settings on a capture device.

Y os preguntaréis… WTF!! Pero si es análogo!! Pues no exactamente. Digamos que la diferencia es que Torch está pensado simplemente para alumbrar porque sí y Flash está pensando para realizar la acción de flash durante una captura de una foto o un vídeo aunque en definitiva, sea prácticamente lo mismo. De hecho, FlashControl contiene alguans propiedades más como RedEyeReduction y RedEyeReductionSupported que nos dan esa misma idea.

Sea cual sea lo que decidamos usar y que vaya acorde con nuestra aplicación, su uso es muy similar, necesitando únicamente una instancia de MediaCapture desde la que obtener el acceso al controlador tal y como muestro en los ejemplos

TorchControl

public void TurnTorch(bool on)
{
if (mediaCapture.VideoDeviceController.TorchControl.Supported)
{
if (on)
{
if (mediaCapture.VideoDeviceController.TorchControl.PowerSupported)
mediaCapture.VideoDeviceController.TorchControl.PowerPercent = 100;
mediaCapture.VideoDeviceController.TorchControl.Enabled = true;
}
else
mediaCapture.VideoDeviceController.TorchControl.Enabled = false;
}
}

FlashControl

        public void TurnFlash(bool on)
{
var flashControl = mediaCapture.VideoDeviceController.FlashControl;

            if (flashControl.Supported)
{
if (on)
{
if (flashControl.PowerSupported)
flashControl.PowerPercent = 100;
#if WINDOWS_PHONE_APP
if (flashControl.AssistantLightSupported)
flashControl.AssistantLightEnabled = true;
#endif
if (flashControl.RedEyeReductionSupported)
{
flashControl.RedEyeReduction = true;
}
flashControl.Enabled = true;
}
else
flashControl.Enabled = false;
}
}

 

Como podéis observar, con el control del flash se pueden realizar más tareas que sólo tienen sentido en la captura de una imagen pero, que en el caso de mi aplicación de linterna no tendrían razón de ser, por eso, debéis usar la que se adapte mejor a vuestra aplicación en cada momento.

Notas importantes

Como siempre, recordad liberar los recursos de la cámara como os indiqué en el artículo anterior y, como apunte a este artículo, no os asustéis si el led no se enciende cuando estéis desarrollando, simplemente, tened en cuenta que si el dispositivo está conectado al PC (o a la corriente) el led no se activará con este código

 

Espero que os sea de ayuda. Enjoy coding!!

Windows Phone 8.1 | Iniciar cámara para previsualización

posterSupongamos que estamos realizando una aplicació y necesitamos ver lo que estamos enfocando con la cámara ya sea para iniciar una grabación, tomar una foto o simplemente, como en mi caso para hacer una linterna con cámara (Torch8). Dado que ya tenemos disponible el desarrollo para Windows 10 (desktop y mobile) la información escasea acerca de esta temática para la plataforma Windows Phone 8.1 y Windows 8.1, así que he recopilado lo que he encontrado al respecto y os lo condensaré en este artículo.

Seleccionar cámara

Para empezar, debemos seleccionar la cámara del dispositivo dado que podemos tener delantera, trasera o las dos.

// Get all the cameras
DeviceInformationCollection cameras = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);

// Selecting frotal camera
DeviceInformation frontCam = (from webcam in cameras
                              where webcam.EnclosureLocation != null
                              && webcam.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Front
                              select webcam).FirstOrDefault();

// Selecting rear camera
DeviceInformation rearCam = (from webcam in cameras
                                where webcam.EnclosureLocation != null
                                && webcam.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back
                                select webcam).FirstOrDefault();

 

Inicializar parámetros de captura

Una vez tengamos la cámara deseada, tendremos que inicializar la captura de vídeo con los parámetros que necesitemos como por ejemplo el código que muestro a continuación

// Initialize MediaCapture parameters
await mediaCapture.InitializeAsync(new MediaCaptureInitializationSettings
{
    VideoDeviceId = rearCam.Id, // Using rear camera
    AudioDeviceId = "", // Don’t capture audio
    StreamingCaptureMode = StreamingCaptureMode.Video, // We want to capture video
    PhotoCaptureSource = PhotoCaptureSource.VideoPreview // Capture mode (Auto | Photo | VideoPreview)

});

Comenzar a obtener visualización de la cámara

Llegados a este punto, ya podemos visualizar lo que enfoquemos con la cámara en nuestro dispositivo y, para ello necesitamos tener preparado el control en la vista XAML y referenciarlo desde el código C#

XAML

<CaptureElement Name="PreviewControl"
                Stretch="UniformToFill"
                />

C#

// Set primary use as Video.

mediaCapture.VideoDeviceController.PrimaryUse = Windows.Media.Devices.CaptureUse.Video;

// Set the source of the CaptureElement to your MediaCapture
PreviewControl.Source = mediaCapture;

// Start Preview of Video.

await mediaCapture.StartPreviewAsync();

Más información

Toda esta información y podéis encontrarla con mayor profundidad en este enlace de MSDN 

Nota Importante

Debeis recordar que es absolutamente necesario liberar los recursos de la cámara al cerrar/suspender la aplicación ya que si no, puede haber conflictos con otras aplicaciones e incluso la nuestra no funcionará como esperamos, para ello, en el enlace que os he puesto tenéis a vuestra dispocisión una muestra de código para limpiar los recursos

public async Task CleanupCaptureResources()
{
    if (IsRecording && MediaCapture != null)
    {
        await MediaCapture.StopRecordAsync();
        IsRecording = false;
    }
    if (IsPreviewing && MediaCapture != null)
    {
        await MediaCapture.StopPreviewAsync();
        IsPreviewing = false;
    }

    if (MediaCapture != null)
    {
        if (PreviewElement != null)
        {
            PreviewElement.Source = null;
        }
        MediaCapture.Dispose();
    }
}

Esta limpieza debéis llevarla a cabo al menos al suspender la aplicación tal y como os copio y pego de la documentación

private async void OnSuspending(object sender, SuspendingEventArgs e)
{
    var deferral = e.SuspendingOperation.GetDeferral();

    //cleanup camera resources
    await CleanupCaptureResources();

    deferral.Complete();
}

No obstante debéis consultar en profundidad la documentación acerca de los estados y el ciclo de vida de las aplicaciones Windows Phone 8.1 o incluso estudiar la posibilidad de manejar la suspensión en la vista tal y como se explica en este artículo de MSDN.

 

Espero que os sea de ayuda. Enjoy coding!!!