Добрый день всем! Давненько я здесь не писал. Для тех, кто пишет надстройки/книги на C# VSTO, есть быстрый способ поменять местами два диапазона. Данный способ использует кортежи.
Делал-делал я один запрос, но в итоге вдруг у меня стали вываливаться ошибки. Сначала не понял, почему, но потом разобрался - PowerQuery после группировки (например, суммирование) не сохраняет типы данных, которые я присвоил столбцам в предыдущих шагах. Например, есть такая табличка:
Запрос PowerQuery:
Код
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
ChangedType = Table.TransformColumnTypes(Source,{{"ID", Int64.Type}, {"Date1", type date}, {"Sum", Int64.Type}}),
GroupedRows = Table.Group(ChangedType, {"ID"}, {{"SUM_GROUP", each List.Sum([Sum]), type number}, {"ALL_ROWS", each _, type table}}),
ExpandedALLROWS = Table.ExpandTableColumn(GroupedRows, "ALL_ROWS", {"ID", "Date1", "Sum"}, {"ALL_ROWS.ID", "ALL_ROWS.Sum", "ALL_ROWS.Date1"})
in
ExpandedALLROWS
На шаге ChangedType всё ОК:
Но на шаге ExpandedALLROWS типы данных слетают:
Это никак не лечится? Или придётся в конце заново изменять типы? Или лучше сначала вообще не изменять типы, а изменть их только в конце?
Привет всем! В SQL существуют так называемые оконные функции (window functions), одна из которых - ROW_NUMBER. Эта функция позволяет вывести номер строки для каждой группы значений. Чтобы было понятно, вот пример, что нужно получить:
Как видно из таблицы, для каждой группы ID определяется своя нумерация строк (ROW_NUMBER). Возможно ли такое сделать с помощью Power Query?
Компания Microsoft без предупреждения прекратила поддержку операционной системы Windows 7 на старых компьютерах, процессоры которых не поддерживают инструкции SSE2. Последние появились в процессорах Intel Pentium 4. Таким образом, компьютеры на базе процессоров предыдущих поколений не будут получать обновления операционной системы, несмотря на то, что Microsoft официально продлила поддержку Windows 7 до середины января 2020 года, пишет РГ со ссылкой на ComputerWorld. Помимо этого, стало известно, что с июля сотрудники Microsoft не будут консультировать пользователей форума техподдержки по вопросам, связанным с программными продуктами Windows 7, 8. и 8.1 RT, Microsoft Security Essentials, Internet Explorer 10, Office 2010 и 2013, планшетами Surface Pro, Surface Pro 2, Surface RT и Surface 2, фитнес-браслетом Microsoft Band и сервисом Zune.
New features coming: - Inking feature (Использование пера) - Improved data analysis capabilities (Улучшенные возможности анализа данных) - Expanded PowerPoint animation features (Расширенные возможности анимации в PowerPoint) - Better security (Улучшенная безопасность)
Самое главное - Office 2019 будет работать только в Windows 10.
Приветствую! Возникла необходимость создавать динамически элементы управления через WinAPI. Стал разбираться в этой теме. Удалось создать ListBox и добавить в него некоторые строки. Проблема в том, что созданный ListBox никак ни на что не реагирует: полосы прокрутки не работают, выделение не работает. Как будто он в режиме Disabled или Locked. Есть у кого-либо какие идеи, как заставить ListBox отвечать на действия?
Что имеем: 1. WinAPI функции:
Код
Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" ( _
ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
Declare Function CreateWindow Lib "user32.dll" Alias "CreateWindowExA" ( _
ByVal dwExStyle As WindowStylesEx, _
ByVal lpClassName As String, _
ByVal lpWindowName As String, _
ByVal dwStyle As Long, _
ByVal x As Long, _
ByVal y As Long, _
ByVal nWidth As Long, _
ByVal nHeight As Long, _
ByVal hWndParent As Long, _
ByVal hMenu As Long, _
ByVal hInstance As Long, _
ByVal lpParam As Long) As Long
Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" ( _
ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Any) As Long
2. В UserForm'e создаём ListBox и добавляем значения:
Код
hlist = CreateWindow( _
dwExStyle:=WS_EX_CLIENTEDGE, _
lpClassName:="LISTBOX", _
lpWindowName:="MYLISTBOX", _
dwStyle:=WS_CHILD Or WS_VISIBLE Or LBS_NOTIFY Or WS_VSCROLL Or WS_BORDER Or LBS_HASSTRINGS, _
x:=10, _
y:=10, _
nWidth:=100, _
nHeight:=100, _
hWndParent:=FindWindow("ThunderDFrame", Me.Caption), _
hMenu:=0, _
hInstance:=Application.hInstance, _
lpParam:=0 _
)
' Добавляем значения
For x = 1 To 10
Call SendMessage(hlist, LB_ADDSTRING, 0, CStr(x))
Next
Хочу поделиться одной идеей, как в C# можно эффективно использовать dynamic в EF (на примере WPF приложения). Например, есть три таблицы в базе данных (по сути - справочники) с одной и той же структурой:
Код
class Strategy
{
public int Id { get; set; }
public string Name { get; set; }
}
class Operator
{
public int Id { get; set; }
public string Name { get; set; }
}
class OrderState
{
public int Id { get; set; }
public string Name { get; set; }
}
Задача: создать функционал для изменения значений справочников. У нас есть два комбобокса (ComboBox) и текстовое поле (TextBox): 1) сmbDictionaries - список доступных справочников 2) cmbDictionaryEntries - список значений в выбранном справочнике 3) txtEntryName - выбранное значение справочника
Итак, сначала подгружаем список доступных справочников:
private async void OnChangeEntry(object sender, RoutedEventArgs e)
{
// Taк как Binding у текстового поля использует режим TwoWay,
// то все изменения транслируются автоматически в сущность.
// По умолчанию, у текстового поля изменения транслируются при потере фокуса.
int count = await context.SaveChangesAsync();
MessageBox.Show($"Сохранено записей: {count}");
}
private async void OnAddEntry(object sender, RoutedEventArgs e)
{
var set = GetDbSet();
// Используем dynamic, чтобы проще было добраться до свойства Name
dynamic entry = set.Create();
entry.Name = txtEntryName.Text;
set.Add(entry);
int count = await context.SaveChangesAsync();
MessageBox.Show($"Сохранено записей: {count}");
}
На данный момент мы уже с помощью dynamic облегчаем себе работу. Так как у нас таблицы (и сущности) одинаковые, то мы можем использовать обобщённый (generic) метод Set, чтобы создавать новые сущности и сохранять их. Вся изюминка - в методе GetDbSet:
Код
private DbSet GetDbSet()
{
// cmbDictionaries в качестве ItemContainer использует ComboBoxItem.
// Ранее был показан код добавления значений словаря. В свойство Tag было записано название класса сущности.
// Здесь SelectedItem возвращает нам Object, а в конечном итоге - ComboBoxItem, у которого мы должны взять Tag.
// По идее, можно сделать кастинг SelectedItem'a в ComboBoxItem, взять свойство Tag и сконвертировать в String...
// Но используя dynamic, всё становится намного проще. В итоге setName имеет тип String. В этом можно убедиться,
// если в Immediate Window выполнить запрос: ?setName.GetType().FullName
// Ответом будет "System.String".
dynamic setName = ((dynamic)cmbDictionaries.SelectedItem).Tag;
// После получения названия целевой сущности, нужно получить её тип.
// Нужно в строке указать полный путь к классу. Здесь для удобства используется фишка C#7.0 - Interpolation String.
var type = Type.GetType($"DynamicEFWPF.{setName}");
// Далее получаем DbSet, но не типизированный (Object).
var set = context.Set(type);
return set;
// Или всё в одну строку:
//return context.Set(Type.GetType($"DynamicEFWPF.{((dynamic)cmbDictionaries.SelectedItem).Tag}"));
}
Таким образом, нам не надо плодить кучу if'ов, чтобы выбрать тип. Но опять же повторюсь - это работает только для сущностей одинаковой структуры. Полный WPF проект можно посмотреть/скачать здесь. Скрипт для создания базы данных - файл Scripts.sql в папке Database (работает с SQL Server 2016 и выше).
Всем привет! На сайте channel 9 есть много видео с конференций и выступлений от Microsoft (Build, Ignite, Visual Studio Live и так далее). Видео также можно скачать, причём к некоторым видео можно скачать субтитры. Я всегда смотрю с субтитрами, так как иногда не совсем понятно, что говорят участники выступлений, поэтому субтитры являются большим подспорьем. Но вот незадача - субтитры в формате VTT, то есть в плеер (например, Light Alloy) их не вставишь. Я посмотрел отличия, и оказалось, что нужно внести совсем небольшие изменения - и SRT готов! Я написал простую программу для конвертации. Если кто-то заинтересовался, то исполняемый файл - в папке build, исходники - в папке source. Можно указать несколько файлов. После конвертации файл VTT удаляется.
Установил Excel 2016. Решил почитать, чего там нового. Интересное из диаграмм - водопады. И ещё интегрировали Power Query, который раньше был надстройкой (Data => Get & Transform/Данные => Скачать & Преобразовать [ну и перевели!!! ]). Решил посмотреть, что за зверь, так как Andrey VG частенько отвечал в виде Power Query. Прочитал, что у Power Query есть свой язык Power Query Formula Language ("M" Language). Решил бегло пробежаться и понажимать кнопки. Благо, и повод есть - база в SQL Server'е, в которой 250 000 строк. При подсоединении задал свой простенький SQL:
Код
SELECT * FROM dbo.MyTable
WHERE Id = 0;
Первое, что бросилось в глаза - данные не все были загружены, а точнее - всего лишь 58 строк с сообщением "The data in the preview has been truncated due to size limits". Но где регулировать этот "size limits" - я так и не нашёл. Я не зря написал SQL-запрос выше. В строке формулы был мой запрос: [Query="SELECT * FROM dbo.MyTable#(lf)WHERE Id = 0;"]. Сначала не понял, где у меня в запросе #(lf), а потом понял, что это знак новой строки (Line Feed). В общем, думаю почитать про Power Query, но у меня вопрос - насколько необходимо знать язык "M"? Другими словами, какие вещи нельзя сделать в GUI, для которых необходимо знать "M"? И какие есть хорошие книги/статьи?
Субж, собственно. Вот примерчик. Михаил Лебедев пишет "Зачем Вам такое бешеное количество (385 + еще 2) листов в книге?", однако ТС отредактировал своё оригинальное сообщение - и теперь ничего непонятно.
Есть файл Эксель с макросами. Его расширение - XLSM. В спешке при копировании похожего названия с некоторым изменением вы переименовываете его, но не заметили, что у того файла было расширение XLSX - и теперь у нового файла тоже расширение XLSX. И вот вы пытаетесь открыть его, но у вас не получится. Внимание, знатоки, вопрос - почему?
Сегодня как-то между делом Александр (ikki) спросил про код, который позволяет создавать базу данных (и структуру) без наличия установленного Access'а. Я ответил ему, но продублирую ответ здесь - на всякий случай. Для этого потребуется библиотека "Microsoft ADO Ext. 6.0 for DDL and Security".
Код
Sub CreateAccessDatabaseWithoutAccess()
Dim cat As ADOX.Catalog '// Каталог (база данных)
Dim t As ADOX.Table '// Таблица
Dim c As ADOX.Column '// Столбец
'// Создаём файл базы данных "C:\Temp\1.mdb".
Set cat = New ADOX.Catalog
'// Excel 2007+
cat.Create "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Temp\1.mdb"
'// Excel 97-2003
'// cat.Create "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Temp\1.mdb"
'// Создаём таблицу
Set t = New ADOX.Table
t.Name = "User"
'// Создаём два столбца: Id и UserName
Set c = New ADOX.Column
c.Name = "Id" '// Название столбца
c.Type = adInteger '// Тип данных
t.Columns.Append c '// Добавляем столбец в таблицу
Set c = New ADOX.Column
c.Name = "UserName"
c.Type = adWChar
c.DefinedSize = 255
t.Columns.Append c
'// Добавляем таблицу в базу
cat.Tables.Append t
Set cat = Nothing
End Sub
Насколько я заметил, имя ОП сохраняется вместе с темой, а не берётся из профиля. Дело в том, что когда модератор просит ОП изменить имя и когда он его меняет, то: 1) имя в списке тем остаётся старым; 2) имя в самой теме не меняется до тех пор, пока ОП не сменил имя. Привожу пример подобного ОП. Данная тема примечательна ещё и тем, что непонятно, что ОП сменил имя (с "s7263808" на "Korss"), так как обычно изменению имени предшествует просьба модератора сменить имя. Таким образом, делаю заключение, что имя ОП, отображаемое в списке тем и в самом сообщении берётся не из профиля (как было бы правильно). Поэтому есть просьба брать имя ОП из профиля.
Здравствуйте, товарищи! Бью к вам челом! Вопрос к тем, кто программировал/программирует Excel в C# (.NET Framework).
В общем, проблема такого характера. Имеется некий диапазон. Фильтрую его. Мне нужно получить этот отфильтрованный диапазон и пихнуть его в массив. В VBA я делаю так:
Код
Sub F1()
Dim rng As Range, arr As Variant
Set rng = Sheets(1).Range("AS5:AS6094").SpecialCells(xlCellTypeVisible)
arr = rng.Value
End Sub"
Это в VBA. А вот аналогичный метод в C#:
Код
using Excel = Microsoft.Office.Interop.Excel;
......
private void LoadExcelFile()
{
// Выбираем файл и открываем его
var dialog = new Microsoft.Win32.OpenFileDialog { InitialDirectory = Directory.GetCurrentDirectory() };
if (!dialog.ShowDialog(this).Value) return;
var excelFile = dialog.FileName;
Excel.Application xlApp = new Excel.Application() { Visible = true };
Excel.Workbook book = xlApp.Workbooks.Open(excelFile);
Excel.Worksheet sheet = book.Sheets[1];
// Убираем автофильтр
if (sheet.AutoFilter != null) sheet.AutoFilterMode = false;
// Фильтруем
sheet.Range["A5:BA5"].AutoFilter(Field: 25, Criteria1: "31.07.2014");
// Получаем фильтрованный диапазон
var rng1 = sheet.Range["AS5", "AS6094"].SpecialCells(Excel.XlCellType.xlCellTypeVisible);
// Получаем весь диапазон
var rng2 = sheet.Range["AS5", "AS6094"];
// Значение диапазона (ожидаем массив)
dynamic val1 = rng1.Value;
dynamic val2 = rng2.Value;
MessageBox.Show(val1.GetType().Name); // Возвращает: String <= Ожидался массив Object[,]
MessageBox.Show(val2.GetType().Name); // Возвращает: Object[,] <= Правильно
book.Close();
xlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(book);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
}
Как видно, диапазон, полученный через SpecialCells, даёт нам String, а не массив. Кто-нибудь знает, как решить эту проблему?
Привет всем! Очень интересная тема - перевод американских фильмов на русский язык. Хочу сказать, что смотрю американские фильмы исключительно с субтитрами! Многие скажут, что мне делать нечего - лучше расслабиться и смотреть картинку, чем бегать глазами по тексту. Так-то оно так, но... Дело в том, что перевод текста 1) может быть не совсем точным, 2) может содержать одно неверно переведённое слово, 3) иметь вольный перевод (так сказать, "близко к тексту" и, наконец, 4) иметь вообще другой перевод и, соответственно, другой смысл. Самый интересный пункт - это, конечно, четвёртый. И я вам покажу примерчик. Фильм "Враг государства" (Enemy of the state) 1998 года. На времени 38:30 мужик говорит такую фразу: I've seen KILLERS walk free because the EYEWITNESS was an ALCOHOLIC Вот перевод: Я видел, как НАСИЛЬНИКОВ отпускают, потому что ЖЕРТВА была ПРОСТИТУТКОЙ Вот правильный перевод: Я видел, как УБИЙЦ отпускают, потому что СВИДЕТЕЛЬ был АЛКОГОЛИКОМ
Из этого перевода следует, что проституток можно насиловать - и насильника просто отпустят. Предлагаю сюда выкладывать несуразицы перевода.
Только что на форуме MrExcel.com задали вопрос о том, как можно узнать те столбцы, где применён фильтр в автофильтре. Действительно, иногда попадаются длинные таблицы, где стоит автофильтр, и возникает необходимость найти, где чего применено. Если кому-то пригодится, то вот код. :)
Код
Sub ShowFilterInfo()
Dim af As AutoFilter, f As Filter
Dim sCols As String
Dim c As Integer, iCol As Integer, firstCell As Integer
Dim re As Object
If Not ActiveSheet.AutoFilterMode Then
MsgBox "Автофильтр на листе не найден.", vbExclamation
Exit Sub
End If
Set af = ActiveSheet.AutoFilter
firstCell = af.Range(1).Column
Set re = CreateObject("VBScript.RegExp")
re.Pattern = "[A-Z]+"
For Each f In af.Filters
c = c + 1
If f.On Then
iCol = c + firstCell - 1
sCols = sCols & re.Execute(Cells(1, iCol).Address)(0) & ", "
End If
Next
If Len(sCols) > 0 Then
MsgBox "В следующих столбцах установлен фильтр: " & Chr(13) & Left$(sCols, Len(sCols) - 2)
Else
MsgBox "Фильтры не найдены.", vbExclamation
End If
Set re = Nothing
End Sub
Как-то нужно было мне скопировать таблицу из одного места в другое в одном и том же документе. Так как с Word'овским VBA почти не знаком, то за неимением знания, как сделать, решить пойти методом копипаста. :D
Код
Dim doc As Document
Dim t As Table
Set doc = ThisDocument
Set t = doc.Tables(1)
t.Select
Selection.Copy
doc.Bookmarks("bm46").Select
Selection.Paste
Но потом подумал, что всё-таки должен быть более другой метод, который был бы более верным. Решил зайти на буржуйский форум и задал вопрос. На что мне ответили так:
Код
Sub TableDuplicate()
With ActiveDocument
.Bookmarks("bm46").Range.FormattedText = .Tables(1).Range.FormattedText
End With
End Sub
Так вот как так можно догадаться интуитивно, что таблица в терминах Word'а - это форматированный текст (FormattedText)? Интересно, есть ли у кого-нибудь опыт работы с Word VBA и какое впечатление от его использования? :)
Как вы знаете, MSFT внедрило в Office 2013 так называемые Office Apps. Для написания его используется JavaScript. Честно скажу, мне лично не нравится этот язык. Я стал изучать его, но так в нём ничего не понял. Сегодня прочитал вот эту статью на Хабре про JavaScript. Очень интересно. P.S. Для заметки - для написания Apps необходимо знание всей внутренней структуры файла, а это значит, что надо знать всю спецификацию. Кто готов? P.P.S. Слышу гневные слова Саши.
Недавно начал изучать язык программирования C и меня сразу заинтересовала такая тема, что можно написать для себя функции для использования в Excel'е. Вроде где-то читал, что функции, написанные на C/C++, быстро работают в Экселе по сравнению с VBA функциями, ну и решил написать простейшие функции для теста. На выходе мы получаем Win32 библиотеку (DLL), которую используем в Declare Function. Далее я узнал, что можно написать XLL надстройки, которые позволяют использовать функции С сразу в ячейках, а не в VBA, но это я не осилил, конечно. С улыбкой Если кто-то знает, есть ли разница в скорости работы VBA и функций, буду очень благодарен.0 На ваш суд выношу библиотеку с двумя функциями. Первая из них (addOne) совсем простая - прибавляет единичку к аргументу Double и возвращает результат. Вторая функция - очень интересная. Если мне не изменяет память, этот вопрос задавал nerv - можно ли использовать VBA-функцию в качестве callback-функции. Ответ - с помощью C DLL можно! Библиотеки сделал в двух вариантах - 32 и 64-х битные. Предпроцессорная директива (#If Win64) сама выберет нужную библиотеку. От вас требуется скопировать куда-нибудь эти две библиотеки и указать к ним полный путь после Lib. Файл с кодом я приложу. Итак, сначала код VBA.
Код
#If Win64 Then
' Excel 64-бит
Private Declare PtrSafe Function addOne Lib "c:\DLLs\ExcelFuncs_x64.dll" _
(ByVal x As Double) As Double
Private Declare PtrSafe Function addOneWithCallback Lib "c:\DLLs\ExcelFuncs_x64.dll" _
(ByVal funcPtr As LongPtr, ByVal x As Double) As Double
#Else
' Excel 32-бит
Private Declare Function addOne Lib "c:\DLLs\ExcelFuncs_x86.dll" _
(ByVal x As Double) As Double
Private Declare Function addOneWithCallback Lib "c:\DLLs\ExcelFuncs_x86.dll" _
(ByVal funcPtr As Long, ByVal x As Double) As Double
#End If
Sub AddOneTest()
MsgBox "Сумма = " & addOne(5)
End Sub
Sub AddOneUsingCallback()
' C-фукнция получает указатель VBA функции "AddOneCallback" и передаёт ей пятёрку.
' VBA функция прибавляет 1 к аргументу и возвращает 6.
' С функция возвращает в VBA шестёрку.
MsgBox "5 + 1 = " & addOneWithCallback(AddressOf AddOneCallback, 5)
End Sub
Function AddOneCallback(ByVal x As Double) As Double
AddOneCallback = x + 1
End Function
Итак, разберём, что к чему. Как я и говорил выше, директива #If Win64 автоматически загрузит нужную библиотеку - свою для 32 и 64-битного Офиса. Если вы не программировали Win32 API для 64-битного Офиса, то для 64-битного Офиса поменялись некоторые типы данных, которые необходимо использовать. Например, вместо Long - LongPtr и т.д. На моём примере мы видим для 64-битного Экселя "PtrSafe" и вместо Long используется LongPtr (так как указатели имеют длину не 32 бита (Integer - 4 байта)). После того, как вы подправили путь к библиотеке, далее идут две тестовые процедуры (AddOneTest и AddOneUsingCallback) и вспомогательная функция (callback) для AddOneUsingCallback. Первая простейшая C-функция - addOne в AddOneTest. Как видно, ничего нет сложного - вызываем функцию обычно как будто это VBA-функция. В примере в неё передаётся пятёрка, к ней прибавляется единичка, на выходе - 6. Вторая C-функция - addOneWithCallback. Она имеем два аргумента. Первый - это адрес callback-функции, которая будет вызываться в C-функции. Второй аргумент я сделал для наглядности - он будет передаваться в VBA-функцию в C-библиотеке. В комментариях я написал, что получается. Итак, callback'и в VBA возможны. Думаю, Саша прочитает эту тему. Исходный C код:
Уважаемые товарищи! Вышла новая версия очень удобного редактора ленты Ribbon XML Editor 4 с большим количеством доработок. Среди фишек новой версии - подсветка парных тегов, автооткрытие документа в редакторе после его закрытия в родном приложении, быстрые переходы по тегам, стили подсветки кода и вменяемая справка. Здесь описание от автора.
Наша повседневная работа написания кода так или иначе связана с обращением к ячейкам. Хотелось бы написать про методы обращения к ячейкам. Если что-то пропустил - не ругайте. Итак, поехали...
Код
Sub CellsSelection()
Dim cell As Range
Dim severalCells As Range
Dim rng As Range
'=======================================
'Выделяем ячейку F6
'=======================================
Set cell = Range("F6")
Set cell = Cells(6, 6)
Set cell = Cells(6, "F")
Set cell = Cells(81926) ' (16384 * 5) + 6
Set cell = Cells.Item(6, 6)
Set cell = Cells.Cells(6, 6)
'=======================================
'1. Выделяем диапазон D4:G10
'=======================================
Set rng = Range("D4:G10")
Set rng = Range(Cells(4, "D"), Cells(10, "G"))
Set rng = Range(Cells(4, 4), Cells(10, 7))
Set rng = Range("D4", Cells(10, 7))
Set rng = Range("D4", "G10")
Set rng = Range(Range("D4"), "G10")
Set rng = Range("D4").Resize(7, 4)
'Обращаемся к диапазону без привязки к объекту Worksheet
Set rng = Range("Лист1!D4:G10")
'Во всех нижеприведённых методах необходимо
'представить диапазон D4:G10 как лист
'с верхней левой ячейкой A1, то есть мысленно
'переносим D4:G10 в A1. :)
'========================================
'2. Выделяем ячейку F6 в диапазоне D4:G10
'========================================
Set cell = rng.Range("C3")
Set cell = rng(3, 3)
Set cell = rng(11)
Set cell = rng.Item(3, 3)
Set cell = rng.Item(11)
Set cell = rng.Cells(11)
Set cell = rng.Cells(3, 3)
'===========================================
'3. Выделяем ячейку E11 ВНЕ диапазона D4:G10
'===========================================
Set cell = rng(30)
Set cell = rng.Item(30)
Set cell = rng.Cells(30)
Set cell = rng.Range("B8")
Set cell = rng.Cells(8, 2)
Set cell = rng(8, 2)
Set cell = rng.Item(8, 2)
Set cell = rng.Cells(8, 2)
'=============================================
'4. Выделяем диапазон E8:F9 в диапазоне D4:G10
'=============================================
Set severalCells = rng.Range("B5:C6")
Set severalCells = rng.Range("B5", "C6")
'В общем, принцип такой же, что и в пункте 2. :)
End Sub