草庐IT

c# - UIControllerView 不会从委托(delegate)函数更新

coder 2024-01-17 原文

我想通过委托(delegate)方法更新 UIViewController 中的 UIView

有草图: 用户从 UIViewController 触发下载,下载由类管理,当 UploadAsyncData 完成时,下载方法将处理的响应传递给另一个类。此类将接收到的数据写入本地数据库。

我想通知用户将 UIViewController 从流程进度中扔到哪里。

我现在做了什么:

  • UIViewController 中,我得到了一个 UIView,它代表一个带有一些消息的 OverlayUIView 也设置为静态帮助器类,以帮助从外部引用它。

  • 当用户按下下载按钮时,Overlay 会出现并通知用户操作已被触发。

  • 当操作传递给下载类时,Overlay 文本更新为“您的下载正在进行中”

  • 下载完成后,下载类中处理响应的方法将 Overlay 文本更新为“下载完成,正在处理收到的数据...”

  • 由于接收到的数据是一个 C# 对象,我从该对象调用 SaveToDatabase 方法。

  • SaveToDatabase 方法使用进度指示器更新 Overlay

到目前为止,除了 SaveToDatabase 步骤之外,所有步骤都正确地更新了 Overlay 消息。 调试时我可以看到更新 Overlay 文本的方法在每一步都被调用,但是 UIView 文本没有更新。

我不能使用 InvokeOnMainThread 因为 SaveToDatabase 不是 UIViewController 我不明白的是为什么所有步骤都正确更新 UIView 但最后一个不是.

这里是所有这一步的一些提取代码。

主要方法

public class Program:UIViewController
{
    {...}
    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        AddOverlay();
    }

    public void AddOverlay()
    {
        var bounds = UIScreen.MainScreen.Bounds;
        bounds.Size = new CGSize(bounds.Size.Width, bounds.Size.Height);
        loadingOverlay = new LoadingOverlay(bounds);
        loadingOverlay.Hidden = true;

        View.Add(loadingOverlay);
        System.Diagnostics.Debug.WriteLine(this.GetType().Name + loadingOverlay.GetHashCode());
        Helpers.LoadingOverlay = loadingOverlay;
    }

    public void DisplayOverlay(string text)
    {
        if(loadingOverlay != null){
            View.BringSubviewToFront(loadingOverlay);
            System.Diagnostics.Debug.WriteLine(this.GetType().Name + loadingOverlay.GetHashCode());
            loadingOverlay.Hidden = false;
            loadingOverlay.SetLoadingLabel( text );
        }   
    }

    void Tablesource_OnRowSelected(object sender, eConversion5.DownloadTableSource.RowSelectedEventArgs e)
    {
        bool isReacheable = myParameters.IsReachable();
        if (isReacheable) {
            DisplayOverlay("Your download is about to start...");
            Request request = new Request(url, myParameters);
            request.CanBeSaved = false;
            request.Action = "display";
            httpCommunication.DoRequest(request);
        }
    }
}

处理 downloadAction 的方法

public class HttpCommunication
{
    {...}
    public HttpCommunication(Parametrage parameters, HttpResponseAction responseAction)
    {
        client = new XSWebClient();
        client.UploadDataCompleted += OnUploadDataCompleted;
    }

    public void DoRequest(Request JRequest)
    {
        {...}
        SendRequest();
    }

    void SendRequest()
    {
        {...}
        client.UploadDataAsync(Request.Uri, "POST", bytes);
        {...}
    }

    void OnUploadDataCompleted(object sender, UploadDataCompletedEventArgs e)
    {
        Helpers.UpdateOverlayMessage("Processing recieved response...");
        {...}
        HandleResponse handler = new HandleResponse(myParameters, e.Result);
        {...}
    }
}

处理服务器响应的类

public class HttpResponseAction
{
    {...}
    public void ExecuteAction(HandleResponse handled, Request request)
    {
        {...}
        Helpers.UpdateOverlayMessage("Processing response...");
        {...}
        HandleTrainings(queryId, action, JsonConvert.DeserializeObject<List<TrainingContainer>>(json, Settings));
        {...}
    }

    void HandleFormation(string queryId, string action, object nestedResult)
    {
        {...}
        if (action == "display") {
            result.SaveToDatabase();
            {...}
        }
        {...}
    }

}

最后一步,不更新 UIView(之前的所有步骤都正确更新它)

public class TrainingContainer
{
    {...}
    public void SaveToDatabase()
    {
        if(SignList != null){
            Helpers.UpdateOverlayMessage("Updating sign list in progress, may be take a while...");
            int updated = 0;
            int total = SignList.Count();
            if(total > 0){
                foreach (Training training in SignList) {
                    updated++;
                    float progress = (float) updated / total;
                    Helpers.UpdateProgressValue(progress); //From debbuging, i can see that this method is called, and Overlay object is the same throw all class calls from the starting point.
                    {...}
                }
            }
        }
        {...}
    }
}

Helper 类

public static class Helpers
{
    public static LoadingOverlay LoadingOverlay;
    {...}
    public static void UpdateOverlayMessage(string message)
    {
        if(LoadingOverlay != null){
            StackTrace stackTrace = new StackTrace();
            System.Diagnostics.Debug.WriteLine(typeof(Helpers).Name + " (called from " + stackTrace.GetFrame(1).GetMethod().Name  + ")" + LoadingOverlay.GetHashCode());

            LoadingOverlay.SetLoadingLabel(message);
        }
    }

    public static void UpdateProgressValue(float progessValue)
    {
        if (LoadingOverlay != null) {
            StackTrace stackTrace = new StackTrace();
            System.Diagnostics.Debug.WriteLine(typeof(Helpers).Name + " (called from " + stackTrace.GetFrame(1).GetMethod().Name + ")" + LoadingOverlay.GetHashCode());
            LoadingOverlay.UpdateProgress(progessValue);
        }
    }
}

编辑:一些跟踪记录来自对 Helper 的调用。

Helpers <UpdateOverlayMessage> :Transmitting request to the server...(called from Apply) -2037862263
Helpers <UpdateOverlayMessage> :Processing recieved response...(called from Apply) -2037862263
Helpers <UpdateOverlayMessage> :Processing response...(called from Apply) -2037862263
Helpers <UpdateOverlayMessage> :Updating sign list in progress, may be take a while...(called from Apply) -2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263
Helpers <UpdateProgressValue> (called from Apply)-2037862263

更新 2: 忘记显示 Overlay 类

public class LoadingOverlay : UIView {
        // control declarations
        UIActivityIndicatorView activitySpinner;
        UILabel loadingLabel;
        UIProgressView progressView;

        public LoadingOverlay (CGRect frame) : base (frame)
        {
            // configurable bits

            BackgroundColor = UIColor.Black;
            Alpha = 0.55f;
            AutoresizingMask = UIViewAutoresizing.All;

            nfloat labelHeight = 22;
            nfloat labelWidth = Frame.Width - 20;

            // derive the center x and y
            nfloat centerX = Frame.Width / 2;
            nfloat centerY = Frame.Height / 2;

            // create the activity spinner, center it horizontall and put it 5 points above center x
            activitySpinner = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.WhiteLarge);
            activitySpinner.Frame = new CGRect ( 
                centerX - (activitySpinner.Frame.Width / 2) ,
                centerY - activitySpinner.Frame.Height - 20 ,
                activitySpinner.Frame.Width,
                activitySpinner.Frame.Height);
            activitySpinner.AutoresizingMask = UIViewAutoresizing.All;
            AddSubview (activitySpinner);
            activitySpinner.StartAnimating ();

            // create and configure the "Loading Data" label
            loadingLabel = new UILabel(new CGRect (
                centerX - (labelWidth / 2),
                centerY + 20 ,
                labelWidth ,
                labelHeight
            ));
            loadingLabel.BackgroundColor = UIColor.Clear;
            loadingLabel.TextColor = UIColor.White;
            loadingLabel.Text = "Wait a moment...";
            loadingLabel.TextAlignment = UITextAlignment.Center;
            loadingLabel.AutoresizingMask = UIViewAutoresizing.All;
            AddSubview (loadingLabel);

            progressView = new UIProgressView();
            progressView.Progress = 0.0f;
            var screenParts = Frame.Width / 3;
            progressView.Frame = new CGRect(new CGPoint(screenParts,loadingLabel.Frame.Y + loadingLabel.Frame.Height + 20), new CGSize(screenParts,40));
            progressView.Hidden = true;

            AddSubview(progressView);
        }

        /// <summary>
        /// Fades out the control and then removes it from the super view
        /// </summary>
        public void Hide ()
        {
            progressView.Progress = 0.0f;
            InvokeOnMainThread(() => {
                UIView.Animate(
                    0.5, // duration
                    () => { Alpha = 0; },
                    () => { RemoveFromSuperview(); }
                );
            });
        }

        public void SetLoadingLabel(String text)
        {
            InvokeOnMainThread(() => {
                loadingLabel.Text = text;
            });
        }

        public void UpdateProgress(float progressValue){
            if(progressView.Hidden){
                progressView.Hidden = false;
            }
            if(progressValue > 1){
                progressValue = 1;
            }
            InvokeOnMainThread(() => {
                progressView.SetProgress(progressValue, true);
            });
        }
    }

最佳答案

更新 UI 时,请确保它在主线程上运行。 InvokeOnMainThread 方法是在 NSObject 上定义的,因此使 Helper 类继承自 NSObject。所以 Helper 类可以改进为:

     public sealed class Helpers:NSObject
     {
         public LoadingOverlay LoadingOverlay;

         private static readonly Helpers instance = new Helpers(); 
         private Helpers(){} 
         public static Helpers Instance 
         { 
            get  
            { 
                return instance;  
            } 
         }

         public void UpdateOverlayMessage(string message)
         {
            InvokeOnMainThread ( () => {
                if(LoadingOverlay != null){
                    StackTrace stackTrace = new StackTrace();
                    System.Diagnostics.Debug.WriteLine(typeof(Helpers).Name + " (called from " + stackTrace.GetFrame(1).GetMethod().Name  + ")" + LoadingOverlay.GetHashCode());

                    LoadingOverlay.SetLoadingLabel(message);
                }
            });
         }
         //So does the method "UpdateProgressValue".
     }

在主要方法中:

Helpers.Instance.LoadingOverlay = loadingOverlay;

更新用户界面时:

Helpers.Instance.UpdateOverlayMessage("...");

关于c# - UIControllerView 不会从委托(delegate)函数更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43386614/

有关c# - UIControllerView 不会从委托(delegate)函数更新的更多相关文章

  1. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  2. ruby - Highline 询问方法不会使用同一行 - 2

    设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案

  3. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  4. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  5. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  6. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  7. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  8. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  9. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  10. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

随机推荐