Passing function as parameter to create delegate - c#

I'm trying to make a helper function to make BackgroundWorkers.
Here is what I have so far.
using System.ComponentModel;
using System;
public class BackgroundThread {
BackgroundWorker worker;
public BackgroundThread(Delegate workerFunction, Delegate workerCallback) {
this.worker = new BackgroundWorker();
this.worker.DoWork += new DoWorkEventHandler(workerFunction);
this.worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerCallback);
}
public void Start(object argument) {
this.worker.RunWorkerAsync(argument);
}
}
Although I am getting this error.
Expression denotes a 'variable', where a 'type' or 'method group' was expected
It makes sense since normally you pass a reference to a function to the Handlers but I don't know how to do it in this context. Or is this just not possible. I don't know enough about C# delegates and such to know what to do.

Like this?
public class BackgroundThread
{
System.ComponentModel.BackgroundWorker worker;
public BackgroundThread(System.ComponentModel.DoWorkEventHandler workerFunction, System.ComponentModel.RunWorkerCompletedEventHandler workerCallback)
{
this.worker = new System.ComponentModel.BackgroundWorker();
this.worker.DoWork += workerFunction;
this.worker.RunWorkerCompleted += workerCallback;
}
public BackgroundThread(Action<object> anyWorkFunctionWithObjectArgument, Action<object> anyCallback)
{
this.worker = new System.ComponentModel.BackgroundWorker();
this.worker.DoWork += (sender, e) => { anyWorkFunctionWithObjectArgument.Invoke(e.Argument); };
this.worker.RunWorkerCompleted += (sender, e) => { anyCallback.Invoke(e.Result); };
}
public void Start(object argument)
{
this.worker.RunWorkerAsync(argument);
}
public static BackgroundThread GetDoNothingInstance()
{
return new BackgroundThread(
(sender, e) =>
{
// e is DoWorkEventArgs
},
(sender, e) =>
{
// e is RunWorkerCompletedEventArgs
});
}
public static BackgroundThread GetDoNothingInstance2()
{
Action<object> workfunction = delegate(object argument)
{
// Do nothing
};
Action<object> callback = delegate(object result)
{
// Do nothing
};
return new BackgroundThread(workfunction, callback);
}
}

Just saw your comment. This should allow you to just pass a "plain old function" without having to shape it like a handler:
class Program
{
protected static void plainOldWorkerFunction(object argument)
{
return;
}
protected static void plainOldCallbackFunction()
{
return;
}
static void Main(string[] args)
{
BackgroundThread bt = new BackgroundThread(plainOldWorkerFunction, plainOldCallbackFunction);
bt.Start(1234);
}
}
public class BackgroundThread
{
BackgroundWorker worker;
Action<object> workerAction;
Action callbackAction;
protected void doWork(object sender, DoWorkEventArgs e)
{
workerAction(e.Argument);
}
protected void callback(object sender, RunWorkerCompletedEventArgs e)
{
callbackAction();
}
public BackgroundThread(Action<object> workerFunction, Action workerCallback)
{
this.workerAction = workerFunction;
this.callbackAction = workerCallback;
this.worker = new BackgroundWorker();
this.worker.DoWork += doWork;
this.worker.RunWorkerCompleted += callback;
}
public void Start(object argument)
{
this.worker.RunWorkerAsync(argument);
}
}
Original answer:
Try this constructor instead:
public BackgroundThread(DoWorkEventHandler workerFunction, RunWorkerCompletedEventHandler workerCallback)
{
this.worker = new BackgroundWorker();
this.worker.DoWork += workerFunction;
this.worker.RunWorkerCompleted += workerCallback;
}
And just make sure your workerFunction and workerCallback have these parameters:
protected static void workerFunction (object sender, DoWorkEventArgs e)
{
return;
}
protected static void workerCallback (object sender, RunWorkerCompletedEventArgs e)
{
return;
}

Related

BackgroundWorker does not fire inside User Control

I am currently creating a Windows Form Application and I am wanting to use a BackgroundWorker. I have created a very simple example which works perfectly:
public partial class Form1 : Form
{
private BackgroundWorker bgw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
bgw.WorkerReportsProgress = true;
bgw.DoWork += new DoWorkEventHandler(DoWork);
bgw.ProgressChanged += new ProgressChangedEventHandler(ProgressChanged);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Completed);
}
private void button1_Click(object sender, EventArgs e)
{
bgw.RunWorkerAsync();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 10; i++)
{
bgw.ReportProgress(i * 10, i.ToString());
Thread.Sleep(1000);
}
}
private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = string.Format("{0}% : Message = '{1}'", e.ProgressPercentage, e.UserState.ToString());
}
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Completed");
}
}
Now, when I move the same code to my current application it does not fire. The only difference is that instead of running the code at the Form level, I am attempting to run it inside a custom User Control. As such:
public partial class LobbyForm : UserControl
{
private BackgroundWorker bgw = new BackgroundWorker();
public LobbyForm()
{
InitializeComponent();
bgw.WorkerReportsProgress = true;
bgw.DoWork += new DoWorkEventHandler(DoWork);
bgw.ProgressChanged += new ProgressChangedEventHandler(ProgressChanged);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Completed);
}
public LobbyForm(List<TaskFile> tasks)
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
bgw.RunWorkerAsync();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i <= 10; i++)
{
bgw.ReportProgress(i * 10, i.ToString());
Thread.Sleep(1000);
}
}
private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label5.Text = string.Format("{0}% : Message = '{1}'", e.ProgressPercentage, e.UserState.ToString());
}
private void Completed(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Completed");
}
}
Any thoughts on if I am missing something? Perhaps something I am misunderstanding with attempting to run this from a User Control?
I just copied your code and tested it and it worked perfectly if you drag-drop the user control using the designer.
However, if you create he control at runtime and add it to your form, make sure you're using the correct constructor.
LobbyForm lf = new LobbyForm();
this runs this constructor:
public LobbyForm()
{
InitializeComponent();
bgw.WorkerReportsProgress = true;
bgw.DoWork += new DoWorkEventHandler(DoWork);
bgw.ProgressChanged += new ProgressChangedEventHandler(ProgressChanged);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Completed);
}
and not
LobbyForm lf = new LobbyForm(tasks);
which runs this constructor (that doesn't hook up events):
public LobbyForm(List<string> tasks)
{
InitializeComponent();
}
Solution (Call the default constructor from the second one)
public LobbyForm(List<string> tasks) : this()
{
//InitializeComponent();
}

Passing a method to a BackgroundWorker.DoEvent C#

I am currently trying to make a regular function run as an anonymous BackgroundWorker's DoWork event. The issue I have is that the method is not running at all. The current code I have is as follows;-
public class Worker
{
BackgroundWorker worker;
public Worker(Func<bool> action)
{
worker = new BackgroundWorker();
worker.DoWork += (sender, e) => e.Result = action;
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
this.action = action;
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("Thread completed : "+ e.Result.ToString());
}
public void DoWork()
{
Console.WriteLine("worker thread: working...");
worker.RunWorkerAsync();
//Wait for worker to complete
do { } while (worker.IsBusy);
}
}
The function is passed like this:-
Worker workerObject = new Worker(new Func<bool>(() => methodThatReturnsBool(param1, param2)));
Thread workerThread = new Thread(workerObject.DoWork);
workerThread.Start();
How is it possible to pass the method and have it run within the background worker?
From the looks of it, you are just assigning the action itself as a result, instead of calling it.
worker.DoWork += (sender, e) => e.Result = action();
Also the waiting loop might cause problems. At least put a
do {Thread.Yield();} while (worker.IsBusy);
in there
Or use a cleaner (no busy-waiting) approach:
public class Worker
{
private BackgroundWorker _worker;
private AutoResetEvent _event;
private Func<bool> _action;
public Worker(Func<bool> action)
{
_action = action;
_event = new AutoResetEvent(false);
_worker = new BackgroundWorker();
_worker.DoWork += (sender, e) =>
{
try
{
e.Result = _action();
}
finally
{
_event.Set();
}
};
_worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("Thread completed : "+ e.Result.ToString());
}
public void DoWork()
{
Console.WriteLine("worker thread: working...");
_worker.RunWorkerAsync();
_event.WaitOne();
}
}

C# Backgroundworker ConsoleWriteline

I have a simple Backgroundworker and want to write my result to the Console and I also want to report the process.
class Program
{
private static BackgroundWorker worker;
static int counter;
static void Main(string[] args)
{
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.RunWorkerAsync();
Console.ReadLine();
}
static void worker_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
counter++;
worker.ReportProgress(counter);
}
}
static void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Console.WriteLine(counter);
}
static void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
}
But how can I give my String (or more then 1 String) to my ReportProcess Function?
You're not assigning the event handlers to the BackgroundWorker events:
static void Main(string[] args)
{
worker = new BackgroundWorker();
worker.DoWork += Worker_DoWork; //here
worker.ProgressChanged += Worker_ProgressChanged; //and here
worker.WorkerReportsProgress = true;
worker.RunWorkerAsync();
Console.ReadLine();
}
Cheers
You're passing counter as the first (int percentProgress) parameter to ReportProgress, which you can access as shown in the example below using e.ProgressPercentage. You can also pass a second (object userState) parameter, which could be a string or any other object, accessed as shown in the example below using e.UserState.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
backgroundWorker.ReportProgress(100, "Complete!");
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
toolStripProgressBar.Value = e.ProgressPercentage;
toolStripStatusLabel.Text = e.UserState as String;
}
See full example at https://msdn.microsoft.com/en-us/library/system.windows.forms.toolstripprogressbar(v=vs.110).aspx

service is returning null wpf mvvm

I'm trying to bind data in my data context but service is returning null. I'm using ninject as DI. I'm sharing my app.xaml.cs code. Please guide me.
public partial class App
{
private IKernel container;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
AutoMapperConfig.RegisterMappings();
ConfigureContainer();
ComposeObjects();
Current.MainWindow.Show();
}
private void ConfigureContainer()
{
this.container = new StandardKernel();
container.Bind(typeof(IAppServiceBase<>)).To(typeof(AppServiceBase<>));
container.Bind<IJvDetailAppService>().To<JvDetailAppService>().InSingletonScope();
container.Bind<IJvMasterAppService>().To<JvMasterAppService>().InSingletonScope();
container.Bind<IJvDimensionAppService>().To<JvDimensionAppService>().InSingletonScope();
container.Bind(typeof(IServiceBase<>)).To(typeof(ServiceBase<>));
container.Bind<IJvDetailService>().To<JvDetailService>();
container.Bind<IJvMasterService>().To<JvMasterService>();
container.Bind<IJvDimensionService>().To<JvDimensionService>();
container.Bind(typeof(IRepositoryBase<>)).To(typeof(RepositoryBase<>));
container.Bind<IJvDetailRepository>().To<JvDetailRepository>();
container.Bind<IJvMasterRepository>().To<JvMasterRepository>();
container.Bind<IJvDimensionRepository>().To<JvDimensionRepository>();
}
private void ComposeObjects()
{
Current.MainWindow = this.container.Get<MainWindow>();
Current.MainWindow.Title = "JustApp";
}
}
MainWindowViewModel
public class MainWindowViewModel : ViewModelBase
{
private readonly BackgroundWorker _worker = new BackgroundWorker();
private ObservableCollection<JvDetailViewModelBase> _jvDetailMenu;
private readonly IJvDetailAppService _jvDetailAppService;
public ObservableCollection<JvDetailViewModelBase> JvDetailMenu
{
get { return this._jvDetailMenu; }
set
{
_jvDetailMenu = value;
RaisedPropertyChanged("JvDetailMenu");
}
}
public MainWindowViewModel()
{
_worker.DoWork += worker_DoWork;
_worker.RunWorkerCompleted += worker_RunWorkerCompleted;
_worker.RunWorkerAsync();
}
readonly ObservableCollection<JvDetailViewModelBase> _tempProductMenu = new ObservableCollection<JvDetailViewModelBase>();
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
_tempProductMenu.Add(new ModifyJvDetailViewModel(_jvDetailAppService));
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (_tempProductMenu.Any())
{
JvDetailMenu = _tempProductMenu;
}
}
}
ModifyJvDetailViewModel.cs
public class ModifyJvDetailViewModel : JvDetailViewModelBase
{
private readonly BackgroundWorker _worker = new BackgroundWorker();
private IEnumerable<JvDetail> _tempLoadJvDetails;
private readonly IJvDetailAppService _jvDetailAppService;
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
int ab = _jvDetailAppService.GetByCompanyId(3).Count(); // it is returning null here and everywhere which is fetching records.
_tempLoadJvDetails = _jvDetailAppService.GetByCompanyId(3);
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
JvDetails = _tempLoadJvDetails;
}
public override string Name
{
get { return JustAppHelper.JvDetail; }
}
public override string Icon
{
get { return JustAppHelper.JvDetailIcon; }
}
public ModifyJvDetailViewModel(IJvDetailAppService jvDetailAppService)
{
_jvDetailAppService = jvDetailAppService;
var ab = _jvDetailAppService.GetAll().Count();
_worker.DoWork += worker_DoWork;
_worker.RunWorkerCompleted += worker_RunWorkerCompleted;
_worker.RunWorkerAsync();
BindGrid();
}
protected void BindGrid()
{
JvDetails = _jvDetailAppService.GetByCompanyId(3);
}
private IEnumerable<JvDetail> _jvDetails;
public IEnumerable<JvDetail> JvDetails
{
get { return _jvDetails; }
set
{
_jvDetails = value;
RaisedPropertyChanged("JvDetails");
}
}
}
Mainwindow.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
ListBoxProducts.SelectedIndex = 0;
}
}
One approach would be to change MainWindowViewModel constructor:
public MainWindowViewModel(IJvDetailAppService detailAppService)
{
_jvDetailAppService = detailAppService;
_worker.DoWork += worker_DoWork;
_worker.RunWorkerCompleted += worker_RunWorkerCompleted;
_worker.RunWorkerAsync();
}
and MainWindow constructor:
public MainWindow(IJvDetailAppService detailAppService)
{
InitializeComponent();
this.DataContext = new MainWindowViewModel(detailAppService);
ListBoxProducts.SelectedIndex = 0;
}

Cannot use use ref or out parameter for anonymous methods

static BackgroundWorker worker;
static void Main(string[] args)
{
worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerAsync();
Console.ReadLine();
}
static void worker_DoWork(object sender,DoWorkEventArgs e)
{
string strClientId = "2211"; Authenticate(ref strClientId);
}
static void Authenticate(ref string strClientId)
{
Timer timer = new Timer(500);
//Error in this line
//Cannot use ref or out parameter 'strClientId' inside an anonymous method,lambda expression or query expression
timer.Elapsed += (sender, e) => Authenticates_Timer(sender, e,ref strClientId);
//timer.Elapsed += Authenticates_Timer();
timer.Start();
}
static void Authenticates_Timer(object sender, ElapsedEventArgs e, ref string strClientId)
{
//want to use variable here
strClientId = "";
}
if there is a way i can use ref variable while passing
parameter to event Cannot use ref or out parameter 'strClientId'
inside an anonymous method,lambda expression or query
expression.I know this is repeated question but i am unable to
figure out how to solve this have refered different posts and
posted question in codeproject too but no one is responding any
help is appreciated
I would recommend sharing strClientId as static variable:
static BackgroundWorker worker;
static string strClientId;
static void Main(string[] args)
{
worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerAsync();
Console.ReadLine();
}
static void worker_DoWork(object sender,DoWorkEventArgs e)
{
strClientId = "2211";
Authenticate();
}
static void Authenticate()
{
Timer timer = new Timer(500);
timer.Elapsed += (sender, e) => Authenticates_Timer(sender, e);
timer.Start();
}
static void Authenticates_Timer(object sender, ElapsedEventArgs e)
{
strClientId = "";
}
Will it work for you?
Update: Ok, let's try this one:
static void worker_DoWork(object sender,DoWorkEventArgs e)
{
string strClientId = "";
var setClientId = new Action<string>(v => { strClientId = v; });
setClientId("2211");
Authenticate(setClientId);
}
static void Authenticate(Action<string> setClientId)
{
Timer timer = new Timer(500);
timer.Elapsed += (sender, e) => Authenticates_Timer(sender, e, setClientId);
timer.Start();
}
static void Authenticates_Timer(object sender, ElapsedEventArgs e, Action<string> setClientId)
{
setClientId("");
}
As simple as that:
static void Authenticate(ref string strClientId)
{
Timer timer = new Timer(500);
var strClientIdVar = strClientId;
timer.Elapsed += (sender, e) => Authenticates_Timer(sender, e,ref strClientIdVar);
timer.Start();
}

Categories