Accessing legacy Winforms code from WPF MVVM Control

Hello,

I have been tasked with working on a legacy application.  This application is written in VB.NET WinForms, and there is quite a lot of code in the project already to handle things like database connectivity, error handling, reporting, logging, user notifications, etc.

The last developer to work on the app added a second project to the solution for a custom WPF control he created.  It's still titled "WpfControLibrary1", and the control is "UserControl1" so i'm guessing he didn't spend much time on it.  The control itself uses MVVM C# and it's been added into a winform in the original project with no code behind it.

My question is this: How can I access this pre-existing classes, modules, and forms in the original project from the new control?

For example, if I want to export data to Excel in the old project I would simply instantiate the "DataExport" class and pass the dataset to its "ToExcel" method.   Similarly, how could I access a property/method from the main form?

I'm really not very familiar with WPF, and could use a nudge in the right direction.  Perhaps i'm not searching for the right terms, or maybe it's just not possible.  However, I'm really not looking to re-invent the wheel here, just need to figure out how to leverage/access the pre-existing code for what would normally be 5 minutes worth of work if it weren't for the WPF.

Thanks in advance for your time.
LVL 13
TorrwinAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Chinmay PatelChief Technology NinjaCommented:
Hi Torrwin,

You are right WPF can be tricky sometimes. If you have the source code for the WPF project, how about changing its constructor to pass in the additional details? Also, you will get a reference of the WinForm hosting the WPF using Parent property, you should be able to call any Public methods after you get the reference.
https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.parent?view=netframework-4.8#System_Windows_Forms_Control_Parent

Regards,
Chinmay.
TorrwinAuthor Commented:
Thanks for the reply!  It makes logical sense: "Add code to the control to access its parent."  However, I tried adding the code in various places, but to no avail.

So let me try putting it another way, here are my files:

App Main Project
    WinForm1.vb - Contains UserControl1

WpfControlLibrary1 Project
     MainViewModel.cs
     UserControl1.xaml - Contains Button1
          UserControl1.xaml.cs (no code behind)


Button1 has a binding path to a function in the MVM.  What I need to be able to do is add code to this function that can access App Main objects.

Where should I be adding the parent/child references you mentioned?

Thanks again.
gr8gonzoConsultantCommented:
So the first step is to add a project reference. So if your WPF application is going to be using the control from the Winforms app, then you would:
1. Within Solution Explorer, expand the "WpfControlLibrary1" project so you can see the "References" item inside and right-click on it.
2. On the pop-up menu, the first item should be "Add Reference...." - click on that.
3. If you're on a recent version of Visual Studio, you should see a "Reference Manager" pop-up window with some categories on the left side. One of those should be "Projects" - click on that once.
4. You should see the App Main Project option with a checkbox next to it - check it and click on OK to close the window.

What this does is configure your WPF project so that your Winforms app is seen as a dependency. So when you build your WPF app, it will actually build the Winforms app first, and then copy the resulting file into your WPF app output. Then, when your WPF app actually runs, it will load all the classes/functionality from the Winforms app and make it available for your WPF app to use. It's basically the same as if you were to add any other 3rd party library into your project.

At development-time, as soon as you add the reference, your code in your WPF app will be able to see the namespaces/classes from the Winforms app. So you could open up the code-behind file in your WPF app and then type in your VB.Net app's namespace and you'll see the Intellisense start showing it in the little popup.

What you should be aware of is that -IF- your VB.Net app and your WPF app are started separately, as independent processes, the above approach does not provide any sort of magical way to transfer data from one process to the other. When you start running a program, it's almost like you're building a house in a virtual neighborhood. Anyone who is within the same house can talk to each other (like all the pieces of your app can see each other), but someone in house A cannot directly talk to someone in house B (at least not without some special measures).

However, you could have your WPF application run and instantiate a new control of your VB.net control and have it run and keep a reference to it, and then it would be like two human beings within the same house - they can talk to each other directly, since it's all running within one big process.

Hopefully that provides a little direction.
Become a CompTIA Certified Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

Chinmay PatelChief Technology NinjaCommented:
Hah...

Button1 has a binding path to a function in the MVM.  What I need to be able to do is add code to this function that can access App Main objects.
This is going to be fun.

I have a different idea to make this communication happen but I think nothing wrong in trying what comments in above post suggests.

I shall wait for the update from your side.
Snarf0001Commented:
If you can post some of the code from the WPF control that would help, but if I were you I would change that to trigger events which would in turn be caught by the containing WinForm to trigger the proper data flows.

I doubt you'll be able to add a reference as suggested above.  Based on what you've described, I'm assuming that the WPF app has already been added as a reference to the winforms one.  Now adding the reverse is going to create a cyclic dependency and will be blocked.

Moreover, if it's a control library, then it really shouldn't be having the controlling code as part of it anyway.  Should be a reusable item that knows what it needs to do with it's own UI, but leave application dependent functionality to the controlling system.

If you can create other events or triggers on the WPF code and bind to them from the winform that would be your best bet.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Chinmay PatelChief Technology NinjaCommented:
I partially agree with Snarf. If you follow MVVM through n through, ideally you would pass the reference of the WinForm to the UserControl's constructor(Dependency Injection), which then will set it as UserControl's ViewModel's property and can act as a bridge to call WinForm's functions.
Snarf0001Commented:
In theory I agree with Chinmay, but you're going to have issues actually passing in the reference to the winform, without getting the cyclic dependency issue mentioned.

I'm guessing that was the basis for "This is going to be fun." ;)

Ideally, you would have a separate project, that contained the references to the Excel functions and DataExport routines you mentioned off the start, and be passing those in through DI as necessary.  But that's a lot of reconstruction on your system, so just firing an event might be the quickest course.
Chinmay PatelChief Technology NinjaCommented:
I'm guessing that was the basis for "This is going to be fun." ;)
Yes :)

And no I am not asking to add reference in the project per say. The control anyways is added on WinForm right? So WinForm should be able to pass its own reference during the runtime when the constructor is called.
Snarf0001Commented:
Right, but without that reference, you wouldn't be able to actually pass the class type of the winform, as you still wouldn't have visibility of the Winform classes and objects.  The best you could do would be pass it as an object:

IE:
public WPFControl(object winForm) { }

In which case you'd have to use reflection to access any underlying items.

Or optionally could pass an interface in, which would go back to the 3rd shared project item.

Unless I'm completely missing something?
Chinmay PatelChief Technology NinjaCommented:
Yupp Object or ... dynamic ;) I don't endorse dynamic all the times but ... sometimes... it is ok ... thoughts?
Snarf0001Commented:
Yep, dynamic would be far easier than trying to code through reflection (on object).

Personally I would still code the other way, and have the wpf trigger events which the winform could call.  But just a matter of personal preference.
Dynamic ref passed in should work too.
TorrwinAuthor Commented:
Thanks everyone for jumping in!

After taking a deeper look, it seems like the original dev may not have understood WPF or perhaps we are just trying to use it differently.  

My gut feeling is similar to what you've mentioned above, which is to use this WPF control as a control only, and have very little code behind it other than what's necessary to trigger events, etc.  Thus, leveraging all the existing code in the main project.
gr8gonzoConsultantCommented:
On a side note, unless there's a good reason to have 2 separate projects (e.g. they each need to run separately or provide reusable functionality to other projects), I would just suggest merging them into one project, preferably making both into WPF. If the Winforms app was coded correctly well, then it shouldn't be a huge change to make.

WPF and Winforms have different view/rendering techniques, but the underlying C# code is the same, so if you have code that performs calculations or contacts a remote API or something like that, then that code should work the same in WPF as it did in Winforms. So the difficult here is just a matter of whether or not the original developer wrote code that TIGHTLY integrated into Winforms. If the controls make good use of data binding and/or models, then it's probably easier to migrate to WPF.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
WPF

From novice to tech pro — start learning today.