Chatra
Chatra

Reputation: 3129

Save and Close in Current Window in WPF-MVVM

I have two buttons Save, Save & Close in my window. If user clicks on Save, I am able to successfully save the details. I am unable to figure out on how to close window, when user clicks on Save & Close. Here is my code for Save

<telerik:RadButton x:Name="button_Save" Content="Save" Command="{Binding SaveProductCommand}" CommandParameter="{Binding ElementName=ProductName, Path=Text}" />

Here is my Relay Command.

public ICommand SaveProductCommand
{
  get 
  {
    return new RelayCommand<string>(SaveProductExecute);
  } 
 }

My First Question:

Can we pass one more parameter True or false for Save and Save&Close ? So that we can use only one Relay Command for both ?

Second Question:

How to close current Window after Saving ?

Upvotes: 1

Views: 2952

Answers (3)

Rohit
Rohit

Reputation: 10236

Good Question..the key here is to use Action.Take a look at my sample

We will try to keep coding to minimal..

Can we pass one more parameter True or false for Save and Save&Close ? So that we can use only one Relay Command for both ?

Since you havent mentioned how you are passing true or false I have included a Listbox which has two string items True and False.

If true is selected only one part of command will execute and if false is selected we will perform both the methods in the command.

  1. Create a view with Button and Listbox

      <ListBox x:Name="items">
        <System:String>True</System:String>
        <System:String>False</System:String>
      </ListBox>
    
    <Button Content="MyButton" Command="{Binding Path=MyCustomCommand}" 
    CommandParameter="{Binding SelectedItem,ElementName=items}"/> 
    
  2. Create ViewModel i.e MyViewModel.cs

    public class MyViewModel : INotifyPropertyChanged
    {
    
       public Action CloseAction { get; set; }
       public ICommand MyCustomCommand { get; set; }
    
    
       public MyViewModel()
       {
          MyCustomCommand = new RelayCommand(new Action<object>(MyFunction));
       }
    
    
       private void MyFunction(object MyCommandParameter)
       {
        if (Convert.ToString(MyCommandParameter) == "True")
        {
            MessageBox.Show("Save Executed");
        }
        else
        {
            MessageBox.Show("Save Execcuted");
            CloseAction();
        }
    }
    
  3. In View Codebehind

      public partial class MainWindow : Window
      {
         public MainWindow()
         {
            InitializeComponent();
            MyViewModel mv = new MyViewModel();
            this.DataContext = mv;
    
            if (mv.CloseAction == null)
                mv.CloseAction = new Action(() => this.Close());
          }
      }
    

Upvotes: 2

Scott Nimrod
Scott Nimrod

Reputation: 11595

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

You can use an EventAggregator or MessageBus.

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);
    }
}

Upvotes: 0

Muds
Muds

Reputation: 4116

to ans your 2 questions --

yes you can multi bind ... doing something like this ..

<Button.CommandParameter>
    <MultiBinding>
         <Binding Path="path" ElementName="elementName"/>
         <Binding Path="path2" ElementName="elementName2"/>
    </MultiBinding>
</Button.CommandParameter>

and there are many ways to close the window please have a look here and here

Upvotes: 0

Related Questions