Kinect Hack

Written by Bruno Pires on Fevereiro 2nd, 2012

33ª Edição - Fevereiro 2012

Para esta edição da Revista Programar, resolvi escrever um artigo sobre um dispositivo de hardware que está a mudar a forma como os utilizadores interagem com  jogos e  aplicações.

O Kinect é um dispositivo para a consola Microsoft Xbox 360, que através da detecção de movimentos e gestos realizados pelo utilizador ou até através do reconhecimento por voz, permite que o leitor consiga interagir com a consola e com os jogos de vídeo que suportam este hardware de uma forma natural, substituindo assim os controlos tradicionais que as consolas disponibilizam.
Foi anunciado pela primeira vez em Junho de 2009 conferência E3 sob o nome de código “Natal”. Colocado à venda em Novembro de 2010, o Kinect garantiu um lugar na história, em apenas 60 dias foram comercializados 8 milhões de unidades.
À primeira vista, o Kinect assemelha-se a uma webcam com um formato não muito convencional, mas na verdade, trata-se de muito mais do que isso. É composto por uma câmara RGB, um projector de raios IR que em conjunto com uma segunda câmara monocromática de IR constrói a informação em 3D com os metadados e um microfone vectorial (composto por quatro microfones colocados estrategicamente no dispositivo), que o tornam capaz de isolar e identificar as vozes dos vários jogadores e, para finalizar, possui um pequeno motor que lhe permite ajustar automaticamente o seu ângulo de visão para detectar todos os jogadores presentes.
As características técnicas que o Kinect apresenta a um preço acessível, suscitaram imediatamente muito interesse a uma comunidade que reconheceu de imediato as potencialidades que um dispositivo como este proporciona.
Sendo assim, ainda durante o mês de lançamento, uma empresa ofereceu uma recompensa a quem conseguisse desenvolver um driver open-source que permitisse o Kinect ser utilizado foram do seu âmbito, ou seja, fora do ecossistema da Xbox 360, para que o dispositivo pudesse ser utilizado para outros fins que não o entretenimento.
Apenas alguns dias após o seu lançamento, foi disponibilizado um driver para o Sistema Operativo Linux (Libfreenect) que permitia a utilização tanto da câmara RGB como dos sensores de profundidade 3-D. Em Dezembro do mesmo ano, a empresa PrimeSense, que é proprietária de tecnologia semelhante à apresentada pelo Kinect, lançou a sua própria versão do driver Open-Source para Kinect, bem como um Middleware dotado de um conjunto de funcionalidades até então apenas disponíveis na consola da Microsoft, como a capacidade de detecção de gestos e tracking de indivíduos.

Toda esta comoção gerada à volta do Kinect e a sua utilização fora do seu ambiente natural, levou à criação da organização sem fins lucrativos OpenNI (Open Natural Interaction) e em última instância, pressionou a Microsoft para relevar/alterar os seus planos para o Kinect e disponibilizar o Microsoft Kinect SDK.
Assim, o leitor tem ao seu dispor a escolha entre duas soluções para desenvolver as suas aplicações com o Kinect, a Framework OpenNI ou o Kinect SDK da Microsoft, atualmente em versão Beta, no entanto já foi anunciado que a versão comercial vai estar disponível em Fevereiro de 2012, acompanhada de uma nova versão de hardware, suportado oficialmente Microsoft.

Para ler mais sobre este e sobre outros temas, não deixe de descarregar a Revista Programar Nº33, disponível aqui.

kinect_hack_01.png

A aplicação descrita no decorrer de este artigo encontra-se disponível em http://kinecthack.codeplex.com

 

Artigos incluídos nesta edição:

Tema de capa
Kinect Hack

A programar
Geração de Números Aleatórios – Parte 3
Programação Orientada aos Objectos em Pascal
Herança com JavaScript
CORE DUMP – Ambientes Produtivos
Enigmas de C#: Disposable Structs
SQL Azure Federations na Pratica

Visual (Not) Basic
VISUAL (NOT) BASIC -Iterators

Comunidades
BizTalk Server – Princípios Básicos dos Mapas – Parte 2
Desenvolvimento em SharePoint 2010 – Parte 2

 

iOS, Cocoa Touch & MVC

Written by Bruno Pires on Dezembro 20th, 2011

ed32

Está disponível para download a Revista Programar nº 32. Nesta edição tive a oportunidade de escrever mais um artigo  “iOS, Cocoa Touch & MVC”, espero que gostem.

Além de este artigo podem encontrar os seguintes temas:

  • Geração de Números Aleatórios – Parte 2
    • O segundo de 4 artigos do mesmo autor da  excelente série “Programação em Lua”, desta vez sobre geração de números
      aleatórios.
  • Automatização de tarefas usando atributos
    • Continuação do artigo sobre atributos em C# da  edição número 30. Neste artigo, conheça melhor o funcionamento do  conceito de contextos nesta linguagem.
  • SQL Azure Fedarations
    • Introdução às SQL Azure Federations.
  • Enigmas de C#: Arrays
    • Saiba porque motivo, um array pode invocar uma  System.ArrayTypeMismatchException.
  • VISUAL (NOT) BASIC – Um pouco mais de Windows  Phone 7
    • Saiba como pode tirar partido de algumas  funcionalidades e características no desenvolvimento de aplicações para  esta plataforma.
  • CORE DUMP – Free as in Beer
    • Atualmente, as empresas usam software open  source, não por ser livre, mas por ser grátis. Conheça a opinião do autor  sobre este tema.

E ainda em colaboração com as comunidades AzurePt e NetPonto, respectivamente:

  • Como suportar múltiplas identidades no seu  WebSite com Windows Azure AppFabric ACS
    • Saiba como resolver o problema das identidades  em demasia através do Azure.
  • BizTalk Server – Princípios Básicos dos Mapas
    • Explore através deste artigo, o editor de mapas do  BizTalk Server.

Clique aqui para download.

 

Revista Programar Nº30

Written by Bruno Pires on Agosto 22nd, 2011

ed30

Publiquei na edição nº 30 da Revista Programar um artigo com o nome “Introdução ao Objective-C e à plataforma iOS”.

Nesta edição os leitores tiveram 15 dias para votar nos seus 3 artigos favoritos.

Após a conclusão da votação, o meu artigo ficou classificado em 2º lugar. Devo confessar que não estava à espera, ainda mais sendo este artigo a minha primeira contribuição para a revista.

Aproveito para agradecer às pessoas que me entusiasmaram a aceitar este desafio (Caio Proiete e Jorge Paulino) e a todos os leitores da Revista Programar que votaram no artigo.

 Edição nº 30 disponível para download aqui.

 

HTML5 & CSS3 no Visual Studio 2010

Written by Bruno Pires on Junho 20th, 2011

 

logohtml5Muito se tem falados nos últimos meses nos novos standards para Web HTML5 e CSS3, comparações com outras tecnologias, milhares de blog posts, artigos de opinião e discussões sobre o assunto.

Embora ainda não sejam um standard fechado, já existem projectos desenvolvidos outros projectos em desenvolvimento recorrendo a estas tecnologias, no entanto a grande maioria das ferramentas de desenvolvimento para web ainda não suportam HTML5 e CSS3, e até é compreensível dado que ainda não estão fechados os grupos de trabalho sobre as tecnologias, mas dado o interesse que se tem levantado sobre o assunto, Mads Kristensen, Program Manager na Microsoft e fundados do BlogEngine.NET, decidiu lançar o Visual Studio Web Standards Update, um pacote de actualização para o VS2010 SP1 que disponibiliza aos utilizadores de Visual Studio Intellisense e validações tão próximo quanto possível das espicíficações definidas até agora pelo W3C.

 

As funcionalidades de maior relevo são:

HTML5 – Video, Audio, Input Type, Drag & Drop, WAI-ARIA, Microdata, Schema.org

Browser API – GeoLocation & Local Storage

CSS3 – 2D Transforms, 3D Transforms, Animations, Background & Borders, Basic Box Model, Basic UI, Behavior, Color, Flexible Box Layout, Fonts, Paged Media, Hyperlink Presentation, Line, Lists, Marquee, Media Queries, Multi Column, Namespaces, Presentation Levels, Ruby, Selectors, Speech, Syntax, Template Layout, Text & Transitions.

 

Pode efectuar o download em http://visualstudiogallery.msdn.microsoft.com/a15c3ce9-f58f-42b7-8668-53f6cdc2cd83

Para mais informações: http://blogs.msdn.com/b/webdevtools/archive/2011/06/15/web-standards-update-for-visual-studio-2010-sp1.aspx

 

Silverlight & Model-View-ViewModel

Written by Bruno Pires on Maio 26th, 2011

pic1

Existem várias formas diferentes de definir a camada de apresentação, pode-se seguir uma aproximação tradicional, na qual toda a responsabilidade da camada de apresentação se encontra na View ou então podemos seguir um pattern para prodecer à separação de responsabilidades da camada de apresentção.

A aproximação mais tradicional torna-se mais simples e criar permite rapidamente uma camada de apresentação. É ideal quando se trata de aplicações de pequena dimensão .

O problema é que não existem aplicações de pequena dimensão, algumas podem começar dessa forma, mas muito rapidamente crescem e transforma-se em uma dor de cabeça para qualquer equipa de manutenção, dando origem a mais uma “Black Box” passados alguns anos.

Para ajudar a solucionar esse tipo de problema recorrente, nasceram algumas patterns que nos permitem estruturar de uma melhor forma a camada de apresentação das aplicações, entre elas estão o MVC (Model-View-Controller), MPV (Model-View-Presenter) e o MVVM (Model-View-ViewModel) que é o tema de este post.

Como não podemos deixar de falar em Silverlight ou WPF quando o tema é MVVM, vou apresentar um tutorial no qual demonstro como implementar MVVM no Silverlight.

O MVVM pretende estabelecer uma separação clara de responsabilidades na camada de apresentação, a View apenas é responsável pela User Interface, o Model detém as regras de negócio (classes de negócio, acesso a dados, etc) e o ViewModel é o responsável de fornecer à View apenas os dados que ela necessita e é também o ViewModel quem tem a responsabilidade de reagir aos eventos  gerados pela View.

Uma das grandes vantagens na utilização de um pattern como este, é que permite alterar completamente a UI apresentada ao utilizador sem que se torne necessário alterar mais do que a View, ou então, num caso mais extremo, partilhar o Model e o ViewModel e criar dois Front-End diferentes, como Silverlight e Windows Phone 7.

Vamos então ao que interessa, criar uma Demo de uma aplicação de gestão de Clientes, que apresenta a lista  de clientes de uma empresa e também permite adicionar um novos clientes à lista actual.

Vamos criar um novo projecto do tipo Silverlight Application no VS2010

image

 

Seleccionar a check-box “Host the Silverlight application in a new Web site”

image

 

Adicionar duas novas referências ao projecto Silverlight

image

 

Adicionar as referências à página MainPage.xaml

<UserControl x:Class="Silverlight_MVVM_Demo.MainPage"
    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:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"             

    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">

    </Grid>
</UserControl>

 

Vamos definir a View

image

Agora em XAML

<UserControl x:Class="Silverlight_MVVM_Demo.MainPage"
    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:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="Gray" Width="800" Height="600">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--DataGrid Definition-->
        <sdk:DataGrid Height="300" Grid.Row="0" BorderThickness="1"/>

        <!--Data Input Definition-->
        <sdk:Label
            Grid.Row="1"
            Height="28"
            HorizontalAlignment="Left"
            Margin="10,10,0,0"
            VerticalAlignment="Top"
            Width="171"
            Content="Adicionar novo cliente"
            FontFamily="Verdana"
            FontSize="13.333"
            FontWeight="Bold" />
        <TextBlock
            HorizontalAlignment="Left"
            Margin="80,59,0,0"
            Grid.Row="1"
            TextWrapping="Wrap"
            Text="Nome"
            VerticalAlignment="Top"/>
        <TextBox
            HorizontalAlignment="Left"
            Margin="80,79,0,0"
            Grid.Row="1"
            TextWrapping="Wrap"
            VerticalAlignment="Top"
            Width="245"/>
        <TextBlock
            HorizontalAlignment="Left"
            Margin="80,120,0,0"
            Grid.Row="1"
            TextWrapping="Wrap"
            Text="NIF"
            VerticalAlignment="Top"/>
        <TextBox
            HorizontalAlignment="Left"
            Margin="80,140,0,136"
            Grid.Row="1"
            TextWrapping="Wrap"
            Width="245"
            d:LayoutOverrides="Height"/>
        <TextBlock
            HorizontalAlignment="Left"
            Margin="80,0,0,98"
            Grid.Row="1"
            TextWrapping="Wrap"
            Text="Telemóvel"
            VerticalAlignment="Bottom"/>
        <TextBox
            HorizontalAlignment="Left"
            Margin="80,0,0,70"
            Grid.Row="1"
            TextWrapping="Wrap"
            Width="245"
            VerticalAlignment="Bottom"/>
        <TextBlock
            Margin="0,0,229,98"
            Grid.Row="1"
            TextWrapping="Wrap"
            Text="Número de Cliente"
            VerticalAlignment="Bottom"
            HorizontalAlignment="Right"
            Width="111"/>
        <TextBox
            Margin="0,0,96,70"
            Grid.Row="1"
            TextWrapping="Wrap"
            VerticalAlignment="Bottom"
            HorizontalAlignment="Right"
            Width="245"/>
        <TextBlock
            Margin="0,120,321,0"
            Grid.Row="1"
            TextWrapping="Wrap"
            Text="Fax"
            VerticalAlignment="Top"
            HorizontalAlignment="Right"
            RenderTransformOrigin="-1.579,0.438"/>
        <TextBox
            Margin="0,140,96,136"
            Grid.Row="1"
            TextWrapping="Wrap"
            d:LayoutOverrides="Height"
            HorizontalAlignment="Right"
            Width="245"/>
        <TextBlock
            Margin="0,59,293,0"
            Grid.Row="1"
            TextWrapping="Wrap"
            Text="Telefone"
            VerticalAlignment="Top"
            HorizontalAlignment="Right"/>
        <TextBox
            Margin="0,79,96,0"
            Grid.Row="1"
            TextWrapping="Wrap"
            VerticalAlignment="Top"
            HorizontalAlignment="Right"
            Width="245"/>
        <Button
            Content="Adicionar"
            HorizontalAlignment="Right"
            Margin="0,0,8,8"
            Grid.Row="1"
            VerticalAlignment="Bottom"
            Width="75"/>
    </Grid>
</UserControl>

 

Criar a estrutura de directórios

image

 

De seguida adicionar ao directório Model uma nova classe com o nome Cliente.cs com a seguinte estrutura

namespace Silverlight_MVVM_Demo.Model
{
    public class Cliente
    {
        public string ClienteID { get; set; }
        public string Nome { get; set; }
        public string NIF { get; set; }
        public string Telefone { get; set; }
        public string Telemovel { get; set; }
        public string Fax { get; set; }

    }
}

Vamos adicionar duas classe base que implementam os Interfaces ICommand e INotifyPropertyChanged.

Classe RelayCommand

using System;
using System.Windows.Input;

namespace Silverlight_MVVM_Demo.ViewModel
{
    public class RelayCommand : ICommand
    {
        private Action<Object> _handler;
        public RelayCommand(Action<Object> handler)
        {
            _handler = handler;
        }

        private bool _isEnabled = true;
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                if (value != _isEnabled)
                {
                    _isEnabled = value;
                    if (CanExecuteChanged != null)
                    {
                        CanExecuteChanged(this, EventArgs.Empty);
                    }
                }
            }
        }

        public bool CanExecute(object parameter)
        {
            return IsEnabled;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            _handler(parameter);
        }
    }
}

Se seguirmos uma abordagem simplista, podemos olhar para o ICommand como o interface que permite o ViewModel receber notificações de eventos da View.

 

Classe ViewModelBase

namespace Silverlight_MVVM_Demo.ViewModel
{
    using System.ComponentModel;
    /*TODOS OS VIEWMODEL HERDAM DESTA CLASSE*/
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler  PropertyChanged;
        public void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Vamos herdar todos os ViewModel da classe ViewModelBase para simplificar as notificações quando existem alterações nos conteúdos das propriedades, assim apenas vai ser necessário chamar o método RaisePropertyChanged(“NomeDaPropriedade”) para notificar o ViewModel e a View caso tal seja necessário.

 

De seguida criamos a classe de ViewModel

namespace Silverlight_MVVM_Demo.ViewModel
{
    using Model;
    using System.Collections.ObjectModel;

    public class MainPageViewModel : ViewModelBase
    {
        #region View Data Collection
        private ObservableCollection<Cliente> _ClientList;
        public ObservableCollection<Cliente> ClientList
        {
            get { return _ClientList; }
            set
            {
                _ClientList = value;
                /*Notificar alteração de conteúdo*/
                RaisePropertyChanged("ClientList");
            }
        }
        #endregion

        /*Propriedades utilizadas na View*/
        #region View Properties
        private string _ClientID;
        public string ClientID
        {
            get { return _ClientID; }
            set
            {
                _ClientID = value;
                /*Notificar alteração de conteúdo*/
                RaisePropertyChanged("ClientID");
            }
        }

        private string _ClientName;
        public string ClientName
        {
            get { return _ClientName; }
            set
            {
                _ClientName = value;
                /*Notificar alteração de conteúdo*/
                RaisePropertyChanged("ClientName");
            }
        }

        private string _ClientNIF;
        public string ClientNIF
        {
            get { return _ClientNIF; }
            set
            {
                _ClientNIF = value;
                /*Notificar alteração de conteúdo*/
                RaisePropertyChanged("ClientNIF");
            }
        }

        private string _ClientPhone;
        public string ClientPhone
        {
            get { return _ClientPhone; }
            set
            {
                _ClientPhone = value;
                /*Notificar alteração de conteúdo*/
                RaisePropertyChanged("ClientPhone");
            }
        }

        private string _ClientFax;
        public string ClientFax
        {
            get { return _ClientFax; }
            set
            {
                _ClientFax = value;
                /*Notificar alteração de conteúdo*/
                RaisePropertyChanged("ClientFax");
            }
        }

        private string _ClientCell;
        public string ClientCell
        {
            get { return _ClientCell; }
            set
            {
                _ClientCell = value;
                /*Notificar alteração de conteúdo*/
                RaisePropertyChanged("ClientCell");
            }
        }
        #endregion

        #region Commands
        public RelayCommand LoadClientData { get; set; }
        public RelayCommand SubmitForm { get; set; }
        #endregion

        public MainPageViewModel()
        {
            /*Comandos que o ViewModel vai reconhecer da View*/
            this.LoadClientData = new RelayCommand(MockClientList);
            this.SubmitForm = new RelayCommand(Submit);
        }

        /// <summary>
        /// Adiciona um novo cliente
        /// </summary>
        /// <param name="parameter"></param>
        protected void Submit(object parameter)
        {
            /*
             Como utilizamos as notificações quando
             é alterado o conteúdo de uma propriedade
             da View, já temos no ViewModel todos os
             dados.
             */
            var c = new Cliente
            {
                ClienteID = ClientID,
                Fax = ClientFax,
                NIF = ClientNIF,
                Nome = ClientName,
                Telefone = ClientPhone,
                Telemovel = ClientCell
            };

            ClientList.Add(c);

            ClientID = string.Empty;
            ClientFax = string.Empty;
            ClientCell = string.Empty;
            ClientName = string.Empty;
            ClientPhone = string.Empty;
            ClientNIF = string.Empty;
        }

        /// <summary>
        /// Dados iniciais da DataGrid
        /// </summary>
        /// <param name="parameter"></param>
        public void MockClientList(object parameter)
        {
            ClientList = new ObservableCollection<Cliente>();

            for (int i = 0; i < 3; i++)
            {
                var c = new Cliente{
                 ClienteID=i.ToString(),
                 Fax="123456789",
                 NIF="789456123",
                 Nome="Client "+i,
                 Telefone="5556623",
                 Telemovel="3237656511"
                };

                ClientList.Add(c);
            }
        }
    }
}

Agora ja temos definidas as três componentes do MVVM, apenas falta ligar a View com o ViewModel, e isso é conseguido através do Databinding, que o Silverlight nos proporciona para facilitar essa operação. Vamos então completar a página MainPage.xaml com os bindings.

<UserControl x:Class="Silverlight_MVVM_Demo.MainPage"
    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:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
    xmlns:vm="clr-namespace:Silverlight_MVVM_Demo.ViewModel"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <!--DATACONTEXT DEFINITION-->
    <UserControl.DataContext>
        <!--Link entre o ViewModel e a View-->
        <vm:MainPageViewModel/>
    </UserControl.DataContext>

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <!--Quando a página é carregada é executado o comando LoadClientData-->
            <i:InvokeCommandAction Command="{Binding LoadClientData}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>

    <Grid x:Name="LayoutRoot" Background="Gray" Width="800" Height="600">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--DataGrid Definition-->
        <sdk:DataGrid Height="300" Grid.Row="0" BorderThickness="1"/>

        <!--Data Input Definition-->
        <sdk:Label
            Grid.Row="1"
            Height="28"
            HorizontalAlignment="Left"
            Margin="10,10,0,0"
            VerticalAlignment="Top"
            Width="171"
            Content="Adicionar novo cliente"
            FontFamily="Verdana"
            FontSize="13.333"
            FontWeight="Bold" />
        <TextBlock
            HorizontalAlignment="Left"
            Margin="80,59,0,0"
            Grid.Row="1"
            TextWrapping="Wrap"
            Text="Nome"
            VerticalAlignment="Top"/>
        <TextBox
            Text="{Binding ClientName, Mode=TwoWay}"
            HorizontalAlignment="Left"
            Margin="80,79,0,0"
            Grid.Row="1"
            TextWrapping="Wrap"
            VerticalAlignment="Top"
            Width="245"/>
        <TextBlock
            HorizontalAlignment="Left"
            Margin="80,120,0,0"
            Grid.Row="1"
            TextWrapping="Wrap"
            Text="NIF"
            VerticalAlignment="Top"/>
        <TextBox
            Text="{Binding ClientNIF, Mode=TwoWay}"
            HorizontalAlignment="Left"
            Margin="80,140,0,136"
            Grid.Row="1"
            TextWrapping="Wrap"
            Width="245"
            d:LayoutOverrides="Height"/>
        <TextBlock
            HorizontalAlignment="Left"
            Margin="80,0,0,98"
            Grid.Row="1"
            TextWrapping="Wrap"
            Text="Telemóvel"
            VerticalAlignment="Bottom"/>
        <TextBox
            Text="{Binding ClientCell, Mode=TwoWay}"
            HorizontalAlignment="Left"
            Margin="80,0,0,70"
            Grid.Row="1"
            TextWrapping="Wrap"
            Width="245"
            VerticalAlignment="Bottom"/>
        <TextBlock
            Margin="0,0,229,98"
            Grid.Row="1"
            TextWrapping="Wrap"
            Text="Número de Cliente"
            VerticalAlignment="Bottom"
            HorizontalAlignment="Right"
            Width="111"/>
        <TextBox
            Text="{Binding ClientID, Mode=TwoWay}"
            Margin="0,0,96,70"
            Grid.Row="1"
            TextWrapping="Wrap"
            VerticalAlignment="Bottom"
            HorizontalAlignment="Right"
            Width="245"/>
        <TextBlock
            Margin="0,120,321,0"
            Grid.Row="1"
            TextWrapping="Wrap"
            Text="Fax"
            VerticalAlignment="Top"
            HorizontalAlignment="Right"
            RenderTransformOrigin="-1.579,0.438"/>
        <TextBox
            Text="{Binding ClientFax, Mode=TwoWay}"
            Margin="0,140,96,136"
            Grid.Row="1"
            TextWrapping="Wrap"
            d:LayoutOverrides="Height"
            HorizontalAlignment="Right"
            Width="245"/>
        <TextBlock
            Margin="0,59,293,0"
            Grid.Row="1"
            TextWrapping="Wrap"
            Text="Telefone"
            VerticalAlignment="Top"
            HorizontalAlignment="Right"/>
        <TextBox
            Text="{Binding ClientPhone, Mode=TwoWay}"
            Margin="0,79,96,0"
            Grid.Row="1"
            TextWrapping="Wrap"
            VerticalAlignment="Top"
            HorizontalAlignment="Right"
            Width="245"/>
        <Button
            Content="Adicionar"
            HorizontalAlignment="Right"
            Margin="0,0,8,8"
            Grid.Row="1"
            VerticalAlignment="Bottom"
            Width="75">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <!--Quando chamado o evento click, é executado o commando SubmitForm no ViewModel -->
                    <i:InvokeCommandAction Command="{Binding SubmitForm}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</UserControl>


E Finalmente temos a aplicação a funcionar com MVVM e nenhum código na View a não ser a definição do User Interface.

image

 

Solução VS2010 do projecto executado neste tutorial disponível aqui para download.

Referências:

http://www.silverlight.net/learn/videos/silverlight-4-videos/mvvm-introduction/

http://www.silverlight.net/learn/tutorials/silverlight-4/using-the-mvvm-pattern-in-silverlight-applications/

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090016

 

Comunidade NetPonto na UTAD – Evento Presencial

Written by Bruno Pires on Janeiro 31st, 2011

No dia 12/02/2011 a Comunidade NetPonto irá reunir-se em Vila Real pela 1ª vez, na Universidade de Trás-os-Montes e Alto Douro (UTAD). Para participar, efectue o registo de acordo com as instruções abaixo.

Agenda

13:45  – Recepção dos participantes

14:00 – Boas-vindas e apresentação da Comunidade NetPonto

14:10 – Desenvolvimento de Aplicações para Android em C# com o MonoDroidBruno Pires

15:40 – Integração Contínua com o HudsonBruno Lopes

17:10 – Coffee-break

17:40 – Desenvolvimento de Jogos em XNA para Windows Phone 7Virgílio Esteves e Andreas Vilela

19:10 – Painel de Discussão


Registo / Inscrição

Para participar, basta efectuar a inscrição através do site http://netponto-utad-fevereiro-2011.eventbrite.com/.
A entrada é gratuita.
Qualquer dúvida / esclarecimento, entre em contacto connosco.


Local

UTAD (Vila Real) – Engenharias I
Quinta de Prados
5001-801 Vila Real

Clique para ampliar o mapa.

Trajecto aconselhado desde Lisboa, Coimbra, Évora, Beja, Faro:
http://bit.ly/ehzMEE
Trajecto aconselhado desde o Porto:
http://bit.ly/fcgQIl
Trajecto aconselhado desde Portalegre, Castelo Branco, Guarda:
http://bit.ly/dHHt07

 

Sessões Técnicas Portugal GTUG

Written by Bruno Pires on Novembro 10th, 2010

Google_GTUG_Pt

Nos dias 16 e 30 de Novembro vão-se realizar na TB Store duas sessões técnicas da Comunidade GTUG(Google Technical User Group) Portugal.

Na sessão de dia 30 de Novembro vou ter o prazer se estar presente na qualidade de orador com o tema “Como desenvolver aplicações Android e iOS com C#”.

 

Introdução:

Há pouco mais de um ano, a Novell colocou no mercado um produto, o MonoTouch.

Este produto permite aos developers com conhecimentos em .NET e C# reutilizar código e conhecimento bem como assegurar uma transição mais suave para a plataforma Apple iOS.

Dado o sucesso do produto no mercado, a Novell está a preparar uma proposta semelhante ao MonoTouch, mas desta vez dirigida aos developers da plataforma Android.

O MonoDroid encontra-se neste momento em Closed Beta Preview, no entanto vai ser possível demonstrar alguns dos detalhes e potencialidades do produto.

 

Podem efectuar o registo em http://portugalgtug-lisboa-2010-11-30.eventbrite.com/ e obter mais informações em http://portugal-gtug.blogspot.com/

 

Visual Studio 2010 XAML Editor–Quick Tips #4

Written by Bruno Pires on Outubro 9th, 2010

xamllogo

O Visual Studio 2010 é sem dúvida alguma uma ferramenta excelente de trabalho. Já tive oportunidade de trabalhar com esta ferramenta em alguns projectos e até agora tem sido uma boa experiência.

Neste estou envolvido num projecto no qual que utilizo Visual Studio 2010, Silverlight e Expression Blend e tenho-me deparado com um problema em concreto, no Editor de XAML do Visual Studio 2010, cada vez que abro um ficheiro XAML, o editor abre por defeito em modo split (Editor/Preview).

xaml_screen_02

O problema é que o preview demora constantemente vários segundos a carregar o ficheiro e a executar o preview, quando na grande maioria das ocasiões não me interessa pré-visualizar o documento, apenas tenho interesse em editar o XAML.

É possível solucionar este problema, selecionar na barra de ferramentas do Visual Studio 2010 Tools –> Options e depois seleccionar como indica a imagem  Text Editor –> XAML –> Miscellaneous

xaml_options

 

 

 

 

 

 

 

 

 

Na Default View, selecionar “Always open documents in full XAML view” e a partir desse momento, sempre que abrir um documento XAML, este vai ser apresentado sempre em modo Markup.

 

SQL Server 2008 Intelisense – Quick Tips #3

Written by Bruno Pires on Outubro 9th, 2010

sql_server_2008O SQL Server 2008 trás muitas novidades, algumas introduzidas na ferramenta de produtividade Management Studio.

A mais interessante para muitos dos seus utilizadores é o Intelisense, uma funcionalidade algo polémica dadas as suas limitações.

Assim, muitos dos utilizadores preferem não utilizar o Intelisense ou então confiar em ferramentas externas para o desempenho desse trabalho.sqlprompt

No meu caso, tenho tido uma excelente experiência com as ferramentas que a Red Gate disponibiliza para o SQL Server, nomeadamento o SQL Prompt, e quando passei a utilizar o SQL Management Studio 2008, continuei a  confiar nesta ferramenta para me disponibilizar esta funcionalidade.

Para aqueles que preferem utilizar uma ferramenta externa para lhe fornecer o Intelisense ou apenas não querem  utilizar o Intelisense no Management Studio 2008, existe a possibilidade de desligar esta funcionalidade.

Para isso basta seleccionar no menu de topo do Management Studio 2008     Tools –> Options e no ecrã de contexto selecionar Text Editor -> Transact SQL –> Intelisense e de seguida remover a selecção na check box Enable Intelisense, como exemplificado na imagem.

options_intelisense

 

jQuery + Ajax + ASP.NET Generic Handler = Interactividade e Performance

Written by Bruno Pires on Agosto 23rd, 2010

jquery-logo

O título pode parecer demasiado confuso com a utilização de tantos termos, no entanto estou confiante que no fim do artigo, vai estar de acordo com a escolha.

Recentemente deparei-me com uma nova situação, por um lado necessitava de toda a interactividade e flexibilidade proporcionada pelo jQuery no cliente mas também queria continuar a utilizar no lado do servidor Microsoft ASP.NET de forma convencional, ou seja, eu precisava do melhor dos dois mundos.

Depois de executar alguns testes, encontrei rapidamente alguns entraves, limitações e complexidades, o que me levou à procura de uma solução simples e  eficaz.

Deparei-me com um cenário em que o utilizador necessitava de preencher um formulário extenso, para tornar mais agradável a experiência do utilizador, para isso implementei vários plugins do jQueryUI, conforme se pode verificar nas imagens em baixo.

 

img_6

img_7

img_8

 

A informação a inserir é extensa e necessita de validação no lado do servidor, não se torna prático executar tudo isso postback atrás de postback até estar tudo correcto, utilizar update panels torna-se demasiado complexo para o tipo de validação necessário e a biblioteca Ajax do ASP.NET não é das mais agradáveis de utilizar quando necessitamos de performance, optei por isso experimentar utilizar o método Ajax disponibilizado pelo jQuery.

Para simplificar o artigo, e porque o que realmente interessa é o conceito, optei por criar um formulário de teste cujo objectivo é adicionar um cliente ao sistema.

img_9

 

Depois adiciona-se um novo item ao projecto, um Generic Handler

img_10

Visto de uma forma mais simplista, um Generic Handler é uma página ASP.NET que contém apenas um método e não suporta eventos nem controlos.

De seguida vamos adicionar um novo ficheiro JS e utilizando método Ajax da biblioteca jQuery, vai ser chamado o Generic Handler AdicionarClienteHandler.

A função Ajax é de simples implementação, como se pode verificar ao analisar o script apresentado.

$(document).ready(function () {

    //activa o plugin Tabs
    $(function () {
        $("#tabs").tabs();
    });

    //método adicionar cliente
    $('#btnAdicionar').click(function () {

        $.ajax({
            url: '../../Handlers/AdicionarClienteHandler.ashx',
            data: $('form').serialize(),
            type: 'POST',
            success: function (data) {
                alert('Cliente adicionado com sucesso.');
                $('#listClientes').append(data);
            },
            error: function (data) {
                alert("Ocorreu um erro ao processar o seu pedido.");
            }
        });
    });
});

O utilizador vai preencher o formulário e quando é executado o click sobre o botão adicionar, vai ser executado o script apresentado anteriormente.

img_1

Este script vai serializar todos os campos de input que se encontram dentro da tag <form> e enviar esta informação para o Generic Handler através de um POST executado de forma assíncrona.

img_2

 

Depois o Generic Handler vai processar a informação enviada, executar as suas validações e construir a resposta.

using System;
using System.Linq;
using System.Web;
using System.Text;
using System.Collections.Generic;
using System.Collections.Specialized;

namespace WebApplication1.Handlers
{

    public class AdicionarClienteHandler : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            var form = context.Request.Form;
            context.Response.ContentType = "text/html";
            context.Response.Write(ProcessaFormulario(form));
        }

        protected string ProcessaFormulario(NameValueCollection form)
        {
            string username, nome, email, telefone, telemovel, fax;

            nome        = form["txtNome"];
            username    = form["txtUsername"];
            email       = form["txtEmail"];
            telefone    = form["txtTelefone"];
            telemovel   = form["txtTelemovel"];
            fax         = form["txtFax"];

            var buildResponse = new StringBuilder();

            buildResponse.AppendLine("<div class=\"DefaultRow\">");
            buildResponse.AppendLine(string.Format("<h6>{0}</h6>", nome));
            buildResponse.AppendLine(string.Format("<span class=\"DafaultRowLabel\">Username: {0}</span>", username));
            buildResponse.AppendLine(string.Format("<span class=\"DafaultRowLabel\">Email: {0}</span>", email));
            buildResponse.AppendLine(string.Format("<span class=\"DafaultRowLabel\">Telefone: {0}</span>", telefone));
            buildResponse.AppendLine(string.Format("<span class=\"DafaultRowLabel\">Telemóvel: {0}</span>", telemovel));
            buildResponse.AppendLine(string.Format("<span class=\"DafaultRowLabel\">Fax: {0}</span>", fax));
            buildResponse.AppendLine("</div>");

            return buildResponse.ToString();
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

 

A resposta por sua vez, é a informação do cliente formatada de acordo com a forma pretendida e pronta para ser adicionada à lista de clientes.

img_3

img_5

Tudo isto é executado de forma assíncrona, simples, eficaz e sem a necessidade de executar qualquer postback.

 

/*Versão JSON*/

Depois de verificar que surgiram alguns pedidos relativamente à utilização de JSON na resposta do Generic Handler, deixo aqui as alterações necessárias:

using System;
using System.Linq;
using System.Web;
using System.Text;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web.Script.Serialization;

namespace WebApplication1.Handlers
{

    public class AdicionarClienteHandler : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            var form = context.Request.Form;
            var serializer = new JavaScriptSerializer();

            context.Response.Charset = "utf-8";
            context.Response.ContentType = "application/json";
            context.Response.Write(serializer.Serialize(JsonResponse(form)));
        }

        public List<string> JsonResponse(NameValueCollection form)
        {
            string username, nome, email, telefone, telemovel, fax;

            var lista   = new List<string>();
            nome        = form["txtNome"];
            username    = form["txtUsername"];
            email       = form["txtEmail"];
            telefone    = form["txtTelefone"];
            telemovel   = form["txtTelemovel"];
            fax         = form["txtFax"];

            lista.Add(nome);
            lista.Add(username);
            lista.Add(email);
            lista.Add(telefone);
            lista.Add(telemovel);
            lista.Add(fax);

            return lista;

        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

Como podemos verificar na imagem em baixo, a resposta é agora JSON

foto_2

 

img_5

O projecto de teste aqui demonstrado , desenvolvido em Visual Studio 2010, está disponível para download aqui.

 

Referências:

http://api.jquery.com/serialize/

http://api.jquery.com/category/ajax/

http://msdn.microsoft.com/en-us/library/bb398986.aspx