• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2267
  • Last Modified:

C# .Net WPF & Delegates

Firstly I am not a C# developer, although I have plenty of programming in my past, but it's all pre .NET days, so please go easy :-)
So I have a little WPF app that I am trying to create. I want to run some methods, I think that's what they're called. (I would have called them a function back in my day). Now I want those methods to report back to a listbox on the main GUI for the app.

After a bit of digging I have found a way, but I don't think it's really very neat and seems wrong somehow, although it works.

I have a basic WPF form, one button and one listbox.  When you click the button it calls the button event and then runs the method and updates the listbox.

If I have several other buttons doing other jobs, do I have to re-create the "SomeOtherCode.LogHandler myLogger = new SomeOtherCode.LogHandler(Logger);"  and pass the myLogger through to the method each time?

It seems mad to me that you would have to do this, and I'm sure that's it's just my inexperience that's holding me back. Can anyone shed a little light on this?

There is another issue in that the listbox doesn't update until you are out of the method you're calling, so it's hard to really track progress within a method. I've started to look at data binding of the listbox, but I haven't researched it much yet. I'm open to suggestions on how to Log events to the UI.

Many Thanks, Mike...
*** Window1.xaml.cs ***
-----------------------
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Management;
 
namespace WMI_Tester
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        SomeOtherCode SOC = new SomeOtherCode();
        public Window1()
        {
            InitializeComponent();
        }
 
        private void btn_Connect_Click(object sender, RoutedEventArgs e)
        {
            listBox1.Items.Add("About to run method? in a class");
            SomeOtherCode.LogHandler myLogger = new SomeOtherCode.LogHandler(Logger);
            SOC.ConnectToSomething(myLogger);
        }
 
        public void Logger(string updateWith)
        {
            listBox1.Items.Add(updateWith);
        }
    }
}
 
*** OtherFile.cs ***
--------------------
using System;
using System.Management;
 
namespace WMI_Tester
{
    class SomeOtherCode
    {
        public delegate void LogHandler(string updateWith);
 
        public void ConnectToSomething(LogHandler logHandler)
        {
            //Some code
            logHandler("Report on Progress");
            //Some more code
        }
    }
}

Open in new window

0
Mikey_TT
Asked:
Mikey_TT
1 Solution
 
bhmahlerCommented:
The only reason you would need a delegate is if you were running the processing code in a  background thread. Then a delegate would be required to invoke the UI thread in order to access the controls.  It would seem to me from your example that an event in the processing class would suffice.
0
 
anarki_jimbelCommented:
Don't thing events would make life easier in this case :)

 I changed the signature for the delegate and relating methods.
And I have just one logger. The idea is to pass botha destination listbox and a string to the logging method. I reckon you have more than one ListBox...

Mikey TT, I didn't try my code, you may try but probably will need to debug...
** Window1.xaml.cs ***
-----------------------
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Management;
 
namespace WMI_Tester
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        SomeOtherCode SOC = new SomeOtherCode();
        SomeOtherCode.LogHandler myLogger;
        public Window1()
        {
            InitializeComponent();
            myLogger = new SomeOtherCode.LogHandler(Logger);
        }
 
        private void btn_Connect_Click(object sender, RoutedEventArgs e)
        {
            listBox1.Items.Add("About to run method? in a class");
            SOC.ConnectToSomething(listBox1, myLogger);
        }
 
        public void Logger(ListBox lbox, string updateWith)
        {
            lbox.Items.Add(updateWith);
        }
    }
}
 
*** OtherFile.cs ***
--------------------
using System;
using System.Management;
 
namespace WMI_Tester
{
    class SomeOtherCode
    {
        public delegate void LogHandler(ListBox lbox, string updateWith);
 
        public void ConnectToSomething(ListBox lbox, LogHandler logHandler)
        {
            //Some code
            logHandler(lbox, "Report on Progress");
            //Some more code
        }
    }
}

Open in new window

0
 
Mikey_TTAuthor Commented:
anarki that certainly worked. I don't need to keep on recreating the definition for the myLogger variable. I do still need to pass it through to any calling method tho, which is a pain.

Is there not the concept of global variables now in C#. Where you can set something that the entire app will be able to access? I know you can set some stuff that's visible to the entire class, but I would have expected to have a way of accessing a global style variable, as in VBScript or HTA programming. I do however understand that C#.Net is grown up compared to them ;-)

bhmahler - Could you expand a little on what you mean. I don't know C# that well yet, I am very much on a huge learning curve. Even all of the naming methodologies have changed since I did any real development work.

Thanks both for your help tho.

Mike...
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
AndreSteffensCommented:
The nearest to global variables is using static properties (on static classes)
See the code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
 
namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private SomeOtherCode SOC;
        public Window1()
        {
            InitializeComponent();
            
        }
 
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            SOC=new SomeOtherCode(this.listBox1);
        }
 
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            listBox1.Items.Add("Going to make ends meet...");
            SOC.DoSomethingIntelligent();
        }
 
        private void button2_Click(object sender, RoutedEventArgs e)
        {
            listBox1.Items.Add("Going to buy shares in GM...");
            SOC.DoSomethingStupid();
        }
 
    }
 
    public class SomeOtherCode
    {
        public SomeOtherCode(ListBox logPresenter)
        {
            Logger.LogPresenter = logPresenter;
        }
        public void DoSomethingIntelligent()
        {
            Logger.Log("I did something smart.");
        }
        public void DoSomethingStupid()
        {
            Logger.Log("That did not work out as expected...");
        }
    }
 
    public static class Logger
    {
        public static ListBox LogPresenter;
 
        public static void Log(string log)
        {
            LogPresenter.Items.Add(log);
        }
 
    }
}

Open in new window

0
 
anarki_jimbelCommented:
If you define some a variable as public it can be seen in the entire project. However all variables should be defined in a class, there are no e.g. modules for global variables as say in VB6.
0
 
Mikey_TTAuthor Commented:
Thanks very much for your help everyone. It appears the steep learning curve is a little steeper than anticipated. I may well be back ;-)

Cheers, Mike...
0
 
Mikey_TTAuthor Commented:
Better late than never in accepting this.
Thanks. I ended up running this all via Background Threads to stop the UI from locking up. This did fix my initial problem tho.
BTW This is the third or fourth solution I've seen you post on, I really like the way you actually explain with a code snippet that's complete and not just a quick excerpt. For a C# noob it's a real help.
Cheers, Mike...
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now