c# – 如何在事件之外使用事件参数

我正在尝试创建自定义下载应用.它的全部工作除了下载所有按钮,无法从“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”来尝试和访问其percentage1变量,但它没有用.我试过用webClient做同样的事情,但也没办法.我使用谷歌和stackflow搜索无济于事.所以我不确定问题是否过于愚蠢,或者有一种不同的方式来看待完全脱离我心态的问题.

所以主要问题是更新“percentage1”变量并使用它.
关于“progressBarAll.Value”计算还有其他问题,当我可以得到正确的值时,将会解决这个问题.所以如果你看到它就不用担心.

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

使用属性来简化更新逻辑:

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

在这种情况下,我必须记住,一旦我更改百分比1,我必须更新栏.在我的例子中,我只是创建一个严格的规则,它只在一个地方,每次都有效.所以我不能忘记它.如果我需要改变规则,我只需要改变一个地方,所以我再也不能犯错误.

我演示的技术可以表达为一个众所周知的规则:“一个规则 – 一个地方”,这意味着您应该尝试在代码中只有一个位置来表示程序中存在的每个逻辑规则.这是一个非常重要的想法,我建议你学习和使用它.

点赞