Earn More by Sharing What You Love
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Tim Corey
44m 47s
In Lesson 16 of the "C# App Start to Finish" course, Tim Corey continues building the Create Tournament form, but the real learning objective goes far beyond wiring buttons and list boxes. As Tim works through connecting forms together, he introduces a core software design concept in C#: interfaces used for loose coupling. This lesson shows interfaces not as an abstract academic idea, but as a practical tool to solve real problems in a WinForms application.
In this article, we take a deeper look at how Tim Corey explains interfaces, why he uses them, and how they help avoid tight coupling. All explanations, reasoning, and conclusions come directly from Tim's walkthrough, using his flow, terminology, and examples from the transcript.
At 1:18, Tim begins wiring up the Create Prize and Create Team UI elements. He immediately points out that this step can feel intimidating, not because calling another form is hard, but because getting data back correctly is where people usually go wrong.
Tim explains that the challenge isn't opening another form - that part is easy. The challenge is how one form communicates back to another without creating long-term design problems. This is where the idea of defining contracts instead of dependencies starts to matter.
Around 1:34, Tim explicitly calls out a common mistake: directly tying the Create Tournament form to the Create Prize form. In this approach, one class knows exactly which other class it is talking to.
Tim explains that this creates tight coupling, meaning the forms depend on each other directly. If one form changes, the other is affected. If another part of the program later wants the same functionality, it can't reuse it.
He emphasizes that while this might compile and work, it's not a good long-term design choice, especially in larger systems or professional environments.
At 2:02, Tim pauses and writes out the steps instead of jumping straight into code. He lists:
Tim explains that writing steps first helps avoid logic errors and makes the intent of the code clear. This structured thinking becomes especially important once interfaces are introduced, because interfaces define what must happen, not how it happens.
Around 4:56, Tim explains an important detail about models being passed around. He reminds viewers that they are passing around addresses, not copies of objects.
When the prize is saved through the data connector, the model already has its ID populated. Tim points out that returning the model again is often unnecessary because the instance has already been modified.
This reinforces why interfaces don't exist to move data blindly - they exist to signal completion and responsibility, not duplication.
At 6:42, Tim discusses the idea of passing a PrizeModel into the form constructor so both forms share the same instance.
He explains why this fails in a real use case: if the user cancels the form, you end up with an empty or invalid prize in your list. Tim shows that just because two classes can share instance data doesn't mean they should.
This moment reinforces the idea that interfaces define behavior, not data storage.
Around 7:46, Tim addresses another common approach: passing the entire Create Tournament Form into the Create Prize Form and calling a public method like SavePrize.
Tim explains why this is even worse:
He explicitly names this as tight coupling, which is what we are trying to avoid.
At 9:01, Tim introduces the solution: an interface.
He creates a new interface using the interface keyword and names it IPrizeRequester. Tim reminds viewers that an interface:
The interface contains a single method:
Tim explains that this method defines what must happen, not how it happens.
At 9:40, Tim explains that whoever implements this interface agrees to support that method. The interface has public members by default, and it does not declare instance data.
This is where Tim makes it clear that interfaces define capability, not storage. The implementing class decides what to do when the method is called.
At 10:19, Tim modifies the Create Prize Form constructor to accept an IPrizeRequester instead of a concrete form.
He explains that this means:
This is loose coupling in practice. The prize form depends on an interface type, not a specific class.
At 11:06, Tim stores the interface instance at the class level. He explains that constructor parameters only exist inside the constructor unless they are stored.
This allows the prize form to later call PrizeComplete from inside the button click event.
At 11:49, Tim demonstrates the key moment:
callingForm.PrizeComplete(model);
He explains that the prize form is now calling back to whoever implemented the interface and saying:
"I'm done, and here is the completed model."
Only after this call does the form close. This guarantees that the prize is only added when creation was successful.
At 13:29, Tim switches to the Create Tournament Form and implements the interface.
He explains the this keyword at 13:58, describing it as the current instance - the actual object in memory. By passing this, the form is handing over its address, but only through the interface contract.
At 18:41, Tim introduces a second interface: ITeamRequester.
He explains that while a class can inherit from only one base class (like Form), it can implement multiple interfaces. This allows a single class to support multiple unrelated behaviors without multiple inheritance.
Tim emphasizes that interfaces do not bring in code - they only define required methods.
Near 42:08, Tim reflects on why using patterns matters. Repeating the same interface-based structure makes missing steps obvious and debugging easier.
Tim encourages writing things down, using consistent patterns, and not trying to hold everything in your head. According to him, good design is not about perfection - it's about clarity, structure, and making future changes easier.
In Lesson 16, Tim Corey uses a real WinForms use case to demonstrate how interfaces enable loose coupling. Rather than relying on abstract examples, he shows how interfaces:
By the end of the lesson, the application doesn't just work - it is structured in a way that supports growth, reuse, and clarity. Tim's approach makes interfaces feel practical, purposeful, and essential in real-world C# development.
For a complete, end-to-end application of these interface and loose-coupling concepts in action, watch the full Lesson 16 video, where every step is implemented, tested, and refined within the working C# application.
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!
Join our newsletter, you’ll get exclusive access on article updates. We value your privacy