Безопасное управление документами на C#

Это довольно привлекательный пример, который показывает, как безопасно управлять документами. Части все просты, но есть много плотно интегрированных частей.

В этом примере вы можете создавать, редактировать, открывать и сохранять файлы в текстовых и форматированных форматах. Он предоставляет команды New, Open, Save, Save As и Exit. Основная цель этого примера - скоординировать все эти команды, чтобы документ всегда был безопасным.

Например, если вы открываете файл, вносите изменения, а затем пытаетесь открыть другой файл, программа говорит, что есть несохраненные изменения, спрашивает, хотите ли вы их сохранить. Если вы нажмете «Да», программа сохранит файл с его текущим именем файла или предложит вам имя файла, если оно не было сохранено ранее.

В этом примере также обновляется строка заголовка программы, чтобы отобразить имя загружаемого файла (если у него есть имя-новые файлы не имеют имен до их сохранения) и отображает звездочку, если загруженный документ имеет несохраненные изменения.

Программа использует два ключевых свойства, чтобы гарантировать, что изменения загруженного документа не будут потеряны и обновить строку заголовка программы: FileName и DocumentChanged . Следующий код показывает эти два свойства.

// Имя файла документа.
private string _FileName = "";
private string FileName
{
    get { return _FileName; }
    set
    {
        if (value == _FileName) return;
        _FileName = value; 
        SetFormCaption(); 
    }
}

// Истина, если документ был изменен с момента открытия / создания.
private bool _DocumentChanged = false;
private bool DocumentChanged
{
    get { return _DocumentChanged; }
    set
    {
        if (value == _DocumentChanged) return;
        _DocumentChanged = value;
        SetFormCaption();
    }
}

Эти свойства используют резервные переменные _FileName и _DocumentChanged для хранения своих значений. Геттер Каждое свойство просто возвращает значение переменной основы.

Каждый установщик свойства определяет, изменяется ли его значение и выходит, если это не так. Затем он сохраняет новое значение и вызывает описанный нижеметод SetFormCaption для обновления строки заголовка формы.

Обратите внимание, что элемент управления RichTextBox имеет свойство Modified,которое также отслеживает, был ли документ изменен так же, как и свойство DocumentChanged . Программа использует свое собственное свойство вместо свойства Модифицированного элемента управления, чтобы свойство могло вызвать SetFormCaption.

Следующий код показывает метод SetFormCaption.

// Установите заголовок формы, чтобы указать файл
// Имя и есть несохраненные изменения.
private void SetFormCaption()
{
    string caption = "howto_save_as ";

    // Если есть изменения, добавьте звездочку.
    if (DocumentChanged) caption += "* ";
    else caption += " ";

    // Добавить имя файла без его пути.
    if (FileName == "") caption += "[ ]";
    else caption += "[" + Path.GetFileName(FileName) + "]";

    // Отображение результата.
    this.Text = caption;
}

Этот метод просто составляет заголовок формы, используя текущее имя файла документа (если оно есть) и добавление звездочки, если документ изменен.

Это поможет обновить заголовок формы. Обеспечение безопасности документа немного более активно, но все еще довольно просто. Ключ - это метод IsDocumentSafe, показанный в следующем коде.

// Возвращаем true, если безопасно отбрасывать текущий документ.
private bool IsDocumentSafe()
{
    // Если в документе нет текущих изменений, это безопасно.
    if (!DocumentChanged) return true;

    // Посмотрите, хочет ли пользователь сохранить изменения.
    switch (MessageBox.Show(
        "There are unsaved changes. Do you want to save the document?",
        "Save Changes?", MessageBoxButtons.YesNoCancel))
    {
        case DialogResult.Yes:
            // Save the changes.
            SaveDocument();

            // Если у документа все еще есть несохраненные изменения,
            // тогда мы не сохранили, поэтому документ небезопасен.
            return (!DocumentChanged);

        case DialogResult.No:
            // Безопасно потерять текущие изменения.
            return true;

        default:
           // Отмена. Нельзя потерять изменения.
            return false;
    }
}

Этот метод возвращает true, если безопасно отбрасывать текущий документ.

Сначала метод проверяет свойство DocumentChanged и, если нет несохраненных изменений, метод возвращает true . Это происходит, если не было никаких изменений, поскольку документ был загружен, сохранен или создан.

Если есть несохраненные изменения, метод предупреждает пользователя и спрашивает, должен ли он сохранить изменения.

Если пользователь нажимает «Да», программа вызывает SaveDocument, чтобы попытаться сохранить изменения. Это может привести к сбою (вы поймете, почему, когда вы смотрите на метод SaveDocument ), поэтому IsDocumentSafe возвращает true, только если после вызова SaveDocument нет несохраненных изменений .

Если пользователь нажимает «Нет», пользователь не хочет сохранять текущие изменения, поэтому IsDocumentSafe возвращает true, чтобы указать, что программа может отменить изменения.

Если пользователь нажимает кнопку « Отмена», пользователь решил не делать того, что запустило вызов программы IsDocumentSafe . Возможно, это было создание нового документа, открытие существующего документа или выход из программы. ( Вскоре вы увидите эти вызовы в IsDocumentSafe .) В этом случае IsDocumentSafeвозвращает false, чтобы сообщить вызывающему коду, что небезопасно отбрасывать текущие изменения.

Существует два способа, которыми пользователь может попытаться напрямую сохранить текущий документ: с помощью команд меню «Сохранить» или «Сохранить как». Следующий код показывает эти обработчики событий в меню.

// Сохранить с использованием текущего имени документа.
private void mnuFileSave_Click(object sender, EventArgs e)
{
    SaveDocument();
}

// Сохраним документ с новым именем.
private void mnuFileSaveAs_Click(object sender, EventArgs e)
{
    SaveDocumentAs();
}

Эти обработчики событий просто вызывают методы SaveDocument и SaveDocumentAsсоответственно.

Следующий код показывает метод SaveDocumentAs.

// Попытайтесь сохранить документ с новым именем файла.
private void SaveDocumentAs()
{
    // Позвольте пользователю выбрать файл для сохранения.
    if (sfdDocument.ShowDialog() == DialogResult.OK)
    {
       // Сохранить с использованием имени выбранного файла.
        SaveDocumentAs(sfdDocument.FileName);
    }
}

Этот метод отображает SaveFileDialog пользователю, чтобы пользователь мог выбрать файл для сохранения документа. Если пользователь выбирает файл и щелкает «Сохранить», код вызывает перегруженную версию SaveDocumentAs, которая принимает имя файла в качестве параметра, передавая этот метод имени файла, выбранному пользователем. Следующий код показывает перегруженную версию SaveDocumentAs.

// Сохраним документ с указанным именем.
private void SaveDocumentAs(string file_name)
{
   // Сохранить с указанным именем.
    try
    {
        // Сохраним файл.
        if (Path.GetExtension(sfdDocument.FileName).ToLower() == "txt")
        {
            // Сохранить как текстовый файл.
            File.WriteAllText(rchDocument.Text, rchDocument.Text);
        }
        else
        {
           // Сохранить как RTF-файл.
            rchDocument.SaveFile(file_name);
        }

        // Обновляем имя файла документа.
        FileName = file_name;

       // Теперь нет несохраненных.
        DocumentChanged = false;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Эта версия SaveDocumentAs является единственной частью кода, которая фактически сохраняет файл. Сначала он проверяет расширение имени файла. Если расширение является .txt, код использует метод WriteAllText класса File для сохранения текста текущего документа в указанный файл. Если расширение не является .txt, код использует метод SaveFile элемента управления RichTextBox для сохранения содержимого элемента управления в формате Rich Text.

Если код успешно сохраняет файл, он обновляет свойства FileName и DocumentChanged.

Другим методом, который сохраняет файлы, является следующий метод SaveDocument.

// Попытаемся сохранить документ.
// Если у нас нет имени файла, используйте это как Сохранить как.
private void SaveDocument()
{
   // Посмотрим, есть ли у нас имя файла.
    if (FileName == "")
    {
       // У нас нет имени файла. Обработайте как Сохранить как.
        SaveDocumentAs();
    }
    else
    {
        // Сохранить с текущим именем.
        SaveDocumentAs(FileName);
    }
}

Этот метод проверяет свойство FileName. Если у программы нет имени файла для текущего документа (потому что он создал новый файл и еще не сохранил его), тогда программа вызывает SaveDocumentAs, чтобы пользователь мог выбрать файл для сохранения документа. Если у программы есть имя файла для документа, метод вызывает SaveDocumentAs, передавая ему текущее имя файла, чтобы программа сохраняла документ в этом файле.

Это самые сложные части программы. Остальная часть кода просто вызывает эти методы, когда это необходимо.

Следующий код показывает, как программа создает новый файл, когда пользователь выбирает команду «Создать» меню «Файл».

// Создаем новый документ.
private void mnuFileNew_Click(object sender, EventArgs e)
{
    // Удостоверьтесь, что безопасно удалять текущий документ.
    if (!IsDocumentSafe()) return;

    // Очистите документ.
    rchDocument.Clear();

   // Нет изменений.
    DocumentChanged = false;

  // У нас пока нет имени файла.
    FileName = "";
}

Этот код проверяет IsDocumentSafe и возвращает, если небезопасно отменять текущие изменения. Если безопасно продолжать, метод очищает RichTextBox, устанавливает DocumentChanged в false и очищает имя файла.

Следующий код показывает, как программа открывает файл, когда пользователь выбирает команду «Открыть» меню «Файл».

// Открыть существующий файл.
private void mnuFileOpen_Click(object sender, EventArgs e)
{
    // Удостоверьтесь, что безопасно удалять текущий документ.
    if (!IsDocumentSafe()) return;

   // Позвольте пользователю выбрать файл.
    if (ofdDocument.ShowDialog() == DialogResult.OK)
    {
        // Откройте файл.
        OpenFile(ofdDocument.FileName);
    }
}

Как и код, используемый для создания нового документа, этот код проверяет IsDocumentSafe, чтобы убедиться, что он безопасен. Если это безопасно, код отображает OpenFileDialog, чтобы пользователь мог выбрать файл. Если пользователь выбирает файл и нажимает OK, код вызывает метод OpenFile, передавая ему имя выбранного файла. Следующий код показывает метод OpenFile.

// Открыть указанный файл.
private void OpenFile(string file_name)
{
    try
    {
       // Загрузите файл.
        if (Path.GetExtension(file_name).ToLower() == ".txt")
        {
            // Читаем как текстовый файл.
            rchDocument.Text = File.ReadAllText(file_name);
        }
        else
        {
            // Читаем как RTF-файл.
            rchDocument.LoadFile(file_name);
        }

      // Нет изменений.
        DocumentChanged = false;

      // Сохраните имя файла.
        FileName = file_name;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Метод OpenFile проверяет расширение имени файла и пытается открыть соответственно текстовый файл или файл Rich Text. Если код успешно открывает файл, он обновляет свойства DocumentChanged и FileName.

Следующий код показывает обработчики событий, которые выполняются, когда пользователь выбирает команды «Сохранить», «Сохранить как» и «Выйти» меню «Файл».

// Сохранить с использованием текущего имени документа.
private void mnuFileSave_Click(object sender, EventArgs e)
{
    SaveDocument();
}

// Сохраним документ с новым именем.
private void mnuFileSaveAs_Click(object sender, EventArgs e)
{
    SaveDocumentAs();
}

// Выход. Просто попытайтесь закрыть.
private void mnuFileExit_Click(object sender, EventArgs e)
{
    Close();
}

Команды Save и Save As вызывают методы SaveDocument и SaveDocumentAs. Команда меню «Выход» просто пытается закрыть форму. Когда форма пытается закрыть, выполняется следующий обработчик события FormClosing.

// Если закрытие небезопасно, отмените закрытие.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    e.Cancel = !IsDocumentSafe();
}

Обработчик события FormClosing просто вызывает IsDocumentSafe и, если небезопасно отбрасывать текущий документ, устанавливает e.Cancel в true, чтобы форма оставалась открытой.

Последние два фрагмента кода - обработчик события TextChanged элемента управления RichTextBox и обработчик события Load формы.

// Отметить документ как измененный.
private void rchDocument_TextChanged(object sender, EventArgs e)
{
    DocumentChanged = true;
}

// Изначально у нас есть новый неизменный документ.
private void Form1_Load(object sender, EventArgs e)
{
    mnuFileNew_Click(null, null);
}

Обработчик события TextChanged устанавливает DocumentChanged в true. Обработчик события Load формы вызывает обработчик события mnuFileNew_Click для запуска нового документа так же, как если бы пользователь нажал кнопку «Создать» меню «Файл».

Вот и все! Простой, не так ли? Существует много частей, потому что существует много возможных последовательностей событий, но индивидуально каждая из частей является относительно простой.

Источник: csharphelper.com/blog/2017/07/safely-manage-documents-in-c/

1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (2 оценок, среднее: 5,00 из 5)
Adblock
detector