-1

This relates to my previous post here, where I asked why I should use SynchronizationContext's .Send or .Post, over just a regular .Invoke or .BeginInvoke on my main UI Form.

My issue is that the delegate I used to use with Invoke is associated with a method that takes two parameters: one string that holds the actual text the label should be changed to, and another string that holds the name of the label whose text should change.

The issue now is that .Send and .Post only takes the SendOrPostCallbake delegate as its input, and that delegate can only be associated with methods that have a single object as its parameter. As everything can be packed into an object, I was advised to either create a class to pack my variables in (that option I understand how to implement), and the other was to use lambda expressions with closures. It is the latter that I do not understand how to do.

Any guidance on how to use lambda expressions in _synch.Send() when my underlying method has two string parameters, would be greatly appreciated.

EDIT. Based on guidance in comments I was able to answer my own question. I have posted the solution below for the benefit of future visitors.

Community
  • 1
  • 1
Anders
  • 580
  • 8
  • 17
  • So when you did your basic research on the topic that you don't understand what did you find? There is *tons* of information out there on closures that is readily available. – Servy Sep 25 '14 at 20:00
  • @Servy Let's take this resource for instance: http://stackoverflow.com/questions/595482/what-are-closures-in-c. I do not get how lambda expressions are going to save me from having to create a whole new class to store my two strings (like the Person class in the example). – Anders Sep 25 '14 at 20:07
  • Why *would* you need to create a whole new type to store these two instances when you could just close over each of them, as shown right there in that example? Note that `p` is not closed over in that example; that's the parameter. `id` is the closed over variable. – Servy Sep 25 '14 at 20:09
  • @Servy Sorry, I am really confused. How can he write `delegate(Person p)` if the class Person does not exist? – Anders Sep 25 '14 at 20:12
  • The delegate that you write will need to accept a grand total of zero parameters. The example in that link happened to require a delegate that accepts a person and closes over an integer. Nothing about the person is relevant in the slightest to the closure. – Servy Sep 25 '14 at 20:14
  • @Servy I have added some example code to the post. I am just stabbing in the dark here. I am missing some key understanding of how this would be structured... – Anders Sep 25 '14 at 20:28
  • And what is the problem that you're having with that code? What happens when you try to use it? – Servy Sep 25 '14 at 20:29
  • @Servy Haha, I actually don't feel that the .Send I have written makes any sense at all. First of all, I do not think the UI thread/class have access to those two _sendBackValue objects, so it would probably get incredibly confused when it tries to run that lambda. Secondly, let's say for some reason that it did run fine, then all that would happen would be that the UI thread would initialize two strings. Great, but that does not make my labels change text. And I cannot add any code to change the label, becasue I am in the worker class and do not have access to the controls. – Anders Sep 25 '14 at 20:37
  • Then your question has nothing to do with anonymous methods or closures, but rather how to effectively design a UI application so that a non-UI worker can update the UI without actually knowing anything at all about the UI itself. That's a radically different question that what you're asking. The actual question you've asked answers itself, as your code already does what you're asking to be able to do. – Servy Sep 25 '14 at 20:40
  • @Servy I do appreciate the help here. I am a bit lost as to why I got downvoted as my question was how to use .Send to update my UI from another class/thread. It feels like we are getting to the bottom of it and I hope the post will be helpful to other people as well. I added some new code, does that look correct? – Anders Sep 25 '14 at 20:48
  • Your question is being downvoted because you're asking how to close over two different variables, something so simple *you figured it out on your own already*. The answer to the question you've asked here is already in your question. The code that you have already successfully closes over the two variables you have. If you have some other question about how to properly design a worker for a UI based application you haven't actually asked it. – Servy Sep 25 '14 at 20:50
  • 1
    @Servy In all fairness, if I knew the answer to my question, or thought it was straight forward to solve, I would not be on here asking the question in the first place. Moreover, I was not directly asking how to close over two variables, but rather how to use lambdas as part of .Send, in order to communicate with my UI on another class/thread. I do not think it should be discouraged for people to ask questions when they are faced with a problem they do not know how to solve. After all, this forum exists for the purpose of spreading knowledge. – Anders Sep 25 '14 at 21:02
  • @Servy Two quick add-on questions: If the lambda expression works, why can I not just have another method in the worker class that takes in an object parameter and closes over the two variables, just like the lambda? Would that not work as well? Also, is InvokeRequired needed in the UpdateText method, or does the SynchCOntext ensure that that isn't necessary? – Anders Sep 26 '14 at 08:45
  • You *did* know the answer to your question, and it *was* straightforward for you to solve. You just needed me to tell you to do it yourself and you did. People *are* discouraged from asking questions that can be trivially solved through some basic research, such as this one, as asking questions here consumes a lot of other people's time. Not even spending a few minutes to attempt to solve such simple problems yourself is extremely inconsiderate to the rest of the community. – Servy Sep 26 '14 at 13:54
  • I did not know the answer to my question upfront and I did try to research it. If you do not understand a concept it can often be hard to make sense of articles and papers on the topic. Your post 3 and 4 helped me come up with what I am guessing is a solution to this particular problem. Surely there will be other people with the same question who will now be able to find a straight-forward answer. Value added for sure. – Anders Sep 26 '14 at 14:40
  • No, there was no value added. There must be *tens of thousands* of web pages that demonstrate how to close over a variable. If you think that there was no place that anyone could go on the internet to figure out how to close over a variable before now, you're very much mistaken. – Servy Sep 26 '14 at 14:42
  • This question was not simply about closing over variables. That happened to be part of the solution yes, but the question was how to use .Send with multiple parameters. No point in arguing about it, I do appreciate the help. I will keep trying to research a lot before posting. Thanks again – Anders Sep 26 '14 at 14:48

1 Answers1

0

Based on guidance provided in comments, I have written the below solution.

In main UI class:

public SynchronizationContext UISynchContext { get; private set; }
public static MainForm Get { get; private set; }

public MainForm()
{
    InitializeComponent();
    Get = this;
    UISynchContext = SynchronizationContext.Current;
}

public void UpdateText(string labelName, string text)
{
    var label = (Label)Controls.Find(labelName, true).FirstOrDefault();
    if (label != null) label.Text = text;
}

In worker class:

private readonly SynchronizationContext _uiSynch;

public Worker(UpdateValueCallback updateValueCallback, Player player)
{
    _uiSynch = MainForm.Get.UISynchContext;
}

_uiSynch.Send(o =>
{
    string labelName = "lbOne";
    string labelText = methodThatReturnsNewText();

    MainForm.Get.UpdateText(labelName, labelText);
}, null);
Anders
  • 580
  • 8
  • 17