Модераторы: gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Copy-Paste для DataGridView(Virtual Mode), копирование в системный Clipboard 
V
    Опции темы
allknower
Дата 20.6.2008, 15:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 21.12.2006
Где: Краснодар

Репутация: нет
Всего: нет



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

Код

        private void copyClipMenuItem_Click(object sender, EventArgs e)
        {

            DataFormats.Format myFormat = DataFormats.GetFormat("SimpleData");
            DataObject myDataObject = new DataObject(myFormat.Name, grid.CurrentCell.Value);
            Clipboard.SetDataObject(myDataObject);
        }

        private void pasteClipMenuItem_Click(object sender, EventArgs e)
        {
            DataFormats.Format myFormat = DataFormats.GetFormat("SimpleData");
            string oldName = (grid.CurrentCell.Value as SimpleData).name;
            grid.CurrentCell.Value = Clipboard.GetDataObject().GetData(myFormat.Name);
            (grid.CurrentCell.Value as SimpleData).name = oldName;
        }


Теперь встала задача реализовать копирование любой выделенной области. То есть строк, столбцов, нескольких ячеяк нескольких строк:


+------+------+------+------+------+
|      |      |      |      |      |
+------+------+------+------+------+
|      |      |  S   |  S   |      |
+------+------+------+------+------+
|      |      |  S   |  S   |      |
+------+------+------+------+------+

S - выделенные ячейки


Я создал класс Range

Код

    [Serializable]
    public class Range
    {
        private SimpleData[,] _range;

        public SimpleData this[int rowIndex, int colIndex]
        {
            get
            {
                return (this._range[rowIndex, colIndex] as SimpleData);
            }

            set 
            {
                this._range[rowIndex, colIndex] = value;
            }
        }

        public Range(int rowCount, int colCount)
        {
            _range = new SimpleData[rowCount, colCount];
        }
    }


Идея такова: оборачиваем коллекцию DataGridView.SelectedCell в этот класс и толкаем в буфер.
При вставке - выталкиваем из буфера и втавляем в грид начиная с ячейки, над которой было вызвано меню. Все что не вошло усекаем.

Проблема в том что DataGridView.SelectedCell - есть ничто иное как ArrayList в котором списком хранятся выделенные ячейки. Как мне получить количество колонок и столбцов?? Свойства DataGridView.SelectedRow.Count и DataGridView.SelectedColumn.Count при неполном выборе (как на картинке) хранят нули. Хотя реально выбрано две строки и два столбца. Хотелось бы увидеть какой то SelectedRange (на подобие Delphi'йского. У StringGrid'a кажется таковой был.)
PM MAIL ICQ   Вверх
Idsa
Дата 21.6.2008, 02:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 2086
Регистрация: 5.12.2006
Где: Томск

Репутация: 15
Всего: 62



Цитата(allknower @  20.6.2008,  19:41 Найти цитируемый пост)
Свойства DataGridView.SelectedRow.Count и DataGridView.SelectedColumn.Count при неполном выборе (как на картинке) хранят нули. 

Ага, есть такое.
В MSDN'е объяснено такое поведение:
Цитата

The SelectionMode property must be set to FullColumnSelect or ColumnHeaderSelect for the SelectedColumns property to be populated with selected columns.

The SelectionMode property must be set to FullRowSelect or RowHeaderSelect for the SelectedRows property to be populated with selected rows.

Такое поведение вполне логично. Стоит представить, что ячейки выделены не так, как Вы описали, а, например, вот так:
+------+------+------+------+------+
|      |      |      |      |      |
+------+------+------+------+------+
|      |      |  S   |  S   |      |
+------+------+------+------+------+
|      |      |  S   |  S   |      |     S
+------+------+------+------+------+
Действительно, непонятно, чему должны быть равны SelectedRowCount и SelectedColumnCount. Так что пусть уж они будут равны нулю от греха подальше smile

Это небольшой офтоп. А теперь к делу.
Вообще, в MSDN'е в Best Practices по DataGridView есть интересная заметка по поводу использования SelectionMode.CellSelect
Цитата

Avoid cell-based selection modes. Instead, set the SelectionMode property to FullRowSelect or FullColumnSelect. 

Мило, да? smile

На фоне всего этого безобразия, думаю, придется Вам писать алгоритм на базе DataGridViewCell.ColumnIndex и DataGridViewCell.RowIndex.
Мне на ум пришел примерно следующий алгоритм.
1. Находим минимальный ColumnIndex и минимальный RowIndex из SelectedCells.
2. Вычитаем для всех выделенных ячеек из их ColumnIndex минимальный ColumnIndex, а из их RowIndex минимальный RowIndex. Если рассматривать предыдущий пример, то мы получим ячейки, которые расположились бы в DataGridView следующим образом:
+------+------+------+------+------+
|   S   |   S   |      |      |      |
+------+------+------+------+------+
|   S   |   S   |      |   S   |      |  
+------+------+-----+------+------+
|      |      |     |     |      |     |
+------+------+------+------+------+
На самом деле мы работаем с массивом ячеек: эта таблица только для демонстрации.
3. При вставке располагаем наши ячейки в ячейке с номером колонки, равным: номер колонки, в которой было вызвано контекстное меню, + "нормированный" номер текущей вставляемой ячейки. Аналогично со строками.

P. S. Не исключаю, что есть красивый способ реализовать подобный функционал... но поверхностный гуглинг не помог.


--------------------
Мой блог: alexidsa.blogspot.com
PM MAIL ICQ   Вверх
allknower
Дата 23.6.2008, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 21.12.2006
Где: Краснодар

Репутация: нет
Всего: нет



Idsa, обнаружился такой вот негатиффчик:

Пи выделении строк в ArrayList "DataGridView.SelectedCell" они попадают в совершенно немыслемом порядке.

Выкладываю то что наваял, может кому пригодится. Конечно сыровато, но работает. Пинами не ногать!!!

Класс Range
Код

    [Serializable]
    public class Range
    {
        private SimpleData[,] _range;

        public SimpleData this[int rowIndex, int colIndex]
        {
            get
            {
                return (this._range[rowIndex, colIndex] as SimpleData);
            }

            set
            {
                this._range[rowIndex, colIndex] = value;
            }
        }

        public int RowCount
        {
            get { return _range.GetLength(0); }
        }

        public int ColCount
        {
            get { return _range.GetLength(1); }
        }

public Range(System.Windows.Forms.DataGridViewSelectedCellCollection SelectedRange)
        {
            int maxRow = 0; int minRow = SelectedRange[0].RowIndex;
            int maxCol = 0; int minCol = SelectedRange[0].ColumnIndex;
            for (int indx = 0; indx < SelectedRange.Count; indx++)
            {
                if (SelectedRange[indx].RowIndex > maxRow)
                { maxRow = SelectedRange[indx].RowIndex; }
                else if (SelectedRange[indx].RowIndex < minRow)
                { minRow = SelectedRange[indx].RowIndex; }

                if (SelectedRange[indx].ColumnIndex > maxCol)
                { maxCol = SelectedRange[indx].ColumnIndex; }
                else if (SelectedRange[indx].ColumnIndex < minCol)
                { minCol = SelectedRange[indx].ColumnIndex; }
            }
            int rowCount = maxRow - minRow + 1;
            int colCount = maxCol - minCol + 1;
            _range = new SimpleData[rowCount, colCount];

            foreach (System.Windows.Forms.DataGridViewCell cell in SelectedRange)
            {
                _range[cell.RowIndex - minRow, cell.ColumnIndex - minCol] = (cell.Value as SimpleData);
            }
        }

SimpleData здесь это просто пользовательский тип данных, не более того. На логику никак не влияет.

Клик по пунктам Copy и Paste:
Код

 private void copyClipMenuItem_Click(object sender, EventArgs e)
        {
            Range r = new Range(grid.SelectedCells);
            
            DataFormats.Format myFormat = DataFormats.GetFormat("ArrayOffCell");
            DataObject myDataObject = new DataObject(myFormat.Name, r);
            Clipboard.SetDataObject(myDataObject);
        }

        private void pasteClipMenuItem_Click(object sender, EventArgs e)
        {
            int startRowIndx = grid.CurrentCell.RowIndex;
            int startColIndx = grid.CurrentCell.ColumnIndex;
            DataFormats.Format myFormat = DataFormats.GetFormat("ArrayOffCell");
            Range r = (Clipboard.GetDataObject().GetData(myFormat.Name) as Range);
            for (int rowIndx = 0; rowIndx < r.RowCount; rowIndx++)
            for (int colIndx = 0; colIndx < r.ColCount; colIndx++ )
            {
                try
                {
                    grid.Rows[startRowIndx + rowIndx].Cells[startColIndx + colIndx].Value = r[rowIndx, colIndx];
                }
                catch (Exception ex)
                { MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK); }
            }
        }


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

Это сообщение отредактировал(а) allknower - 23.6.2008, 14:18
PM MAIL ICQ   Вверх
stashe
Дата 24.6.2008, 13:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 153
Регистрация: 5.1.2007
Где: Донецк

Репутация: нет
Всего: 1



Код

private void copyToClipBoardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dataGridView.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
            Clipboard.SetDataObject(dataGridView.GetClipboardContent());
        }       


А это не в тему?
PM   Вверх
allknower
Дата 24.6.2008, 15:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 21.12.2006
Где: Краснодар

Репутация: нет
Всего: нет



Цитата(stashe @ 24.6.2008,  13:17)
Код

private void copyToClipBoardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dataGridView.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
            Clipboard.SetDataObject(dataGridView.GetClipboardContent());
        }       


А это не в тему?

Сколько я не колдовал с ячейками - вытащить их из буфера у меня так и не получилось. Может что не правильно делал? Какой format нужно указать в 

Код

Clipboard.GetDataObject.GetData(format);


C пользовательским форматом у меня не заработало. :(

А самописный Range развязал руки, и теперь я копирую, дублирую (как в Excel) как хочу...

Это сообщение отредактировал(а) allknower - 24.6.2008, 15:48
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
stab
mr.DUDA
Exception

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, stab, mr.DUDA, Exception.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Базы данных под .NET | Следующая тема »


 




[ Время генерации скрипта: 0.0814 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.