Windows no Xamarin.Mac

Este artigo aborda o trabalho com janelas e painéis em um aplicativo Xamarin.Mac. Ele descreve a criação de janelas e painéis no Xcode e no Construtor de Interfaces, carregando-os de storyboards e arquivos .xib e trabalhando com eles programaticamente.

Ao trabalhar com C# e .NET em um aplicativo Xamarin.Mac, você tem acesso ao mesmo Windows e Painéis em Objective-C que um desenvolvedor está trabalhando e o Xcode . Como o Xamarin.Mac se integra diretamente ao Xcode, você pode usar o Construtor de Interfaces do Xcode para criar e manter seus Windows e Painéis (ou, opcionalmente, criá-los diretamente no código C#).

Com base em sua finalidade, um aplicativo Xamarin.Mac pode apresentar um ou mais Windows na tela para gerenciar e coordenar as informações com as quais ele exibe e trabalha. As funções principais de uma janela são:

  1. Para fornecer uma área na qual modos de exibição e controles podem ser colocados e gerenciados.
  2. Para aceitar e responder a eventos em resposta à interação do usuário com o teclado e o mouse.

O Windows pode ser usado em um estado de Modeless (como um editor de texto que pode ter vários documentos abertos ao mesmo tempo) ou Modal (como uma caixa de diálogo Exportar que deve ser descartada antes que o aplicativo possa continuar).

Os painéis são um tipo especial de Janela (uma subclasse da classe base NSWindow ), que normalmente servem a uma função auxiliar em um aplicativo, como janelas de utilitário como inspetores de formato de texto e seletor de cores do sistema.

Editando uma janela no Xcode

Neste artigo, abordaremos as noções básicas de como trabalhar com Windows e Painéis em um aplicativo Xamarin.Mac. É altamente sugerido que você trabalhe primeiro no artigo Olá, Mac , especificamente nas seções Introdução ao Xcode e Construtor de Interfaces e Saídas e Ações , pois aborda os principais conceitos e técnicas que usaremos neste artigo.

Talvez você queira dar uma olhada na seção Expondo classes/métodos C# do Objective-C documento Interno do Xamarin.Mac , ele explica os Register comandos e Export usados para conectar suas classes C# a Objective-C objetos e elementos de interface do usuário.

Introdução às janelas

Conforme indicado acima, uma Janela fornece uma área na qual modos de exibição e controles podem ser colocados e gerenciados e responde a eventos com base na interação do usuário (seja por teclado ou mouse).

De acordo com a Apple, há cinco tipos de main do Windows em um aplicativo macOS:

  • Janela do Documento – uma janela de documento contém dados de usuário baseados em arquivo, como uma planilha ou um documento de texto.
  • Janela do Aplicativo – uma janela do aplicativo é a janela main de um aplicativo que não é baseado em documento (como o aplicativo Calendário em um Mac).
  • Painel – um painel flutua acima de outras janelas e fornece ferramentas ou controles com os quais os usuários podem trabalhar enquanto os documentos estão abertos. Em alguns casos, um painel pode ser translúcido (como ao trabalhar com gráficos grandes).
  • Caixa de diálogo – uma caixa de diálogo é exibida em resposta a uma ação do usuário e normalmente fornece maneiras de os usuários concluirem a ação. Uma caixa de diálogo requer uma resposta do usuário antes que ela possa ser fechada. (Consulte Trabalhando com caixas de diálogo)
  • Alertas – um alerta é um tipo especial de caixa de diálogo que aparece quando ocorre um problema grave (como um erro) ou como um aviso (como se preparar para excluir um arquivo). Como um alerta é uma caixa de diálogo, ele também requer uma resposta do usuário antes que ele possa ser fechado. (Consulte Trabalhando com alertas)

Para obter mais informações, consulte a seção Sobre o Windows dos temas de design do macOS da Apple.

Janelas principais, de chave e inativas

O Windows em um aplicativo Xamarin.Mac pode parecer e se comportar de forma diferente com base em como o usuário está interagindo com eles no momento. O principal documento ou janela do aplicativo que atualmente é o foco da atenção do usuário é chamado de Janela Principal. Na maioria dos casos, essa Janela também será a Janela de Chave (a janela que está aceitando a entrada do usuário). Mas nem sempre esse é o caso, por exemplo, um Seletor de Cores pode estar aberto e ser a janela Chave com a qual o usuário está interagindo para alterar o estado de um item na Janela do Documento (que ainda seria a Janela Principal).

O Main e o Key Windows (se eles estiverem separados) estão sempre ativos, o Windows inativo são janelas abertas que não estão em primeiro plano. Por exemplo, um aplicativo editor de texto poderia ter mais de um documento aberto por vez, apenas a Janela Principal estaria ativa, todas as outras estariam inativas.

Para obter mais informações, consulte a seção Sobre o Windows dos temas de design do macOS da Apple.

Janelas de nomenclatura

Uma Janela pode exibir uma Barra de Título e, quando o Título é exibido, geralmente é o nome do aplicativo, o nome do documento em que está sendo trabalhado ou a função da janela (como Inspetor). Alguns aplicativos não exibem uma Barra de Título porque são reconhecíveis à vista e não funcionam com documentos.

A Apple sugere as seguintes diretrizes:

  • Use o nome do aplicativo para o título de uma janela main, não document.
  • Nomeie uma nova janela untitledde documento. Para o primeiro novo documento, não acrescente um número ao Título (como untitled 1). Se o usuário criar outro novo documento antes de salvar e titular o primeiro, chame essa janela untitled 2, untitled 3etc.

Para obter mais informações, consulte a seção Nomenclatura do Windows dos temas de design do macOS da Apple.

Janelas de tela inteira

No macOS, a janela de um aplicativo pode ir para a tela inteira ocultando tudo, incluindo a Barra de Menus do Aplicativo (que pode ser revelada movendo o cursor para a parte superior da tela) para fornecer interação livre de distrações com seu conteúdo.

A Apple sugere as seguintes diretrizes:

  • Determine se faz sentido uma janela ficar em tela inteira. Aplicativos que fornecem interações breves (como uma Calculadora) não devem fornecer um modo de tela inteira.
  • Mostre a barra de ferramentas se a tarefa de tela inteira exigir. Normalmente, a barra de ferramentas fica oculta enquanto está no modo de tela inteira.
  • A janela de tela inteira deve ter todos os recursos que os usuários precisam para concluir a tarefa.
  • Se possível, evite a interação do Localizador enquanto o usuário estiver em uma janela de tela inteira.
  • Aproveite o maior espaço de tela sem desviar o foco da tarefa main.

Para obter mais informações, consulte a seção Windows em tela inteira dos temas de design do macOS da Apple.

Painéis

Um Painel é uma janela auxiliar que contém controles e opções que afetam o documento ativo ou a seleção (como o Seletor de Cores do sistema):

Um painel de cores

Os painéis podem ser específicos do aplicativo ou de todo o sistema. App-Specific Painéis flutuam sobre a parte superior das janelas de documento do aplicativo e desaparecem quando o aplicativo está em segundo plano. Painéis em todo o sistema (como o painel Fontes ), flutuam sobre todas as janelas abertas, independentemente do aplicativo.

A Apple sugere as seguintes diretrizes:

  • Em geral, use um painel padrão, os painéis transparentes só devem ser usados com moderação e para tarefas graficamente intensivas.
  • Considere usar um painel para dar aos usuários acesso fácil a controles ou informações importantes que afetam diretamente sua tarefa.
  • Ocultar e mostrar painéis conforme necessário.
  • Os painéis sempre devem incluir a barra de título.
  • Os painéis não devem incluir um botão minimizar ativo.

Inspectores

A maioria dos aplicativos macOS modernos apresenta controles auxiliares e opções que afetam o documento ativo ou a seleção como Inspetores que fazem parte da Janela Principal (como o aplicativo Pages mostrado abaixo), em vez de usar o Painel Windows:

Um inspetor de exemplo

Para obter mais informações, consulte a seção Painéis dos temas de design do macOS da Apple e nosso aplicativo de exemplo MacInspector para uma implementação completa de uma Interface do Inspetor em um aplicativo Xamarin.Mac.

Criando e mantendo janelas no Xcode

Ao criar um novo aplicativo Xamarin.Mac Cocoa, você obtém uma janela padrão em branco, por padrão. Essas janelas são definidas em um .storyboard arquivo incluído automaticamente no projeto. Para editar o design do windows, no Gerenciador de Soluções, clique duas vezes no Main.storyboard arquivo:

Selecionando o storyboard main

Isso abrirá o design da janela no Construtor de Interfaces do Xcode:

Editando a interface do usuário no Xcode

No Inspetor de Atributos, há várias propriedades que você pode usar para definir e controlar sua janela:

  • Título – esse é o texto que será exibido na barra de título da janela.
  • Salvamento automático – essa é a chave que será usada para ID da janela quando a posição e as configurações forem salvas automaticamente.
  • Barra de Título – a janela exibe uma barra de título.
  • Título unificado e barra de ferramentas – se a janela incluir uma Barra de Ferramentas, ela deverá fazer parte da barra de título.
  • Exibição de conteúdo de tamanho completo – permite que a área de conteúdo da janela esteja na barra Título.
  • Sombra – a janela tem uma sombra.
  • Texturizado – janelas texturizados podem usar efeitos (como vibração) e podem ser movidas por aí arrastando qualquer lugar em seu corpo.
  • Fechar – a janela tem um botão fechar.
  • Minimizar – a janela tem um botão minimizar.
  • Redimensionar – a janela tem um controle de redimensionamento.
  • Botão barra de ferramentas – a janela tem um botão ocultar/mostrar barra de ferramentas.
  • Restaurável – a posição e as configurações da janela são salvas e restauradas automaticamente.
  • Visível na inicialização – a janela é mostrada automaticamente quando o .xib arquivo é carregado.
  • Ocultar Em Desativar – é a janela oculta quando o aplicativo entra em segundo plano.
  • Versão Quando Fechada – a janela é limpa da memória quando está fechada.
  • Sempre Exibir Dicas de Ferramenta – as dicas de ferramenta são exibidas constantemente.
  • Recalcula o Loop de Exibição – a ordem de exibição é recalculada antes que a janela seja desenhada.
  • Espaços, Exposé e Ciclismo – todos definem como a janela se comporta nesses ambientes macOS.
  • Tela Inteira – determina se essa janela pode entrar no modo de tela inteira.
  • Animação – controla o tipo de animação disponível para a janela.
  • Aparência – controla a aparência da janela. Por enquanto há apenas uma aparição, Aqua.

Confira a documentação Introdução ao Windows e ao NSWindow da Apple para obter mais detalhes.

Definindo o tamanho e o local padrão

Para definir a posição inicial da janela e controlar seu tamanho, alterne para o Inspetor de Tamanho:

O tamanho e o local padrão

A partir daqui, você pode definir o tamanho inicial da janela, dar a ela um tamanho mínimo e máximo, definir o local inicial na tela e controlar as bordas ao redor da janela.

Definindo um controlador de janela de main personalizado

Para poder criar Saídas e Ações para expor elementos da interface do usuário ao código C#, o aplicativo Xamarin.Mac precisará usar um Controlador de Janela Personalizado.

Faça o seguinte:

  1. Abra o Storyboard do aplicativo no Construtor de Interfaces do Xcode.

  2. Selecione o NSWindowController na Superfície de Design.

  3. Alterne para a exibição Inspetor de Identidade e insira WindowController como o Nome da Classe:

    Definindo o nome da classe

  4. Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar.

  5. Um WindowController.cs arquivo será adicionado ao projeto no Gerenciador de Soluções no Visual Studio para Mac:

    Selecionando o controlador do Windows

  6. Reabra o Storyboard no Construtor de Interfaces do Xcode.

  7. O WindowController.h arquivo estará disponível para uso:

    Editando o arquivo WindowController.h

Adicionando elementos de interface do usuário

Para definir o conteúdo de uma janela, arraste os controles do Inspetor de Biblioteca para o Editor de Interface. Consulte nossa documentação introdução ao Xcode e ao Construtor de Interfaces para obter mais informações sobre como usar o Interface Builder para criar e habilitar controles.

Por exemplo, vamos arrastar uma Barra de Ferramentas do Inspetor de Biblioteca para a janela no Editor de Interface:

Selecionando uma Barra de Ferramentas na Biblioteca

Em seguida, arraste um Modo de Exibição de Texto e dimensione-o para preencher a área sob a barra de ferramentas:

Adicionando um modo de exibição de texto

Como queremos que a Exibição de Texto diminua e cresça conforme o tamanho da janela for alterado, vamos alternar para o Editor de Restrições e adicionar as seguintes restrições:

Editando restrições

Clicando nas quatro I-Beams Vermelhas na parte superior do editor e clicando em Adicionar 4 Restrições, estamos dizendo ao modo de exibição de texto para manter as coordenadas X,Y fornecidas e crescer ou reduzir horizontal e verticalmente à medida que a janela é redimensionada.

Por fim, exponha a Exibição de Texto ao código usando uma Tomada (certificando-se de selecionar o ViewController.h arquivo):

Configurando uma tomada

Salve as alterações e volte para Visual Studio para Mac para sincronizar com o Xcode.

Para obter mais informações sobre como trabalhar com saídas e ações, consulte nossa documentação de Saída e Ação .

Fluxo de trabalho de janela padrão

Para qualquer janela com a qual você cria e trabalha em seu aplicativo Xamarin.Mac, o processo é basicamente o mesmo que acabamos de fazer acima:

  1. Para novas janelas que não são o padrão adicionado automaticamente ao projeto, adicione uma nova definição de janela ao projeto. Isso será discutido em detalhes abaixo.
  2. Clique duas vezes no Main.storyboard arquivo para abrir o design da janela para edição no Construtor de Interfaces do Xcode.
  3. Arraste uma nova Janela para o design da Interface do Usuário e conecte a janela à Janela Principal usando Segues (para obter mais informações, consulte a seção Segues da nossa documentação Trabalhando com Storyboards ).
  4. Defina as propriedades de janela necessárias no Inspetor de Atributos e no Inspetor de Tamanho.
  5. Arraste os controles necessários para criar sua interface e configurá-los no Inspetor de Atributos.
  6. Use o Inspetor de Tamanho para lidar com o redimensionamento dos elementos da interface do usuário.
  7. Exponha os elementos da interface do usuário da janela ao código C# por meio de Saídas e Ações.
  8. Salve as alterações e volte para Visual Studio para Mac para sincronizar com o Xcode.

Agora que temos uma janela básica criada, examinaremos os processos típicos que um aplicativo Xamarin.Mac faz ao trabalhar com janelas.

Exibindo a janela padrão

Por padrão, um novo aplicativo Xamarin.Mac exibirá automaticamente a janela definida no MainWindow.xib arquivo quando ele for iniciado:

Uma janela de exemplo em execução

Como modificamos o design dessa janela acima, ela agora inclui um controle padrão da Barra de Ferramentas e do Modo de Exibição de Texto . A seção a seguir no Info.plist arquivo é responsável por exibir esta janela:

Editando Info.plist

A lista suspensa Interface Principal é usada para selecionar o Storyboard que será usado como a interface do usuário do aplicativo main (nesse casoMain.storyboard).

Um Controlador de Exibição é adicionado automaticamente ao projeto para controlar o Windows Principal que é exibido (juntamente com sua exibição primária). Ele é definido no ViewController.cs arquivo e anexado ao Proprietário do Arquivo no Construtor de Interfaces no Inspetor de Identidade:

Definindo o proprietário do arquivo

Para nossa janela, gostaríamos que ele tivesse um título de untitled quando ele é aberto pela primeira vez, portanto, vamos substituir o ViewWillAppear método no ViewController.cs para ter a seguinte aparência:

public override void ViewWillAppear ()
{
    base.ViewWillAppear ();

    // Set Window Title
    this.View.Window.Title = "untitled";
}

Observação

A propriedade da Title janela é definida no ViewWillAppear método em vez do ViewDidLoad método porque, embora a exibição possa ser carregada na memória, ela ainda não está totalmente instanciada. Ao acessar a Title propriedade no ViewDidLoad método, obteremos uma null exceção, pois a janela ainda não foi construída e conectada à propriedade.

Fechar programaticamente uma janela

Pode haver ocasiões em que você deseja fechar programaticamente uma janela em um aplicativo Xamarin.Mac, além de fazer com que o usuário clique no botão Fechar da janela ou use um item de menu. O macOS fornece duas maneiras diferentes de fechar programaticamente NSWindow : PerformClose e Close.

PerformClose

Chamar o PerformClose método de um NSWindow simula o usuário clicando no botão Fechar da janela realçando momentaneamente o botão e fechando a janela.

Se o aplicativo implementar o NSWindowevento do WillClose , ele será gerado antes que a janela seja fechada. Se o evento retornar false, a janela não será fechada. Se a janela não tiver um botão Fechar ou não puder ser fechada por qualquer motivo, o sistema operacional emitirá o som do alerta.

Por exemplo:

MyWindow.PerformClose(this);

Tentaria fechar a MyWindowNSWindow instância. Se tiver sido bem-sucedida, a janela será fechada, caso contrário, o som do alerta será emitido e o permanecerá aberto.

Fechar

Chamar o Close método de um NSWindow não simula o usuário clicando no botão Fechar da janela realçando momentaneamente o botão, ele simplesmente fecha a janela.

Uma janela não precisa estar visível para ser fechada e uma NSWindowWillCloseNotification notificação será postada no Centro de Notificações padrão para a janela que está sendo fechada.

O Close método difere de duas maneiras importantes do PerformClose método :

  1. Ele não tenta acionar o WillClose evento.
  2. Ele não simula o usuário clicando no botão Fechar realçando momentaneamente o botão.

Por exemplo:

MyWindow.Close();

Seria fechar a MyWindowNSWindow instância.

Conteúdo modificado do Windows

No macOS, a Apple forneceu uma maneira de informar ao usuário que o conteúdo de uma Janela (NSWindow) foi modificado pelo usuário e precisa ser salvo. Se a Janela contiver conteúdo modificado, um pequeno ponto preto será exibido em seu widget Close :

Uma janela com o marcador modificado

Se o usuário tentar fechar a Janela ou sair do Aplicativo Mac enquanto houver alterações não salvas no conteúdo da Janela, você deverá apresentar uma Caixa de Diálogo ou Planilha Modal e permitir que o usuário salve suas alterações primeiro:

Uma planilha de salvamento sendo mostrada quando a janela é fechada

Marcando uma janela como modificada

Para marcar uma Janela como tendo modificado o conteúdo, use o seguinte código:

// Mark Window content as modified
Window.DocumentEdited = true;

E depois que a alteração for salva, limpe o sinalizador modificado usando:

// Mark Window content as not modified
Window.DocumentEdited = false;

Salvando alterações antes de fechar uma janela

Para watch para o usuário fechar uma Janela e permitir que ele salve o conteúdo modificado com antecedência, você precisará criar uma subclasse de NSWindowDelegate e substituir seu WindowShouldClose método. Por exemplo:

using System;
using AppKit;
using System.IO;
using Foundation;

namespace SourceWriter
{
    public class EditorWindowDelegate : NSWindowDelegate
    {
        #region Computed Properties
        public NSWindow Window { get; set;}
        #endregion

        #region constructors
        public EditorWindowDelegate (NSWindow window)
        {
            // Initialize
            this.Window = window;

        }
        #endregion

        #region Override Methods
        public override bool WindowShouldClose (Foundation.NSObject sender)
        {
            // is the window dirty?
            if (Window.DocumentEdited) {
                var alert = new NSAlert () {
                    AlertStyle = NSAlertStyle.Critical,
                    InformativeText = "Save changes to document before closing window?",
                    MessageText = "Save Document",
                };
                alert.AddButton ("Save");
                alert.AddButton ("Lose Changes");
                alert.AddButton ("Cancel");
                var result = alert.RunSheetModal (Window);

                // Take action based on result
                switch (result) {
                case 1000:
                    // Grab controller
                    var viewController = Window.ContentViewController as ViewController;

                    // Already saved?
                    if (Window.RepresentedUrl != null) {
                        var path = Window.RepresentedUrl.Path;

                        // Save changes to file
                        File.WriteAllText (path, viewController.Text);
                        return true;
                    } else {
                        var dlg = new NSSavePanel ();
                        dlg.Title = "Save Document";
                        dlg.BeginSheet (Window, (rslt) => {
                            // File selected?
                            if (rslt == 1) {
                                var path = dlg.Url.Path;
                                File.WriteAllText (path, viewController.Text);
                                Window.DocumentEdited = false;
                                viewController.View.Window.SetTitleWithRepresentedFilename (Path.GetFileName(path));
                                viewController.View.Window.RepresentedUrl = dlg.Url;
                                Window.Close();
                            }
                        });
                        return true;
                    }
                    return false;
                case 1001:
                    // Lose Changes
                    return true;
                case 1002:
                    // Cancel
                    return false;
                }
            }

            return true;
        }
        #endregion
    }
}

Use o seguinte código para anexar uma instância desse delegado à janela:

// Set delegate
Window.Delegate = new EditorWindowDelegate(Window);

Salvando alterações antes de fechar o aplicativo

Por fim, seu aplicativo Xamarin.Mac deve marcar para ver se algum de seus Windows contém conteúdo modificado e permitir que o usuário salve as alterações antes de sair. Para fazer isso, edite o AppDelegate.cs arquivo, substitua o ApplicationShouldTerminate método e faça com que ele se pareça com o seguinte:

public override NSApplicationTerminateReply ApplicationShouldTerminate (NSApplication sender)
{
    // See if any window needs to be saved first
    foreach (NSWindow window in NSApplication.SharedApplication.Windows) {
        if (window.Delegate != null && !window.Delegate.WindowShouldClose (this)) {
            // Did the window terminate the close?
            return NSApplicationTerminateReply.Cancel;
        }
    }

    // Allow normal termination
    return NSApplicationTerminateReply.Now;
}

Trabalhando com várias janelas

A maioria dos aplicativos Mac baseados em documentos pode editar vários documentos ao mesmo tempo. Por exemplo, um editor de texto pode ter vários arquivos de texto abertos para edição ao mesmo tempo. Por padrão, um novo aplicativo Xamarin.Mac tem um menu Arquivo com um novo item conectado automaticamente à AçãonewDocument:.

O código a seguir ativará esse novo item e permitirá que o usuário abra várias cópias da Janela Principal para editar vários documentos ao mesmo tempo.

Edite o AppDelegate.cs arquivo e adicione a seguinte propriedade computada:

public int UntitledWindowCount { get; set;} =1;

Use isso para acompanhar o número de arquivos não salvos para que possamos enviar comentários ao usuário (de acordo com as diretrizes da Apple, conforme discutido acima).

Em seguida, adicione o seguinte método:

[Export ("newDocument:")]
void NewDocument (NSObject sender) {
    // Get new window
    var storyboard = NSStoryboard.FromName ("Main", null);
    var controller = storyboard.InstantiateControllerWithIdentifier ("MainWindow") as NSWindowController;

    // Display
    controller.ShowWindow(this);

    // Set the title
    controller.Window.Title = (++UntitledWindowCount == 1) ? "untitled" : string.Format ("untitled {0}", UntitledWindowCount);
}

Esse código cria uma nova versão do nosso Controlador de Janela, carrega a nova Janela, torna-a a Janela Principal e Chave e define o título. Agora, se executarmos nosso aplicativo e selecionarMos Novo no menu Arquivo , uma nova janela do editor será aberta e exibida:

Uma nova janela sem título foi adicionada

Se abrirmos o menu do Windows , você poderá ver que o aplicativo está acompanhando e manipulando automaticamente nossas janelas abertas:

O menu janelas

Para obter mais informações sobre como trabalhar com Menus em um aplicativo Xamarin.Mac, consulte nossa documentação Trabalhando com Menus .

Obtendo a janela ativa no momento

Em um aplicativo Xamarin.Mac que pode abrir várias janelas (documentos), há momentos em que você precisará obter a janela atual e superior (a janela de teclas). O código a seguir retornará a janela de teclas:

var window = NSApplication.SharedApplication.KeyWindow;

Ele pode ser chamado em qualquer classe ou método que precise acessar a janela de chave atual. Se nenhuma janela estiver aberta no momento, ela retornará null.

Acessando todas as janelas do aplicativo

Pode haver momentos em que você precisa acessar todas as janelas que seu aplicativo Xamarin.Mac está aberto no momento. Por exemplo, para ver se um arquivo que o usuário deseja abrir já está aberto em uma janela de saída.

O NSApplication.SharedApplication mantém uma Windows propriedade que contém uma matriz de todas as janelas abertas em seu aplicativo. Você pode iterar nessa matriz para acessar todas as janelas atuais do aplicativo. Por exemplo:

// Is the file already open?
for(int n=0; n<NSApplication.SharedApplication.Windows.Length; ++n) {
    var content = NSApplication.SharedApplication.Windows[n].ContentViewController as ViewController;
    if (content != null && path == content.FilePath) {
        // Bring window to front
        NSApplication.SharedApplication.Windows[n].MakeKeyAndOrderFront(this);
        return true;
    }
}

No código de exemplo, estamos convertendo cada janela retornada para a classe personalizada ViewController em nosso aplicativo e testando o valor de uma propriedade personalizada Path no caminho de um arquivo que o usuário deseja abrir. Se o arquivo já estiver aberto, estamos trazendo essa janela para a frente.

Ajustando o tamanho da janela no código

Há momentos em que o aplicativo precisa redimensionar uma janela no código. Para redimensionar e reposicionar uma janela, ajuste sua Frame propriedade. Ao ajustar o tamanho de uma janela, geralmente você também precisa ajustar sua origem para manter a janela no mesmo local devido ao sistema de coordenadas do macOS.

Ao contrário do iOS em que o canto superior esquerdo representa (0,0), o macOS usa um sistema de coordenadas matemáticas em que o canto inferior esquerdo da tela representa (0,0). No iOS, as coordenadas aumentam à medida que você se move para baixo em direção à direita. No macOS, as coordenadas aumentam de valor para cima para a direita.

O código de exemplo a seguir redimensiona uma janela:

nfloat y = 0;

// Calculate new origin
y = Frame.Y - (768 - Frame.Height);

// Resize and position window
CGRect frame = new CGRect (Frame.X, y, 1024, 768);
SetFrame (frame, true);

Importante

Ao ajustar o tamanho e o local de uma janela no código, você precisa respeitar os tamanhos mínimo e máximo definidos no Construtor de Interfaces. Isso não será automaticamente respeitado e você poderá tornar a janela maior ou menor do que esses limites.

Monitorando alterações de tamanho da janela

Pode haver momentos em que você precisa monitorar as alterações no tamanho de uma Janela dentro do aplicativo Xamarin.Mac. Por exemplo, para redesenhar o conteúdo para se ajustar ao novo tamanho.

Para monitorar as alterações de tamanho, primeiro verifique se você atribuiu uma classe personalizada para o Controlador de Janela no Construtor de Interfaces do Xcode. Por exemplo, MasterWindowController no seguinte:

O Inspetor de Identidade

Em seguida, edite a classe personalizada Controlador de Janela e monitore o DidResize evento na Janela do Controlador para ser notificado sobre alterações de tamanho dinâmico. Por exemplo:

public override void WindowDidLoad ()
{
    base.WindowDidLoad ();

    Window.DidResize += (sender, e) => {
        // Do something as the window is being live resized
    };
}

Opcionalmente, você pode usar o DidEndLiveResize evento para ser notificado somente depois que o usuário terminar de alterar o tamanho da Janela. Por exemplo:

public override void WindowDidLoad ()
{
    base.WindowDidLoad ();

        Window.DidEndLiveResize += (sender, e) => {
        // Do something after the user's finished resizing
        // the window
    };
}

Definindo o título e o arquivo representado de uma janela

Ao trabalhar com janelas que representam documentos, tem uma DocumentEdited propriedade que, NSWindow se definida comotrue, exibe um pequeno ponto no Botão Fechar para dar ao usuário uma indicação de que o arquivo foi modificado e deve ser salvo antes de fechar.

Vamos editar nosso ViewController.cs arquivo e fazer as seguintes alterações:

public bool DocumentEdited {
    get { return View.Window.DocumentEdited; }
    set { View.Window.DocumentEdited = value; }
}
...

public override void ViewWillAppear ()
{
    base.ViewWillAppear ();

    // Set Window Title
    this.View.Window.Title = "untitled";

    View.Window.WillClose += (sender, e) => {
        // is the window dirty?
        if (DocumentEdited) {
            var alert = new NSAlert () {
                AlertStyle = NSAlertStyle.Critical,
                InformativeText = "We need to give the user the ability to save the document here...",
                MessageText = "Save Document",
            };
            alert.RunModal ();
        }
    };
}

public override void AwakeFromNib ()
{
    base.AwakeFromNib ();

    // Show when the document is edited
    DocumentEditor.TextDidChange += (sender, e) => {
        // Mark the document as dirty
        DocumentEdited = true;
    };

    // Overriding this delegate is required to monitor the TextDidChange event
    DocumentEditor.ShouldChangeTextInRanges += (NSTextView view, NSValue[] values, string[] replacements) => {
        return true;
    };

}

Também estamos monitorando o WillClose evento na janela e verificando o estado da DocumentEdited propriedade. Se for true , precisamos dar ao usuário a capacidade de salvar as alterações no arquivo. Se executarmos nosso aplicativo e inserirmos algum texto, o ponto será exibido:

Uma janela alterada

Se você tentar fechar a janela, receberá um alerta:

Exibindo uma caixa de diálogo salvar

Se você estiver carregando um documento de um arquivo, defina o título da janela como o nome do arquivo usando o window.SetTitleWithRepresentedFilename (Path.GetFileName(path)); método (dado que é uma cadeia de caracteres que path representa o arquivo que está sendo aberto). Além disso, você pode definir a URL do arquivo usando o window.RepresentedUrl = url; método .

Se a URL estiver apontando para um tipo de arquivo conhecido pelo sistema operacional, seu ícone será exibido na barra de título. Se o usuário clicar com o botão direito do mouse no ícone, o caminho para o arquivo será mostrado.

Edite o AppDelegate.cs arquivo e adicione o seguinte método:

[Export ("openDocument:")]
void OpenDialog (NSObject sender)
{
    var dlg = NSOpenPanel.OpenPanel;
    dlg.CanChooseFiles = true;
    dlg.CanChooseDirectories = false;

    if (dlg.RunModal () == 1) {
        // Nab the first file
        var url = dlg.Urls [0];

        if (url != null) {
            var path = url.Path;

            // Get new window
            var storyboard = NSStoryboard.FromName ("Main", null);
            var controller = storyboard.InstantiateControllerWithIdentifier ("MainWindow") as NSWindowController;

            // Display
            controller.ShowWindow(this);

            // Load the text into the window
            var viewController = controller.Window.ContentViewController as ViewController;
            viewController.Text = File.ReadAllText(path);
                    viewController.View.Window.SetTitleWithRepresentedFilename (Path.GetFileName(path));
            viewController.View.Window.RepresentedUrl = url;

        }
    }
}

Agora, se executarmos nosso aplicativo, selecione Abrir... no menu Arquivo , selecione um arquivo de texto na caixa de diálogo Abrir e abra-o:

Uma caixa de diálogo aberta

O arquivo será exibido e o título será definido com o ícone do arquivo:

O conteúdo de um arquivo carregado

Adicionando uma nova janela a um projeto

Além da janela main documento, um aplicativo Xamarin.Mac pode precisar exibir outros tipos de janelas para o usuário, como Preferências ou Painéis de Inspetor.

Para adicionar uma nova janela, faça o seguinte:

  1. No Gerenciador de Soluções, clique duas vezes no Main.storyboard arquivo para abri-lo para edição no Construtor de Interfaces do Xcode.

  2. Arraste um novo Controlador de Janela da Biblioteca e solte-o na Superfície de Design:

    Selecionando um novo Controlador de Janela na Biblioteca

  3. No Inspetor de Identidade, insira PreferencesWindow para a ID do Storyboard:

    Definindo a ID do storyboard

  4. Projete sua interface:

    Projetando a interface do usuário

  5. Abra o Menu do Aplicativo (MacWindows), selecione Preferências..., Control-Click e arraste para a nova janela:

    Criando um segue

  6. Selecione Mostrar no menu pop-up.

  7. Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.

Se executarmos o código e selecionarmos as Preferências... no Menu do Aplicativo, a janela será exibida:

Um menu de preferências de exemplo

Trabalhando com painéis

Conforme mencionado no início deste artigo, um painel flutua acima de outras janelas e fornece ferramentas ou controles com os quais os usuários podem trabalhar enquanto os documentos estão abertos.

Assim como qualquer outro tipo de janela com a qual você cria e trabalha em seu aplicativo Xamarin.Mac, o processo é basicamente o mesmo:

  1. Adicione uma nova definição de janela ao projeto.
  2. Clique duas vezes no .xib arquivo para abrir o design da janela para edição no Construtor de Interfaces do Xcode.
  3. Defina as propriedades de janela necessárias no Inspetor de Atributos e no Inspetor de Tamanho.
  4. Arraste os controles necessários para criar sua interface e configurá-los no Inspetor de Atributos.
  5. Use o Inspetor de Tamanho para lidar com o redimensionamento dos elementos da interface do usuário.
  6. Exponha os elementos da interface do usuário da janela ao código C# por meio de Saídas e Ações.
  7. Salve as alterações e volte para Visual Studio para Mac para sincronizar com o Xcode.

No Inspetor de Atributos, você tem as seguintes opções específicas para Painéis:

O Inspetor de Atributos

  • Estilo – permita ajustar o estilo do painel de: Painel Regular (parece uma janela padrão), Painel utilitário (tem uma barra de título menor), Painel HUD (é translúcido e a barra de título faz parte da tela de fundo).
  • Não ativação – determina que no painel se torna a janela de teclas.
  • Modal do Documento – se o Documento Modal, o painel só flutuará acima das janelas do aplicativo, caso contrário, flutua acima de tudo.

Para adicionar um novo Painel, faça o seguinte:

  1. Na Gerenciador de Soluções, clique com o botão direito do mouse no Projeto e selecione Adicionar>Novo Arquivo....

  2. Na caixa de diálogo Novo Arquivo, selecione Janela Xamarin.Mac>Cocoa com Controlador:

    Adicionando um novo controlador de janela

  3. Digite DocumentPanel para o Nome e clique no botão Novo.

  4. Clique duas vezes no DocumentPanel.xib arquivo para abri-lo para edição no Construtor de Interfaces:

    Editando o painel

  5. Exclua a janela existente e arraste um Painel do Inspetor de Biblioteca no Editor de Interface:

    Excluindo a janela existente

  6. Conecte o painel até asaída da janela - Proprietário - do Arquivo:

    Arrastando para conectar o painel

  7. Alterne para o Inspetor de Identidade e defina a classe do Painel como DocumentPanel:

    Definindo a classe do painel

  8. Salve suas alterações e retorne ao Visual Studio para Mac para sincronizar com o Xcode.

  9. Edite o DocumentPanel.cs arquivo e altere a definição de classe para o seguinte:

    public partial class DocumentPanel : NSPanel

  10. Salve as alterações no arquivo.

Edite o AppDelegate.cs arquivo e faça com que o DidFinishLaunching método se pareça com o seguinte:

public override void DidFinishLaunching (NSNotification notification)
{
        // Display panel
    var panel = new DocumentPanelController ();
    panel.Window.MakeKeyAndOrderFront (this);
}

Se executarmos nosso aplicativo, o painel será exibido:

O painel em um aplicativo em execução

Importante

O Painel Windows foi preterido pela Apple e deve ser substituído por Interfaces do Inspetor. Para obter um exemplo completo de criação de um Inspetor em um aplicativo Xamarin.Mac, consulte nosso aplicativo de exemplo MacInspector .

Resumo

Este artigo deu uma olhada detalhada em trabalhar com Windows e Painéis em um aplicativo Xamarin.Mac. Vimos os diferentes tipos e usos de Windows e Painéis, como criar e manter Windows e Painéis no Construtor de Interfaces do Xcode e como trabalhar com Windows e Painéis em código C#.