Создание пользовательских элементов управления в Xamarin.Mac
При работе с C# и .NET в приложении Xamarin.Mac у вас есть доступ к тем же элементам управления пользователем, в которых работает Objective-Cразработчик, Swift и Xcode . Так как Xamarin.Mac интегрируется непосредственно с Xcode, вы можете использовать конструктор интерфейсов Xcode для создания и поддержания пользовательских элементов управления (или при необходимости создавать их непосредственно в коде C#).
Хотя macOS предоставляет множество встроенных пользовательских элементов управления, может потребоваться создать пользовательский элемент управления, чтобы обеспечить функциональность, не предоставляемую вне коробки или соответствовать пользовательской теме пользовательского интерфейса (например, игровому интерфейсу).
В этой статье мы рассмотрим основы создания повторно используемых пользовательских элементов управления пользовательским интерфейсом в приложении Xamarin.Mac. Настоятельно рекомендуется сначала ознакомиться со статьей Hello, Mac , в частности в разделах "Введение в Xcode" и "Конструктор интерфейсов" и "Торговых точек" и "Действия ", поскольку рассматриваются основные понятия и методы, которые мы будем использовать в этой статье.
Вы можете ознакомиться с классами И методами C# в Objective-Cразделе документа Xamarin.Mac Internals, а также объяснить Register
Export
команды, используемые для подключения классов C# к Objective-C объектам и элементам пользовательского интерфейса.
Общие сведения о пользовательских элементах управления
Как упоминалось выше, может возникнуть время, когда необходимо создать повторно используемый пользовательский интерфейс, пользовательский элемент управления пользовательским интерфейсом, чтобы обеспечить уникальные функциональные возможности пользовательского интерфейса приложения Xamarin.Mac или создать пользовательскую тему пользовательского интерфейса (например, игровой интерфейс).
В таких ситуациях можно легко наследовать и NSControl
создать пользовательское средство, которое можно добавить в пользовательский интерфейс приложения с помощью кода C# или с помощью конструктора интерфейсов Xcode. Наследуя от NSControl
пользовательского элемента управления, автоматически будут иметь все стандартные функции, имеющие встроенный элемент управления пользовательским интерфейсом (например NSButton
, ).
Если пользовательский элемент управления пользовательским интерфейсом просто отображает сведения (например, пользовательское средство диаграммы и графического инструмента), то вместо него NSControl
может потребоваться наследоватьNSView
.
Независимо от того, какой базовый класс используется, основные шаги по созданию пользовательского элемента управления одинаковы.
В этой статье описано, как создать пользовательский компонент Flip Switch, который предоставляет уникальную тему пользовательского интерфейса и пример создания полнофункциональным пользовательским элементом управления пользовательским интерфейсом.
Создание пользовательского элемента управления
Так как настраиваемый элемент управления, который мы создаем, будет отвечать на входные данные пользователя (нажатия левой кнопки мыши), мы будем наследовать от NSControl
. Таким образом, наш пользовательский элемент управления автоматически будет иметь все стандартные функции, которые встроенный элемент управления пользовательского интерфейса имеет и отвечать как стандартный элемент управления macOS.
В Visual Studio для Mac откройте проект Xamarin.Mac, для которого требуется создать пользовательский элемент управления пользовательским интерфейсом (или создать новый). Добавьте новый класс и вызовите его NSFlipSwitch
:
Затем измените NSFlipSwitch.cs
класс и сделайте его следующим образом:
using Foundation;
using System;
using System.CodeDom.Compiler;
using AppKit;
using CoreGraphics;
namespace MacCustomControl
{
[Register("NSFlipSwitch")]
public class NSFlipSwitch : NSControl
{
#region Private Variables
private bool _value = false;
#endregion
#region Computed Properties
public bool Value {
get { return _value; }
set {
// Save value and force a redraw
_value = value;
NeedsDisplay = true;
}
}
#endregion
#region Constructors
public NSFlipSwitch ()
{
// Init
Initialize();
}
public NSFlipSwitch (IntPtr handle) : base (handle)
{
// Init
Initialize();
}
[Export ("initWithFrame:")]
public NSFlipSwitch (CGRect frameRect) : base(frameRect) {
// Init
Initialize();
}
private void Initialize() {
this.WantsLayer = true;
this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}
#endregion
#region Draw Methods
public override void DrawRect (CGRect dirtyRect)
{
base.DrawRect (dirtyRect);
// Use Core Graphic routines to draw our UI
...
}
#endregion
#region Private Methods
private void FlipSwitchState() {
// Update state
Value = !Value;
}
#endregion
}
}
Первое, что следует заметить о пользовательском классе в том, что мы наследуем и NSControl
используем команду Register, чтобы предоставить этот класс Objective-C и построитель интерфейсов Xcode:
[Register("NSFlipSwitch")]
public class NSFlipSwitch : NSControl
В следующих разделах мы подробно рассмотрим остальную часть приведенного выше кода.
Отслеживание состояния элемента управления
Так как наш пользовательский элемент управления — это переключатель, нам нужен способ отслеживания состояния включено и выключение переключателя. Мы обработаем это с помощью следующего кода:NSFlipSwitch
private bool _value = false;
...
public bool Value {
get { return _value; }
set {
// Save value and force a redraw
_value = value;
NeedsDisplay = true;
}
}
При изменении состояния коммутатора нам нужен способ обновления пользовательского интерфейса. Мы делаем это, заставляя элемент управления перерисовывать его пользовательский интерфейс.NeedsDisplay = true
Если наш элемент управления требует больше одного состояния on/Off (например, переключателя с несколькими состояниями с 3 позициями), мы могли бы использовать перечисление для отслеживания состояния. В нашем примере простой логическое значение будет выполняться.
Мы также добавили вспомогательный метод для замены состояния переключателя между вкл. и выкл.
private void FlipSwitchState() {
// Update state
Value = !Value;
}
Позже мы развернем этот вспомогательный класс, чтобы сообщить вызывающему объекту о изменении состояния коммутаторов.
Рисование интерфейса элемента управления
Мы будем использовать основные процедуры рисования рисунков для рисования пользовательского интерфейса элемента управления во время выполнения. Прежде чем это сделать, необходимо включить слои для нашего элемента управления. Мы делаем это с помощью следующего закрытого метода:
private void Initialize() {
this.WantsLayer = true;
this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}
Этот метод вызывается из каждого конструктора элемента управления, чтобы убедиться, что элемент управления настроен правильно. Например:
public NSFlipSwitch (IntPtr handle) : base (handle)
{
// Init
Initialize();
}
Затем необходимо переопределить DrawRect
метод и добавить основные графические подпрограммы для рисования элемента управления:
public override void DrawRect (CGRect dirtyRect)
{
base.DrawRect (dirtyRect);
// Use Core Graphic routines to draw our UI
...
}
Мы изменим визуальное представление элемента управления при изменении состояния элемента управления (например, переход с "Вкл. вкл.). В любой момент изменения состояния можно использовать NeedsDisplay = true
команду, чтобы принудительно перераскрыть элемент управления для нового состояния.
Реагирование на входные данные пользователя
Существует два основных способа добавления пользовательских входных данных в пользовательский элемент управления: переопределение процедур обработки мыши или распознавителей жестов. Какой метод мы используем, будет основан на функциональных возможностях, необходимых нашему элементу управления.
Внимание
Для любого создаваемого пользовательского элемента управления следует использовать методы переопределения или распознаватели жестов, но не одновременно, так как они могут конфликтовать друг с другом.
Обработка ввода пользователей с помощью методов переопределения
Объекты, наследуемые от NSControl
(или NSView
) имеют несколько методов переопределения для обработки ввода мыши или клавиатуры. В нашем примере управления мы хотим переключить состояние переключателя между вкл . и выкл . Когда пользователь щелкает элемент управления с помощью левой кнопки мыши. Для обработки этого можно добавить следующие методы NSFlipSwitch
переопределения в класс:
#region Mouse Handling Methods
// --------------------------------------------------------------------------------
// Handle mouse with Override Methods.
// NOTE: Use either this method or Gesture Recognizers, NOT both!
// --------------------------------------------------------------------------------
public override void MouseDown (NSEvent theEvent)
{
base.MouseDown (theEvent);
FlipSwitchState ();
}
public override void MouseDragged (NSEvent theEvent)
{
base.MouseDragged (theEvent);
}
public override void MouseUp (NSEvent theEvent)
{
base.MouseUp (theEvent);
}
public override void MouseMoved (NSEvent theEvent)
{
base.MouseMoved (theEvent);
}
## endregion
В приведенном выше коде метод (определенный выше) вызывается FlipSwitchState
для перевернутого состояния переключателя в методе MouseDown
. Это также приведет к повторному выводу элемента управления для отражения текущего состояния.
Обработка ввода пользователей с помощью распознавателей жестов
При необходимости можно использовать распознаватели жестов для обработки взаимодействия пользователя с элементом управления. Удалите переопределения, добавленные выше, измените Initialize
метод и сделайте его следующим образом:
private void Initialize() {
this.WantsLayer = true;
this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
// --------------------------------------------------------------------------------
// Handle mouse with Gesture Recognizers.
// NOTE: Use either this method or the Override Methods, NOT both!
// --------------------------------------------------------------------------------
var click = new NSClickGestureRecognizer (() => {
FlipSwitchState();
});
AddGestureRecognizer (click);
}
Здесь мы создадим новый NSClickGestureRecognizer
метод и вызываем наш FlipSwitchState
метод, чтобы изменить состояние переключателя, когда пользователь щелкает его с помощью левой кнопки мыши. Метод AddGestureRecognizer (click)
добавляет распознаватель жестов в элемент управления.
Опять же, какой метод мы используем, зависит от того, что мы пытаемся выполнить с помощью пользовательского элемента управления. Если нам нужен низкий уровень доступа к взаимодействию с пользователем, используйте методы Переопределения. Если нам нужна предопределенная функциональность, например щелчки мыши, используйте распознаватели жестов.
Реагирование на события изменения состояния
Когда пользователь изменяет состояние пользовательского элемента управления, нам нужен способ реагирования на изменение состояния кода (например, при нажатии пользовательской кнопки).
Чтобы предоставить эту функциональность, измените NSFlipSwitch
класс и добавьте следующий код:
#region Events
public event EventHandler ValueChanged;
internal void RaiseValueChanged() {
if (this.ValueChanged != null)
this.ValueChanged (this, EventArgs.Empty);
// Perform any action bound to the control from Interface Builder
// via an Action.
if (this.Action !=null)
NSApplication.SharedApplication.SendAction (this.Action, this.Target, this);
}
## endregion
Затем измените FlipSwitchState
метод и сделайте его следующим образом:
private void FlipSwitchState() {
// Update state
Value = !Value;
RaiseValueChanged ();
}
Во-первых, мы предоставляем ValueChanged
событие, в которое можно добавить обработчик в код C#, чтобы можно было выполнить действие, когда пользователь изменяет состояние коммутатора.
Во-вторых, поскольку пользовательский элемент управления наследует от NSControl
, он автоматически имеет действие , которое можно назначить в построителе интерфейсов Xcode. Чтобы вызвать это действие при изменении состояния, мы используем следующий код:
if (this.Action !=null)
NSApplication.SharedApplication.SendAction (this.Action, this.Target, this);
Сначала мы проверяем, назначено ли действие элементу управления. Затем мы вызываем действие , если оно определено.
Использование пользовательского элемента управления
С помощью полного пользовательского элемента управления мы можем добавить его в пользовательский интерфейс приложения Xamarin.Mac с помощью кода C# или в конструкторе интерфейсов Xcode.
Чтобы добавить элемент управления с помощью конструктора интерфейсов, сначала выполните чистую сборку проекта Xamarin.Mac, а затем дважды щелкните Main.storyboard
файл, чтобы открыть его в Interface Builder для редактирования:
Затем перетащите фигуру Custom View
в конструктор пользовательского интерфейса:
При выборе пользовательского представления перейдите в инспектор удостоверений и измените класс NSFlipSwitch
представления на:
Перейдите в редактор помощника и создайте выход для пользовательского элемента управления (обязательно привязав его в ViewController.h
файле, а не .m
в файле):
Сохраните изменения, вернитесь к Visual Studio для Mac и разрешите синхронизацию изменений. Измените ViewController.cs
файл и сделайте ViewDidLoad
метод следующим образом:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Do any additional setup after loading the view.
OptionTwo.ValueChanged += (sender, e) => {
// Display the state of the option switch
Console.WriteLine("Option Two: {0}", OptionTwo.Value);
};
}
Здесь мы реагируем на ValueChanged
событие, указанное выше в NSFlipSwitch
классе, и выписываем текущее значение , когда пользователь щелкает элемент управления.
При необходимости мы можем вернуться к построителю интерфейсов и определить действие для элемента управления:
Снова измените ViewController.cs
файл и добавьте следующий метод:
partial void OptionTwoFlipped (Foundation.NSObject sender) {
// Display the state of the option switch
Console.WriteLine("Option Two: {0}", OptionTwo.Value);
}
Внимание
Вы должны использовать событие или определить действие в построителе интерфейсов, но не следует использовать оба метода одновременно или они могут конфликтовать друг с другом.
Итоги
В этой статье подробно рассматривается создание повторно используемых пользовательских элементов управления пользовательским интерфейсом в приложении Xamarin.Mac. Мы узнали, как нарисовать пользовательский интерфейс пользовательских элементов управления, два основных способа реагирования на ввод мыши и пользователя и как предоставить новый элемент управления действиям в конструкторе интерфейсов Xcode.