931666

Xamarin e SignalR – Chat Cross-Plataform – Parte 2

Fala galera!

Vamos continuar o chat que começamos no último post Parte 1?

Dessa vez vamos criar nosso App utilizando o Xamarin.Forms, é um meio de criar um aplicativo atingindo iOS, Android e Windows Phone compartilhando além do Backend a nossa UI (User Interface) que é a parte que o usuário irá visualizar.

 

Com o Xamarin.Forms nós podemos criar o layout em código C# ou XAML, nesse caso vamos utilizar o C# pois no Visual Studio 2015 está acontecendo um problema ao editar o layout com XAML, não dá erro de compilação, mas no código os controles ficam sublinhados de vermelho e não funciona o intellisense no .xaml, tal bug só está acontecendo no Visual Studio, no Xamarin Studio você consegue utilizar tranquilamente o layout do XAML.

Vamos ao projeto então!

Primeiramente vamos criar nosso novo projeto Xamarin.Forms, para isso tem que ter instalado toda a parte de desenvolvimento de C# com Xamarin, no blog você irá encontrar posts ensinando como instalar.

Como de costume no Visual Studio: File -> New Project -> Visual C# -> Mobile Apps -> Blank App (Xamarin.Forms Portable):

Chat_00

Ao apertar OK, será criado 3 projetos dentro da solução: Class Library (Portable), Android, iOS e Window Phone (8.0):

Chat_01

No Xamarin.Forms o principal projeto será o Portable, mas para rodar a aplicação é necessária configurar um projeto como StartUp Project, para isso botão direito do mouse em cima do projeto que irá rodar e selecionar “Set as StartUp Project”:

Chat_02

 

Você podem verificar que no Portable há apenas uma classe, a App.cs, ela é a principal classe do Xamarin.Forms, pois nela é definida a página principal, ciclo de vida, etc. E ela é chamada em todos os outros projetos:

Chat_03Até aqui é um passo comum para todos os projetos Xamarin.Forms, se quiser ver o emulador funcionando ou tiver dispositivos configurados é só selecionar (StartUp Project) o projeto que quer rodar (iOS, Android ou Windows Phone) e apertar F5! =]

Um detalhe sobre esse projeto que vem como template, no Windows Phone ele vem com a versão 8.0, você pode com o botão direito nele dar um Retarget para o 8.1, mas tem um problema que acontece às vezes sim e às vezes não, de se der o retarget antes de compilar a DLL System.Windows.Interactivity não é gerada e fica como dependência não encontrada ao rodar o projeto Windows Phone. Nesse caso há duas opções: Compilar o projeto Windows Phone 8.0, ir na pasta bin e verificar se a dll está lá e ai sim dar o retarget para o 8.1, ou se já deu o retarget para 8.1, compilar um outro projeto com o 8.0 e copiar a dll de uma pasta bin para a outra.

Continuando o exemplo vamos agora configurar o client do ASP.NET SignalR, para isso vamos utilizar novamente o NuGet (para quem não se lembra como utilizar o NuGet, só olhar na parte 1) para adicionar referências, no caso o Microsoft.AspNet.SignalR.Client no projeto Portable:

Chat_06

 

Vamos organizar a solução para não ficarmos perdidos na solução que fica imensa no Visual Studio. Dentro do Portable vamos criar dois folders, o Models e o Views:

Chat_04

 

 

Dentro da pasta Models vamos criar duas classes, a ChatMessage.cs e a ChatModel.cs conforme abaixo:

using System;

namespace XSP.SignalR.Movel.Models
{
   public class ChatMessage
   {
      public string Name { get; set; }
      public string Text { get; set; }
      public DateTime Date { get; set; }
   }
}
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace XSP.SignalR.Movel.Models
{
    public class ChatModel : INotifyPropertyChanged
    {
        public ChatModel()
        {
            ListMessage = new ObservableCollection();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        ObservableCollection _listMessage;
        public ObservableCollection ListMessage
        {
            get { return _listMessage; }
            set
            {
                _listMessage = value;
                OnPropertyChanged();
            }
        }

        void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Uma breve explicação sobre o que escrevemos acima é que na classe ChatMessage.cs é simplesmente uma classe para guardamos os valores das mensagens que irão aparecer no App. E a classe ChatModel.cs é a Model que vamos usar na View correspondente ao Chat, nela implementamos a interface INotifyPropertyChanged para que ao mudar algum valor ele seja transmitido na tela e no código do App quando necessário. Esse é um conceito mais simplificado que futuramente iremos implementar com o MVVM, mas como esse não é o foco agora e vale um artigo só para ele vou apenas passar por cima.

Agora vamos criar nossas Views, nesse App teremos duas Views, a primeira onde coloco meu nome e aperto salvar e a do chat em si, bem simples, apenas para demonstrar para vocês um norte de como pode ser feito.

Vamos criar uma Content Page no projeto Portable:

Chat_07

 

E o código dela é esse:

using System;

using Xamarin.Forms;

namespace XSP.SignalR.Movel.Views
{
    public class UserPage : ContentPage
    {
        // Controles do Xamarin.Forms
        Entry _txtName;
        Button _btnSave;
        Label _lblName;

        public UserPage()
        {
            // Propriedades do Label
            _lblName = new Label
            {
                Text = "Enter a name:",
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Center
            };
            // Propriedades da caixa de texto
            _txtName = new Entry
            {
                HorizontalOptions = LayoutOptions.Fill,
                VerticalOptions = LayoutOptions.Center,
            };

            // Propriedades do botão
            _btnSave = new Button
            {
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Center,
                Text = "Save"
            };

            // Utilizando Event Handling para atribuir uma ação quando o botão for clicado, pra quem já trabalhou com Asp.NET Web Forms está em casa.
            _btnSave.Clicked += OnSave;

            // O Content é o conteúdo em si da tela, aqui definimos layouts, configurações específicas por plataformas e os controles que colocamos na tela.
            this.Content = new StackLayout
            {
                VerticalOptions = LayoutOptions.FillAndExpand,
                Padding = new Thickness(
                    left: 0,
                    right: 0,
                    bottom: 0,
                    top: Device.OnPlatform(iOS: 20, Android: 0, WinPhone: 0)),
                Children = {
                    _lblName,
                    _txtName,
                    _btnSave
                }
            };
        }

        private void OnSave(object sender, EventArgs e)
        {
            // Aqui eu estou dizendo pro aplicativo que ao salvar a nova tela principal será o tela de Chat passando o valor do usuário.
            App.Current.MainPage = new ChatPage(_txtName.Text);
        }
    }
}

Agora vamos criar a tela do Chat, a ChatPage.cs:

Chat_05

E seu código será:

using Microsoft.AspNet.SignalR.Client;
using System;
using Xamarin.Forms;
using XSP.SignalR.Movel.Models;

namespace XSP.SignalR.Movel.Views
{
    public class ChatPage : ContentPage
    {
        // Controles do Xamarin.Forms
        ListView _lstMessage;
        Entry _txtMessage;
        Button _btnSend;
        
        string _userName;

        // Variáveis para utilização do SignalR
        IHubProxy _hub;
        string url = @"http://localhost:63853/";
        HubConnection connection;

        public ChatPage(string userName)
        {
            _userName = userName;

            connection = new HubConnection(url);
            _hub = connection.CreateHubProxy("ChatHub");

            var viewModel = new ChatModel();

            // Aqui é onde funciona a mágica do SignalR, quando o evento broadcastMessage que definimos no outro projeto for acionado é aqui que tratamos o que irá acontecer quando receber as mensagens.
            _hub.On<string, string="">("broadcastMessage", (name, message) => viewModel.ListMessage.Add(new ChatMessage()
            {
                Date = DateTime.Now,
                Text = message,
                Name = name
            }));

            OnConnect();

            this.Content = new Label
            {
                HorizontalOptions = LayoutOptions.CenterAndExpand,
                VerticalOptions = LayoutOptions.CenterAndExpand
            };

            _lstMessage = new ListView
            {
                HorizontalOptions = LayoutOptions.FillAndExpand,
                VerticalOptions = LayoutOptions.FillAndExpand,
            };

            _txtMessage = new Entry
            {
                HorizontalOptions = LayoutOptions.FillAndExpand,
                VerticalOptions = LayoutOptions.FillAndExpand,
            };

            _btnSend = new Button
            {
                HorizontalOptions = LayoutOptions.FillAndExpand,
                VerticalOptions = LayoutOptions.FillAndExpand,
                Text = "Send"
            };

            // Aqui é o template do ListView que irá receber o conteúdo das mensagens e como serão apresentadas na tela
            var cell = new DataTemplate(typeof(TextCell));
            cell.SetBinding(TextCell.TextProperty, "Text");
            cell.SetBinding(TextCell.DetailProperty, "Name");

            _lstMessage.ItemTemplate = cell;

            // Lembra do INotifyPropertyChanged que implementamos na Model, é aqui que ele vai trabalhar atualizando os valores quando as mensagens forem adicionadas.
            _lstMessage.ItemsSource = viewModel.ListMessage;

            _btnSend.Clicked += OnSend;

            this.Content = new StackLayout
            {
                VerticalOptions = LayoutOptions.FillAndExpand,
                Padding = new Thickness(
                    left: 0,
                    right: 0,
                    bottom: 0,
                    top: Device.OnPlatform(iOS: 20, Android: 0, WinPhone: 0)),
                Children = {
                    _lstMessage,
                    _txtMessage,
                    _btnSend
                }
            };
        }

        private async void OnConnect()
        {
            await connection.Start();
        }

        private async void OnSend(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(_txtMessage.Text))
            {
                await DisplayAlert("Alert", "Type a message!", "OK");
            }
            else
            {
                await _hub.Invoke("Send", _userName, _txtMessage.Text);

                _txtMessage.Text = string.Empty;
            }
        }
    }
}

Um detalhe importante: haverá problemas se utilizar como url o endereço localhost que fizemos no chat web da parte anterior, pois o android identifica o localhost como algo interno dele e não consegue lê a aplicação que fizemos, no caso você deve hospedar ele no IIS local da máquina. Caso queiram uma explicação sobre como fazer isso, deixa nos comentários pois se colocar aqui ficará muito grande.

Por fim temos que ir no App.cs e dizer que a tela que irá iniciar o projeto será a UserPage.cs:

public App()
        {
            // The root page of your application
            MainPage = new UserPage();
        }

Agora é só selecionar com qual plataforma irá rodar e apertar F5 e ver a mágica acontecer!

 

Chat

 

Como brinde no repositório do GitHub coloquei uma console application pra brincar junto no Chat! =]

Código no GitHub:

https://github.com/viniciusoreis/XSP-SignalR

Xamarin e SignalR – Chat Cross-Plataform – Parte 2 5.00/5 (100.00%) 1 voto

Vinicius Reis

Xamarin Student Partner, Xamarin Certified Mobile Developer, MCT, MCSD e apaixonado por novas tecnologias!

3 comentários em “Xamarin e SignalR – Chat Cross-Plataform – Parte 2

  1. Hi there Sir/ Madame,

    Could i simply use google translate and follow your code to setup this project?

    I wanted to ask if SignalR from Xamarin app will still use websockets? I am told that from the APP, transports are downgraded to SSE and others, since MONO does not have a working websockets implementation

    1. Hi,

      Yes, you can translate, but in a few days our blog will have some posts in english.

      When you try to use AutoTransport specifying WebSocketTransport it’s not recognized from the SignalR.Client.Transport, one requirements is that client and server use .NET 4.5, but in Xamarin now I can’t use this way, you can implement WebSockets directly using plugins.

Deixe uma resposta

O seu endereço de email não será publicado Campos obrigatórios são marcados *

%d blogueiros gostam disto: