1
votes

I have an application in which a user fills out a form, if the user doesn't press save and loads another control/button i need to stop the user leaving and destroying the user control. There isn't a Closing event on a User Control. i tried Unloaded but this has already disconnected from the visual tree. Do i have to have to create variables throughout to check? is there an event to use for this situation?

Update

So i have one window for the application and many user controls load in a grid, for example if a client press contact then a new contact user control will occur as a child of the window. If the user hasn't pressed save i want the user control to not be removed and prompt a message. Hope that explains a bit more.

3
I had a variable as a flag in my mind, but it seemed too outdated. Looking for an event based solution. - timblistic
Maybe LostFocus event may help you. Can you be more specific? - cdmnk
So, you need to block user ability to close child window without pressing specific button, right? - cdmnk
Best way is probably be a flag. If you try to change page and the usercontrol has not been saved, prompt a message - nkoniishvt
if the child window is a user control, then that is correct :) - Bish25

3 Answers

1
votes

So, as far as I understand your question, you swap user controls in your main window's code. You don't want one of the controls to be swapped if inputs are incomplete.

You have to code this yourself. Probably you have a method like the following in your main window's code to switch to another UserControl:

private void SwapView(UserControl newView)
{
    // Remove old user control
    ...

    // Show new user control
    ...
}

What you need is some flag in your UserControl derived class that indicates whether it is possible to swap or not. Best, you define an interface like this:

public interface IView
{
    bool CanClose();
}

and have all your UserControls implement it:

public class MyControl : UserControl, IView
{
    ...

    public bool CanClose()
    {
        // Determine whether control can be closed
        bool result = ...
        return result;
    }

    ...
}

Then you can change the above method to:

private void SwapView(IView newView)
{
    // Get current view
    IView currentView = ...

    // Check whether it can be closed
    if (!currentView.CanClose())
    {
        ...
        return;
    }

    // Remove old user control
    ...

    // Show new user control
    ...
}

You can easily extend this so that a message is shown to the user providing a reason for not being able to change views.

0
votes

The simpliest and probably most elegant solution is to use this attached property

public static class WindowEventHelpers
    {
        #region Static Fields

        /// <summary>
        /// Attached property to define the command to run when the windows is closing
        /// </summary>
        public static readonly DependencyProperty WindowClosingCommandProperty = DependencyProperty.RegisterAttached(
            "WindowClosingCommand",
            typeof(ICommand),
            typeof(WindowEventHelpers),
            new PropertyMetadata(null, OnWindowClosingCommandChanged));


        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Returns the WindowClosingCommand dependency property value.
        /// </summary>
        /// <param name="target">
        /// The <see cref="DependencyProperty"/> identifier.
        /// </param>
        /// <returns>
        /// The WindowClosingCommand dependency property value.
        /// </returns>
        public static ICommand GetWindowClosingCommand(DependencyObject target)
        {
            return (ICommand)target.GetValue(WindowClosingCommandProperty);
        }

        /// <summary>
        /// Set the WindowClosingCommand dependency property value
        /// </summary>
        /// <param name="target">
        /// The <see cref="DependencyProperty"/> identifier.
        /// </param>
        /// <param name="value">
        /// The dependency property value.
        /// </param>
        public static void SetWindowClosingCommand(DependencyObject target, ICommand value)
        {
            target.SetValue(WindowClosingCommandProperty, value);
        }

        /// <summary>
        /// Returns the WindowClosingCommand dependency property value.
        /// </summary>
        /// <param name="target">
        /// The <see cref="DependencyProperty"/> identifier.
        /// </param>
        /// <returns>
        /// The WindowClosingCommand dependency property value.
        /// </returns>
        public static ICommand GetWindowContentRenderedCommand(DependencyObject target)
        {
            return (ICommand)target.GetValue(WindowContentRenderedCommandProperty);
        }

        #endregion

        #region Methods

        private static void ClosingEventHandler(object sender, CancelEventArgs e)
        {
            var control = (Window)sender;
            var command = (ICommand)control.GetValue(WindowClosingCommandProperty);
            command.Execute(e);
        }


        private static void OnWindowClosingCommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
        {
            var command = (ICommand)e.NewValue;

            if (target is Window)
            {
                // var fe = (FrameworkElement)target;
                var control = (Window)target;

                //check if we need to add the event handler or we need to remove it
                if ((command != null) && (e.OldValue == null))
                {
                    control.Closing += ClosingEventHandler;
                }
                else if ((command == null) && (e.OldValue != null))
                {
                    control.Closing += ClosingEventHandler;
                }
            }
        }


        #endregion
    }

In the XAML you then need to bind

ap:WindowEventHelpers.WindowClosingCommand="{Binding CheckBeforeClosing}"

finally in the code behind or ViewModel you need to define and initiate a new command:

public ICommand CheckBeforeClosing
{
  get;
  private set;
}

this.CheckBeforeClosing = new Command<CancelEventArgs>(this.CheckBeforeClosingMethod);

private void CheckBeforeClosingMethod(CancelEventArgs EventArgs)
{
      //Cancel the closing TODO Add the check
      EventArgs.Cancel = true;       
}
-1
votes

You can override the OnClosing event.

    protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
    {
        base.OnClosing(e);
    }