views:

5364

answers:

5

Hello, I am trying to find the right way to get the data from a ChildWindow/popup using a MVVM pattern in Silverlight (3). For example: I have a main page with a data entry form and I want to open a popup with a list of customers. When user selects a customer I want to transfer selected customer into the main page. This is what the (example) code which I am using at the moment:

Main page

public partial class MainPage : UserControl
{
    public MainPageViewModel ViewModel { get; private set; }

    public MainPage()
    {
        InitializeComponent();
        ViewModel = new MainPageViewModel();
        DataContext = ViewModel;
    }

    private void SearchCustomer_Click(object sender, RoutedEventArgs e)
    {
        ViewModel.SearchCustomer();
    }
}

public class MainPageViewModel: ViewModel
{
    private string customer;
    public string Customer
    {
        get { return customer; }
        set { customer = value; RaisePropertyChanged("Customer"); }
    }

    public void SearchCustomer()
    {
        // Called from a view
        SearchWindow searchWindow = new SearchWindow();
        searchWindow.Closed += (sender, e) =>
        {
            if ((bool)searchWindow.DialogResult)
            {
                Customer = searchWindow.ViewModel.SelectedCustomer.ToString();
            }
        };
        searchWindow.Show();
    }
}

Child window

public partial class SearchWindow : ChildWindow
{
    public SearchWindowViewModel ViewModel { get; private set; }

    public SearchWindow()
    {
        InitializeComponent();
        ViewModel = new SearchWindowViewModel();
        DataContext = ViewModel;
    }

    private void OKButton_Click(object sender, RoutedEventArgs e)
    {
        DialogResult = ViewModel.OkButtonClick();
    }

    private void CancelButton_Click(object sender, RoutedEventArgs e)
    {
        DialogResult = ViewModel.CancelButtonClick();
    }
}

public class SearchWindowViewModel: ViewModel
{
    private Customer selectedCustomer;        
    private ObservableCollection<Customer> customers;

    public ObservableCollection<Customer> Customers
    {
        get { return customers; }
        set {customers = value; RaisePropertyChanged("Customers"); }
    }

    public Customer SelectedCustomer
    {
        get { return selectedCustomer; }
        set { selectedCustomer = value; RaisePropertyChanged("SelectedCustomer"); }
    }

    public SearchWindowViewModel()
    {
        Customers = new ObservableCollection<Customer>();
        ISearchService searchService = new FakeSearchService();
        foreach (Customer customer in searchService.FindCustomers("dummy"))
            Customers.Add(customer);
    }

    public bool? OkButtonClick()
    {
        if (SelectedCustomer != null)
            return true;
        else
            return null; // show some error message before that
    }

    public bool? CancelButtonClick()
    {
        return false;
    }
}

Is this the right way or is there anything more "simple"?

Cheers, Rok

+4  A: 

More problematic here is the use of View specific terms and types in your VMs. Click events, DialogResults should not be anywhere near your ViewModels.

With regards to the question, I had a similiar question about this here: http://stackoverflow.com/questions/454868/handling-dialogs-in-wpf-with-mvvm

The answer I accepted was the use of the Mediator pattern to get around this. Have a look. :)

Ray Booysen
Thanks, I will take a look. I have found out that I'am doing it "completely" wrong and I already changed my code to use commands (binding to ICommand) and remove dialogresult out of the VM. The next step is to look at the Mediator pattern :)
rrejc
A: 

I have created a simple mvvm pattern example http://www.codeproject.com/KB/silverlight/Silverlightmvvm.aspx

prabhjot
The codeproject article appears to be deleted?
russau
A: 

I recently wrote an article that discusses MVVM in details, which also includes several samples related to using dialog box and message box in MVVM pattern. Check out http://tinyurl.com/383odnm for details.

Hope this helps.

James
A: 

A good MVVM library which supports opening child window is Chinch mvvm helper library. You can look at a sample at http://www.codeproject.com/KB/silverlight/SL4FileUploadAnd_SL4_MVVM.aspx.

Peter Starbek
+1  A: 

So, you have a simple problem with a simple solution. But you've decided to increase the complexity ten-fold by adhering to a design pattern (the fact that you've asked for help/clarification is evidence enough). Do yourself a favour. Just program the thing to do it's job. YOU tell the computer how to do it. Don't let something like a design pattern that is not necessary, divert your focus from the actual problem you are trying to solve.

Put yourself in the scenario of being face to face with a client who wants to know why the project he assigned you took four times longer to do and went 100K over budget.Your reply-

"You don't understand. That popup box there, to select the customer, knows nothing about the
main form to edit the customer. Absolutely nothing. Everything totally decoupled. Even the main
form is unaware of where it is or what it is for!!!"

Before any MVVM proffessionals (if this is being read more than three months after posting, replace MVVM with the current fad that is being adopted so that REAL programmers can be identified from the rest of the rabble) say it is much more than that and that I haven't got a clue what I am talking about, let me know when you are in the above situation. I would love to watch both your attempts at justification and the innevitable reaction.

Just a thought.

PS You may read this very same rant on other sites. I am trying to save others from feeling that they are missing something or there must be a reason for using it (MVVM). If your preferred method works, so what. Use a programming style that YOU find comfortable and that is most productive for YOU.

pdelaci