События в C# или как сделать свой Event

Events – это события которые вызывает ваш класс, информируя тем самым своих подписчиков о том что произошло какое-то либо событие.
Если вам нужно передавать какие-либо параметры то кроме самого event’a вам нужно реализовать свой класс EventArgs через который вы и будете передавать параметры.

//создаем своей EventArgs.
public class TestEventArgs: EventArgs
{
public TestEventArgs(string s) { Text = s; }
public String Text {get; set;} 
}
public class Publisher
{
// создали делегат
public delegate void TestEventHandler(object sender, TestEventArgs e);
// объявили event
public event TestEventHandler TestEvent;
// функция вызова делегата
protected virtual void DoSomethingEvent()
{
if (TestEvent != null)
TestEvent(this, new TestEventArgs("Hi"));
}
}

 или

public class Publisher
{
	// объявили event
	public event EventHandler<TestEventArgs> TestEvent;
	// функция вызова делегата           
	protected virtual void DoSomethingEvent()
	{
		var handler = Interlocked.CompareExchange(ref this.TestEvent, null, null);

		if (handler != null)
		{
			handler(this, new TestEventArgs("Hi"));
		}
	}
}

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

if (TestEvent != null)
TestEvent(this, new TestEventArgs("Hi"));

А еще лучше вот так:

var handler = Interlocked.CompareExchange(ref this.TestEvent, null, null);

                if (handler != null)
                {
                    handler(this, new TestEventArgs("Hi"));
                }

Если проверки не сделать, то у вас может образоваться исключение.

Ну и в завершении, подписываться на события:

Test.TestEvent += new TestEventHandler();

Или так:

var handler = Volatile.Read(ref this.TestEvent);

                if (handler != null)
                {
                    handler(this, new TestEventArgs("Hi"));
                }

Или вот так, для C# 6:

Volatile.Read(ref this.TestEvent)?.Invoke(this, new TestEventArgs("Hi"));;

Или вот так, для C# 6:

Interlocked.CompareExchange(ref this.TestEvent, null, null)?.Invoke(this, new TestEventArgs("Hi"));

Отписывается от события:

Test.TestEvent -= new TestEventHandler();


Что почитать:
http://msdn.microsoft.com/ru-ru/library/8627sbea.aspx

https://habrahabr.ru/post/272571/

https://habrahabr.ru/post/240385/

Как создать поток C#

void RunThread()
{
System.Threading.Thread newThread;
newThread = new System.Threading.Thread(Run);
newThread.Start();
}

void Run()
{
//какая-то работа
}

WebBrowser WPF как сохранить изображение (CAPTCHA), и как изменить HTML код в странице

Столкнулся я проблемой, как сохранить динамическую картинку из браузера, например это Captcha – ведь сколько бы я не обращался по адресу картинки она каждый раз будет новая.
Для решения задачи я решил использовал WPF WebBrower, вам понадобиться подключить библиотеку Microsoft.mshtml для удобной работы с DOM.
В общем получился вот такой код, который позволяет сохранить именно ту картинку которая должна отображаться в странице, для этого: 

try
{
mshtml.HTMLDocumentClass dom = (mshtml.HTMLDocumentClass)wborwser.Document;
foreach (var item in dom.images)
{
if ((item as mshtml.HTMLImgClass).alt == "CAPTCHA")// я как-то идентифицирую нужную картинку
{
mshtml.IHTMLElement2 body2 = (mshtml.IHTMLElement2)dom.body;
mshtml.IHTMLControlRange controlRange = (mshtml.IHTMLControlRange)body2.createControlRange();
//  (item as mshtml.HTMLImgClass).
string strElName;
controlRange.add((mshtml.IHTMLControlElement)item);
controlRange.execCommand("Copy", false, System.Reflection.Missing.Value);
controlRange.remove(0);
strElName = (item as mshtml.HTMLImgClass).nameProp;
if (Clipboard.GetDataObject() != null)
{
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.Bitmap))
{
System.Windows.Interop.InteropBitmap image = (System.Windows.Interop.InteropBitmap)data.GetData(DataFormats.Bitmap, true);
Cap_Img.Source = (ImageSource)data.GetData(DataFormats.Bitmap, true);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
string ThumbnailPath = Guid.NewGuid().ToString() + ".jpg";
FileStream stream = new FileStream(ThumbnailPath, FileMode.Create);
encoder.Save(stream);
stream.Close();
ImageSourceConverter conv = new ImageSourceConverter();
ImageSource imageSource = (ImageSource)conv.ConvertFromString(ThumbnailPath);
Cap_Img.Source = imageSource;
}
}
}
}
}
catch
{
Status.Content = "Ошибка загруки";
BusyIndicator.IsBusy = false;
}

 

В результате в папке с exe файлом появляется нужная мне картинка.

 

Дальше для заполнения полей или еще чего либо можно использовать:

dom.getElementById("TextBoxID").innerText = "какой-то текст";

 

А для имитации нажатия или клика на контрол:

 

dom.getElementById("ButtinID").click();

 

Как получить доступ из потока к элементам интерфейса в C# WPF / Silverlight

Dispatcher.BeginInvoke(new ThreadStart(delegate { 
//ваш код
}));

или

Dispatcher.BeginInvoke(new ThreadStart(()=> { 
//ваш код
}));

или

Dispatcher.BeginInvoke(()=> { 
//ваш код
});

или

Dispatcher.Invoke(new Action(() =>
{
//ваш код
}));

или

System.Windows.Application.Current.Dispatcher.Invoke(() =>
{
//ваш код
})

 

и добавить:

using System.Threading;

Кстати, никогда не используйте Dispatcher.CurrentDispatcher. 

В место него используйте Application.Current.Dispatcher.

Подробнее об этом: http://it3xl.wordpress.com

Скриншот с WPF WebBrowser

Взял отсюда http://nethelp.wikidot.com/save-as-image-using-drawingimage-in-wpf

public static string GetThumbnailImage(WebBrowser CurrentBrowser)
{
Guid guid = Guid.NewGuid();
string ThumbnailPath =  guid.ToString() + ".png";
Image imgScreen = new Image();
imgScreen.Width = 120;
imgScreen.Height = 100;
imgScreen.Source = new DrawingImage(VisualTreeHelper.GetDrawing(CurrentBrowser));
FileStream stream = new FileStream(ThumbnailPath, FileMode.Create);
DrawingVisual vis = new DrawingVisual();
DrawingContext cont = vis.RenderOpen();
cont.DrawImage(imgScreen.Source, new Rect(new Size(120d, 100d)));
cont.Close();
RenderTargetBitmap rtb = new RenderTargetBitmap((int)imgScreen.Width,
(int)imgScreen.Height, 96d, 96d, PixelFormats.Default);
rtb.Render(vis);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(stream);
stream.Close();
return ThumbnailPath;
}

Скирншот экрана WPF

var topLeftCorner = this.PointToScreen(new System.Windows.Point(0, 0));
var topLeftGdiPoint = new System.Drawing.Point((int)topLeftCorner.X, (int)topLeftCorner.Y);
var size = new System.Drawing.Size((int)this.ActualWidth, (int)this.ActualHeight);
var screenShot = new Bitmap((int)this.ActualWidth, (int)this.ActualHeight);
using (var graphics = Graphics.FromImage(screenShot))
{
graphics.CopyFromScreen(topLeftGdiPoint, new System.Drawing.Point(),
size, CopyPixelOperation.SourceCopy);
}
screenShot.Save(@"screenshot.png", ImageFormat.Png);

Как сделать скриншот с WPF контрола

public void SaveImage(Visual visual, string filePath)
{
Rect bounds = VisualTreeHelper.GetDescendantBounds(visual);
RenderTargetBitmap bitmap = new RenderTargetBitmap((Int32)bounds.Width, (Int32)bounds.Height, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(visual);
PngBitmapEncoder image = new PngBitmapEncoder();
image.Frames.Add(BitmapFrame.Create(bitmap));
using (Stream fs = File.Create(filePath))
{
image.Save(fs);
}
}

А загрузить изображение в Image можно вот так:

ImageSourceConverter conv = new ImageSourceConverter();
ImageSource imageSource = (ImageSource)conv.ConvertFromString(name);
image.Source = imageSource;

Динамическая компиляция и в выполнение кода C#

//выполнение 
private string EvalCode(string typeName, string methodName, string sourceCode)
{
string output = ":)";
var compiler = CodeDomProvider.CreateProvider("CSharp");
var parameters = new CompilerParameters
{
CompilerOptions = "/t:library",
GenerateInMemory = true,
IncludeDebugInformation = true,
};

foreach (var reference in AppDomain.CurrentDomain.GetAssemblies())
{
try
{
parameters.ReferencedAssemblies.Add(reference.Location);
}
catch (Exception ex)
{
//Debug.WriteLine("Cannot add assembly " + reference.FullName + " as reference.");
}
}
//если надо
parameters.ReferencedAssemblies.Add(Application.StartupPath + "\\Some.dll");

var results = compiler.CompileAssemblyFromSource(parameters, sourceCode);

if (!results.Errors.HasErrors)
{
var assembly = results.CompiledAssembly;
var evaluatorType = assembly.GetType(typeName);
var evaluator = Activator.CreateInstance(evaluatorType);

output = (string)InvokeMethod(evaluatorType, methodName, evaluator, new object[] { output });
return output;
}

output = "\r\Что-то пошло не так!";
return results.Errors.Cast<CompilerError>().Aggregate(output, (current, ce) => current + string.Format("\r\nline {0}: {1}", ce.Line, ce.ErrorText));
}
//[FileIOPermission(SecurityAction.Deny, Unrestricted = true)]
private object InvokeMethod(Type evaluatorType, string methodName, object evaluator, object[] methodParams)
{
try
{
return evaluatorType.InvokeMember(methodName, System.Reflection.BindingFlags.InvokeMethod, null, evaluator, methodParams);
}
catch
{
return null;
}
}

WCF Data Services 5.0 ошибка System.Data.Services.Providers.ResourceType

Если вы делаете ODate сервисы версии 5.0 то скорее всего столкнетесь с проблемой 'System.Data.Services.Providers.ResourceType' threw an exception.'

для того чтобы это исправить нужно добавить в  Reference проекта следующие библиотеки:

Microsoft.Data.Edm.dll
Microsoft.Data.OData.dll
System.Spatial.dll

также возможно понадобиться:

Microsoft.Data.Services.dll
Microsoft.Data.Services.Client.dll

Если вы используете OpenAccess ORM то в проекте должны быть следующие библиотеки, которые должны копироваться локально:

Обязательные:
Telerik.OpenAccess.dll
Telerik.OpenAccess.35.Extensions.dll
Telerik.OpenAccess.Runtime.dll

для OData:
Telerik.OpenAccess.DataServices.50.dll

Вообще для просмотра зависимостей лучше всего использовать Telerik JustDecompile http://www.telerik.com/products/decompiler.aspx

 

Как работать с DateTime в C#

Как мы знаем тип DateTime хранит время и дату, по этому этот класс достаточно спечифично выглядит для математических операций типа получения разницы в минутах. Или добавление или вычитания времени.
1. Добавление времени:
Тут все просто DateTime.Add (AddDays, AddHours, AddMonths и т.п.) и все что с ним связано, так можно добавлять к времени дни, часы, минуты и прочее.  Если нужно вычесть то добавляйте со знаком минус.

2. Математические операции:

Для этого нам нужен прекрасный класс TimeSpan.
Например, нам нужно узнать разницу между двумя DateTime в минутах
Для этого нужно сделать:

var time = (time1 – time2);
double rez = time.TotalMinutes();

Смысл в том что операции над DateTime возвращают TimeSpan, у которого есть свойства Total* – вот там и храниться общее время в выбранных единицах.

В свойстве Minutes в данном случае будут просто текущее количество минут (скажем для 1 час, 22 минуты – там будет храниться 22 минуты. А TotalMinutes вернет 82 минуты.

В общем все операции нужно делать через TimeSpan.

По скольку данные из в TimeSpan можно получить в виде double то их можно округлить http://acroblog.acrovations.com/post/2012/09/11/Как-получить-целую-часть-или-округлить-double.aspx

Также хорошо можно использовать класс  Calendar который позволяет работать с неделями, месяцами, днями и тп.

DateTime myDT = DateTime.Now();
// Используются установленные по умолчанию календарь InvariantCulture.      
Calendar myCal = CultureInfo.InvariantCulture.Calendar;
// пример
myDT = myCal.AddYears( myDT, 5 );
myDT = myCal.AddMonths( myDT, 5 );
myDT = myCal.AddWeeks( myDT, 5 );
myDT = myCal.AddDays( myDT, 5 );
myDT = myCal.AddHours( myDT, 5 );
myDT = myCal.AddMinutes( myDT, 5 );
myDT = myCal.AddSeconds( myDT, 5 );
myDT = myCal.AddMilliseconds( myDT, 5 )

MSDN: http://msdn.microsoft.com/en-us/library/system.globalization.calendar.addweeks.aspx

Как получить целую часть или округлить double

Для этого есть стандартные функции в пространстве Math

Нас интересует:

Math.Floor – который округляет в сторону меньшего числа.

Math.Truncate – который округляет в сторону большего числа.

В зависимости от того что именно вам нужно – то и используйте.

Но скорее вам нужен именно Math.Floor, который и вернет целое число.

 

Шаблон C# MVVM

Хороший шаблон ViewModel для MVVM паттерна в WPF

public class BaseViewModel : INotifyPropertyChanged
{
public virtual void OnNavigatedTo(NavigationEventArgs args) { }  
public virtual void OnNavigatedFrom(NavigationEventArgs args) { }
public virtual void OnViewUnloaded(object sender, RoutedEventArgs e) { }
public virtual void OnViewLoaded(object sender, RoutedEventArgs e) { }
#region Propertychanged
protected void OnPropertyChanged(Expression> action)
{
var propertyName = GetPropertyName(action);
OnPropertyChanged(propertyName);
}
private static string GetPropertyName(Expression> action)
{
var expression = (MemberExpression)action.Body;
var propertyName = expression.Member.Name;
return propertyName;
}
private void OnPropertyChanged(string propertyName)
{
try
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
catch { }
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}

 

или

public class BaseViewModel : INotifyPropertyChanged
{
#region Propertychanged
protected void OnPropertyChanged<T>(Expression<Func<T>> action)
{
var propertyName = GetPropertyName(action);
this.OnPropertyChanged(propertyName);
}
private static string GetPropertyName<T>(Expression<Func<T>> action)
{
var expression = (MemberExpression)action.Body;
var propertyName = expression.Member.Name;
return propertyName;
}
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}

Использовать потом в виде OnPropertyChanged(()=> PorpertyName)

Паралельные операции в C# и как это использовать

 Паралельность может быть в двух видах.

1. Паралельные циклы

2. Паралельный LINQ

Как этим пользоваться?

Для паралельных операций надо использовать конструкции вида:

 

Parallel.ForEach(collection,
currentElement =>
{
// что-то делаем
});

 

Parallel.For(0, 50, i =>
{
// что-то делаем
});

 

для остановки Parallel.For:

Parallel.For(0, source.Length, (i, loopState) =>
{
// Take the first 100 values that are retrieved
// from anywhere in the source.
if (i < 100)
{
// Accessing shared object on each iteration
// is not efficient. See remarks.
double d = Compute(source[i]);
results.Push(d);
}
else
{
loopState.Stop();
return;
}

} // Close lambda expression.
); // Close Parallel.For

Очень важно использовать коллекции типа ConcurrentBag(T)
Из неймспейса  System.Collections.Concurrent
Иначе будут ошибки.

Что касается LINQ  то к запросу нужно добавить .AsParallel()

var test = from i in test.TestTables.AsParallel()
where i.PayDate >= date.Date 
select new { PaySum = i.PaySum};

 

Для сохранения порядка при выполнении запроса можно дописать .AsOrdered(), но это замедлит выполенение запроса.


Опять же надо быть осторожным, т.к. возможны ошибки связанными с доступом к переменным условия.

.