Windows forms сортировка массива c

В данной теме подробно описывается процесс создания Windows Forms приложения, которое реализует сортировку массива чисел в трех параллельных потоках. Тема будет полезна начинающим программистам при изучении особенностей работы с потоками выполнения, основанных на компоненте (классе) BackgroundWorker. Демонстрационное приложение создается в системе Microsoft Visual Studio 2019.

Перед изучением данной темы рекомендуется ознакомиться со следующими темами:

  • Элемент управления BackgroundWorker. Работа с потоками (фоновыми операциями). Обзор методов, свойств, событий
  • Отображение прогресса выполненных работ. Отмена потока выполнения

Содержание

  • Условие задачи
  • Решение
    • 1. Запустить MS Visual Studio. Сохранить проект
    • 2. Размещение элементов управления на форме
    • 3. Настройка визуальных элементов управления формы
    • 4. Настройка невизуальных элементов управления типа BackgroundWorker
    • 5. Ввод внутренних переменных в класс формы
    • 6. Дополнительные внутренние методы
      • 6.1. Метод DisplayArray(). Отображение массива в ListBox
      • 6.2. Метод Active(). Активация/деактивация элементов управления
    • 7. Программирование обработчиков событий визуальных элементов управления
      • 7.1. Загрузка формы. Конструктор формы Form1
      • 7.2. Обработчик события Click кнопки button1. Команда Generate array
      • 7.3. Обработчик события Click кнопки button2. Команда Sort
      • 7.4. Обработчик события Click кнопки button3. Команда Stop
    • 8. Программирование обработчиков событий элементов управления типа BackgroundWorker
      • 8.1. Событие DoWork выполнения потока
        • 8.1.1. Обработчик события DoWork элемента управления backgroundWorker1. Генерирование массива
        • 8.1.2. Обработчик события DoWork элемента управления backgroundWorker2. Сортировка методом пузырька
        • 8.1.3. Обработчик события DoWork элемента управления backgroundWorker3. Сортировка вставками
        • 8.1.4. Обработчик события DoWork элемента управления backgroundWorker4. Сортировка выбором
      • 8.2. Событие ProgressChanged. Изменение прогресса выполнения потока
        • 8.2.1. Обработчик события ProgressChanged элемента управления backgroundWorker1. Отображение прогресса генерирования массива
        • 8.2.2. Обработчик события ProgressChanged элемента управления backgroundWorker2. Отображение прогресса при сортировке пузырьком
        • 8.2.3. Обработчик события ProgressChanged элемента управления backgroundWorker3. Отображение прогресса при сортировке вставками
        • 8.2.4. Обработчик события ProgressChanged элемента управления backgroundWorker3. Отображение прогресса в методе сортировки выбором
      • 8.3. Событие RunWorkerCompleted. Остановка выполнения потока
        • 8.3.1. Обработчик события RunWorkerCompleted элемента управления backgroundWorker1
        • 8.3.2. Обработчик события RunWorkerCompleted элемента управления backgroundWorker2. Завершение потока сортировки пузырьком
        • 8.3.3. Обработчик события RunWorkerCompleted элемента управления backgroundWorker3. Завершение потока выполнения при сортировке вставками
        • 8.3.4. Обработчик события RunWorkerCompleted элемента управления backgroundWorker4. Завершение потока сортировки выбором
    • 9. Запуск программы. Тестирование
  • Связанные темы

Поиск на других ресурсах:

Условие задачи

Разработать приложение типа Windows Forms Application. В приложении реализовать следующие операции:

  • генерирование массива случайных чисел указанной размерности;
  • сортировку сгенерированного массива тремя алгоритмами: вставки, пузырьком, выбором;
  • визуализацию процесса сортировки каждым алгоритмом;
  • вывод информации о продолжительности сортировки каждым алгоритмом с целью сравнения.

Генерирование массива и его сортировку реализовать в различных потоках. Для представления отдельного потока использовать возможности класса (элемента управления) BackgroundWorker.

 

Решение

1. Запустить MS Visual Studio. Сохранить проект

Создание приложения типа Windows Forms осуществляется стандартным способом. Процесс создания нового проекта и его сохранение подробно описывается здесь.

После создания система автоматически сгенерирует новую форму с именем Form1 (рисунок 1).

C#. Windows Forms. Создание приложения с использованием потоков

Рисунок 1. Основная форма проекта

 

2. Размещение элементов управления на форме

На этом этапе нужно разместить следующие элементы управления на форме (рисунок 2):

  • 7 элементов управления типа Label с именами label1, label2, label3, label4, label5, label6, label7;
  • 4 элемента управления типа Button с именами button1, button2, button3;
  • 3 элемента управления типа ListBox, которые имеют имена lisbBox1, listBox2, listBox3;
  • 3 элемента управления типа ProgressBar, которые имеют имена progressBar1, progressBar2, progressBar3;
  • 4 элемента управления типа BackgroundWorker с именами backgroundWorker1, backgroundWorker2, backgroundWorker3, backgroundWorker4;
  • один элемент управления типа TextBox с именем textBox1.

C#. Windows Forms. Создание приложения сортировки в потоках разными алгоритмами

Рисунок 2. Форма программы после размещения элементов управления

 

3. Настройка визуальных элементов управления формы

После размещения элементов управления нужно настроить их свойства. В окне Properties настраиваются следующие свойства элементов управления:

  • в элементе управления label1 свойство Text = «Array size:» (далее label1.Text = «Array size: «);
  • button1.Text = «Generate array»;
  • button2.Text = «Sort»;
  • button3.Text = «Stop»;
  • label2.Text = «Bubble sorting»;
  • label3.Text = «Insertion sorting»;
  • label4.Text = «Selection sorting»;
  • label5.Text = «»;
  • label6.Text = «»;
  • label7.Text = «»;
  • Form1.Text = «Demo of BackgroundWorker class».

После настройки, форма будет выглядеть как показано на рисунке 3.

C#. Windows Form. Форма программы демонстрации работы потоковРисунок 3. Форма программы после настройки

 

4. Настройка невизуальных элементов управления типа BackgroundWorker

Элементы управления типа BackgroundWorker относятся к невизуальным элементам управления. Каждый элемент управления предназначен для реализации отдельного потока. Во всех четырех элементах управления нужно настроить свойства следующим образом:

  • свойство WorkerReportProgress = True. Это означает, что разрешено отражать прогресс изменения (прогресс выполненной работы) потока;
  • свойство WorkerSupportsCancellation = True. Это означает, что разрешено отменять (останавливать) выполнение потока.

 

5. Ввод внутренних переменных в класс формы

На этом этапе в класс формы нужно ввести дополнительные внутренние переменные. В нашем случае, вводятся следующие массивы:

  • массив array типа int[]. Этот массив является массивом-оригиналом. Если в процессе сортировки будет вызвана команда отмены выполнения потоков, то все остальные недосортованные массивы получат начальное значение из этого массива;
  • массив arrayBub типа int[]. Используется для представления данных при сортировке методом пузырька;
  • массив arrayIns типа int[] представляет данные для сортировки методом вставки;
  • массив arraySel типа int[] представляет данные для сортировки методом выбора;
  • дополнительные переменные tsBubble, tsIns, tsSel типа TimeSpan, которые экономят время начала сортировки соответствующим алгоритмом;
  • переменные fCancelBub, fCancelIns, fCancelSel. Эти переменные определяют, были ли вызвана команда отмены выполнения соответствующего потока (значение true).

После введенных данных сокращенный вид класса Form1 формы следующий.

public partial class Form1 : Form
{
  // Внутренние переменные
  int[] array; // массив-оригинал
  int[] arrayBub; // массив данных после сортировки пузырьком
  int[] arrayIns; // массив после сортировкой вставкой
  int[] arraySel; // массив после сортировки выбором

  // Переменные, фиксирующие время начала выполнения алгоритмов
  TimeSpan tsBubble; // алгоритм пузырька
  TimeSpan tsIns;   // вставка
  TimeSpan tsSel;   // выбор

  bool fCancelBub; // Если true, то была нажата кнопка Stop - остановить все потоки
  bool fCancelIns;
  bool fCancelSel;

  ...

}

 

6. Дополнительные внутренние методы
6.1. Метод DisplayArray(). Отображение массива в ListBox

Исходное состояние сортируемого массива отражается в следующих элементах управления:

  • listBox1 — сортировка методом пузырька;
  • listBox2 — сортировка вставкой;
  • listBox3 — сортировка выбором.

Поскольку операция отображения массива одинакова для любого массива, то в класс формы целесообразно ввести метод, который отображает массив

public partial class Form1 : Form
{
  ...

  // Внутренний метод, который отображает массив в элементе управления типа ListBox
  private void DisplayArray(int[] A, ListBox LB)
  {
    LB.Items.Clear();
    for (int i = 0; i < A.Length; i++)
      LB.Items.Add(A[i]);
  }

  ...

}

 

6.2. Метод Active(). Активация/деактивация элементов управления

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

В нашем случае, активность/неактивность элементов управления устанавливается в методе Active() класса Form1. Используются элементы управления, которые предназначены для реализации и визуализации процесса сортировки.

public partial class Form1 : Form
{
  ...

  // Внутренний метод активации элементов управления
  private void Active(bool active)
  {
    // Сделать активными/неактивными некоторые элементы управления
    label2.Enabled = active;
    label3.Enabled = active;
    label4.Enabled = active;
    label5.Enabled = active;
    label6.Enabled = active;
    label7.Enabled = active;
    listBox1.Enabled = active;
    listBox2.Enabled = active;
    listBox3.Enabled = active;
    progressBar1.Enabled = active;
    progressBar2.Enabled = active;
    progressBar3.Enabled = active;
    button2.Enabled = active;
    button3.Enabled = active;
  }

  ...

}

 

7. Программирование обработчиков событий визуальных элементов управления
7.1. Загрузка формы. Конструктор формы Form1

В конструктор формы целесообразно поместить код начальной инициализации элементов управления и некоторых внутренних переменных. В нашем случае текст конструктора следующий

...

public Form1()
{
  InitializeComponent();

  // Очистить поле textBox1
  textBox1.Text = "";

  // Очистить ListBox
  listBox1.Items.Clear();
  listBox2.Items.Clear();
  listBox3.Items.Clear();

  // Очистить ProgressBar
  progressBar1.Value = 0;
  progressBar2.Value = 0;
  progressBar3.Value = 0;

  // Деактивировать некоторые элементы управления
  Active(false);

  // Настроить внутренние переменные
  fCancelBub = false;
  fCancelIns = false;
  fCancelSel = false;
}

...

 

7.2. Обработчик события Click кнопки button1. Команда Generate array

Для выполнения потока генерирования массива, в программе используется элемент управления backgroundWorker1. Запуск потока происходит вызовом метода RunWorkerAsync(). Чтобы избежать повторного запуска потока, который еще не закончился, используется свойство backgroundWorker1.isBusy, определяющее, выполняется ли поток на данный момент.

// Кнопка "Generate array"
private void button1_Click(object sender, EventArgs e)
{
  // Деактивировать некоторые элементы управления
  Active(false);

  // Настроить метки
  label5.Text = "";
  label6.Text = "";
  label7.Text = "";

  // Запустить генерирование массива в потоке
  if (!backgroundWorker1.IsBusy)
    backgroundWorker1.RunWorkerAsync(); // сгенерировать событие DoWork
}

 

7.3. Обработчик события Click кнопки button2. Команда Sort

При нажатии на кнопку Sort (button2) осуществляется сортировка тремя алгоритмами. Каждый алгоритм выполняется в отдельном потоке выполнения (backgroundWorker2, backgroundWorker3, backgroundWorker4).

// Кнопка "Sort" - запустить потоки на выполнение
private void button2_Click(object sender, EventArgs e)
{
  // Деактивировать кнопку генерирования массива
  button1.Enabled = false;

  // Запуск методов сортировки в потоках
  if (!backgroundWorker2.IsBusy)
    backgroundWorker2.RunWorkerAsync();

  if (!backgroundWorker3.IsBusy)
    backgroundWorker3.RunWorkerAsync();

  if (!backgroundWorker4.IsBusy)
    backgroundWorker4.RunWorkerAsync();
}

 

7.4. Обработчик события Click кнопки button3. Команда Stop

В программе существует возможность остановить процесс сортировки в потоках с помощью кнопки Stop (button3). Для программной отмены потока выполнения служит метод CancelAsync(). Этот метод имеет смысл, если свойство WorkerSupportsCancellation = true (смотрите пункт 4).

// Кнопка Stop - отменить выполнение всех потоков
private void button3_Click(object sender, EventArgs e)
{
  try
  {
    backgroundWorker2.CancelAsync(); // остановить сортировку пузырьком
    backgroundWorker3.CancelAsync(); // остановить сортировку вставками
    backgroundWorker4.CancelAsync(); // остановить сортировку выбором
  }
  catch (InvalidOperationException ex)
  {
    MessageBox.Show(ex.Message);
  }
}

 

8. Программирование обработчиков событий элементов управления типа BackgroundWorker
8.1. Событие DoWork выполнения потока

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

8.1.1. Обработчик события DoWork элемента управления backgroundWorker1. Генерирование массива

Обработчик события DoWork элемента управления backgroundWorker1 реализует выполнение потока, в котором генерируется массив случайных чисел типа int. Для вызова обработчика события DoWork нужно выполнить следующие шаги:

  • активировать элемент управления backgroundWorker1;
  • в окне Properties перейти во вкладку Events (события);
  • в перечне событий сделать двойной клик в поле события DoWork.

Более подробно о программировании события в Microsoft Visual Studio можно прочитать здесь.

Для нашего случая, текст метода обработки события DoWork, следующий

// Выполнение потока, в котором генерируется массив чисел
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
  // 1. Объявление внутренних переменных
  Random rnd = new Random();

  // 2. Получить количество элементов в массиве
  int n = Convert.ToInt32(textBox1.Text);

  // 3. Выделить память для массивов и заполнить их значениями
  array = new int[n];
  arrayBub = new int[n];
  arrayIns = new int[n];
  arraySel = new int[n];

  for (int i = 0; i < n; i++)
  {
    Thread.Sleep(1);
    array[i] = rnd.Next(1, n + 1); // случайное число
    arrayBub[i] = arraySel[i] = arrayIns[i] = array[i]; // скопировать это число

    // Вызвать отображение прогресса (изменения) выполнения потока
    try
    {
      backgroundWorker1.ReportProgress((i * 100) / n);
    }
    catch (InvalidOperationException ex)
    {
      MessageBox.Show(ex.Message);
      return;
    }
  }
}

 

8.1.2. Обработчик события DoWork элемента управления backgroundWorker2. Сортировка методом пузырька

Сортировка методом пузырька запускается в обработчике события DoWork элемента управления backgroundWorker2. По образцу предыдущего пункта нужно сформировать код обработчика события DoWork.

// Сортировка методом пузырька - поток
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
{
  // Сортируется массив arrayBub
  int x;

  // Инициализировать время
  tsBubble = new TimeSpan(DateTime.Now.Ticks);

  for (int i = 0; i < arrayBub.Length; i++)
  {
    Thread.Sleep(1); // дать возможность другим потокам выполняться параллельно

    for (int j = arrayBub.Length - 1; j > i; j--)
    {
      if (arrayBub[j - 1] > arrayBub[j]) // сортировка по возрастанию
      {
        x = arrayBub[j];
        arrayBub[j] = arrayBub[j - 1];
        arrayBub[j - 1] = x;
      }
    }

    // Отобразить изменение прогресса
    try
    {
      backgroundWorker2.ReportProgress((i * 100) / arrayBub.Length);
    }
    catch(InvalidOperationException ex)
    {
      MessageBox.Show(ex.Message);
      return;
    }

    // Проверка, был ли остановлен поток
    if (backgroundWorker2.CancellationPending)
    {
      fCancelBub = true;
      break;
    }
  }
}

 

8.1.3. Обработчик события DoWork элемента управления backgroundWorker3. Сортировка вставками

Сортировка методом вставок реализуется в методе обработки события DoWork элемента управления backgroundWorker3.

// Сортировка вставками
private void backgroundWorker3_DoWork(object sender, DoWorkEventArgs e)
{
  // 1. Объявить внутренние переменные
  int x, i, j;

  // Инициализировать время
  tsIns = new TimeSpan(DateTime.Now.Ticks);

  // 2. Цикл сортировки
  for (i = 0; i < arrayIns.Length; i++)
  {
    // дать возможность другим потокам выполняться параллельно
    Thread.Sleep(1);

    x = arrayIns[i];

    // Поиск места элемента в последовательности
    for (j = i - 1; j >= 0 && arrayIns[j] > x; j--)
      arrayIns[j + 1] = arrayIns[j]; // сдвинуть элемент вправо
    arrayIns[j + 1] = x;

    // Отобразить изменение прогресса
    try
    {
      backgroundWorker3.ReportProgress((i * 100) / arrayIns.Length);
    }
    catch (InvalidOperationException ex)
    {
      MessageBox.Show(ex.Message);
      return;
    }

    // Проверка, был ли остановлен поток
    if (backgroundWorker3.CancellationPending)
    {
      fCancelIns = true;
      break;
    }
  }
}

 

8.1.4. Обработчик события DoWork элемента управления backgroundWorker4. Сортировка выбором

Сортировка выбором выполняется в потоке, которому соответствует обработчик события DoWork элемента управления backgroundWorker4.

// Сортировка выбором
private void backgroundWorker4_DoWork(object sender, DoWorkEventArgs e)
{
  // 1. Объявить переменные
  int i, j, k;
  int x;

  // 2. Установить начальное время
  tsSel = new TimeSpan(DateTime.Now.Ticks);

  // 3. Цикл сортировки выбором
  for (i = 0; i < arraySel.Length; i++)
  {
    // дать возможность другим потокам выполняться параллельно
    Thread.Sleep(1);

    k = i;

    // поиск наименьшего элемента
    x = arraySel[i];

    for (j = i + 1; j < arraySel.Length; j++)
      if (arraySel[j] < x)
      {
        k = j; // k - индекс наименьшего элемента
        x = arraySel[j];
      }

    // поменять местами наименьший элемент с arraySel[i]
    arraySel[k] = arraySel[i];
    arraySel[i] = x;

    // Отобразить изменение прогресса
    try
    {
      backgroundWorker4.ReportProgress((i * 100) / arraySel.Length);
    }
    catch (InvalidOperationException ex)
    {
      MessageBox.Show(ex.Message);
      return;
    }

    // Проверка, был ли остановлен поток
    if (backgroundWorker4.CancellationPending)
    {
      fCancelSel = true;
      break;
    }
  }
}

 

8.2. Событие ProgressChanged. Изменение прогресса выполнения потока

В обработчике события ProgressChanged вставляется код, который должен отражать прогресс проделанной на данный момент работы. В нашем случае прогресс проделанной работы отображается в элементах управления типа ProgressBar. Процент выполненной работы отображается в элементах управления типа Label.

 

8.2.1. Обработчик события ProgressChanged элемента управления backgroundWorker1. Отображение прогресса генерирования массива

Более подробно о программировании события в Microsoft Visual Studio описывается здесь. В нашем случае, текст обработчика события ProgressChanged элемента управления backgroundWorker1 имеет вид:

// Изменение (прогресс) выполненной работы в потоке генерирования массива
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
  // Отобразить изменение в тексте кнопки "Generate array"
  button1.Text = "Generate array " + e.ProgressPercentage.ToString() + "%";
}

 

8.2.2. Обработчик события ProgressChanged элемента управления backgroundWorker2. Отображение прогресса при сортировке пузырьком

По образцу предыдущего обработчика формируется прогресс и для backgroundWorker2. Этот прогресс отражает выполненную часть сортировки пузырьком.

// Изменение прогресса в методе сортировки пузырьком
private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
  label5.Text = Convert.ToString(e.ProgressPercentage) + " %";
  progressBar1.Value = e.ProgressPercentage;
}

 

8.2.3. Обработчик события ProgressChanged элемента управления backgroundWorker3. Отображение прогресса при сортировке вставками

Для метода сортировки вставками обработчик события ProgresChanged имеет вид

// Прогресс для метода сортировки вставками
private void backgroundWorker3_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
  label6.Text = Convert.ToString(e.ProgressPercentage) + " %";
  progressBar2.Value = e.ProgressPercentage;
}

 

8.2.4. Обработчик события ProgressChanged элемента управления backgroundWorker3. Отображение прогресса в методе сортировки выбором

Для сортировки выбором обработчик события ProgressChanged следующий

// Изменение прогресса для алгоритма сортировки выбором
private void backgroundWorker4_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
  label7.Text = Convert.ToString(e.ProgressPercentage) + " %";
  progressBar3.Value = e.ProgressPercentage;
}

 

8.3. Событие RunWorkerCompleted. Остановка выполнения потока

Событие RunWorkerCompleted элемента управления BackgroundWorker вызывается после завершения выполнения потока. В этом событии целесообразно вписывать код завершающих операций, которые должны быть выполнены после завершения потока.

8.3.1. Обработчик события RunWorkerCompleted элемента управления backgroundWorker1
// Действия после завершения потока, генерирующего массив чисел
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  // После того, как массив сгенерирован, сделать соответствующие настройки
  button1.Text = "Generate array";

  // Сделать активными видимые элементы управления
  Active(true);

  // Отобразить массив-оригинал в элементах управления типа ListBox
  DisplayArray(array, listBox1);
  DisplayArray(array, listBox2);
  DisplayArray(array, listBox3);
}

 

8.3.2. Обработчик события RunWorkerCompleted элемента управления backgroundWorker2. Завершение потока сортировки пузырьком
// Завершение сортировки методом пузырька - выполнить конечные операции
private void backgroundWorker2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  // Если была отмена сортировки
  if (fCancelBub)
  {
    // Настроить соответственно элементы управления
    label5.Text = "";

    // Отобразить массив-оригинал
    DisplayArray(array, listBox1);

    fCancelBub = false;
  }
  else
  {
    // Зафиксировать время и вывести его
    TimeSpan time = new TimeSpan(DateTime.Now.Ticks) - tsBubble;
    label5.Text = String.Format("{0}.{1}.{2}.{3}", time.Hours, time.Minutes,
    time.Seconds, time.Milliseconds);

    // Отобразить отсортированный массив
    DisplayArray(arrayBub, listBox1);
  }

  // Настроить другие элементы управления
  progressBar1.Value = 0;
  button1.Enabled = true;
}

 

8.3.3. Обработчик события RunWorkerCompleted элемента управления backgroundWorker3. Завершение потока выполнения при сортировке вставками
// Завершение потока сортировки вставками
private void backgroundWorker3_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  // Если была отмена сортировки
  if (fCancelIns)
  {
    // Настроить соответственно элементы управления
    label6.Text = "";

    // Отобразить массив-оригинал
    DisplayArray(array, listBox2);

    fCancelIns = false;
  }
  else
  {
    // Зафиксировать время и вывести его
    TimeSpan time = new TimeSpan(DateTime.Now.Ticks) - tsIns;
    label6.Text = String.Format("{0}.{1}.{2}.{3}", time.Hours, time.Minutes,
    time.Seconds, time.Milliseconds);

    // Отобразить отсортированный массив
    DisplayArray(arrayIns, listBox2);
  }

  // Настроить другие элементы управления
  progressBar2.Value = 0;
  button1.Enabled = true;
}

 

8.3.4. Обработчик события RunWorkerCompleted элемента управления backgroundWorker4. Завершение потока сортировки выбором
// Завершение сортировки выбором
private void backgroundWorker4_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  // Если была отмена сортировки
  if (fCancelSel)
  {
    // Настроить соответственно элементы управления
    label7.Text = "";

    // Отобразить массив-оригинал
    DisplayArray(array, listBox3);

    fCancelSel = false;
  }
  else
  {
    // Зафиксировать время и вывести его
    TimeSpan time = new TimeSpan(DateTime.Now.Ticks) - tsSel;
    label7.Text = String.Format("{0}.{1}.{2}.{3}", time.Hours, time.Minutes,
      time.Seconds, time.Milliseconds);

    // Отобразить отсортированный массив
    DisplayArray(arraySel, listBox3);
  }

  // Настроить другие элементы управления
  progressBar3.Value = 0;
  button1.Enabled = true;
}

 

9. Запуск программы. Тестирование

C#. Windows Forms. BackgroundWorker. Программа сортировки массива в разных потоках

Рисунок 4. Процесс сортировки. Параллельное выполнение потоков

 


Связанные темы

  • Элемент управления BackgroundWorker. Работа с потоками (фоновыми операциями). Обзор методов, свойств, событий
  • Отображение прогресса выполненных работ. Отмена потока выполнения

 


Vlad891

0 / 0 / 0

Регистрация: 04.10.2014

Сообщений: 11

1

Сортировка массива на форме

13.02.2016, 22:54. Показов 4722. Ответов 5

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Ребят помогите , не могу понять как сделать сортировку одномерного массива на форме….
Составить программу расположения элементов массива в следующем порядке – положительные, отрицательные и нулевые
Сам массив есть , не могу допереть как сортировку сделать …

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void button1_Click(object sender, EventArgs e)
        {
            Random rdm = new Random();
            int[] mass = new int[15];
            int pol, otr, nul;
            string str = "";
            for (int i = 0; i < mass.Length; i++)
            {
                mass[i] = rdm.Next(-3, 9);
                str += String.Format("{0} ", mass[i].ToString());
            }
 
 
 
                listBox1.Items.Add("Массив: " + str);
                listBox1.Items.Add("Отсортированный массив: ");
        }

Объясните или помогите. Спасибо.



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

13.02.2016, 22:54

Ответы с готовыми решениями:

Сортировка в форме
Подскажите, пожалуйста, в ленточной форме можно как-то сделать так, чтобы данные были отсортированы…

Сортировка в форме
Не знаю с какого края подойти.
Есть таблица, и форма для отображения и работы с данными(Картинку…

Сортировка записей в форме
Друзья, простите за наверняка надоедливый вопрос, но своими неопытными руками перепробовал все…

Сортировка ТЧ в печатной форме
Добрый день!
Такая проблема, ни как не идет сортировка в печатной форме по значению Номенклатура….

5

Ankoo

2 / 2 / 3

Регистрация: 20.03.2015

Сообщений: 112

13.02.2016, 23:23

2

Лучший ответ Сообщение было отмечено Vlad891 как решение

Решение

Я бы создала 3 массива(полож эл, отриц эл и нулевые). И перебрала бы исходный массив, рассортировав значения по новым массивам. А потом вывела бы в нужном порядке 3 новых массива.

C#
1
2
3
if (mass[i] > 0) pol[i] = mass[i];
                if (mass[i] < 0) otr[i] = mass[i];
                if (mass[i] == 0) nul[i] = mass[i];



1



0 / 0 / 0

Регистрация: 04.10.2014

Сообщений: 11

14.02.2016, 13:45

 [ТС]

3

Не знаю с чем это связано но мне выдаёт ошибку для pol[i], otr[i], nul[i] — Cannot apply indexing with [] to an expression of type ‘int’ .



0



bodynar

340 / 302 / 135

Регистрация: 14.03.2015

Сообщений: 1,120

Записей в блоге: 1

14.02.2016, 14:04

4

Цитата
Сообщение от Vlad891
Посмотреть сообщение

C#
1
2
int[] mass = new int[15];
int pol, otr, nul;

одно у вас массив, другое — не массив. К немассиву с помощью индексатора пытаетесь обратиться вы.
Сделайте pol, otr, nul массивами.



1



Даценд

Эксперт .NET

5868 / 4745 / 2940

Регистрация: 20.04.2015

Сообщений: 8,361

14.02.2016, 15:35

5

Лучший ответ Сообщение было отмечено Vlad891 как решение

Решение

Цитата
Сообщение от bodynar
Посмотреть сообщение

К немассиву с помощью индексатора пытаетесь обратиться вы.

К темной стороне силы путь это.
Еще вариант:

C#
1
2
3
4
5
6
7
8
9
10
Random rdm = new Random();
int[] mass = new int[15];
int[] sortedMass = new int[15];
for (int i = 0; i < mass.Length; i++)
{
    mass[i] = rdm.Next(-3, 9);
}
sortedMass = (mass.Where(x => x > 0).Concat(mass.Where(x => x < 0))).Concat(mass.Where(x => x == 0)).ToArray();
listBox1.DataSource = mass;
listBox2.DataSource = sortedMass;



1



0 / 0 / 0

Регистрация: 04.10.2014

Сообщений: 11

14.02.2016, 15:42

 [ТС]

6

Все большое спасибо. Я разобрался



0



I want to get an bunch of items from a list box, add them to an array, sort it, then put it back into a different listbox. Here is what I have came up with:

ArrayList q = new ArrayList();
        foreach (object o in listBox4.Items)
            q.Add(o);
        q.Sort();
        listBox5.Items.Add(q.ToString());

But it doesnt work. Any ideas?

asked Sep 8, 2010 at 11:13

Codie Vincent's user avatar

1

You could just use the ListBox.Sorted built in functionality

  foreach (object o in listBox4.Items)
  {
    listBox5.Items.Add(o);
  }
  listBox5.Sorted = true;

Setting ListBox5.Sorted=true will ensure that the items in the listbox are sorted and any subsequent items added to the listbox will be added in the correct order.

Of course this assumes that you have simple sort requirements as suggested by your example.

answered Sep 8, 2010 at 11:27

Chris Taylor's user avatar

Chris TaylorChris Taylor

52.7k10 gold badges78 silver badges89 bronze badges

ArrayList q = new ArrayList(); 
foreach (object o in listBox4.Items) 
        q.Add(o);
} 
q.Sort(); 
listBox5.Items.Clear();
foreach(object o in q){
    listBox5.Items.Add(o); 
}

answered Sep 8, 2010 at 11:15

HCL's user avatar

HCLHCL

36.1k27 gold badges163 silver badges214 bronze badges

2

Try this:

var list = lstBox.Items.Cast<ListItem>().OrderBy(item => item.Text).ToList();
lstBox.Items.Clear();
foreach (ListItem listItem in list)
{
    lstBox.Items.Add(listItem);
}

If you need it to sort by the Values, just switch out item.Text with item.Value.

Enjoy!

answered Jun 6, 2012 at 20:49

Trey Gramann's user avatar

Trey GramannTrey Gramann

2,00420 silver badges23 bronze badges

Try the following without adding elements to any array

Listbox5.Items.AddRange(Listbox4.Items);
Listbox5.Sorted=true;

answered Mar 13, 2020 at 15:53

Herbert's user avatar

Add the items to array and close the loop. Then sort the array values and bind it to listbox

answered Sep 8, 2010 at 11:16

Bala's user avatar

BalaBala

1,3861 gold badge14 silver badges27 bronze badges

Try AddRange

    ArrayList q = new ArrayList();

    foreach (object o in listBox4.Items)
        q.Add(o);
    q.Sort();

    listBox5.Items.AddRange(q.ToArray());

answered Sep 8, 2010 at 11:21

Branimir's user avatar

BranimirBranimir

4,3371 gold badge21 silver badges33 bronze badges

If you are using .Net3.5 use linq to finish this task.Here i used list to convert and sorted

        var list = ListBox1.Items.Cast<ListItem>().Select(item => item.Value).ToList();
        list.Sort();

        ListBox2.DataSource =list;
        ListBox2.DataBind();

answered Sep 8, 2010 at 11:31

anishMarokey's user avatar

anishMarokeyanishMarokey

11.3k2 gold badges34 silver badges47 bronze badges

    private void SortListBox(ListBox listBox)
    {
        SortedList<string, string> list = new SortedList<string, string>(); 
        foreach (ListItem i in listBox.Items) {
                list.Add(i.Text, i.Value);
        } 
        listBox.Items.Clear();
        foreach(KeyValuePair<string, string> i in list){
            listBox.Items.Add(new ListItem(i.Key, i.Value)); 
        }
    }

answered Apr 11, 2013 at 23:20

ErikRasmussen's user avatar

also you can use «extension methods» that i wrote:

public static class ExtensionMethods
{
    public static void Sort(this ListControl lb, bool desc = false)
    {
        var list = lb.Items.Cast<ListItem>().ToArray();
        list = desc
                    ? list.OrderByDescending(x => x.Text).ToArray()
                    : list.OrderBy(x => x.Text).ToArray();
        lb.Items.Clear();
        lb.Items.AddRange(list);
    }
    public static void SortByValue(this ListControl lb, bool desc = false)
    {
        var list = lb.Items.Cast<ListItem>().ToArray();
        list = desc
                    ? list.OrderByDescending(x => x.Value).ToArray()
                    : list.OrderBy(x => x.Value).ToArray();
        lb.Items.Clear();
        lb.Items.AddRange(list);
    }
    public static void SortByText(this ListControl lb, bool desc = false)
    {
        lb.Sort(desc);
    }
    public static void SortRandom(this ListControl lb)
    {
        var list = lb.Items.Cast<ListItem>()
                            .OrderBy(x => Guid.NewGuid().ToString())
                            .ToArray();
        lb.Items.Clear();
        lb.Items.AddRange(list);
    }
}

answered May 31, 2015 at 21:57

Devrim Altınkurt's user avatar

Devrim AltınkurtDevrim Altınkurt

2,8871 gold badge10 silver badges7 bronze badges

Sort Listbox Desc

void sort()
    {
        if (listBox1.Items.Count <= 1)
            return;
        for (int j = 0; j < listBox1.Items.Count - 1; j++)
        {
            for (int i = 0; i < listBox1.Items.Count - 1; i++)
            {
                listBox1.SetSelected(i, true);
                string a = listBox1.SelectedItem.ToString();
                listBox1.SetSelected(++i, true);
                i--;
                string b = listBox1.SelectedItem.ToString();
                if (b.CompareTo(a) == 1)
                {
                    listBox1.Items.RemoveAt(i);
                    listBox1.Items.Insert(i, b);
                    i++;
                    listBox1.Items.RemoveAt(i);
                    listBox1.Items.Insert(i, a);
                    i--;
                }
            }
        }
    }

help-info.de's user avatar

help-info.de

6,73516 gold badges39 silver badges41 bronze badges

answered Jun 18, 2016 at 9:01

Moein Atari's user avatar

protected void Sort(ListBox lbox)
    {
        try
        {
            List<KeyValuePair<string, string>> ListBoxList = new 
            List<KeyValuePair<string, string>>();
            foreach (ListItem li in lbox.Items)
            {
                ListBoxList.Add(new KeyValuePair<string, string>(li.Value, li.Text));
            }
            if (ListBoxList.Count > 0)
            {
                ListBoxList = ListBoxList.OrderBy(x => x.Value).ToList();
                lbox.DataTextField = "Value";
                lbox.DataValueField = "Key";
                lbox.DataSource = ListBoxList;
                lbox.DataBind();
            }
        }
        catch (Exception error)
        {
            error.WriteEvent();
            throw;
        }
    }

answered Oct 2, 2017 at 18:28

Stewart's user avatar

For ASP.NET Listbox:

    private void SortListBox(ListBox oListBox)
    {
        ListBox oSortedListBox = new ListBox();
        oSortedListBox.DataSource = oListBox.Items.Cast<ListItem>().ToDictionary(i => i.Value, i => i.Text).OrderBy(i => i.Value);
        oSortedListBox.DataValueField = "Key";
        oSortedListBox.DataTextField = "Value";
        oSortedListBox.DataBind();

        oListBox.Items.Clear();

        foreach (ListItem oListItem in oSortedListBox.Items)
        {
            oListBox.Items.Add(oListItem);
        }
    }

answered Mar 11, 2019 at 14:03

Msxmania's user avatar

MsxmaniaMsxmania

532 silver badges9 bronze badges

Последнее обновление: 06.01.2022

Все массивы в C# построены на основе класса Array из пространства имен System. Этот класс определяет ряд свойств и
методов, которые мы можем использовать при работе с массивами. Основные свойства и методы:

  • Свойство Length возвращает длину массива

  • Свойство Rank возвращает размерность массива

  • int BinarySearch (Array array, object? value) выполняет бинарный поиск в отсортированном массиве и возвращает индекс найденного элемента

  • void Clear (Array array) очищает массив, устанавливая для всех его элементов значение по умолчанию

  • void Copy (Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
    копирует из массива sourceArray начиная с индекс sourceIndex length элементов в массив destinationArray начиная с индекса destinationIndex

  • bool Exists<T> (T[] array, Predicate<T> match) проверяет, содержит ли массив array элементы, которые удовлеворяют условию делегата match

  • void Fill<T> (T[] array, T value) заполняет массив array значением value

  • T? Find<T> (T[] array, Predicate<T> match) находит первый элемент, который удовлеворяет определенному условию из делегата match. Если элемент не найден, то возвращается null

  • T? FindLast<T> (T[] array, Predicate<T> match) находит последний элемент, который удовлеворяет определенному условию из делегата match. Если элемент не найден, то возвращается null

  • int FindIndex<T> (T[] array, Predicate<T> match) возвращает индекс первого вхождения элемента, который удовлеворяет определенному условию делегата match

  • int FindLastIndex<T> (T[] array, Predicate<T> match) возвращает индекс последнего вхождения элемента, который удовлеворяет определенному условию

  • T[] FindAll<T> (T[] array, Predicate<T> match) возвращает все элементы в виде массива, которые удовлеворяет определенному условию из делегата match

  • int IndexOf (Array array, object? value) возвращает индекс первого вхождения элемента в массив

  • int LastIndexOf (Array array, object? value) возвращает индекс последнего вхождения элемента в массив

  • void Resize<T> (ref T[]? array, int newSize) изменяет размер одномерного массива

  • void Reverse (Array array) располагает элементы массива в обратном порядке

  • void Sort (Array array) сортирует элементы одномерного массива

Разберем самые используемые методы.

Поиск индекса элемента

var people = new string[] { "Tom", "Sam", "Bob", "Kate", "Tom", "Alice" };

// находим индекс элемента "Bob"
int bobIndex = Array.BinarySearch(people, "Bob");
// находим индекс первого элемента "Tom"
int tomFirstIndex = Array.IndexOf(people, "Tom");
// находим индекс последнего элемента "Tom"
int tomLastIndex = Array.LastIndexOf(people, "Tom");
// находим индекс первого элемента, у которого длина строки больше 3
int lengthFirstIndex = Array.FindIndex(people, person => person.Length > 3);
// находим индекс последнего элемента, у которого длина строки больше 3
int lengthLastIndex = Array.FindLastIndex(people, person => person.Length > 3);

Console.WriteLine($"bobIndex: {bobIndex}");					// 2
Console.WriteLine($"tomFirstIndex: {tomFirstIndex}");		// 0
Console.WriteLine($"tomLastIndex: {tomLastIndex}");			// 4
Console.WriteLine($"lengthFirstIndex: {lengthFirstIndex}");	// 3
Console.WriteLine($"lengthLastIndex: {lengthLastIndex}");	// 5

Если элемент не найден в массиве, то методы возвращают -1.

Поиск элемента по условию

var people = new string[] { "Tom", "Sam", "Bob", "Kate", "Tom", "Alice" };

// находим первый и последний элементы
// где длина строки больше 3 символов
string? first = Array.Find(people, person => person.Length > 3);
Console.WriteLine(first); // Kate
string? last = Array.FindLast(people, person => person.Length > 3);
Console.WriteLine(last); // Alice

// находим элементы, у которых длина строки равна 3
string[] group = Array.FindAll(people, person => person.Length == 3);
foreach (var person in group) Console.WriteLine(person);
// Tom Sam Bob Tom

Изменение порядка элементов массива

Например, изменим порядок элементов:

var people = new string[] { "Tom", "Sam", "Bob", "Kate", "Tom", "Alice" };

Array.Reverse(people);

foreach (var person in people) 
    Console.Write($"{person} ");
// "Alice", "Tom", "Kate", "Bob", "Sam", "Tom"

Также можно изменить порядок только части элементов:

var people = new string[] { "Tom", "Sam", "Bob", "Kate", "Tom", "Alice" };

// изменяем порядок 3 элементов начиная c индекса 1  
Array.Reverse(people, 1, 3);

foreach (var person in people) 
    Console.Write($"{person} ");
// "Tom", "Kate", "Bob", "Sam", "Tom", "Alice"

В данном случае изменяем порядок только 3 элементов начиная c индекса 1.

Изменение размера массива

Для изменения размера массива применяется метод Resize. Его первый параметр — изменяемый массив, а второй параметр — количество элементов, которые должны быть в массиве. Если второй параметр меньше длины массива,
то массив усекается. Если значение параметра, наоборот, больше, то массив дополняется дополнительными элементами, которые имеют значение по умолчанию.
Причем первый параметр передается по ссылке:

var people = new string[] { "Tom", "Sam", "Bob", "Kate", "Tom", "Alice" };

// уменьшим массив до 4 элементов
Array.Resize(ref people, 4);

foreach (var person in people) 
    Console.Write($"{person} ");
// "Tom", "Sam", "Bob", "Kate"

Копирование массива

Метод Copy копирует часть одного массива в другой:

var people = new string[] { "Tom", "Sam", "Bob", "Kate", "Tom", "Alice" };

var employees = new string[3];

// копируем 3 элемента из массива people c индекса 1  
// и вставляем их в массив employees начиная с индекса 0
Array.Copy(people,1, employees,0, 3);

foreach (var person in employees) 
    Console.Write($"{person} ");
// Sam Bob Kate

В данном случае копируем 3 элемента из массива people начиная c индекса 1 и вставляем их в массив employees начиная с индекса 0.

Сортировка массива

Отсортируем массив с помощью метода Sort():

var people = new string[] { "Tom", "Sam", "Bob", "Kate", "Tom", "Alice" };

Array.Sort(people);

foreach (var person in people) 
    Console.Write($"{person} ");
	
// Alice Bob Kate Sam Tom Tom

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

var people = new string[] { "Tom", "Sam", "Bob", "Kate", "Tom", "Alice" };

// сортируем с 1 индекса 3 элемента
Array.Sort(people, 1, 3);

foreach (var person in people) 
    Console.Write($"{person} ");
	
// Tom Bob Kate Sam Tom Alice

Naming

Methodnames in C# should be PascalCase
Some examples from your sources

private void init()
private void getStepAlgorithm(Algorithm selected)
private void generateRandomArrayElements()
private void uiInitializePaintArea()

As I read clock I thought, why is he showing a clock for a algorithm. I needed to check the declaration hidden inside the designer file to see it is a timer.
You should just name it timer.

private void getStepAlgorithm(Algorithm selected)
{
    this.stepAlgorithm = algos.GetAlgoImplementationFor(selected, this, ref arrayToSort);
}

Reading the methodname getStepAlgorithm let a reader assume that he is getting an algorithm but what the code does is assigning an algorithm to a class field. So a better name would be AssignAlgorithm

Decoupling

Communication between parent, here MainWindow, and child, here an inplementation of the IAlgoImplementation interface, should be by calling methods and setting of properties. From child to parent it should be done by events. The implementation of the IAlgoImplementation should know nothing of its parent. Also the factory should know nothing of the MainWindow.

 public void SwapIndexes(int i, int p, ref int[] arrayToSort)

This method of the MainWindow class is violating separations of concerns, because it is called from the BubbleSort implementation of the IAlgoImplementation interface.

Refactoring
First we should change the name of interface IAlgoImplementation to interface ISortAlgorithm to make the name more meaningful. The same we do to the void Step() method and rename it to void PerformSortStep(). We add a property to hold the array to be sorted and add events for performing a sortstep, swapping values and for finishing the sorting.

interface ISortAlgorithm
{
    int[] ArrayToSort { set; }

    void PerformSortStep();

    event EventHandler<SortStepPerformedEventArgs> SortStepPerformed;
    event EventHandler<SwapPerformedEventArgs> SwapPerformed;
    event EventHandler SortFinished;
}

public class SortStepPerformedEventArgs : EventArgs
{
    public int CurrentIndex { get; private set; }
    public PointOfStep StepPoint { get; private set; }
    public SortStepPerformedEventArgs(int currentIndex, PointOfStep stepPoint)
    {
        CurrentIndex = currentIndex;
        StepPoint = stepPoint;
    }
}

public enum PointOfStep
{
    BeforeStep, ReAssignedAssumeSorted, CurrentStep
}

public class SwapPerformedEventArgs : EventArgs
{
    public int FirstIndex { get; private set; }
    public int SecondIndex { get; private set; }
    public int FirstValue { get; private set; }
    public int SecondValue { get; private set; }
    public int LengthOfArrayToSort { get; set; }

    public SwapPerformedEventArgs(int firstIndex, int secondIndex, 
        int firstValue, int secondValue, 
        int lengthOfArrayToSort)
    {
        FirstIndex = firstIndex;
        SecondIndex = secondIndex;
        FirstValue = firstValue;
        SecondValue = secondValue;
        LengthOfArrayToSort = lengthOfArrayToSort;
    }

}

Now let us take a look at the BubbleSort class. As you didn’t implement the interface explicit, I added a private get to the ArrayToSort property.

public class BubbleSort : ISortAlgorithm
{
    private int current;
    private int assumeSortedFrom;
    private bool hasSwapped;

    private int[] arrayToSort = null;
    public int[] ArrayToSort
    {
        set {
            if (value == null)
            {
                throw new ArgumentNullException("ArrayToSort", "The array to be sorted can't be null");
            }
            arrayToSort = value;
            InitializeSorting();

        }
        private get { return arrayToSort; }
    }

    private void InitializeSorting()
    {
        current = 0;
        assumeSortedFrom = ArrayToSort.Length;
        hasSwapped = false;

    }

    public void PerformSortStep()
    {

        OnSortStepPerformed(current, PointOfStep.BeforeStep);

        if (current + 1 == assumeSortedFrom)
        {
            assumeSortedFrom = current;
            OnSortStepPerformed(current, PointOfStep.ReAssignedAssumeSorted);

            current = 0;
            OnSortStepPerformed(current, PointOfStep.CurrentStep);

            if (!hasSwapped)
            {
                OnSortFinished();
            }
            else
            {
                hasSwapped = false;
            }
        }
        else
        {
            if (ArrayToSort[current] > ArrayToSort[current + 1])
            {
                SwapIndexes(current, current + 1);
                hasSwapped = true;
            }

            current++;
            OnSortStepPerformed(current, PointOfStep.CurrentStep);
        }
    }

    private void SwapIndexes(int currentIndex, int nextIndex)
    {
        int temp;

        temp = arrayToSort[nextIndex];
        ArrayToSort[nextIndex] = ArrayToSort[currentIndex];
        ArrayToSort[currentIndex] = temp;

        SwapPerformedEventArgs e = new SwapPerformedEventArgs(currentIndex, nextIndex,
            ArrayToSort[currentIndex], ArrayToSort[nextIndex], 
            ArrayToSort.Length);

        OnSwapPerformed(e);

    }

    object objectLock = new Object();
    private EventHandler<SortStepPerformedEventArgs> sortStepPerformed;
    public event EventHandler<SortStepPerformedEventArgs> SortStepPerformed
    {
        add
        {
            lock (objectLock)
            {
                sortStepPerformed += value;
            }
        }
        remove
        {
            lock (objectLock)
            {
                sortStepPerformed -= value;
            }
        }
    }

    private void OnSortStepPerformed(int currentIndex, PointOfStep pointOfStep)
    {
        OnSortStepPerformed(new SortStepPerformedEventArgs(currentIndex, pointOfStep));
    }

    private void OnSortStepPerformed(SortStepPerformedEventArgs e)
    {
        lock (objectLock)
        {
            if (sortStepPerformed != null)
            {
                sortStepPerformed(this, e);
            }
        }
    }

    private EventHandler<SwapPerformedEventArgs> swapPerformed;
    public event EventHandler<SwapPerformedEventArgs> SwapPerformed
    {
        add
        {
            lock (objectLock)
            {
                swapPerformed += value;
            }
        }
        remove
        {
            lock (objectLock)
            {
                swapPerformed -= value;
            }
        }
    }

    private void OnSwapPerformed(SwapPerformedEventArgs e)
    {
        lock (objectLock)
        {
            if (swapPerformed != null)
            {
                swapPerformed(this, e);
            }
        }
    }

    private event EventHandler sortFinished;
    public event EventHandler SortFinished
    {
        add
        {
            lock (objectLock)
            {
                sortFinished += value;
            }
        }
        remove
        {
            lock (objectLock)
            {
                sortFinished -= value;
            }
        }
    }

    private void OnSortFinished()
    {
        lock (objectLock)
        {
            if (sortFinished != null)
            {
                sortFinished(this, new EventArgs());
            }
        }
    }
}  

No reference to any calling owner is needed anymore.

As the factory class also has been coupled with the MainWindow we need to decouple this also.

    public IAlgoImplementation GetAlgoImplementationFor(Algorithm algo, MainWindow owner, ref int[] array)
    {
        IAlgoImplementation impl;
        if (!mapping.TryGetValue(algo, out impl))
        {
            MainWindow.CreateAlert("Falling back to default algorithm!");
            owner.SelectAlgo(Algorithm.BUBBLESORT);
            if (!mapping.TryGetValue(Algorithm.BUBBLESORT, out impl))
            {
                throw new NotSupportedException();
            }
        }
        impl.Initialize(owner, ref array);
        return impl;
    }  

First we rename the class to SortAlgorithmFactory. Now we add a property IEnumerator ImplementedAlgorithms to return the algorithms which the factory can create.

class SortAlgorithmFactory
{

    private static SortAlgorithmFactory _instance;
    private Dictionary<Algorithm, ISortAlgorithm> mapping = new Dictionary<Algorithm, ISortAlgorithm>();

    public IEnumerator ImplementedAlgorithms
    {
        get { return mapping.Keys.GetEnumerator(); }
    }

    private SortAlgorithmFactory()
    {
        mapping.Add(Algorithm.BUBBLESORT, new BubbleSort());
        mapping.Add(Algorithm.COCKTAILSHAKER, new Cocktailshaker());
    }

    public static SortAlgorithmFactory Instance()
    {
        if (_instance == null)
            _instance = new SortAlgorithmFactory();

        return _instance;
    }

    public ISortAlgorithm GetAlgoImplementationFor(Algorithm algo, int[] array)
    {
        ISortAlgorithm sortAlgorithm = mapping[algo];
        sortAlgorithm.ArrayToSort = array;

        return sortAlgorithm;
    }
}  

Now there is no reference to the MainWindow anymore. Also by using the ImplementedAlgorithms property, we remove the possibility of an infinite loop for the case someone commented this mapping.Add(Algorithm.BUBBLESORT, new BubbleSort());.

Let us now move to the MainWindow.

private void generateRandomArrayElements()
{
    Random rnd = new Random();

    for (int i = 0; i < arrayToSort.Length; i++)
    {
        arrayToSort[i] = rnd.Next(1, arrayToSort.Length + 1);
    }

    selectAlgo(dropDownSortAlgorithms, null);
    uiInitializePaintArea();
    sw.Stop();
    sw.Reset();
}  

This method does a lot of things, not only generating random array elements, but also selecting an algorithm … so, let us refactor the method and the 3 usages of this method

    private Random rnd = new Random();
    private void GenerateRandomArrayElements()
    {
        for (int i = 0; i < arrayToSort.Length; i++)
        {
            arrayToSort[i] = rnd.Next(1, arrayToSort.Length + 1);
        }

        sw.Stop();
        sw.Reset();

    }

    private void ArrayLengthChange(object sender, EventArgs e)
    {
        NumericUpDown uiArrayItemCountUpDown = sender as NumericUpDown;
        if ((int)uiArrayItemCountUpDown.Value <= 0)
        {
            ShowAlert("Die Anzahl der Elemente kann nicht 0 oder weniger sein");
            uiArrayItemCountUpDown.Value = 1;
        }
        else
        {
            this.arrayToSort = new int[(int)uiArrayItemCountUpDown.Value];
            GenerateRandomArrayElements();
            AssignArrayToSortAlgorithm();
            uiInitializePaintArea();
        }
    }  

    private void triggerFill_Click(object sender, EventArgs e)
    {
        isSorting = false;
        GenerateRandomArrayElements();
        AssignArrayToSortAlgorithm();
        uiInitializePaintArea();
    }  

And last but not least the former init() method

    private void Initialize()
    {
        this.arrayToSort = new int[STANDARD_ARRAY_SIZE];

        IEnumerator algoEnumerator = algorithmFactory.ImplementedAlgorithms;
        while (algoEnumerator.MoveNext())
        {
            dropDownSortAlgorithms.Items.Add(algoEnumerator.Current);
        }

        dropDownSortAlgorithms.SelectedValueChanged += SelectAlgorithm;

        StepTimer.Start();
        sw = new Stopwatch();

        GenerateRandomArrayElements();

        SelectAlgorithm(Algorithm.BUBBLESORT);

        uiInitializePaintArea();

        isSorting = false;
    }

The complete MainWindow class (note I have also renamed clock to StepTimer)

public partial class MainWindow : Form
{
    private const int STANDARD_ARRAY_SIZE = 10;
    private static SortAlgorithmFactory algorithmFactory = SortAlgorithmFactory.Instance();
    private bool isSorting;
    private int[] arrayToSort;
    private ISortAlgorithm sortAlgorithm;

    private Stopwatch sw;

    public MainWindow()
    {
        InitializeComponent();
        Initialize();
    }

    private void Initialize()
    {
        this.arrayToSort = new int[STANDARD_ARRAY_SIZE];

        IEnumerator algoEnumerator = algorithmFactory.ImplementedAlgorithms;
        while (algoEnumerator.MoveNext())
        {
            dropDownSortAlgorithms.Items.Add(algoEnumerator.Current);
        }

        dropDownSortAlgorithms.SelectedValueChanged += SelectAlgorithm;

        StepTimer.Start();
        sw = new Stopwatch();

        GenerateRandomArrayElements();

        SelectAlgorithm(Algorithm.BUBBLESORT);

        uiInitializePaintArea();

        isSorting = false;
    }

    private void AssignStepAlgorithm(Algorithm selected)
    {
        RemoveSortAlgorithmEventHandler();

        this.sortAlgorithm = algorithmFactory.GetAlgoImplementationFor(selected, arrayToSort);

        AddSortAlgorithmEventHandler();
    }

    private void AssignArrayToSortAlgorithm()
    {
        sortAlgorithm.ArrayToSort = arrayToSort;
    }

    private void RemoveSortAlgorithmEventHandler()
    {
        if (this.sortAlgorithm == null) { return; }
        this.sortAlgorithm.SortFinished -= new EventHandler(StepAlgorithm_SortFinished);
        this.sortAlgorithm.SortStepPerformed -= new EventHandler<SortStepPerformedEventArgs>
            (StepAlgorithm_SortStepPerformed);
        this.sortAlgorithm.SwapPerformed -= new EventHandler<SwapPerformedEventArgs>(StepAlgorithm_SwapPerformed);
    }

    private void AddSortAlgorithmEventHandler()
    {
        this.sortAlgorithm.SortFinished += new EventHandler(StepAlgorithm_SortFinished);
        this.sortAlgorithm.SortStepPerformed += new EventHandler<SortStepPerformedEventArgs>
            (StepAlgorithm_SortStepPerformed);
        this.sortAlgorithm.SwapPerformed += new EventHandler<SwapPerformedEventArgs>(StepAlgorithm_SwapPerformed);
    }

    void StepAlgorithm_SwapPerformed(object sender, SwapPerformedEventArgs e)
    {

        int arrayLength = e.LengthOfArrayToSort;

        Control panelI = this.paintArea.Controls[e.FirstIndex];
        Control panelP = this.paintArea.Controls[e.SecondIndex];

        panelI.Height = (int)(paintArea.Height * e.FirstValue / arrayLength);
        panelP.Height = (int)(paintArea.Height * e.SecondValue / arrayLength);

        panelI.Top = paintArea.Height - panelI.Height;
        panelP.Top = paintArea.Height - panelP.Height;

    }

    void StepAlgorithm_SortStepPerformed(object sender, SortStepPerformedEventArgs e)
    {
        switch (e.StepPoint)
        {
            case PointOfStep.BeforeStep:
                uiRemovePivot(e.CurrentIndex);
                break;

            case PointOfStep.ReAssignedAssumeSorted:
                uiAssumeSorted(e.CurrentIndex);
                break;

            case PointOfStep.CurrentStep:
                uiDeclarePivot(e.CurrentIndex);
                break;
        }

    }

    void StepAlgorithm_SortFinished(object sender, EventArgs e)
    {
        triggerToggleSorting_Click(null, null);
        ShowAlert(String.Format("Alle Elemente sind sortiert\nDauer: {0}", sw.Elapsed));
    }

    private void SelectAlgorithm(Algorithm algorithm)
    {
        dropDownSortAlgorithms.SelectedItem = algorithm;
    }

    private void ShowAlert(string p)
    {
        MessageBox.Show(p);
    }

    private void ArrayLengthChange(object sender, EventArgs e)
    {
        NumericUpDown uiArrayItemCountUpDown = sender as NumericUpDown;
        if ((int)uiArrayItemCountUpDown.Value <= 0)
        {
            ShowAlert("Die Anzahl der Elemente kann nicht 0 oder weniger sein");
            uiArrayItemCountUpDown.Value = 1;
        }
        else
        {
            this.arrayToSort = new int[(int)uiArrayItemCountUpDown.Value];
            GenerateRandomArrayElements();
            AssignArrayToSortAlgorithm();
            uiInitializePaintArea();
        }
    }

    private Random rnd = new Random();
    private void GenerateRandomArrayElements()
    {
        for (int i = 0; i < arrayToSort.Length; i++)
        {
            arrayToSort[i] = rnd.Next(1, arrayToSort.Length + 1);
        }

        sw.Stop();
        sw.Reset();

    }

    #region event handlers

    private void SelectAlgorithm(object sender, EventArgs e)
    {
        ComboBox uiComboBox = sender as ComboBox;
        AssignStepAlgorithm((Algorithm)uiComboBox.SelectedItem);
    }

    private void StepTimer_Tick(object sender, EventArgs e)
    {
        if (isSorting)
        {
            sortAlgorithm.PerformSortStep();
        }
    }

    private void triggerToggleSorting_Click(object sender, EventArgs e)
    {
        isSorting = !isSorting;
        if (isSorting)
        {
            triggerToggleSorting.Text = "Pause";
            sw.Start();
        }
        else
        {
            triggerToggleSorting.Text = "Sortiere";
            sw.Stop();
        }
    }

    private void triggerExit_Click(object sender, EventArgs e)
    {
        Application.Exit();
    }

    private void triggerFill_Click(object sender, EventArgs e)
    {
        isSorting = false;
        GenerateRandomArrayElements();
        AssignArrayToSortAlgorithm();
        uiInitializePaintArea();
    }
    #endregion

    #region ui modification methods
    private void uiInitializePaintArea()
    {
        if (arrayToSort.Length + 1 != paintArea.Controls.Count)
        {
            uiCreateRepresentingPanels();
        }

        for (int i = 0; i < arrayToSort.Length; i++)
        {
            //Should be able to match paintArea.Items[i] with arrayToSort[i]
            Control rectangle = paintArea.Controls.Find(String.Format("_{0}", i), true).First();

            //We do not need to adjust the width, as it always stays the same.
            rectangle.Height = (int)(paintArea.Height * arrayToSort[i] / arrayToSort.Length);
            rectangle.Top = (paintArea.Height - rectangle.Height);
        }

        paintArea.Update();
        paintArea.PerformLayout();
    }

    private void uiCreateRepresentingPanels()
    {
        paintArea.Controls.Clear();

        // the width stays the same for all rectangles
        int width = (int)(paintArea.Width / arrayToSort.Length);

        if (width == 0)
            width = 1;

        for (int i = 0; i < arrayToSort.Length; i++)
        {
            Panel rectangle = new Panel();
            rectangle.Name = String.Format("_{0}", i);
            rectangle.Width = width;
            rectangle.Height = (int)(paintArea.Height * arrayToSort[i] / arrayToSort.Length);
            rectangle.Left = width * i;
            rectangle.Top = (paintArea.Height - rectangle.Height);

            rectangle.BackColor = Color.Green;

            paintArea.Controls.Add(rectangle);
        }
    }

    private void uiAssumeSorted(int index)
    {
        this.paintArea.Controls[index].BackColor = Color.Blue;
    }

    private void uiDeclarePivot(int index)
    {
        this.paintArea.Controls[index].BackColor = Color.Red;
    }

    private void uiRemovePivot(int index)
    {
        this.paintArea.Controls[index].BackColor = Color.Green;
    }
    #endregion
}

Using an abstract class can lead towards less code, if one want to implement the ISortAlgorithm explicit.

public abstract class SortAlgorithm : ISortAlgorithm
{
    protected int current;
    protected int assumeSortedFrom;
    protected bool hasSwapped;
    private int[] arrayToSort = null;
    protected int[] ArrayToSort { get { return arrayToSort; } }
    int[] ISortAlgorithm.ArrayToSort
    {
        set
        {
            if (value == null)
            {
                throw new ArgumentNullException("ArrayToSort", "The array to be sorted can't be null");
            }
            arrayToSort = value;
            InitializeSorting();

        }
    }
    private void InitializeSorting()
    {
        current = 0;
        assumeSortedFrom = ArrayToSort.Length;
        hasSwapped = false;

    }

    void ISortAlgorithm.PerformSortStep()
    {
        this.PerformSortStep();
    }

    protected abstract void PerformSortStep();
    protected abstract void SwapIndexes(int currentIndex, int nextIndex);

    object objectLock = new Object();
    private EventHandler<SortStepPerformedEventArgs> sortStepPerformed;
    event EventHandler<SortStepPerformedEventArgs> ISortAlgorithm.SortStepPerformed
    {
        add
        {
            lock (objectLock)
            {
                sortStepPerformed += value;
            }
        }
        remove
        {
            lock (objectLock)
            {
                sortStepPerformed -= value;
            }
        }
    }
    protected void OnSortStepPerformed(int currentIndex, PointOfStep pointOfStep)
    {
        OnSortStepPerformed(new SortStepPerformedEventArgs(currentIndex, pointOfStep));
    }
    protected void OnSortStepPerformed(SortStepPerformedEventArgs e)
    {
        lock (objectLock)
        {
            if (sortStepPerformed != null)
            {
                sortStepPerformed(this, e);
            }
        }
    }
    private EventHandler<SwapPerformedEventArgs> swapPerformed;
    event EventHandler<SwapPerformedEventArgs> ISortAlgorithm.SwapPerformed
    {
        add
        {
            lock (objectLock)
            {
                swapPerformed += value;
            }
        }
        remove
        {
            lock (objectLock)
            {
                swapPerformed -= value;
            }
        }
    }
    protected void OnSwapPerformed(SwapPerformedEventArgs e)
    {
        lock (objectLock)
        {
            if (swapPerformed != null)
            {
                swapPerformed(this, e);
            }
        }
    }
    private event EventHandler sortFinished;
    event EventHandler ISortAlgorithm.SortFinished
    {
        add
        {
            lock (objectLock)
            {
                sortFinished += value;
            }
        }
        remove
        {
            lock (objectLock)
            {
                sortFinished -= value;
            }
        }
    }
    protected void OnSortFinished()
    {
        lock (objectLock)
        {
            if (sortFinished != null)
            {
                sortFinished(this, new EventArgs());
            }
        }
    }
}  

public class BubbleSort:SortAlgorithm
{
    protected override void PerformSortStep()
    {
        OnSortStepPerformed(current, PointOfStep.BeforeStep);

        if (current + 1 == assumeSortedFrom)
        {
            assumeSortedFrom = current;
            OnSortStepPerformed(current, PointOfStep.ReAssignedAssumeSorted);

            current = 0;
            OnSortStepPerformed(current, PointOfStep.CurrentStep);

            if (!hasSwapped)
            {
                OnSortFinished();
            }
            else
            {
                hasSwapped = false;
            }
        }
        else
        {
            if (ArrayToSort[current] > ArrayToSort[current + 1])
            {
                SwapIndexes(current, current + 1);
                hasSwapped = true;
            }

            current++;
            OnSortStepPerformed(current, PointOfStep.CurrentStep);
        }
    }
    protected override void SwapIndexes(int currentIndex, int nextIndex)
    {
        int temp;

        temp = ArrayToSort[nextIndex];
        ArrayToSort[nextIndex] = ArrayToSort[currentIndex];
        ArrayToSort[currentIndex] = temp;

        SwapPerformedEventArgs e = new SwapPerformedEventArgs(currentIndex, nextIndex,
            ArrayToSort[currentIndex], ArrayToSort[nextIndex],
            ArrayToSort.Length);

        OnSwapPerformed(e);

    }
}

  • Windows forms работа с формами
  • Windows git клиент для windows
  • Windows ftp в пассивном режиме
  • Windows git with ssh key windows
  • Windows forms работа с таблицами