Рассматриваю более детальнее код, который опубликовал в прошлой статье.
1. Это часть кода генерируется автоматически в которой объявляются пространства имён.
Мне интересна, в данном случае, вот эта строка, где указываем размеры формы приложения:
2. Контейнер DockPanel - его очень удобно использовать для создания стандартных интерфейсов.
Верхнюю и левую часть - можно использовать для меню.
Нижнюю часть - для отображение какой-то доп информации(чаще строка состояния, в сайтостроении называют также эту часть "подвал").
Правую часть - для отображения дополнительной части.
Центр - здесь находится основное содержание.
Свойство
3. Элемент управления Menu (выделяю его специально, т.к. в него входят другие элементы) - который расположен в верхней части нашей DockPanel панели.
3.1.
3.2. Свойство
3.3. Элемент
3.4. Событие
Продолжение следует....
#WPF, #Csharp
1. Это часть кода генерируется автоматически в которой объявляются пространства имён.
<Window x:Class="TelegramBot.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TelegramBot"
mc:Ignorable="d"
Title="MainWindow" Height="150" Width="800">
Мне интересна, в данном случае, вот эта строка, где указываем размеры формы приложения:
" Title="MainWindow" Height="150" Width="800"
2. Контейнер DockPanel - его очень удобно использовать для создания стандартных интерфейсов.
Верхнюю и левую часть - можно использовать для меню.
Нижнюю часть - для отображение какой-то доп информации(чаще строка состояния, в сайтостроении называют также эту часть "подвал").
Правую часть - для отображения дополнительной части.
Центр - здесь находится основное содержание.
<DockPanel LastChildFill="True">
..................
..................
..................
</DockPanel>
Свойство
LastChildFill="True"
означает, что последний элемент(в нашем случае, это текстовое поле "TextBox" и кнопка "Button") заполняет всё оставшееся пространство. 3. Элемент управления Menu (выделяю его специально, т.к. в него входят другие элементы) - который расположен в верхней части нашей DockPanel панели.
<Menu DockPanel.Dock="Top">
<MenuItem Header="Данные">
<MenuItem Header="Сохранить"
Command=""/>
<Separator/>
<MenuItem Header="Выход"
Click="MenuItem_Click"/>
</MenuItem>
</Menu>
3.1.
<MenuItem Header="Данные">
- это название меню. Оно может состоять из нескольких т.е. :<MenuItem Header="Данные">
<MenuItem Header="Сохранить">
<MenuItem Header="Выход"">
3.2. Свойство
"Command"
используется для паттерна MVVM(Model-View-ViewModel). О нём буду говорить, в других постах, если будет необходимо.3.3. Элемент
<Separator/>
- это понятно, "разделитель". 3.4. Событие
Click="MenuItem_Click"
с присвоенным ему именем. Оно будет обрабатываться в коде.Продолжение следует....
#WPF, #Csharp
Продолжаю знакомить с WPF.
В предыдущем посте остановился на рассмотрении элемента управления "Menu".
В этом рассмотрю сразу несколько элементов управления(кратко) "ListView", "TextBlock", "StatusBar" и "Grid"
1. Часть кода, который буду рассматривать.
2. Элемент управления ListView(главный элемент в нашем интерфейсе), расположен в левой части интерфейса
2.1. Короткий пример(добавление "Заголовков " столбцов т.е. "Headers"):
2.2. Элемент управления TextBlock - служит для вывода текстовой информации и имеет свойство
3. Переходим к след. элементу управления StatusBar (главный элемент в нашем интерфейсе), располагается в нижней части интерфейса
Интересный момент: Многие элементы управления имеют ограничения в оформлении и для того, чтобы убрать их необходимо использовать другие элементы, которые будут вложены в текущие.
3.1. Обратимся к свойству ItemsPanel у элемента StatusBar т.е.
3.2. Далее обратимся к элементу ItemsPanelTemplate, который будет в какой-то степени отвечать за оформления нашего StatusBar.
Элемент ItemsPanelTemplate, необходимо будет использовать довольно часто при работе с WPF.
3.3. В ItemsPanelTemplate добавляем такой элемент управления, как Grid
Grid - ЭТО мощный и часто используемый контейнер, напоминающий обычную таблицу. Прошу запомнить это т.к. без него интерфейс напоминал "беспорядочность".
3.3.1. Элемент Grid имеет два интересных свойств:
а)
б)
На этом всё.
Продолжение следует.....
#WPF, #Csharp
В предыдущем посте остановился на рассмотрении элемента управления "Menu".
В этом рассмотрю сразу несколько элементов управления(кратко) "ListView", "TextBlock", "StatusBar" и "Grid"
1. Часть кода, который буду рассматривать.
<ListView DockPanel.Dock="Left"
Background="MidnightBlue"
Width="140">
<TextBlock Text="Новое сообщение:" Foreground="White"/>
</ListView>
<StatusBar DockPanel.Dock="Bottom">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
..................
..................
..................
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
..................
..................
..................
</StatusBar>
2. Элемент управления ListView(главный элемент в нашем интерфейсе), расположен в левой части интерфейса
DockPanel.Dock="Left"
. Не смотря на то, что он унаследован от класса другого элемента ListBox, является более "продвинутым" т.к. ещё можно добавлять "заголовки столбцов" т.е. у него есть свойство "View", которое имеет свой элемент(объект) GridView, который позволяет создавать более сложную структуры таблицы(со своими названиями столбцов)2.1. Короткий пример(добавление "Заголовков " столбцов т.е. "Headers"):
<ListView.View>
<GridView>
<GridViewColumn>№</GridViewColumn>
<GridViewColumn>Кол-во штук</GridViewColumn>
<GridViewColumn>Цена</GridViewColumn>
</GridView>
</ListView.View>
2.2. Элемент управления TextBlock - служит для вывода текстовой информации и имеет свойство
Foreground="White".
В котором устанавливается цвет, переднего фона элемента, в нашем случае "цвет текста".3. Переходим к след. элементу управления StatusBar (главный элемент в нашем интерфейсе), располагается в нижней части интерфейса
DockPanel.Dock="Bottom".
Интересный момент: Многие элементы управления имеют ограничения в оформлении и для того, чтобы убрать их необходимо использовать другие элементы, которые будут вложены в текущие.
3.1. Обратимся к свойству ItemsPanel у элемента StatusBar т.е.
<StatusBar.ItemsPanel>
3.2. Далее обратимся к элементу ItemsPanelTemplate, который будет в какой-то степени отвечать за оформления нашего StatusBar.
Элемент ItemsPanelTemplate, необходимо будет использовать довольно часто при работе с WPF.
3.3. В ItemsPanelTemplate добавляем такой элемент управления, как Grid
Grid - ЭТО мощный и часто используемый контейнер, напоминающий обычную таблицу. Прошу запомнить это т.к. без него интерфейс напоминал "беспорядочность".
3.3.1. Элемент Grid имеет два интересных свойств:
а)
<Grid.ColumnDefinitions>
- для работы с размерами столбцов - шириной.б)
<Grid.RowDefinitions>
- для работы с размерами столбцов - высотой.На этом всё.
Продолжение следует.....
#WPF, #Csharp
Отойду от темы WPF, и покажу довольно "тривиальную задачу".
Работают два разных приложения:
Одно создаёт текстовый файл и записывает в него содержимое.
Второе читает это файл.
Проблема заключается в том, что первое приложение не успевает записывать в него информацию, как тут же второе его считывает, получая при этом ошибку "Файл пуст".
Решение для этой проблемы весьма простое:
1. Создаём метод "IsLockedFile" с возвращаемым типом данных bool.
2. Создаём конструкцию try...catch, для того чтобы словить исключение.
3. Добавляем оператор "using" - для того, чтобы правильно освобождать,сбрасывать,удалять неуправляемые ресурсы(аналог метода Dispose)
4. Обращаемся к классу "File" и его методу Open с его параметрами(где задаём enum или ещё называют перечисление: FileMode.Open, FileAccess.Read, FileShare.None) и создаем конструктор класса "FileStream".
5. Если файл успешно открылся и прочитался, то возвращаем false(закрывая при этом объект класса FileStream), если нет то true. И в том и в том случае выходим из метода IsLockedFile.
6. В коде вызываю этот метод передавая путь к файлу. Используя цикл "while" т.е. этот будет работать до тех пор, пока возвращает true.
Пример кода:
Очень удобное вещь, особенно если работаете также в многопоточном режиме. Советую это сохранить и использовать.
#Csharp, #File
Работают два разных приложения:
Одно создаёт текстовый файл и записывает в него содержимое.
Второе читает это файл.
Проблема заключается в том, что первое приложение не успевает записывать в него информацию, как тут же второе его считывает, получая при этом ошибку "Файл пуст".
Решение для этой проблемы весьма простое:
1. Создаём метод "IsLockedFile" с возвращаемым типом данных bool.
2. Создаём конструкцию try...catch, для того чтобы словить исключение.
3. Добавляем оператор "using" - для того, чтобы правильно освобождать,сбрасывать,удалять неуправляемые ресурсы(аналог метода Dispose)
4. Обращаемся к классу "File" и его методу Open с его параметрами(где задаём enum или ещё называют перечисление: FileMode.Open, FileAccess.Read, FileShare.None) и создаем конструктор класса "FileStream".
5. Если файл успешно открылся и прочитался, то возвращаем false(закрывая при этом объект класса FileStream), если нет то true. И в том и в том случае выходим из метода IsLockedFile.
6. В коде вызываю этот метод передавая путь к файлу. Используя цикл "while" т.е. этот будет работать до тех пор, пока возвращает true.
Пример кода:
string pathFile = "D:\Example.txt";
while (IsLockedFile(pathFile));
public bool IsLockedFile(string fileName)
{
try
{
using (FileStream fs = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.None))
{
fs.Close();
return false;
}
}
catch (Exception ex)
{
return true;
}
return true;
}
Очень удобное вещь, особенно если работаете также в многопоточном режиме. Советую это сохранить и использовать.
#Csharp, #File
Продолжаю знакомство с WPF.
В прошлой статье остановился на рассмотрение такого элемента как Grid.
Одно из важных свойств этого элемента(и не только этого) ширина и высота.
Есть несколько вариантов установки размеров:
"Auto" - установка ширины элемента согласно его содержанию.
"100" - фиксированный размер.
"*" - пропорциональный размер(маленький лайфхак, хотите увеличить этот размер в 2 в 3 раза, просто сделайте запись таким образом "2*" или "3*" ).
Для того, чтобы необходимый элемент имел правильные очертания(в моём случае это элемент "Grid"), то рекомендуется комбинировать эти размеры по необходимости.
Завершаем знакомство с элементами ItemsPanelTemplate и StatusBar.ItemsPanel - которые отвечали за основное оформление(т.е. своего рода "заготовки") и перехожу к след.-му.
Здесь появляется новый элемент StatusBarItem. Если прошлые элементы StatusBar.ItemsPanel и ItemsPanelTemplate служили нам заготовкой(разметкой), то уже этот служит нам для заполнения нужной информацией.
Каждый элемент размещается в своей колонке, привязка к определенной колонке происходит таким образом: Grid.Column="1" , где "1" это номер нашей колонки. Таким образом добавив нужные элементы(TextBlock и Separator) и привязав их к нужным колонкам у нас получится готовый StatusBar.
Продолжение следует.....
#WPF,#Csharp
В прошлой статье остановился на рассмотрение такого элемента как Grid.
Одно из важных свойств этого элемента(и не только этого) ширина и высота.
Есть несколько вариантов установки размеров:
"Auto" - установка ширины элемента согласно его содержанию.
"100" - фиксированный размер.
"*" - пропорциональный размер(маленький лайфхак, хотите увеличить этот размер в 2 в 3 раза, просто сделайте запись таким образом "2*" или "3*" ).
Для того, чтобы необходимый элемент имел правильные очертания(в моём случае это элемент "Grid"), то рекомендуется комбинировать эти размеры по необходимости.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
Завершаем знакомство с элементами ItemsPanelTemplate и StatusBar.ItemsPanel - которые отвечали за основное оформление(т.е. своего рода "заготовки") и перехожу к след.-му.
<StatusBarItem>
<TextBlock Text="Статус:" />
</StatusBarItem>
<Separator Grid.Column="1" />
<StatusBarItem Grid.Column="2">
<TextBlock Text="Не отправлено" />
</StatusBarItem>
<Separator Grid.Column="3" />
<StatusBarItem Grid.Column="4">
<TextBlock Text="Кол-во знаков:" />
</StatusBarItem>
<Separator Grid.Column="5" />
<StatusBarItem Grid.Column="6">
<TextBlock Text="259" />
</StatusBarItem>
Здесь появляется новый элемент StatusBarItem. Если прошлые элементы StatusBar.ItemsPanel и ItemsPanelTemplate служили нам заготовкой(разметкой), то уже этот служит нам для заполнения нужной информацией.
Каждый элемент размещается в своей колонке, привязка к определенной колонке происходит таким образом: Grid.Column="1" , где "1" это номер нашей колонки. Таким образом добавив нужные элементы(TextBlock и Separator) и привязав их к нужным колонкам у нас получится готовый StatusBar.
Продолжение следует.....
#WPF,#Csharp
В прошлом посте про WPF, рассмотрел элемент: StatusBar.
В текущем коснусь такого элемента, как TextBox и некоторых его свойств.
Свойства:
AcceptsReturn="True" - служит для того, чтобы переводить по нажатию на клавишу Enter курсор на следующую строку.
VerticalScrollBarVisibility="Auto" и HorizontalScrollBarVisibility="Auto" - служит для отображения полос прокрутки TextBox поддерживает свойства.
Элемент: Button - где ему дал имя в свойстве: x:Name="buttonSentMessage"(это имя будет использоваться в коде).
Надпись(содержание), которая отображается на самой кнопке находится в свойстве: Content="Отправить".
Событие: Click="Button_Click" с собственным названием.
В коде будет примерно так(при нажатие на эту кнопку, выскакивает сообщение "Кнопка была нажата!"):
На этом шаге с оформлением останавливаюсь.
Продолжение следует.....
#WPF,#Csharp
В текущем коснусь такого элемента, как TextBox и некоторых его свойств.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" AcceptsReturn="True" VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto"/>
<Button Grid.Column="1" x:Name="buttonSentMessage" Width="80" Height="30" Content="Отправить" Click="Button_Click" />
</Grid>
Свойства:
AcceptsReturn="True" - служит для того, чтобы переводить по нажатию на клавишу Enter курсор на следующую строку.
VerticalScrollBarVisibility="Auto" и HorizontalScrollBarVisibility="Auto" - служит для отображения полос прокрутки TextBox поддерживает свойства.
Элемент: Button - где ему дал имя в свойстве: x:Name="buttonSentMessage"(это имя будет использоваться в коде).
Надпись(содержание), которая отображается на самой кнопке находится в свойстве: Content="Отправить".
Событие: Click="Button_Click" с собственным названием.
В коде будет примерно так(при нажатие на эту кнопку, выскакивает сообщение "Кнопка была нажата!"):
private
void
Button_Click(object
sender, RoutedEventArgs e)
{
MessageBox.Show("Кнопка была нажата!");
}
На этом шаге с оформлением останавливаюсь.
Продолжение следует.....
#WPF,#Csharp
Продолжаю работать с ZennoPoster - ом. На этот раз задача состоит в том, чтобы отсылать сообщения в Telegram используя бота.
В начале, для того чтобы пользоваться им, необходимо получить токен доступа для него в telegram.
Наши действия:
1. Находим и добавляем в телеграм контакт @BotFather.
2. Заходим к нему в чат. Вызываем команду: /start
далее: /newbot.
3. Печатаем имя нашего бота(например имя моего бота "vkbotanswer").
4. Далее username(обязательно с окончанием "bot")
5. В ответном сообщение получаем токен нашего бота.
6. Дальше добавляем нашего бота(как "администратора") в необходимый канал и одновременно получаем id этого канала, перейдя по ссылке.
https://api.telegram.org/bot1351987:AAGvMM26veDkzXyV72L1PU_7L0jjkO/getUpdates
где: 1351987:AAGvMM26veDkzXyV72L1PU_7L0jjkO(полученный токен доступа).
Внимание: id канала имеет всегда знак "-" т.е. такой вид: -1005758311 .
7. На этом бот наш готов и мы можем отсылать наше сообщение(пример запроса):
https://api.telegram.org/bot1351987:AAGvMM26veDkzXyV72L1PU_7L0jjkO/sendMessage?chat_id=-1005758311&text=Приветствую!Меня зовут vkbotanswer и я готов к вашим командам.
Продолжение следует.....
#ZennoPoster
В начале, для того чтобы пользоваться им, необходимо получить токен доступа для него в telegram.
Наши действия:
1. Находим и добавляем в телеграм контакт @BotFather.
2. Заходим к нему в чат. Вызываем команду: /start
далее: /newbot.
3. Печатаем имя нашего бота(например имя моего бота "vkbotanswer").
4. Далее username(обязательно с окончанием "bot")
5. В ответном сообщение получаем токен нашего бота.
6. Дальше добавляем нашего бота(как "администратора") в необходимый канал и одновременно получаем id этого канала, перейдя по ссылке.
https://api.telegram.org/bot1351987:AAGvMM26veDkzXyV72L1PU_7L0jjkO/getUpdates
где: 1351987:AAGvMM26veDkzXyV72L1PU_7L0jjkO(полученный токен доступа).
Внимание: id канала имеет всегда знак "-" т.е. такой вид: -1005758311 .
7. На этом бот наш готов и мы можем отсылать наше сообщение(пример запроса):
https://api.telegram.org/bot1351987:AAGvMM26veDkzXyV72L1PU_7L0jjkO/sendMessage?chat_id=-1005758311&text=Приветствую!Меня зовут vkbotanswer и я готов к вашим командам.
Продолжение следует.....
#ZennoPoster
Forwarded from vladimir
Сегодня продолжю работать с ZennoPoster и Telegram, но уже в видео формате.
Основные шаги.
1. Создание проекта.
2. Создание переменных.
3. Отправка сообщения в ТГ, 2-мя способами.
#ZennoPoster, #Telegram
Основные шаги.
1. Создание проекта.
2. Создание переменных.
3. Отправка сообщения в ТГ, 2-мя способами.
#ZennoPoster, #Telegram
Media is too big
VIEW IN TELEGRAM
Отправление фото и видео в Telegram используя ZennoPoster и библиотеку "Telegram.Bot"
#ZennoPoster, #Telegram
#ZennoPoster, #Telegram
This media is not supported in your browser
VIEW IN TELEGRAM
Продолжаем работу в программе ZennoPoster, но на этот раз рассматриваю пример работы с Датами.
// Получаем время из переменной с указанием часовго пояса: 15.02.2022 12:00 +00:00
/* 1. Вариат с использованием struct DateTimeOffset .*/
// Парсим и сохраняем значение времени в struct DateTimeOffset.
// Преобразуем struct DateTimeOffset в struct DateTime(для дальнейшей работы).
// Выводим сообщение в лог.
/* 2. Вариат без использования struct DateTimeOffset .*/
// Конвертируем в struct DateTime.
// Выводим сообщение в лог.
/* 3. Получение кол-во времени до события исходя из текущего согласно нашего часового пояса и времени начало самого события.*/
// Получение текущего времени согласно нашего часового пояса.
// Выводим сообщение в лог.
// Преобразование текущего времени согласно нашего часового пояса в UTC.
// Выводим сообщение в лог.
// Подсчёт кол-во времени до события.
// Выводим сообщение в лог.
#ZennoPoster, #DateTime
string capDateAndTimeRunRegistrationInSeil = project.Variables["capDateAndTimeRunRegistrationInSeil"].Value;
/* 1. Вариат с использованием struct DateTimeOffset .*/
// Парсим и сохраняем значение времени в struct DateTimeOffset.
var dtOffset_forSeil = DateTimeOffset.Parse(capDateAndTimeRunRegistrationInSeil);
// Преобразуем struct DateTimeOffset в struct DateTime(для дальнейшей работы).
var time_forSeil_DtOff = dtOffset_forSeil.DateTime;
// Выводим сообщение в лог.
project.SendToLog("ВРЕМЯ РЕГИСТРАЦИИ С ПОМОЩЬЮ DateTimeOffset: " + time_forSeil_DtOff.ToString("dd.MM.yyyy HH:mm:ss"), ZennoLab.InterfacesLibrary.Enums.Log.LogType.Info, true, ZennoLab.InterfacesLibrary.Enums.Log.LogColor.Yellow);
/* 2. Вариат без использования struct DateTimeOffset .*/
// Конвертируем в struct DateTime.
var time_forSeil_Dt = Convert.ToDateTime(capDateAndTimeRunRegistrationInSeil);
// Выводим сообщение в лог.
project.SendToLog("ВРЕМЯ РЕГИСТРАЦИИ С ПОМОЩЬЮ БЕЗ DateTimeOffset: " + time_forSeil_Dt.ToString("dd.MM.yyyy HH:mm:ss"), ZennoLab.InterfacesLibrary.Enums.Log.LogType.Info, true, ZennoLab.InterfacesLibrary.Enums.Log.LogColor.Yellow);
/* 3. Получение кол-во времени до события исходя из текущего согласно нашего часового пояса и времени начало самого события.*/
// Получение текущего времени согласно нашего часового пояса.
DateTime dtNow = DateTime.Now;
// Выводим сообщение в лог.
project.SendToLog("ТЕКУЩЕЕ ВРЕМЯ СОГЛАСНО НАШЕГО ЧАСОВОГО ПОЯСА: " + dtNow.ToString("dd.MM.yyyy HH:mm:ss"), ZennoLab.InterfacesLibrary.Enums.Log.LogType.Info, true, ZennoLab.InterfacesLibrary.Enums.Log.LogColor.Green);
// Преобразование текущего времени согласно нашего часового пояса в UTC.
var utcTime_forNow = dtNow.ToUniversalTime();
// Выводим сообщение в лог.
project.SendToLog("ТЕКУЩЕЕ ВРЕМЯ СОГЛАСНО UTC: " + utcTime_forNow.ToString("dd.MM.yyyy HH:mm:ss"), ZennoLab.InterfacesLibrary.Enums.Log.LogType.Info, true, ZennoLab.InterfacesLibrary.Enums.Log.LogColor.Green);
// Подсчёт кол-во времени до события.
TimeSpan diff = time_forSeil_DtOff.Subtract(utcTime_forNow);
// Выводим сообщение в лог.
project.SendToLog("ОСТАЛОСЬ ВРЕМЕНИ ДО РЕГИСТРАЦИИ СОГЛАСНО UTC(ЗАДАННОГО ВРЕМЕНИ) И НАШЕГО ВРЕМЕНИ(СКОНВЕРТИРОВАННОЕ В UTC): " + diff.Days.ToString("0") + " дн. " + diff.Hours.ToString("0") + " час. " + diff.Minutes.ToString("0") + " мин.", ZennoLab.InterfacesLibrary.Enums.Log.LogType.Info, true, ZennoLab.InterfacesLibrary.Enums.Log.LogColor.Orange);
#ZennoPoster, #DateTime
Рассматриваю интересные моменты для получения информации используя метод из API Zennoposter: GetChildren.
1. Кол-во блоков с которых необходимо получить информацию из списка.
Итог: Метод
#ZennoPoster, #Xpath
1. Кол-во блоков с которых необходимо получить информацию из списка.
HtmlElementCollection entries = instance.ActiveTab.FindElementsByXPath("//div[contains(@class,'postlist') and contains(@id,'postsList')]/div");
int countBlocks = entries.Count;
2. Получение блоков в которых содержаться две необходимые части(текст и фото).HtmlElement entry = instance.ActiveTab.FindElementByXPath("//div[contains(@class,'postlist') and contains(@id,'postsList')]/div", numRow);
numRow
- номер блока для парсинга.HtmlElementCollection entries_m = entry.GetChildren(false);
Рекомендую посмотреть на этот метод: GetChildren(false);
Позволяет получить элементы(детей) от главного элемента(родителя). С ним можно "творить" настоящие чудеса т.к. идёт упрощение кода и нет необходимости писать доп.-ые xpath запросы, чтобы обратиться к нужному элементу.for (p = 0; p < entries_m.Count; p++)
{
HtmlElementCollection entries = entries_m.Elements[p].GetChildren(false);
for (s = 0; s < entries.Count; s++)
{
HtmlElementCollection entries_ = entries.Elements[s].GetChildren(false);
for (m = 0; m < entries_.Count; m++)
{
if (string.IsNullOrEmpty(postTitle))
{
postTitle = entries_.Elements[m].InnerHtml;
project.SendInfoToLog(postTitle);
break;
}
}
}
}
entries_m.Count
- полученное кол-во блоков, которое равно 2(т.е. текстовая и фото).HtmlElementCollection entries = entries_m.Elements[p].GetChildren(false);
entries_m.Elements[p].GetChildren(false)
- здесь обращаемся к нужному элементу согласно индекса(т.е. 0), из которого также получаем "детей" элемента.Итог: Метод
GetChildren
очень мощный метод, который даёт возможность обращаться к нижестоящим элементам без Xpath запросов.#ZennoPoster, #Xpath
Затрону тему с LINQ запросами и не только:
#LINQ , #CSharp
static void Main(string[] args)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("LINQ");
// Создание списка с произвольными числами.
List<int> numbers = new List<int> { 1, 5, 10, 12, -1, -300, 500 };
Console.WriteLine($"Min число: {numbers.Min()}");
Console.WriteLine($"Max число: {numbers.Max()}");
Console.WriteLine($"Кол-во чисел в списке: {numbers.Count()}");
Console.WriteLine($"Кол-во чисел в списке больше 0: {numbers.Count(x => x > 0)}");
Console.WriteLine($"Сумма отрицательных чисел:{numbers.Where(x => x < 0).Sum()}");
Console.ReadLine();
Console.ForegroundColor = ConsoleColor.Yellow;
// Генерация чётных чисел.
Console.WriteLine("Генерация чётных чисел");
var result = Enumerable.Range(-4, 10).Where(x => x % 2 == 0);
foreach (var item in result)
{
Console.Write(item + "\t");
}
Console.ForegroundColor = ConsoleColor.Green;
// Повторение объекта.
Console.WriteLine(" ");
Console.WriteLine(" ");
Console.WriteLine("Повторение объектов");
var repeat = Enumerable.Repeat("Привет мир!", 5);
foreach (var item in repeat)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
}
#LINQ , #CSharp
Столкнулся с задачей для сервиса imgbb.com (загрузка фото), точнее с его API. Вроде всё элементарно, но оказалось чуть сложнее, чем на первый взгляд.
Выделяю 3 ключевых момента, на которые необходимо сделать акцент.
1.Обязательно конвертировать фото в base64
2.Обязательно создать экземпляр класса StringContent
3.Обязательно загружать фото используя экземпляр класса MultipartFormDataContent
Вроде всего 3 акцента, но о них нигде и ничего не пишется на их странице, особенно о Multipart.
#API, #POST, #GET, #CSharp
Выделяю 3 ключевых момента, на которые необходимо сделать акцент.
foreach (string pathFile in project.Lists["pathToFoto"])
{
if (!string.IsNullOrEmpty(pathFile.Trim()))
{
string url = $"https://api.imgbb.com/1/upload?key={project.Variables["apiKey"].Value}";
string base64String = null;
1.Обязательно конвертировать фото в base64
using (Image image = Image.FromFile(pathFile))
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
byte[] imageBytes = m.ToArray();
base64String = Convert.ToBase64String(imageBytes);
}
}
HttpClient client = new HttpClient();
2.Обязательно создать экземпляр класса StringContent
StringContent fotoContent = new StringContent(base64String, Encoding.UTF8);
3.Обязательно загружать фото используя экземпляр класса MultipartFormDataContent
var content = new MultipartFormDataContent();
content.Add(fotoContent, "image");
var result = client.PostAsync(url, content);
int code = result.Result.StatusCode.GetHashCode();
Thread.Sleep(1000);
if(result.Result.StatusCode.GetHashCode() != 200) throw new Exception("Problem WITH LOAD FOTO");
string jsonResult = result.Result.Content.ReadAsStringAsync().Result;
}
}
Вроде всего 3 акцента, но о них нигде и ничего не пишется на их странице, особенно о Multipart.
#API, #POST, #GET, #CSharp
Немного предыстории.
Заказчик хотел получать сигналы от биржи в телеграмм используя Emoji.
На первый взгляд, всё просто, если вы знаете как...., но тут явного решения не было, поэтому пришлось напрячься, чтобы найти его.
1. Переходим на сайт с emoji (пример: unicode-table.com)
2. Копируем emoji в Юникоде.
3. Пишем код:
// Читаем данные для нашего бота с ранее подготовленного .json
// Создаём экземпляр класса TelegramBotClient используя ITelegramBotClient
// Получаем чат ID.
// Эмоджи в Юникоде.
// Парсим в INT эмоджи, но уже "1F600"(т.е. без 1-х 2-х знаков), через HexNumber(шестнадцатеричное число)
// Отсылаем сообщение.
// Метод получение данных из .json
На этом всё. Код работает.
#Telegram, #CSharp
Заказчик хотел получать сигналы от биржи в телеграмм используя Emoji.
На первый взгляд, всё просто, если вы знаете как...., но тут явного решения не было, поэтому пришлось напрячься, чтобы найти его.
1. Переходим на сайт с emoji (пример: unicode-table.com)
2. Копируем emoji в Юникоде.
3. Пишем код:
private static ITelegramBotClient _botClient;
static void Main(string[] args)
{
// Читаем данные для нашего бота с ранее подготовленного .json
BotData botData = GetUserCredential<BotData>();
// Создаём экземпляр класса TelegramBotClient используя ITelegramBotClient
_botClient = new TelegramBotClient(botData.Token);
// Получаем чат ID.
string chatID = botData.Chat;
// Эмоджи в Юникоде.
string emoji = "U+1F600";
// Парсим в INT эмоджи, но уже "1F600"(т.е. без 1-х 2-х знаков), через HexNumber(шестнадцатеричное число)
int _emoji = int.Parse(emoji.Substring(2), NumberStyles.HexNumber);
// Отсылаем сообщение.
_botClient.SendTextMessageAsync(chatID, "Как прекрасен этот мир! " + char.ConvertFromUtf32(_emoji)).Wait();
}
// Метод получение данных из .json
private static T GetUserCredential<T>()
{
using (var fileStream = new FileStream("TGbot.json", FileMode.Open, FileAccess.Read))
{
string contents;
using (var sr = new StreamReader(fileStream))
{
contents = sr.ReadToEnd();
}
return JsonConvert.DeserializeObject<T>(contents);
}
}
На этом всё. Код работает.
#Telegram, #CSharp
Публикация приложения одна из простых и желанных вещей в программирование. Поэтому покажу как происходит это у меня: