0

I am showing User Control as Dialog in WPF-MVVM application. Here is the code.

  var ProductView = new Product();
  var ProductViewModel = new ProductViewModel();
  ProductView.DataContext = ProductViewModel;
  this.ShowDialogWindow("Add Product", ProductView);

and this ShowDialogWindow Method is like this

 protected void ShowDialogWindow(string header, UserControl control)
 {
        RadWindow window = new RadWindow();
        window.Owner = App.Current.MainWindow;
        window.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
        window.Content = control;          
        window.Header = header;
        window.CanClose = true;
        window.ResizeMode = ResizeMode.NoResize;
        window.ShowDialog();
 }

Now, I have a button "Close" in the DialogWindow User Control. How can I close window using that button ?

NOTE: This is a WPF User Control not Window. I want to close using MVVM only

Chatra
  • 2,989
  • 7
  • 40
  • 73
  • You say it's not a window, but the ShowDialog creates and shows a window. Are you trying to have a view model close a view? If so I suggest using a mediator pattern to send and subscribe to messages, something like is discussed here: http://www.codeproject.com/Articles/35277/MVVM-Mediator-Pattern – Paul Gibson Apr 01 '15 at 16:23
  • @PaulGibson Window that is showing is also a User Control – Chatra Apr 01 '15 at 16:24

1 Answers1

1

Consider leveraging messaging with parameters to pass around data between your objects.

You can use an EventAggregator or MessageBus.

You can pull in the MessageBus from Nuget.

You can then do a subscribe and publish using MessageBus.Instance.

The idea is to have your user controls subscribe to events that they would like to respond to.

NOTE:

I do this with viewmodels. However, I think it is a code-smell when adding this code to user-controls that are meant to have general use regardless of the application employing them.

I use the Publish Subscribe pattern for complicated class-dependencies:

ViewModel:

    public class ViewModel : ViewModelBase
    {
        public ViewModel()
        {
            CloseComand = new DelegateCommand((obj) =>
                {
                    MessageBus.Instance.Publish(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, null);
                });
        }
}

Window:

public partial class SomeWindow : Window
{
    Subscription _subscription = new Subscription();

    public SomeWindow()
    {
        InitializeComponent();

        _subscription.Subscribe(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, obj =>
            {
                this.Close();
            });
    }
}

You can leverage Bizmonger.Patterns to get the MessageBus.

MessageBus

public class MessageBus
{
    #region Singleton
    static MessageBus _messageBus = null;
    private MessageBus() { }

    public static MessageBus Instance
    {
        get
        {
            if (_messageBus == null)
            {
                _messageBus = new MessageBus();
            }

            return _messageBus;
        }
    }
    #endregion

    #region Members
    List<Observer> _observers = new List<Observer>();
    List<Observer> _oneTimeObservers = new List<Observer>();
    List<Observer> _waitingSubscribers = new List<Observer>();
    List<Observer> _waitingUnsubscribers = new List<Observer>();

    int _publishingCount = 0;
    #endregion

    public void Subscribe(string message, Action<object> response)
    {
        Subscribe(message, response, _observers);
    }

    public void SubscribeFirstPublication(string message, Action<object> response)
    {
        Subscribe(message, response, _oneTimeObservers);
    }

    public int Unsubscribe(string message, Action<object> response)
    {
        var observers = new List<Observer>(_observers.Where(o => o.Respond == response).ToList());
        observers.AddRange(_waitingSubscribers.Where(o => o.Respond == response));
        observers.AddRange(_oneTimeObservers.Where(o => o.Respond == response));

        if (_publishingCount == 0)
        {
            observers.ForEach(o => _observers.Remove(o));
        }

        else
        {
            _waitingUnsubscribers.AddRange(observers);
        }

        return observers.Count;
    }

    public int Unsubscribe(string subscription)
    {
        var observers = new List<Observer>(_observers.Where(o => o.Subscription == subscription).ToList());
        observers.AddRange(_waitingSubscribers.Where(o => o.Subscription == subscription));
        observers.AddRange(_oneTimeObservers.Where(o => o.Subscription == subscription));

        if (_publishingCount == 0)
        {
            observers.ForEach(o => _observers.Remove(o));
        }

        else
        {
            _waitingUnsubscribers.AddRange(observers);
        }

        return observers.Count;
    }

    public void Publish(string message, object payload)
    {
        _publishingCount++;

        Publish(_observers, message, payload);
        Publish(_oneTimeObservers, message, payload);
        Publish(_waitingSubscribers, message, payload);

        _oneTimeObservers.RemoveAll(o => o.Subscription == message);
        _waitingUnsubscribers.Clear();

        _publishingCount--;
    }

    private void Publish(List<Observer> observers, string message, object payload)
    {
        Debug.Assert(_publishingCount >= 0);

        var subscribers = observers.Where(o => o.Subscription.ToLower() == message.ToLower());

        foreach (var subscriber in subscribers)
        {
            subscriber.Respond(payload);
        }
    }

    public IEnumerable<Observer> GetObservers(string subscription)
    {
        var observers = new List<Observer>(_observers.Where(o => o.Subscription == subscription));
        return observers;
    }

    public void Clear()
    {
        _observers.Clear();
        _oneTimeObservers.Clear();
    }

    #region Helpers
    private void Subscribe(string message, Action<object> response, List<Observer> observers)
    {
        Debug.Assert(_publishingCount >= 0);

        var observer = new Observer() { Subscription = message, Respond = response };

        if (_publishingCount == 0)
        {
            observers.Add(observer);
        }
        else
        {
            _waitingSubscribers.Add(observer);
        }
    }
    #endregion
}

}

Subscription

public class Subscription
{
    #region Members
    List<Observer> _observerList = new List<Observer>();
    #endregion

    public void Unsubscribe(string subscription)
    {
        var observers = _observerList.Where(o => o.Subscription == subscription);

        foreach (var observer in observers)
        {
            MessageBus.Instance.Unsubscribe(observer.Subscription, observer.Respond);
        }

        _observerList.Where(o => o.Subscription == subscription).ToList().ForEach(o => _observerList.Remove(o));
    }

    public void Subscribe(string subscription, Action<object> response)
    {
        MessageBus.Instance.Subscribe(subscription, response);
        _observerList.Add(new Observer() { Subscription = subscription, Respond = response });
    }

    public void SubscribeFirstPublication(string subscription, Action<object> response)
    {
        MessageBus.Instance.SubscribeFirstPublication(subscription, response);
    }
}
Scott Nimrod
  • 11,206
  • 11
  • 54
  • 118
  • You are talking about window. I clearly mention that I am using User Control. For Window, I can see this.close() but for User Control, there is Close() method – Chatra Apr 01 '15 at 16:36
  • Dialogs are "clearly" windows regardless of their content. A window is the control that you have the ability to close. – Scott Nimrod Apr 01 '15 at 16:37
  • I understand that but for the following code. there is no this.close() for user control. _subscription.Subscribe(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, obj => { this.Close(); }); – Chatra Apr 01 '15 at 16:39
  • Yes, because your usercontrol is contained within a Window element. So rely on your window instance to handle the close. Get your parent control until it is a window type and do it there. – Scott Nimrod Apr 01 '15 at 16:41
  • How can I get window instance of the user control ? – Chatra Apr 01 '15 at 16:42
  • http://stackoverflow.com/questions/5000228/how-can-you-get-the-parent-of-a-uielement and http://stackoverflow.com/questions/636383/how-can-i-find-wpf-controls-by-name-or-type – Scott Nimrod Apr 01 '15 at 16:43
  • in the window constructor code simply subscribe to the window close message and have the window close itself. – Paul Gibson Apr 01 '15 at 19:24