[英]Key-Value Observing not triggering on a UIViewController subclass?
I'm trying to get notified when the title of a UIViewController changes. 我正试图在UIViewController的标题发生变化时收到通知。
I tried adding an observer to the title of a UIViewController subclass but it never gets triggered. 我尝试将一个观察者添加到UIViewController子类的标题,但它永远不会被触发。 What's strange about this, is that it works on a plain UIViewController.
这有什么奇怪的,它适用于普通的UIViewController。 Am I doing something wrong?
难道我做错了什么?
Here's a code example explaining my issue (Xamarin.iOS C#): 这是一个解释我的问题的代码示例(Xamarin.iOS C#):
using System;
using UIKit;
using System.Collections.Generic;
namespace ObserverTests
{
public partial class ViewController : UIViewController
{
List<UIViewController> viewControllers = new List<UIViewController>();
public override void ViewDidLoad()
{
UIViewController controller1 = new UIViewController() { Title = "Controller1" };
UIViewController controller2 = new Test() { Title = "Controller2" };
this.viewControllers.Add(controller1);
this.viewControllers.Add(controller2);
foreach(UIViewController viewController in viewControllers)
{
viewController.AddObserver("title", Foundation.NSKeyValueObservingOptions.New, (changes) =>
{
Console.WriteLine(viewController.Title);
Console.WriteLine("Title Changed!");
});
}
controller1.Title = "TitleChanged1"; // Works
controller2.Title = "TitleChanged2"; // Fails
}
private class Test : UIViewController
{
}
}
}
In Xamarin the best way might be using inheritance and adding such a feature. 在Xamarin中,最好的方法可能是使用继承并添加这样的功能。 For this you derive from UIViewController
为此,您从UIViewController派生
public class UIObserveTitleChangedViewController : UIViewController
{
public event TitleChangedEvent TitleChanged;
public override string Title
{
get
{
return base.Title;
}
set
{
var oldTitle = base.Title;
if (oldTitle == value)
return;
base.Title = value;
OnTitleChanged(new TitleChangedEventArgs(value, oldTitle));
}
}
protected virtual void OnTitleChanged(TitleChangedEventArgs args)
{
TitleChanged?.Invoke(this, args);
}
#region ctor
public UIObserveTitleChangedViewController() { }
public UIObserveTitleChangedViewController(NSCoder coder) : base(coder) { }
protected UIObserveTitleChangedViewController(NSObjectFlag t) : base(t) { }
protected internal UIObserveTitleChangedViewController(IntPtr handle) : base(handle) { }
public UIObserveTitleChangedViewController(string nibName, NSBundle bundle) : base(nibName, bundle) { }
#endregion
}
and implement missing event types 并实现缺少的事件类型
public delegate void TitleChangedEvent(object sender, TitleChangedEventArgs args);
public class TitleChangedEventArgs : EventArgs
{
public string NewTitle { get; set; }
public string OldTitle { get; set; }
public TitleChangedEventArgs(string newTitle, string oldTitle)
{
NewTitle = newTitle;
OldTitle = oldTitle;
}
}
You can then subscribe to this event and get notified of changes 然后,您可以订阅此事件并获得更改通知
public partial class ViewController : UIObserveTitleChangedViewController
{
public ViewController(IntPtr handle) : base(handle)
{
this.TitleChanged += ViewController_TitleChanged; // Subscribe to TitleChanged
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Title = "Some title"; // triggers TitleChanged
Title = "Another new title"; // triggers TitleChanged
}
private void ViewController_TitleChanged(object sender, TitleChangedEventArgs args)
{
Debug.WriteLine("Title changed from {0} to {1}", args.OldTitle, args.NewTitle);
}
}
The Title
property in UIViewController
is marked virtual
...so as an alternative solution, you could define a BaseViewController
class and override
Title
and call a method in the Setter
: UIViewController
的Title
属性标记为virtual
...作为替代解决方案,您可以定义BaseViewController
类并override
Title
并在Setter
调用方法:
Public class BaseViewController : UIViewController
{
....
public override string Title {
get {
return base.Title;
}
set {
base.Title = value;
OnTitleChanged();
}
}
protected virtual void OnTitleChanged()
{
......
}
}
Then you can override OnTitleChanged
on any of your UIViewControllers
to have a callback when the Title
is changed. 然后,您可以在任何
UIViewControllers
上覆盖OnTitleChanged
,以便在更改Title
时进行回调。
您可以像这样设置标题,它将起作用:
controller2.SetValueForKey(new NSString("TitleChangedHAHA"), new NSString("title"));
You could do this. 你可以做到这一点。 First define a new event argument that will hold the new title when it changes.
首先定义一个新的事件参数,它将在更改时保存新标题。
public class TitleChangedEventArgs: EventArgs
{
public string Title { get; private set; }
public TitleChangedEventArgs(string title)
{
Title = title;
}
}
In your test class, add a new Event Handler for TitleChanged and override Title to raise an event when the new title for the view controller. 在测试类中,为TitleChanged添加一个新的事件处理程序,并覆盖Title以在视图控制器的新标题时引发事件。
public class Test : UIViewController
{
public event EventHandler<TitleChangedEventArgs> TitleChanged;
public override string Title {
get {
return base.Title;
}
set {
base.Title = value;
OnTitleChanged();
}
}
public virtual void OnTitleChanged()
{
if (TitleChanged != null) {
TitleChanged.Invoke(this, EventArgs.Empty);
}
}
}
and finally in your Main View Controller you can do something like this: 最后在您的主视图控制器中,您可以执行以下操作:
public class ViewController : UIViewController
{
private Test _test;
public override void ViewDidLoad()
{
_test = new Test();
base.ViewDidLoad();
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
_test.TitleChanged += Test_TitleChanged;
}
public override void ViewDidDisappear(bool animated)
{
_test.TitleChanged -= Test_TitleChanged;
base.ViewDidDisappear(animated);
}
void Test_TitleChanged(object sender, TitleChangedEventArgs e)
{
Console.WriteLine("Title Changed! " + e.Title);
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.