Продолжаем знакомство с рефлексией, и будем получать информацию о классе и о методах в нём.
Рассматриваем проект, который реализовали ранее.
1. Открываем файл "MainWindow.xaml.cs", который был создан автоматически.
2.Подключаем пространство имён.
3. Метод который описывает действие, которое происходит при нажатие на кнопку(которую создали в прошлый раз).
3.1. Имя нашего текстового блока, который расположен в
нашей разметке.
3.2. Поучаем экземпляр класса Туре, в котором прописываем
"полное имя типа(нашего класса) в строковом
представлении".
3.3. Устанавливаем размер шрифта, для нашего текстового
блока.
3.4. Получаем разную информацию о классе с помощью
методов класса Type.
3.5. Получаем информацию о методах, которые существуют в
этом классе.
Рассмотрел простейшие примеры, но уже и они показывают возможности рефлексии, которые помогают нам узнать некоторые вещи.
#Рефлексия, #Csharp
Рассматриваем проект, который реализовали ранее.
1. Открываем файл "MainWindow.xaml.cs", который был создан автоматически.
2.Подключаем пространство имён.
using System;
using System.Reflection;
using System.Windows;
3. Метод который описывает действие, которое происходит при нажатие на кнопку(которую создали в прошлый раз).
private void GetHumanMethodNames_OnClick(object sender, RoutedEventArgs e)
{
3.1. Имя нашего текстового блока, который расположен в
нашей разметке.
Output.Text = "";
3.2. Поучаем экземпляр класса Туре, в котором прописываем
"полное имя типа(нашего класса) в строковом
представлении".
var infoAboutClass = Type.GetType("HumanizerDemo.Binance",false,true);
3.3. Устанавливаем размер шрифта, для нашего текстового
блока.
Output.FontSize = 16;
3.4. Получаем разную информацию о классе с помощью
методов класса Type.
Output.Text += "Получаем разную информацию о классе с помощью методов класса Type";
Output.Text += Environment.NewLine;
Output.Text += Environment.NewLine;
Output.Text += "Полное Имя: " + infoAboutClass.FullName;
Output.Text += Environment.NewLine;
Output.Text += "Базовый класс: " + infoAboutClass.BaseType.ToString();
Output.Text += Environment.NewLine;
Output.Text += "Абстрактный: " + infoAboutClass.IsAbstract.ToString();
Output.Text += Environment.NewLine;
Output.Text += "Запрещено наследование: " + infoAboutClass.IsSealed.ToString();
Output.Text += Environment.NewLine;
Output.Text += "class: " + infoAboutClass.IsClass.ToString();
Output.Text += Environment.NewLine;
Output.Text += "Публичный: " + infoAboutClass.IsPublic.ToString();
Output.Text += Environment.NewLine;
Output.Text += Environment.NewLine;
3.5. Получаем информацию о методах, которые существуют в
этом классе.
MethodInfo[] mi = infoAboutClass.GetMethods(BindingFlags.Instance
| BindingFlags.Static
| BindingFlags.Public
| BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
Output.Text += "Получаем информацию о методах";
Output.Text += Environment.NewLine;
Output.Text += Environment.NewLine;
foreach (MethodInfo imi in mi)
{
Output.Text += "Полное Имя: " + imi.Name.ToString();
Output.Text += Environment.NewLine;
}
}
Рассмотрел простейшие примеры, но уже и они показывают возможности рефлексии, которые помогают нам узнать некоторые вещи.
#Рефлексия, #Csharp
Продолжаем работать со временем.
В прошлом примере, был получен список 'lstTemp' с временем.
Список выглядит так:
23 часов 58 минут,
23 часов 53 минут,
19 часов 9 минут,
23 часов 57 минут,
и т.д.
Наша цель преобразовать время, которое сейчас является типом данных "string" в тип данных "DateTime".
В C# существуют 2 метода(самые популярные), которые пытаются конвертировать "string" => "DateTime". Рассмотрим их более подробно.
1. DateTime.ParseExact(string s, string format, IFormatProvider? provider) - этот метод в качестве аргументов, кроме строки с датой, принимает еще строку в которой указан формат представления даты, а так же строку с указанием культуры, в которой принято такое представление.
Пример:
Пример:
Поэтому будет разбивать на определённые этапы:
1. Создаёт список с типом данных 'DateTime':
3. Конвертируем и сохраняем полученное время в ранее созданный список 'listTimeTemp':
#Csharp, #Дата
В прошлом примере, был получен список 'lstTemp' с временем.
Список выглядит так:
23 часов 58 минут,
23 часов 53 минут,
19 часов 9 минут,
23 часов 57 минут,
и т.д.
Наша цель преобразовать время, которое сейчас является типом данных "string" в тип данных "DateTime".
В C# существуют 2 метода(самые популярные), которые пытаются конвертировать "string" => "DateTime". Рассмотрим их более подробно.
1. DateTime.ParseExact(string s, string format, IFormatProvider? provider) - этот метод в качестве аргументов, кроме строки с датой, принимает еще строку в которой указан формат представления даты, а так же строку с указанием культуры, в которой принято такое представление.
Пример:
string time = "2021 Четверг октябрь 28 16:01";
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CreateSpecificCulture("ru-RU");
DateTime dt = DateTime.ParseExact(time, "yyyy dddd MMMM dd HH:mm", culture);
Результат: 23.06.2020 14:35:00
2.DateTime.Parse(string s) - этот метод в качестве аргумента принимает строку с датой.Пример:
string time = "23:58";
DateTime dt = = DateTime.Parse(time);
Результат: 28.10.2021 23:58:00
Методы существуют, но в нашем случае они не подходят т.к. не смогут распознать формат такого времени: "23 часов 58 минут".Поэтому будет разбивать на определённые этапы:
1. Создаёт список с типом данных 'DateTime':
var listTimeTemp = new List<DateTime>();
2. Подготовим время в нормальный формат с помощью регулярного выражения, который поймёт метод: DateTime.Parse(string s):tmpData = Regex.Replace(tmpData, @"ча.*?\s", ":");
tmpData = Regex.Replace(tmpData, @"мин.*", "");
после чистки, время уже будет иметь вот такой формат: "23:58"3. Конвертируем и сохраняем полученное время в ранее созданный список 'listTimeTemp':
listTimeTemp.Add(DateTime.Parse(tmpData));
4. Сортируем полученное время в порядке возрастания с помощью 'Linq':listTimeTemp.Sort((a, b) => a.CompareTo(b));
5. Создаёт список с типом данных 'double':var totalMinutes = new List<double>();
6. Создаём цикл для списка 'listTimeTemp'( для того, чтобы получить минуты из часов и минуты из минут, соответственно. Формат времени из которого берутся эти данные:'28.10.2021 23:58:00'(пример)): foreach (var hours in listTimeTemp)
{
int minutesFromHours = hours.Hour * 60;
int minutesFromMinutes = hours.Minute;
totalMinutes.Add(minutesFromHours + minutesFromMinutes);
}
7. Получаем среднюю сумму значения всех полученных минут из списка 'totalMinutes'.var sum = totalMinutes.Sum() / listTimeTemp.Count;
8. Создаём объект 'TimeSpan', для того, чтобы из средней суммы, которую получили выше, получить часы и минуты:TimeSpan ts = TimeSpan.FromMinutes(sum);
int midHours = ts.Hours;
int midMinutes = ts.Minutes;
9. Пример результата:string res = ts.Hours.Tostring() + ":" + ts.Minutes.Tostring();
"22:52" - наше полученное искомое среднее время.
10. Пример всего кода:var tmpData = string.Empty;
var listTimeTemp = new List<DateTime>();
for (x = 0; x < lstTemp.Count; x++)
{
tmpData = lstTemp[x].Trim();
tmpData = Regex.Replace(tmpData, @"ча.*?\s", ":");
tmpData = Regex.Replace(tmpData, @"мин.*", "");
listTimeTemp.Add(DateTime.Parse(tmpData));
}
listTimeTemp.Sort((a, b) => a.CompareTo(b));
var totalMinutes = new List<double>();
foreach (var hours in listTimeTemp)
{
int minutesFromHours = hours.Hour * 60;
int minutesFromMinutes = hours.Minute;
totalMinutes.Add(minutesFromHours +
minutesFromMinutes);
}
var sum = totalMinutes.Sum() / listTimeTemp.Count;
TimeSpan ts = TimeSpan.FromMinutes(sum);
int midHours = ts.Hours;
int midMinutes = ts.Minutes;
string res = ts.Hours.Tostring() + ":" + ts.Minutes.Tostring();
В этом примере рассмотрел те вещи, которые можно делать используя 'DateTime' и 'TimeSpan'.#Csharp, #Дата
Необходимо передавать картинку Post/Get запросами. Подумав, а почему не передавать с помощью кодировки base64?
Пример: №1 (картинку в base64):
1. Путь к нашей картинке и переменную для нашей кодировки base64(тип данных string).
2. Создаём кодировку base64 из нашей картинки, как строку(тип данных string).
2.1. Рекомендую использовать оператор "using" - для того, чтобы правильно освобождать,сбрасывать,удалять неуправляемые ресурсы(аналог метода Dispose)
2.2. Получаем нашу картинку из файла.
{
2.3. Для чтения/записи данных в память, в виде массива, используя класс MemoryStream.
{
2.4. Сохраняем нашу картинку в экземпляр класса MemoryStream.
}
}
3. Полученную строку base64String, уже можем передавать, сохранять и делать с ней что угодно.
3.1. Сервис для просмотра полученной картинки из кодировки base64(тип данных string)
Продолжение следует....
#Csharp, #base64
Пример кодировки.
Пример: №1 (картинку в base64):
1. Путь к нашей картинке и переменную для нашей кодировки base64(тип данных string).
string pathFile = "D:\1_picture.jpeg";
string base64String = null;
2. Создаём кодировку base64 из нашей картинки, как строку(тип данных string).
2.1. Рекомендую использовать оператор "using" - для того, чтобы правильно освобождать,сбрасывать,удалять неуправляемые ресурсы(аналог метода Dispose)
2.2. Получаем нашу картинку из файла.
using (Image image = Image.FromFile(pathFile)
{
2.3. Для чтения/записи данных в память, в виде массива, используя класс MemoryStream.
using (MemoryStream m = new MemoryStream())
{
2.4. Сохраняем нашу картинку в экземпляр класса MemoryStream.
image.Save(m, image.RawFormat);
2.5. Получаем массив для дальнейшей конвертации.byte[] imageBytes = m.ToArray();
2.6. Получаем кодировку картинки в base64. base64String = Convert.ToBase64String(imageBytes);
}
}
3. Полученную строку base64String, уже можем передавать, сохранять и делать с ней что угодно.
3.1. Сервис для просмотра полученной картинки из кодировки base64(тип данных string)
Продолжение следует....
#Csharp, #base64
Пример кодировки.
В предыдущем примере рассмотрел случай кодирования картинку в base64.
Теперь рассмотрим обратный случай.
Пример: №2 (base64 в картинку):
1. Инициализируем новые переменные: путь к нашей картинке и кодировку base64.
2. Получаем массив из переменной base64StringNew.
3. Используем оператор "using"(рекомендую) для работы с картинкой.
3.1. Создаём картинку из полученного массива и сохраняем её, согласно нашего пути (pathFileNew).
Все эти случаи в практике используются довольно часто: сервисы для решения каптч, создание сайтов, работа с Б.Д.
Кодирование и декодирование в base64 - это очень полезная вещь.
#Csharp, #base64
Результаты кодирования и декодирования.
Теперь рассмотрим обратный случай.
Пример: №2 (base64 в картинку):
1. Инициализируем новые переменные: путь к нашей картинке и кодировку base64.
string pathFileNew = "D:\1_pictureCopy.jpeg";
string base64StringNew = base64String
(полученная кодировка base64 из пред. примера);2. Получаем массив из переменной base64StringNew.
byte[] imgBytes = Convert.FromBase64String(base64StringNew);
3. Используем оператор "using"(рекомендую) для работы с картинкой.
using (var imageFile = new FileStream(pathFileNew, FileMode.Create))
{
3.1. Создаём картинку из полученного массива и сохраняем её, согласно нашего пути (pathFileNew).
imageFile.Write(imgBytes, 0, imgBytes.Length);
imageFile.Flush();
}
Все эти случаи в практике используются довольно часто: сервисы для решения каптч, создание сайтов, работа с Б.Д.
Кодирование и декодирование в base64 - это очень полезная вещь.
#Csharp, #base64
Результаты кодирования и декодирования.
Продолжаю писать статьи связанные с созданием приложения используя WPF. Даю ссылку на свой прошлый пост, где касался слегка этой темы.
Планирую написать ряд статей по созданию приложения, которое отсылает текстовые сообщения в ТГ(телеграм), используя его API.
Почему? Потому что, написания приложений используя API ТГ в "тренде" и полагаю он ещё будет долгое время.
В этой части статьи покажу весь код XAML файла, который реализовал т.е. интерфейс самой программы.
Основной код:
В дальнейшем опишу, почему использовал эти блоки и некоторую логику самого приложения.
В результате создания приложения этот код будет корректироваться.
#WPF, #Csharp
Планирую написать ряд статей по созданию приложения, которое отсылает текстовые сообщения в ТГ(телеграм), используя его API.
Почему? Потому что, написания приложений используя API ТГ в "тренде" и полагаю он ещё будет долгое время.
В этой части статьи покажу весь код XAML файла, который реализовал т.е. интерфейс самой программы.
Основной код:
<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">
<DockPanel LastChildFill="True">
<Menu DockPanel.Dock="Top">
<MenuItem Header="Данные">
<MenuItem Header="Сохранить"
Command=""/>
<Separator/>
<MenuItem Header="Выход"
Click="MenuItem_Click"/>
</MenuItem>
</Menu>
<ListView DockPanel.Dock="Left"
Background="MidnightBlue"
Width="140">
<TextBlock Text="Новое сообщение:" Foreground="White"/>
</ListView>
<StatusBar DockPanel.Dock="Bottom">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<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>
</StatusBar>
<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="60" Height="30" Content="Нажать" Click="Button_Click" />
</Grid>
</DockPanel>
</Window>
В дальнейшем опишу, почему использовал эти блоки и некоторую логику самого приложения.
В результате создания приложения этот код будет корректироваться.
#WPF, #Csharp
Рассматриваю более детальнее код, который опубликовал в прошлой статье.
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
Затрону тему с 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
Хочу сегодня добавить несколько сниппетов по LINQ запросам:
1. Поиск текста по регулярке, множество совпадений в список:
2. Создать список ID(индексы строк), в которых содержатся необходимый ключ(особенность: создание анонимного типа с свойствами(Index и Value)):
3. Получение суммы из списка, которые имеет тип данных string(List<string>) т.е. необходимо значения string сконвертировать в int:
4. Создание Dictionary<string,string> из двух разных Списков(List<string>):
5. Создание списка из двух списков, в которых значения не совпадают(т.е. в одном списке, есть в другом нет и те значения, которых нет в другом списке добавляем в новый третий список):
Получается новый список "compR_GBD" состоящий из этих двух значений(
#LINQ , #CSharp
1. Поиск текста по регулярке, множество совпадений в список:
Regex regexJson = new Regex(@"[a-zA-Z0-9]{20,}.*?}");
List<string> tmpList = regexJson.Matches(result).Cast<Match>().Select(m => m.Value).ToList();
List<string> resultsList = tmpList.Where(s => s.Contains("index") && s.Contains("id") && s.Contains("brandId") && !s.Contains("Отзывы") && !s.Contains("advert")).ToList();
2. Создать список ID(индексы строк), в которых содержатся необходимый ключ(особенность: создание анонимного типа с свойствами(Index и Value)):
tmpList.Select((v, i) => new { Index = i, Value = v })
.Where(p => p.Value.Contains("brandId")).Select(p => p.Index.ToString()).ToList();
3. Получение суммы из списка, которые имеет тип данных string(List<string>) т.е. необходимо значения string сконвертировать в int:
var sumTempResList = tmpResList.Where(d => !string.IsNullOrEmpty(d.Trim())).Select(s => int.Parse(s.Replace("-",""))).ToList().Sum();
4. Создание Dictionary<string,string> из двух разных Списков(List<string>):
List<string> keysList = new List<string>{"2569746", "9876415", "6957459"};
List<string> valuesList = new List<string>{"val1", "val2", "val3"};
Dictionary<string,string> resDict = keysList.Zip(valuesList, (k, v) => new { k, v }).ToDictionary(x => x.k, x => x.v);
5. Создание списка из двух списков, в которых значения не совпадают(т.е. в одном списке, есть в другом нет и те значения, которых нет в другом списке добавляем в новый третий список):
List<string> artsG = new List<string>{"2569746", "9876415", "6957459", "5947945", "9874647"};
List<string> skues = new List<string>{"2569746", "9876415", "6957459"};
List<string> compR_GBD = artsG.Where(n => !skues.Any(s => s.ToLower() == n.ToLower())).ToList();
Получается новый список "compR_GBD" состоящий из этих двух значений(
"5947945", "9874647"
)#LINQ , #CSharp
Многие из вас уже знакомы с chatgpt. Не так давно, необходимо было реализовать задачу, по распознаванию фото Локально.
Работаем через API.
1.) Обращаемся к официальной документации по ссылке:
https://platform.openai.com/docs/api-reference/chat/create
( create chat completion )
2.) Выбираем необходимое меню(как на картинке).
3.) Копируем и корректируем код(т.к. там, только через URL, распознаётся фото), нам же надо, если фото находится локально.
Пример моего Кода(Будьте очень Внимательны при его Использование):
4.) Получаем результат и радуемся.
P.S. Внимание!! Распознавание через API в разы хуже, чем через WEB.
#chatgpt, #Csharp, #zennoposter
Работаем через API.
1.) Обращаемся к официальной документации по ссылке:
https://platform.openai.com/docs/api-reference/chat/create
( create chat completion )
2.) Выбираем необходимое меню(как на картинке).
3.) Копируем и корректируем код(т.к. там, только через URL, распознаётся фото), нам же надо, если фото находится локально.
Пример моего Кода(Будьте очень Внимательны при его Использование):
string access_token_chatGpt = project.Variables["access_token_chatGpt"].Value;
//СТАРТ. Чтение файла в котором находится задание для ChatGPT
string pathToFileTaskForDescreptionPicture = project.Variables["pathToFileTaskForDescreptionPicture"].Value;
var taskForDescreptionPicture = string.Join(Environment.NewLine, File.ReadAllLines(pathToFileTaskForDescreptionPicture).ToList().Where(s => !string.IsNullOrEmpty(s)).ToList());
//ФИНИШ.
project.Variables["descreption"].Value = string.Empty;
string url = "https://api.openai.com/v1/chat/completions";
string imagePath = project.Variables["imageFilepath"].Value;
string image_url = imagePath;
string taskFrom = string.Empty;
base64Image = string.Empty;
/*Конвертация локального фото в
необходимую строку для распознавания, вместо адреса URL*/
string base64Image = Convert.ToBase64String(File.ReadAllBytes(imagePath));
image_url = $"data:image/jpeg;base64,{base64Image}";
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", access_token_chatGpt);
client.DefaultRequestHeaders.Host = "api.openai.com";
var requestData = new
{
model = "gpt-4o",
messages = new []
{
new
{
role = "user",
content = new object[]
{
new
{
type = "text", text = taskForDescreptionPicture,
},
new
{
type = "image_url",
image_url = new
{
url = image_url,
detail = "high"
}
}
}
}
},
max_tokens = 500
};
string jsonRequest = JsonConvert.SerializeObject(requestData);
var content = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
HttpResponseMessage response = client.PostAsync(url, content).Result;
string responseData = response.Content.ReadAsStringAsync().Result;
if (response.IsSuccessStatusCode)
{
project.Variables["descreption"].Value = responseData;
}
else
{
project.Variables["batch"].Value = responseData;
throw new Exception("");
}
4.) Получаем результат и радуемся.
P.S. Внимание!! Распознавание через API в разы хуже, чем через WEB.
#chatgpt, #Csharp, #zennoposter
Часто бывает, что есть ключевые слова, которые должны присутствовать в строке, которую анализируем.
Использую такое решение.
1.) Создаю список с "ключевыми словами"
2.) Список(результат) в котором содержатся строки, в которых есть необходимы ключи.
3.) Список(входные данные) строк, которые необходимо Проверить
3.) Основная логика.
#LINQ , #CSharp
Использую такое решение.
1.) Создаю список с "ключевыми словами"
List<string> socialUrls = new List<string>()
{
"youtube.com", "facebook.com", "x.com", "tiktok.com", "onlyfans.com"
};
string url = string.Empty;
2.) Список(результат) в котором содержатся строки, в которых есть необходимы ключи.
List<string> sringWithKeys = new List<string>();
3.) Список(входные данные) строк, которые необходимо Проверить
List<string> valuesOfInnerHtml= project.Lists["valuesOfInnerHtml"].ToList();
3.) Основная логика.
for(int x = 0; x < valuesOfInnerHtml.Count; x++ )
{
url = valuesOfInnerHtml[x];
try
{
url = tab.URL.Replace("&", "&");
// LINQ запрос для проверки ключа в строке из списка
if (socialUrls.Any(url.Contains)) sringsWithKeys .Add(url);
}catch
{
throw new Exception("mistake");
}
}
if (sringsWithKeys .Count == 0) throw new Exception("list is empty");
#LINQ , #CSharp