Вот как я реализовал это сейчас:
- Создание подкласса NSDocumentController
- В AppDelegate создайте экземпляр этого класса - этого достаточно, чтобы установить его как DocumentController для приложения (может быть только один)
- В подклассе установите обработчики для
makeUntitledDocumentOfType:error:
и makeDocumentWithContentsOfURL:ofType:error:
- Там я теперь могу создать диалогчтобы запросить пароль и либо создать (расшифрованный) документ, либо вернуть ошибку.
- MyEncryptedDocument (подкласс NSDocument) требует пароль в своем init / constructor.Это используется в переопределенных
readFromData:ofType:error:
и dataOfType:error:
для загрузки / дешифрования и сохранения / шифрования данных
DocumentController действительно, кажется, место, которое должно иметь дело с этим, по моему мнению, так какпароль / шифрование - это скорее проблема конвейера, чем проблема самого документа или любого пользовательского интерфейса.В целом, это "чувствует" меня как неопытного разработчика MacOS.Я не уверен, является ли NSAlert правильным классом для диалога;глядя на Руководство Apple Я думаю, мне следует создать свой собственный NSPanel или NSWindow.Но это проблема на потом.
В коде Xamarin C # класс выглядит следующим образом:
public class MyEncryptedDocumentController : NSDocumentController
{
public MyEncryptedDocumentController()
{
}
// makeUntitledDocumentOfType:error:
public override NSObject MakeUntitledDocument(string typeName, out NSError error)
{
return LoadOrCreateDocument(typeName, null, out error);
}
// makeDocumentWithContentsOfURL:ofType:error:
public override NSObject MakeDocument(NSUrl url, string typeName, out NSError outError)
{
return LoadOrCreateDocument(typeName, url, out outError);
}
private MyEncryptedDocument LoadOrCreateDocument(string typeName, NSUrl url, out NSError error)
{
error = null;
using (var sb = NSStoryboard.FromName("PasswordView", null))
using (var ctrl = sb.InstantiateControllerWithIdentifier("Password View Controller") as PasswordViewController)
using (var win = new NSAlert())
{
win.MessageText = "Please enter the Password:";
//win.InformativeText = "Error message goes here.";
win.AlertStyle = NSAlertStyle.Informational;
win.AccessoryView = ctrl.View;
var btnOK = win.AddButton("OK");
var btnCancel = win.AddButton("Cancel");
var res = win.RunModal();
var pw = ctrl.Password;
if (res == (int)NSAlertButtonReturn.First)
{
var doc = new MyEncryptedDocument(pw);
if (url != null)
{
if (!doc.ReadFromUrl(url, typeName, out error))
{
// Could check if error is a custom "Wrong Password"
// and then re-open the Alert, setting the Informational Text
// to something like "wrong password"
return null;
}
}
return doc;
}
// MyEncryptedDocument.Domain is a NSString("com.mycompany.myapplication");
// MyErrorCodes is just a custom c# enum
error = new NSError(MyEncryptedDocument.Domain, (int)MyErrorCodes.PasswordDialogCancel);
return null;
}
}
}
PasswordViewController
- довольно простой подкласс NSViewController:
public partial class PasswordViewController : NSViewController
{
public string Password { get => tbPassphrase?.StringValue ?? ""; }
public PasswordViewController(IntPtr handle) : base(handle)
{
}
}
tbPassphrase
- этовыход для текстового поля в представлении (@synthesize tbPassphrase = _tbPassphrase;
в файле .h).Раскадровка - это простая сцена с viewController:
<viewController storyboardIdentifier="Password View Controller" id="5LL-3u-LyJ" customClass="PasswordViewController" sceneMemberID="viewController">
<view key="view" id="yoi-7p-9v6">
<rect key="frame" x="0.0" y="0.0" width="315" height="22"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<secureTextField identifier="tfPassphrase" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="YmM-nK-9Hb">
<rect key="frame" x="0.0" y="0.0" width="315" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" usesSingleLineMode="YES" id="ChX-i5-luo">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<allowedInputSourceLocales>
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
</allowedInputSourceLocales>
</secureTextFieldCell>
</secureTextField>
</subviews>
</view>
<connections>
<outlet property="tbPassphrase" destination="YmM-nK-9Hb" id="sCC-Ve-8FO"/>
</connections>
</viewController>