【问题标题】:How to use event argument outside the event如何在事件之外使用事件参数
【发布时间】:2011-12-11 16:00:02
【问题描述】:

我正在尝试创建自定义下载应用。除了无法从“DownloadProgressChangedEventArgs”中获取“percent1”变量的下载所有按钮之外,它都可以正常工作。我已经在 mainForm 构造函数之前实例化了它,但它不会读取更改的值。

这是代码,由于大部分与问题无关,因此被部分剥离:

public partial class Main : Form
{
//Variables (not all, just the one im having issues with)
    private double percentage1;

//Main form constructor
    public Main(){...}

//Download File Async custom method
    public void DldFile(string url, string fileName, string localPath, AsyncCompletedEventHandler completedName, DownloadProgressChangedEventHandler progressName)
    {
            WebClient webClient = new WebClient();
            webClient.DownloadFileAsync(new Uri(url), localPath + "\\" + fileName);
            webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(completedName);
            webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(progressName);
    }

//Button 1 click event to start download
    private void btnDld1_Click(object sender, EventArgs e)
    {
        if (url1 != "" && Directory.Exists(localPath1))
        {
            _startDate1 = DateTime.Now;
            DldFile(url1, fileName1, localPath1, completed1, progress1);
        }
        //took out the try/catch, other ifs to try and cut it down
    }

//Download Progress Changed event for Download 1
    public void progress1(object sender, DownloadProgressChangedEventArgs e)
    {
        percentage1 = e.ProgressPercentage; //THIS IS WHERE I WAS EXPECTING TO UPDATE "percentage1"
        progressBar1.Value = int.Parse(Math.Truncate(percentage1).ToString());
    }

//Button that starts all downloads click event where all my problems are at the moment
    private void btnDldAll_Click(object sender, EventArgs e)
    {
        //The progress bar that should let me know the global status for all webClients
        progressBarAll.Value = (
            int.Parse(Math.Truncate(percentage1).ToString()) + //HERE IS MY PROBLEM
            int.Parse(Math.Truncate(percentage2).ToString()) + //HERE IS MY PROBLEM
            int.Parse(Math.Truncate(percentage3).ToString()) + //HERE IS MY PROBLEM
            int.Parse(Math.Truncate(percentage4).ToString()) + //HERE IS MY PROBLEM
            int.Parse(Math.Truncate(percentage5).ToString())) / 5; //HERE IS MY PROBLEM

        //Checks if the link exists and starts it from the download button click event
        if (url1 != "")
        {
            btnDld1.PerformClick();
        }
        //Continues for url2, 3, 4, 5 and else
    }
}

所以这是我找到的让你知道我想要完成什么的最短方法,如果有什么遗漏请告诉我,我会尽快添加任何信息。

我试图实例化“progress1”来尝试访问它的百分比1 变量,但它没有工作。我试过用 webClient 做同样的事情,但也没有用。我使用谷歌和堆栈流搜索无济于事。所以我不确定这个问题是否太愚蠢,或者有一种不同的方式来看待这个完全超出我的思维方式的问题。

所以主要问题是更新“percentage1”变量并使用它。 当我掌握正确的值时,还有其他关于“progressBarAll.Value”计算的问题将得到解决。因此,如果您看到它,则无需担心。

【问题讨论】:

  • 嗯,这是一个好问题,我不想添加它,所以这篇文章只针对一个问题,然后我会尝试进一步解决这个问题。但我们的想法是根据正在运行的任何下载来保持progressBarAll 的更新。如果 dld1 正在进行,那么它将显示 download1 进度,如果超过 1 个正在工作,它将显示所有工作下载的平均值。但我想一旦我在事件处理程序之外获得 e.Percentage 值的句柄,我就可以完成它。
  • 它到底是怎么不工作的,DownloadProgressChanged 事件是否从未触发,或者变量从未分配?尝试在progress1() 上放置一个断点,看看它是否被命中。然后逐步调试它以追踪实际问题。据我所知,您在这里没有做错任何事情,您应该能够从事件处理程序中设置 percent1 而不会出现问题。
  • @Aevitas - 好吧,我按照你说的设置了断点,我看到的让我更加困惑,发生了一些奇怪的事情。当我单击下载时,所有事件处理程序都会被触发。但是变量percentage1 的值与e.ProgressPercentage 事件参数不同,即使我在progress1() 中声明percentage1 = e.ProgressPercentage。而且progressBarAll 根本不动,即使我可以看到percentage* 的值都在变化。
  • 这很奇怪,因为你不习惯编程。您似乎将您的代码视为数学表达式。您期望一旦编写了平均进度的代码,该关系应该永远保持。但是,c# 是imperative programming language。这只是机器的一系列命令:执行此操作,然后执行此操作。因此,平均仅在您单击btnDldAll 时发生。有不同的技术可以让它像数学函数一样工作。我在回答中提出了其中一个。
  • 嗯,我学习 C# 的主要问题是改变我的思维方式。编程思想与我过去所做的完全不同。这是一个相当大的挑战,但我会掌握它,因为 StackOverflow 有一个很棒的社区,可以指出什么是错误的以及如何正确地做。感谢 Aevitas 的帮助。

标签: c# events arguments


【解决方案1】:

尽量不要考虑“在事件之外使用事件参数”。考虑更新表单的状态。

使用属性简化更新逻辑:

public partial class Main : Form
{
  private double percentage1;
  private double percentage2;
  private double percentage3;
  private double percentage4;
  private double percentage5;

  private double Percentage1 
  {
    get
    {
      return this.percentage1;
    }
    set
    {
      this.percentage1 = value;
      this.UpdatePercentageAll();  // this will update overall progress whenever the first one changes

      progressBar1.Value = GetValueFromPercentage(value);
    }
  }
  private double Percentage2
  // same code as for Percentage1

  void UpdatePercentageAll()
  {
    this.PercentageAll = (this.Percentage1 + this.Percentage2 + this.Percentage3 + this.Percentage4 + this.Percentage5) / 5;
  }

  static int GetValueFromPercentage(double percentage)
  {
    return (int)Math.Truncate(percentage);
  }

  double percentageAll;
  private double PercentageAll
  {
    get
    {
      return this.percentageAll;
    }
    set
    {
      this.percentageAll = value;

      progressBarAll.Value = GetValueFromPercentage(value);
    }
  }

  //Download File Async custom method
  public void DldFile(string url, string fileName, string localPath, AsyncCompletedEventHandler completedName, DownloadProgressChangedEventHandler progressName)
  {
    WebClient webClient = new WebClient();
    webClient.DownloadFileAsync(new Uri(url), localPath + "\\" + fileName);
    webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(completedName);
    webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(progressName);
  }

  //Button 1 click event to start download
  private void btnDld1_Click(object sender, EventArgs e)
  {
    if (url1 != "" && Directory.Exists(localPath1))
    {
        this.StartDownloadFile1();
    }
    //took out the try/catch, other ifs to try and cut it down
  }
  void StartDownloadFile1()
  {
        this.Percentage1 = 0;
        _startDate1 = DateTime.Now;
        DldFile(url1, fileName1, localPath1, completed1, progress1);
  }
  //Download Progress Changed event for Download 1
  public void progress1(object sender, DownloadProgressChangedEventArgs e)
  {
    this.Percentage1 = e.ProgressPercentage; // update property, not field

    //this will be done in property setters
    //progressBar1.Value = int.Parse(Math.Truncate(percentage1).ToString());
  }
  // then add similar code for other download buttons

  //Button that starts all downloads click event where all my problems are at the moment
  private void btnDldAll_Click(object sender, EventArgs e)
  {
    //Checks if the link exists and starts it from the download button click event
    if (url1 != "")
    {
        this.StartDownloadFile1();
    }
    //Continues for url2, 3, 4, 5 and else
  }
}

我会进一步重构代码,但我认为如果代码更接近原始代码,您会更容易理解。

主要思想是创建一组像数学函数一样工作的链接属性。在编写PercentageX 属性时,我有点说'让PercentageAll 成为所有百分比的平均值'。然后我有每个下载更新它自己的进度。一旦更新了任何进度,它就会更新平均值,我不必在进度更改事件处理程序中记住

最后一点是从百分比属性更新进度条。这很简单:一旦更改百分比,我需要更新一个条形图。如果是这样,为什么还要写类似的东西

this.Percentage1 = x;
this.progressBar1.Value = (int)Math.Truncate(x);

在这种情况下,我必须记住,一旦我更改了Percentage1,我就必须更新栏。在我的例子中,我只是为只在一个地方并且每次都有效的东西创建了一个严格的规则。所以我就是不能忘记它。如果我需要改变规则,我只需要改变一个地方,所以我不能再犯错误了。

我演示的技术可以表达为一个众所周知的规则:“一个规则 - 一个位置”,这意味着您应该尝试在代码中只使用一个位置来表达程序中存在的每个逻辑规则。这是一个很重要的思想,建议大家学习使用。

【讨论】:

  • Pavel 我不太了解您发布的代码的机制。我对您的帖子没有任何具体问题,我只是太缺乏经验,无法一次获得所有信息。所以我要把它打印出来,让一切都明白,测试它,然后再回复。但我几乎肯定你会得到接受的答案,感谢您的快速回答;D
  • 我刚刚浏览了代码,我想你忘了输入GetValueFromPercentage(value) 方法。另一方面,我不确定,但我每次下载都有一个progressBar + progressBarAll,因此各个progressBars 将根据他们自己的下载移动,progressBarAll 将根据正在发生的任何下载的总百分比移动。通过阅读您的代码,我认为您正在尝试使用 1progressBar 来通知正在发生的任何下载。让我知道我是否理解您的正确。
  • @FernandoSilva 对不起,我应该写一个更完整的代码。我刚刚错过了GetValueFromPercentage 方法。你是对的,我知道所有下载只有一个进度条。我已经更新了代码和答案。请检查一下。
  • 好吧,我只是把所有东西放在一起,它工作得很好。感谢帕维尔的帮助和耐心。现在我已经解决了这个问题(这是我唯一遇到的问题),我将向需要并要求应用程序的人发布 v.1.0。然后我会尝试重新制作整个代码,因为我学到了很多将所有这些放在一起的东西,而且我觉得我会做很多不同的事情。我什至可能会在此处重新发布我为使一切正常进行的所有 tweeks 和更改。再次感谢;D
  • @Pavel 在完成这个之后我很好奇,当你说我会进一步重构代码你是什么意思?如果它超出此线程的范围,请随时通过电子邮件向我发送您的建议。将不胜感激,因为我将尝试重新编码整个内容以用于学习目的。
猜你喜欢
  • 2016-12-21
  • 1970-01-01
  • 2020-12-07
  • 1970-01-01
  • 2011-12-20
  • 1970-01-01
  • 2016-10-13
  • 1970-01-01
  • 2020-04-16
相关资源
最近更新 更多