8

I need to implement a custom window decorator where a Close button will behave exactly as the close or x button on all Windows applications.

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
kumarharsh
  • 18,961
  • 8
  • 72
  • 100

6 Answers6

22

Simply call the close() function from your button:

WPF:

<Button Name="CloseButton" Content="x" Click="CloseButton_Click" />

code-behind:

private void CloseButton_Click(object sender, RoutedEventArgs e)
{
    Close();
}
Martin Hennings
  • 16,418
  • 9
  • 48
  • 68
  • 2
    I tried command="close" and nothing happens. Is there something else that needs to be done to get command="close" to actually close the window? – James Sep 11 '14 at 15:23
2

If you want the Button which will close the dialog Window, you can add for him IsCancel property:

<Button Name="CloseButton"
        IsCancel="True" ... />

This means the following MSDN:

When you set the IsCancel property of a Button to true, you create a Button that is registered with the AccessKeyManager. The button is then activated when a user presses the ESC key.

Now, if you click on this Button, or press Esc then dialog Window is closing, but it does not work for the normal MainWindow.

To close the MainWindow, you can simply add a Click handler which has already been shown. But if you want a more elegant solution that would satisfy the MVVM style you can add the following attached behavior:

public static class ButtonBehavior
{
    #region Private Section

    private static Window MainWindow = Application.Current.MainWindow;

    #endregion

    #region IsCloseProperty

    public static readonly DependencyProperty IsCloseProperty;

    public static void SetIsClose(DependencyObject DepObject, bool value)
    {
        DepObject.SetValue(IsCloseProperty, value);
    }

    public static bool GetIsClose(DependencyObject DepObject)
    {
        return (bool)DepObject.GetValue(IsCloseProperty);
    }

    static ButtonBehavior()
    {
        IsCloseProperty = DependencyProperty.RegisterAttached("IsClose",
                                                              typeof(bool),
                                                              typeof(ButtonBehavior),
                                                              new UIPropertyMetadata(false, IsCloseTurn));
    }

    #endregion

    private static void IsCloseTurn(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue is bool && ((bool)e.NewValue) == true)
        {
            if (MainWindow != null)
                MainWindow.PreviewKeyDown += new KeyEventHandler(MainWindow_PreviewKeyDown);

            var button = sender as Button;

            if (button != null)
                button.Click += new RoutedEventHandler(button_Click);
        }
    }

    private static void button_Click(object sender, RoutedEventArgs e)
    {
        MainWindow.Close();
    }

    private static void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Escape)
            MainWindow.Close();
    }
}

And in Window use like this:

<Window x:Class="MyProjectNamespace.MainWindow" 
        xmlns:local="clr-namespace:MyProjectNamespace">

    <Button Name="CloseButton"
            local:ButtonBehavior.IsClose="True" ... />

Now the MainWindow can be closed by clicking on the Button or pressing Esc, and it all happens independent from View (UI).

Anatoliy Nikolaev
  • 22,370
  • 15
  • 69
  • 68
2

If you would like to use MVVM architecture, then you can pass the name of your window as a Command Parameter and in the Command you can close the window.

The code would be something like this:

Button Command="{Binding MainCloseButtonCommand}"
CommandParameter="{Binding ElementName=mainWindow}"

private void performMainCloseButtonCommand(object Parameter)
{
    Window objWindow  = Parameter as Window;
    objWindow.Close();
}
DarthJDG
  • 16,511
  • 11
  • 49
  • 56
Paras
  • 37
  • 1
1

If you add a button to your current view lets say from code behind:

var closeButton = new Button();
closeButton.Click += closeButton_Click;

// Add the button to the window
Content = closeButton;

Then you can respond to the event and just call Close() like this:

void closeButton_Click(object sender, RoutedEventArgs e)
{
    Close();
}

What this basicly does is that it adds a button to your Window / UserControl and when you press it, it will close the Window.

If you do it from XAML it could look like this:

<Button Name="closeButton" Click="closeButton_Click" />

Filip Ekberg
  • 36,033
  • 20
  • 126
  • 183
0

Actually it is this:

<Window Name = "Chrome">
   .
   .
  <Button Name="closeButton" onClick="terminateApplication"/>
   .
</Window>

and in the CS file,

private void terminateApplication(object sender, RoutedEventArgs e)
{
     Chrome.Close();
}
kumarharsh
  • 18,961
  • 8
  • 72
  • 100
  • What do I not understand about this? If you are within the code-behind of the window, you don't need to call it by name. So your code is basically a longer version of the code in the other answers. I'm afraid your answer is risking a downvote. – Martin Hennings Mar 04 '11 at 12:52
  • this was a more 'generalized' answer.... also, i was writing this when 2 more answers poured in... :D – kumarharsh Mar 04 '11 at 13:02
0

Use close button with viewmodel. View model IS NOT DEPEND on gui.

namespace YourLibrary.ComponentModel
{
   /// <summary>
  /// Defines Close method. Use for window, file stream,.... 
  /// </summary>
  public interface IClosable
  {
      /// <summary>
      /// Close of instance (window, file stream,... etc).
      /// </summary>
      void Close();
  }

}

MyWindow.xaml

  <Window  ...
       x:Name="ThisInstance"   
       ...
   >


   <Button Command="{Binding ButtonCommand}" CommandParameter="{Binding ElementName=ThisInstance}">

MyWindow.xaml.cs

public partial class MyWindow : Window, YourLibrary.ComponentModel.IClosable
{
 ....
}

MyViewModel.cs

public class MyViewModel 
{
  ICommand buttonCommand;
  /// <summary>
  /// Command for Button.
  /// Default action is close the window.  
  /// Close window via retyping parameter as <see cref="IClosable"/> 
  /// </summary>
  public ICommand ButtonCommand => buttonCommand ?? (buttonCommand=new RelayCommand(ButtonCommandExecute));
  void ButtonCommandExecute (object obj) 
  {
      var myWindow = (IClosable)obj;
      myWindow.Close();
  };

TESTING, USE VIEWMODEL IN CONSOLE

 class Program
 {
    public class ConsoleWindow : YourLibrary.ComponentModel.IClosable
    {
        public void Close()
        {
            Console.WriteLine("Closing area...");
        }
    }


    static void Main(string[] args)
    {
        var program = new Program();
        program.DoMain(args);
    }

    public void DoMain(string[] args)
    {
        var consoleWindow = new ConsoleWindow();
        var viewModel = new MyViewModel()
        viewModel.ButtonCommand.Execute(consoleWindow);
    }
 }
lison
  • 189
  • 1
  • 6