2016-04-25 32 views
3

我试图在UIViewController的标题发生变化时得到通知。键值观察不在UIViewController子类上触发?

我试图添加一个观察者到UIViewController子类的标题,但它永远不会被触发。奇怪的是,它在一个普通的UIViewController上工作。难道我做错了什么?

下面是一个代码示例解释了我的问题(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 
     { 
     } 
    } 
} 

回答

2

在Xamarin的最佳方式可能会使用继承和加入这样的功能。为此,您从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 
} 

得到贯彻失踪事件类型

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; 
    } 
} 

然后,您可以订阅这个事件,并得到变更通知

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); 
    } 
} 
0

UIViewControllerTitle属性标记virtual ...所以作为替代方案,你可以定义一个类BaseViewControlleroverrideTitle并呼吁在Setter的方法:

Public class BaseViewController : UIViewController 
{ 
    .... 

    public override string Title { 
    get { 
     return base.Title; 
    } 
    set { 
      base.Title = value; 
      OnTitleChanged(); 
     } 
    } 

    protected virtual void OnTitleChanged() 
    { 
     ...... 
    } 
} 

然后你就可以在任何覆盖OnTitleChanged你的UIViewControllersTitle更改时有回拨。

0

您可以设置标题就像这样,它会工作:

 controller2.SetValueForKey(new NSString("TitleChangedHAHA"), new NSString("title")); 
0

你能做到这一点。首先定义一个新的事件参数,当它改变时将保存新的标题。

public class TitleChangedEventArgs: EventArgs 
{ 
    public string Title { get; private set; } 

    public TitleChangedEventArgs(string title) 
    { 
     Title = title; 
    } 
} 

在您的测试类,添加一个新的事件处理程序TitleChanged并覆盖标题引发一个事件时视图控制器的新称号。

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); 
      } 
     } 
    } 

终于在您的主视图控制器,你可以做这样的事情:

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); 
     } 
    }