Наследование: System.Windows.Forms.Form
        private void _uploadButton_Click(object sender, EventArgs e)
        {
            if (_uploadWorker != null)
            {
                // We're already doing an upload, this is now the Cancel button.
                _progressBox.CancelRequested = true;
                return;
            }
            _progressBox.CancelRequested = false;
            ScrollControlIntoView(_progressBox);
            _progressBox.Clear();
            var info = _book.BookInfo;
            if (string.IsNullOrEmpty(info.Id))
            {
                info.Id = Guid.NewGuid().ToString();
            }
            info.Uploader = _bookTransferrer.UserId;

            if (_book.BookInfo.IsSuitableForMakingShells)
            {
                // Hopefully this message is never seen...there is supposed to be no way for an end user to create a template...so I think we can afford
                // not to burden localizers with it.
                if (MessageBox.Show(Form.ActiveForm,
                    @"This book is marked as suitable for making shells, that is, a new template like Basic Book containing blank pages for authoring a new book. "
                    + @"Such books are normally only created and uploaded by HTML specialists. "
                    + @"If this book is intended as a shell to translate, something is wrong, and you should get expert help before uploading this book."
                    + "\n\n"
                    + @"Do you want to go ahead?",
                    "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes)
                    return;
            }

            _progressBox.WriteMessage("Checking bloom version eligibility...");
            if (!_bookTransferrer.IsThisVersionAllowedToUpload())
            {
                MessageBox.Show(this,
                    LocalizationManager.GetString("PublishTab.Upload.OldVersion",
                        "Sorry, this version of Bloom Desktop is not compatible with the current version of BloomLibrary.org. Please upgrade to a newer version."),
                    LocalizationManager.GetString("PublishTab.Upload.UploadNotAllowed", "Upload Not Allowed"),
                    MessageBoxButtons.OK, MessageBoxIcon.Stop);
                _progressBox.WriteMessage("Canceled.");
                return;
            }

            // Todo: try to make sure it has a thumbnail.

            _progressBox.WriteMessage("Checking for existing copy on server...");
            if (_bookTransferrer.IsBookOnServer(_book.FolderPath))
            {
                using (var dlg = new OverwriteWarningDialog())
                {
                    if (dlg.ShowDialog() == DialogResult.Cancel)
                    {
                        _progressBox.WriteMessage("Canceled.");
                        return;
                    }
                }
            }
            _progressBox.WriteMessage("Starting...");
            _uploadWorker = new BackgroundWorker();
            _uploadWorker.DoWork += BackgroundUpload;
            _uploadWorker.WorkerReportsProgress = true;
            _uploadWorker.RunWorkerCompleted += (theWorker, completedEvent) =>
            {
                // Return all controls to normal state. (Do this first, just in case we get some further exception somehow.)
                // I believe the event is guaranteed to be raised, even if something in the worker thread throws,
                // so there should be no way to get stuck in the state where the tabs etc. are disabled.
                SetStateOfNonUploadControls(true);
                // Don't call UpdateDisplay, it will wipe out the progress messages.
                if (_progressBox.CancelRequested)
                {
                    _progressBox.WriteMessageWithColor(Color.Red, LocalizationManager.GetString("PublishTab.Upload.Cancelled", "Upload was cancelled"));
                }
                else {
                    if (completedEvent.Error != null)
                    {
                        string errorMessage = LocalizationManager.GetString("PublishTab.Upload.ErrorUploading",
                            "Sorry, there was a problem uploading {0}. Some details follow. You may need technical help.");
                        _progressBox.WriteError(errorMessage, _book.Title);
                        _progressBox.WriteException(completedEvent.Error);
                    }
                    else if (string.IsNullOrEmpty((string) completedEvent.Result))
                    {
                        // Something went wrong, typically already reported.
                        string sorryMessage = LocalizationManager.GetString("PublishTab.Upload.FinalUploadFailureNotice",
                            "Sorry, \"{0}\" was not successfully uploaded. Sometimes this is caused by temporary problems with the servers we use. It's worth trying again in an hour or two. If you regularly get this problem please report it to us.");
                        _progressBox.WriteError(sorryMessage, _book.Title);
                    }
                    else
                    {
                        var url = BloomLibraryUrlPrefix + "/browse/detail/" + _parseId;
                        string congratsMessage = LocalizationManager.GetString("PublishTab.Upload.UploadCompleteNotice",
                            "Congratulations, \"{0}\" is now available on BloomLibrary.org ({1})");
                        _progressBox.WriteMessageWithColor(Color.Blue, congratsMessage, _book.Title, url);
                    }
                }
                _uploadWorker = null;
            };
            SetStateOfNonUploadControls(false); // Last thing we do before launching the worker, so we can't get stuck in this state.
            _uploadWorker.RunWorkerAsync(_book);
            //_bookTransferrer.UploadBook(_book.FolderPath, AddNotification);
        }