views:

49

answers:

2

I have two windows in my WPF app: a login window and an options window. Both have the same form with a user name and password field, as well as some other fields for providing credentials. I want some code that knows there will be a txt_userName TextBox available, for example, and can do things based on that. I was thinking I could make some kind of IHaveCredentialsForm interface and have both LoginWindow and OptionsWindow implement it, but when I tried, I got "'MyNamespace.LoginWindow' does not implement interface member 'MyNamespace.IHaveCredentialsForm.txt_userName'". Here's my interface so far:

interface IHaveCredentialsForm
{
    TextBox txt_userName { get; set; }
}

I was thinking I got the error because LoginWindow is a partial class that inherits from Window. I can definitely access a TextBox called txt_userName inside the methods of LoginWindow, though I haven't explicitly defined such a property. It magically appeared from having a TextBox with that name in LoginWindow.xaml, I assume.

How can I go about DRYing this out? I already have a method for doing stuff with string values for the user name, password, etc., but it seems redundant to have two different classes that are passing in txt_userName.Text, pwb_password.Password, ...--the same arguments to the same method.

While I'm at it, how could I share a chunk of XAML (the credentials form) between two different windows?

+3  A: 

You could DRY this out by creating a reusable user control which you could place on both forms.

Darin Dimitrov
Awesome! I wasn't familiar with user controls (only recently started using WPF). I implemented your suggestion; that helps my XAML.
Sarah Vessels
After further refactoring, this helps my C#, too, because I have the .xaml.cs class for my user control to do the work specific to my `txt_userName`, etc. fields.
Sarah Vessels
+1  A: 

I would move the logic out of the code behind and into a separate class. Then use data binding to link the properties in the class to the textboxes in the UI.

Something like:

//ViewModel class
public class UserViewModel
{
    public string Username { get; set; }
    public string Password { get; set; }
}

<!--View XAML-->
<TextBox x:Name="txt_username" Text="{Binding Username}" />
<TextBox x:Name="txt_password" Text="{Binding Password}" />

This not only will stop you from repeating yourself, but is good practice because it will allow you to test your business logic code separately from the UI.

For WPF a popular design for this type of programming is the MVVM pattern. There is a question here that will help you grasp the basics, and plenty of tutorials around in the wider web.

After you have moved all the logic out you can create a UserControl that holds the XMAL for the two textboxes (and their bindings) that can be used in both of the views so that you aren't repeating that either.


A couple of quick notes with this approach:

  • Make sure that you implement INotifyPropertyChanged on your viewmodel to make the binding work
  • If you use a PasswordBox in your XAML then there are some gotchas regarding databinding
Martin Harris