├── Example
├── OriginalLogo.png
├── app.config
├── App.xaml
├── App.xaml.cs
├── Controls
│ ├── ExampleControl.xaml
│ └── ExampleControl.xaml.cs
├── Properties
│ └── AssemblyInfo.cs
├── Main.xaml
├── Example.csproj
└── Main.xaml.cs
├── WPF.MDI
├── Themes
│ ├── Aero
│ │ ├── Close.png
│ │ ├── Maximize.png
│ │ ├── Minimize.png
│ │ ├── Restore.png
│ │ ├── MaximizedClose.png
│ │ ├── MaximizedRestore.png
│ │ └── MaximizedMinimize.png
│ ├── Luna
│ │ ├── CloseDown.png
│ │ ├── CloseOver.png
│ │ ├── LeftFocused.png
│ │ ├── RestoreDown.png
│ │ ├── RestoreOver.png
│ │ ├── LeftUnfocused.png
│ │ ├── MaximizeDown.png
│ │ ├── MaximizeOver.png
│ │ ├── MinimizeDown.png
│ │ ├── MinimizeOver.png
│ │ ├── RightFocused.png
│ │ ├── MaximizedClose.png
│ │ ├── MaximizedRestore.png
│ │ ├── MinimizeNormal.png
│ │ ├── RightUnfocused.png
│ │ ├── TopLeftFocused.png
│ │ ├── TopLeftUnfocused.png
│ │ ├── TopMiddleFocused.png
│ │ ├── TopRightFocused.png
│ │ ├── BottomLeftFocused.png
│ │ ├── BottomRightFocused.png
│ │ ├── CloseNormalFocused.png
│ │ ├── MaximizedMinimize.png
│ │ ├── TopMiddleUnfocused.png
│ │ ├── TopRightUnfocused.png
│ │ ├── BottomLeftUnfocused.png
│ │ ├── BottomMiddleFocused.png
│ │ ├── BottomMiddleUnfocused.png
│ │ ├── BottomRightUnfocused.png
│ │ ├── CloseNormalUnfocused.png
│ │ ├── MaximizeNormalFocused.png
│ │ ├── MinimizeNormalFocused.png
│ │ ├── MinimizedLeftFocused.png
│ │ ├── MinimizedRightFocused.png
│ │ ├── RestoreNormalFocused.png
│ │ ├── MaximizeDisabledFocused.png
│ │ ├── MaximizeNormalUnfocused.png
│ │ ├── MinimizeDisabledFocused.png
│ │ ├── MinimizeNormalUnfocused.png
│ │ ├── MinimizedLeftUnfocused.png
│ │ ├── MinimizedMiddleFocused.png
│ │ ├── MinimizedRightUnfocused.png
│ │ ├── RestoreNormalUnfocused.png
│ │ ├── MaximizeDisabledUnfocused.png
│ │ ├── MinimizeDisabledUnfocused.png
│ │ └── MinimizedMiddleUnfocused.png
│ ├── Generic.xaml
│ ├── Aero.xaml
│ └── Luna.xaml
├── Enums
│ ├── ThemeType.cs
│ └── MdiLayout.cs
├── Event
│ └── ClosingEventArgs.cs
├── Properties
│ └── AssemblyInfo.cs
├── WPF.MDI.csproj
├── MdiContainer.cs
└── MdiChild.cs
├── WPF.MDI.sln
├── README.md
├── .gitignore
└── LICENSE.md
/Example/OriginalLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/Example/OriginalLogo.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Aero/Close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Aero/Close.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Aero/Maximize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Aero/Maximize.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Aero/Minimize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Aero/Minimize.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Aero/Restore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Aero/Restore.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/CloseDown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/CloseDown.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/CloseOver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/CloseOver.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/LeftFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/LeftFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/RestoreDown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/RestoreDown.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/RestoreOver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/RestoreOver.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/LeftUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/LeftUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MaximizeDown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MaximizeDown.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MaximizeOver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MaximizeOver.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizeDown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizeDown.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizeOver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizeOver.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/RightFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/RightFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Aero/MaximizedClose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Aero/MaximizedClose.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Aero/MaximizedRestore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Aero/MaximizedRestore.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MaximizedClose.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MaximizedClose.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MaximizedRestore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MaximizedRestore.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizeNormal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizeNormal.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/RightUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/RightUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/TopLeftFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/TopLeftFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/TopLeftUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/TopLeftUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/TopMiddleFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/TopMiddleFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/TopRightFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/TopRightFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Aero/MaximizedMinimize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Aero/MaximizedMinimize.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/BottomLeftFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/BottomLeftFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/BottomRightFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/BottomRightFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/CloseNormalFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/CloseNormalFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MaximizedMinimize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MaximizedMinimize.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/TopMiddleUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/TopMiddleUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/TopRightUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/TopRightUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/BottomLeftUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/BottomLeftUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/BottomMiddleFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/BottomMiddleFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/BottomMiddleUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/BottomMiddleUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/BottomRightUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/BottomRightUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/CloseNormalUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/CloseNormalUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MaximizeNormalFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MaximizeNormalFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizeNormalFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizeNormalFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizedLeftFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizedLeftFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizedRightFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizedRightFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/RestoreNormalFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/RestoreNormalFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MaximizeDisabledFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MaximizeDisabledFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MaximizeNormalUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MaximizeNormalUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizeDisabledFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizeDisabledFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizeNormalUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizeNormalUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizedLeftUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizedLeftUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizedMiddleFocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizedMiddleFocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizedRightUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizedRightUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/RestoreNormalUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/RestoreNormalUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MaximizeDisabledUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MaximizeDisabledUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizeDisabledUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizeDisabledUnfocused.png
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna/MinimizedMiddleUnfocused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dutts/wpfmdi/HEAD/WPF.MDI/Themes/Luna/MinimizedMiddleUnfocused.png
--------------------------------------------------------------------------------
/Example/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Example/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Windows;
6 |
7 | namespace Example
8 | {
9 | ///
10 | /// Interaction logic for App.xaml
11 | ///
12 | public partial class App : Application
13 | {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/WPF.MDI/Enums/ThemeType.cs:
--------------------------------------------------------------------------------
1 | namespace WPF.MDI
2 | {
3 | ///
4 | /// Type of theme to use.
5 | ///
6 | public enum ThemeType
7 | {
8 | ///
9 | /// Generic Visual Studio designer theme.
10 | ///
11 | Generic,
12 | ///
13 | /// Windows XP blue theme.
14 | ///
15 | Luna,
16 | ///
17 | /// Windows Vista and 7 theme.
18 | ///
19 | Aero
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Example/Controls/ExampleControl.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Example/Controls/ExampleControl.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace Example.Controls
4 | {
5 | ///
6 | /// Interaction logic for ExampleControl.xaml
7 | ///
8 | public partial class ExampleControl : UserControl
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | public ExampleControl()
14 | {
15 | InitializeComponent();
16 |
17 | Width = double.NaN;
18 | Height = double.NaN;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/WPF.MDI/Event/ClosingEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace WPF.MDI
4 | {
5 | public class ClosingEventArgs : RoutedEventArgs
6 | {
7 | ///
8 | /// Gets or sets a value indicating whether the event should be canceled.
9 | ///
10 | /// true if the event should be canceled; otherwise, false.
11 | public bool Cancel { get; set; }
12 |
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | /// The routed event.
17 | public ClosingEventArgs(RoutedEvent routedEvent) : base(routedEvent)
18 | {
19 |
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/WPF.MDI/Enums/MdiLayout.cs:
--------------------------------------------------------------------------------
1 | namespace WPF.MDI
2 | {
3 | ///
4 | /// Specifies the layout of MdiChild windows in an MdiContainer control.
5 | ///
6 | public enum MdiLayout
7 | {
8 | ///
9 | /// All MdiChild windows are cascaded within the client region of the MdiContainer control.
10 | ///
11 | Cascade,
12 | ///
13 | /// All MdiChild windows are tiled horizontally within the client region of the MdiContainer control.
14 | ///
15 | TileHorizontal,
16 | ///
17 | /// All MdiChild windows are tiled vertically within the client region of the MdiContainer control.
18 | ///
19 | TileVertical,
20 | ///
21 | /// All MdiChild icons are arranged within the client region of the MdiContainer control.
22 | ///
23 | ArrangeIcons
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Example/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("Example")]
11 | [assembly: AssemblyDescription("http://wpfmdi.codeplex.com/")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("xadet")]
14 | [assembly: AssemblyProduct("Example")]
15 | [assembly: AssemblyCopyright("2009 xadet, 2010 stbear")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 |
20 | [assembly: ThemeInfo(
21 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
22 | //(used if a resource is not found in the page,
23 | // or application resource dictionaries)
24 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
25 | //(used if a resource is not found in the page,
26 | // app, or any theme specific resource dictionaries)
27 | )]
28 | [assembly: AssemblyVersion("1.0.0.0")]
29 | [assembly: AssemblyFileVersion("1.0.0.0")]
30 |
--------------------------------------------------------------------------------
/WPF.MDI/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("WPF.MDI")]
11 | [assembly: AssemblyDescription("http://wpfmdi.codeplex.com/")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("xadet")]
14 | [assembly: AssemblyProduct("WPF.MDI")]
15 | [assembly: AssemblyCopyright("2009 xadet, 2010 stbear")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 |
20 | [assembly: ThemeInfo(
21 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
22 | //(used if a resource is not found in the page,
23 | // or application resource dictionaries)
24 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
25 | //(used if a resource is not found in the page,
26 | // app, or any theme specific resource dictionaries)
27 | )]
28 | [assembly: AssemblyVersion("1.1.1.0")]
29 | [assembly: AssemblyFileVersion("1.1.1.0")]
30 |
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Generic.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
35 |
--------------------------------------------------------------------------------
/WPF.MDI.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPF.MDI", "WPF.MDI\WPF.MDI.csproj", "{BE1ED569-5E0B-4DF0-8964-33AD2AAE4C4A}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{1F896089-1817-4D8A-A352-83B13264FE75}"
7 | EndProject
8 | Global
9 | GlobalSection(TeamFoundationVersionControl) = preSolution
10 | SccNumberOfProjects = 3
11 | SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
12 | SccTeamFoundationServer = https://tfs.codeplex.com/tfs/tfs05
13 | SccLocalPath0 = .
14 | SccProjectUniqueName1 = WPF.MDI\\WPF.MDI.csproj
15 | SccProjectName1 = WPF.MDI
16 | SccLocalPath1 = WPF.MDI
17 | SccProjectUniqueName2 = Example\\Example.csproj
18 | SccProjectName2 = Example
19 | SccLocalPath2 = Example
20 | EndGlobalSection
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Debug|Any CPU = Debug|Any CPU
23 | Release|Any CPU = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {BE1ED569-5E0B-4DF0-8964-33AD2AAE4C4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {BE1ED569-5E0B-4DF0-8964-33AD2AAE4C4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {BE1ED569-5E0B-4DF0-8964-33AD2AAE4C4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {BE1ED569-5E0B-4DF0-8964-33AD2AAE4C4A}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {1F896089-1817-4D8A-A352-83B13264FE75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {1F896089-1817-4D8A-A352-83B13264FE75}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {1F896089-1817-4D8A-A352-83B13264FE75}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {1F896089-1817-4D8A-A352-83B13264FE75}.Release|Any CPU.Build.0 = Release|Any CPU
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | EndGlobal
39 |
--------------------------------------------------------------------------------
/Example/Main.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WPF Multiple Document Interface (MDI)
2 |
3 | ### [ Migrated from [CodePlex](https://wpfmdi.codeplex.com) 24th November 2017 ]
4 |
5 | ## Project Description
6 | A library to add the traditional Windows Forms Multiple Document Interface (MDI) features to WPF. The aim is to resemble the original as much as possible.
7 |
8 | ## Themes
9 | WPF MDI includes two themes, Luna (XP) and Aero (Vista & 7) as well as support for custom themes. Themes are used depending on the operating system, although a theme can be set at compile and/or run time also.
10 |
11 | ## Using the Control
12 | The control supports both XAML and code use.
13 |
14 | To use the control in XAML, add the dll as a reference in the project and add the following line to the top of your XAML file underneath the xmlns declarations
15 |
16 | ```xml
17 | xmlns:mdi="clr-namespace:WPF.MDI;assembly=WPF.MDI"
18 | ```
19 |
20 | To create a container add the following code, it works much like a grid or panel does
21 |
22 | ```xml
23 |
24 | ```
25 |
26 | Optionally, you could specify a theme here too
27 |
28 | ```xml
29 |
30 | ```
31 |
32 | To add a child to the container, add an MdiChild control inside the MdiContainer
33 |
34 | ```xml
35 |
36 |
37 |
38 | ```
39 |
40 | Properties here which can be used are
41 | * Title (e.g. Title="Window 1")
42 | * Icon (e.g. Icon="MyIcon.png")
43 | * ShowIcon - Sets whether the icon should be show (e.g. ShowIcon="false" to hide)
44 | * MinimizeBox - Sets whether the minimize box should be enabled (e.g. MinimizeBox="false" to disable)
45 | * MaximizeBox - Sets whether the maximize box should be enabled (e.g. MaximizeBox="false" to disable)
46 | * Resizable - Sets whether the window is resizable (e.g. Resizable="false" to prevent the user from resizing the window)
47 | * Default FrameworkElement properties - Background, BorderBrush, Margin, Width, Height etc.
48 |
49 | For example, the following will set the title of the window to Window 1, prevent the user from resizing the window, disable the minimize button and make the background of the window dark gray
50 |
51 | ```xml
52 |
53 |
54 |
55 | ```
56 |
57 | Inside the MdiChild element you can specify content such as a custom made user control or create a grid and place all of your control inside the window
58 |
59 | ```xml
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | ```
70 |
71 | To use code to create add windows, create your MdiContainer in the XAML as previously explained, name it something appropriate such as WindowContainer and use the Children list to add windows
72 |
73 | ```csharp
74 | WindowContainer.Children.Add(new MdiChild()
75 | {
76 | Title = "Window 1"
77 | });
78 | ```
79 | To add controls, use the Content property
80 |
81 | ```csharp
82 | WindowContainer.Children.Add(new MdiChild()
83 | {
84 | Title = "Window 1",
85 | Content = new ExampleControl()
86 | });
87 | ```
88 |
89 | For more examples, check out the Examples folder in the repo.
--------------------------------------------------------------------------------
/Example/Example.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 9.0.30729
7 | 2.0
8 | {1F896089-1817-4D8A-A352-83B13264FE75}
9 | WinExe
10 | Properties
11 | Example
12 | Example
13 | v4.0
14 | 512
15 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
16 | 4
17 |
18 |
19 | 4.0
20 |
21 | SAK
22 | SAK
23 | SAK
24 | SAK
25 | publish\
26 | true
27 | Disk
28 | false
29 | Foreground
30 | 7
31 | Days
32 | false
33 | false
34 | true
35 | 0
36 | 1.0.0.%2a
37 | false
38 | false
39 | true
40 | Client
41 |
42 |
43 | true
44 | full
45 | false
46 | bin\Debug\
47 | DEBUG;TRACE
48 | prompt
49 | 4
50 | AllRules.ruleset
51 |
52 |
53 | pdbonly
54 | true
55 | bin\Release\
56 | TRACE
57 | prompt
58 | 4
59 | AllRules.ruleset
60 |
61 |
62 |
63 |
64 |
65 | 3.0
66 |
67 |
68 | 3.0
69 |
70 |
71 | 3.0
72 |
73 |
74 |
75 |
76 | MSBuild:Compile
77 | Designer
78 | MSBuild:Compile
79 | Designer
80 |
81 |
82 | Designer
83 | MSBuild:Compile
84 | MSBuild:Compile
85 | Designer
86 |
87 |
88 | MSBuild:Compile
89 | Designer
90 | MSBuild:Compile
91 | Designer
92 |
93 |
94 | App.xaml
95 | Code
96 |
97 |
98 | Main.xaml
99 | Code
100 |
101 |
102 |
103 |
104 | ExampleControl.xaml
105 |
106 |
107 | Code
108 |
109 |
110 |
111 |
112 |
113 | {BE1ED569-5E0B-4DF0-8964-33AD2AAE4C4A}
114 | WPF.MDI
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | False
123 | .NET Framework 3.5 SP1 Client Profile
124 | false
125 |
126 |
127 | False
128 | .NET Framework 3.5 SP1
129 | true
130 |
131 |
132 | False
133 | Windows Installer 3.1
134 | true
135 |
136 |
137 |
138 |
139 |
140 |
141 |
148 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # Benchmark Results
46 | BenchmarkDotNet.Artifacts/
47 |
48 | # .NET Core
49 | project.lock.json
50 | project.fragment.lock.json
51 | artifacts/
52 | **/Properties/launchSettings.json
53 |
54 | *_i.c
55 | *_p.c
56 | *_i.h
57 | *.ilk
58 | *.meta
59 | *.obj
60 | *.pch
61 | *.pdb
62 | *.pgc
63 | *.pgd
64 | *.rsp
65 | *.sbr
66 | *.tlb
67 | *.tli
68 | *.tlh
69 | *.tmp
70 | *.tmp_proj
71 | *.log
72 | *.vspscc
73 | *.vssscc
74 | .builds
75 | *.pidb
76 | *.svclog
77 | *.scc
78 |
79 | # Chutzpah Test files
80 | _Chutzpah*
81 |
82 | # Visual C++ cache files
83 | ipch/
84 | *.aps
85 | *.ncb
86 | *.opendb
87 | *.opensdf
88 | *.sdf
89 | *.cachefile
90 | *.VC.db
91 | *.VC.VC.opendb
92 |
93 | # Visual Studio profiler
94 | *.psess
95 | *.vsp
96 | *.vspx
97 | *.sap
98 |
99 | # Visual Studio Trace Files
100 | *.e2e
101 |
102 | # TFS 2012 Local Workspace
103 | $tf/
104 |
105 | # Guidance Automation Toolkit
106 | *.gpState
107 |
108 | # ReSharper is a .NET coding add-in
109 | _ReSharper*/
110 | *.[Rr]e[Ss]harper
111 | *.DotSettings.user
112 |
113 | # JustCode is a .NET coding add-in
114 | .JustCode
115 |
116 | # TeamCity is a build add-in
117 | _TeamCity*
118 |
119 | # DotCover is a Code Coverage Tool
120 | *.dotCover
121 |
122 | # AxoCover is a Code Coverage Tool
123 | .axoCover/*
124 | !.axoCover/settings.json
125 |
126 | # Visual Studio code coverage results
127 | *.coverage
128 | *.coveragexml
129 |
130 | # NCrunch
131 | _NCrunch_*
132 | .*crunch*.local.xml
133 | nCrunchTemp_*
134 |
135 | # MightyMoose
136 | *.mm.*
137 | AutoTest.Net/
138 |
139 | # Web workbench (sass)
140 | .sass-cache/
141 |
142 | # Installshield output folder
143 | [Ee]xpress/
144 |
145 | # DocProject is a documentation generator add-in
146 | DocProject/buildhelp/
147 | DocProject/Help/*.HxT
148 | DocProject/Help/*.HxC
149 | DocProject/Help/*.hhc
150 | DocProject/Help/*.hhk
151 | DocProject/Help/*.hhp
152 | DocProject/Help/Html2
153 | DocProject/Help/html
154 |
155 | # Click-Once directory
156 | publish/
157 |
158 | # Publish Web Output
159 | *.[Pp]ublish.xml
160 | *.azurePubxml
161 | # Note: Comment the next line if you want to checkin your web deploy settings,
162 | # but database connection strings (with potential passwords) will be unencrypted
163 | *.pubxml
164 | *.publishproj
165 |
166 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
167 | # checkin your Azure Web App publish settings, but sensitive information contained
168 | # in these scripts will be unencrypted
169 | PublishScripts/
170 |
171 | # NuGet Packages
172 | *.nupkg
173 | # The packages folder can be ignored because of Package Restore
174 | **/[Pp]ackages/*
175 | # except build/, which is used as an MSBuild target.
176 | !**/[Pp]ackages/build/
177 | # Uncomment if necessary however generally it will be regenerated when needed
178 | #!**/[Pp]ackages/repositories.config
179 | # NuGet v3's project.json files produces more ignorable files
180 | *.nuget.props
181 | *.nuget.targets
182 |
183 | # Microsoft Azure Build Output
184 | csx/
185 | *.build.csdef
186 |
187 | # Microsoft Azure Emulator
188 | ecf/
189 | rcf/
190 |
191 | # Windows Store app package directories and files
192 | AppPackages/
193 | BundleArtifacts/
194 | Package.StoreAssociation.xml
195 | _pkginfo.txt
196 | *.appx
197 |
198 | # Visual Studio cache files
199 | # files ending in .cache can be ignored
200 | *.[Cc]ache
201 | # but keep track of directories ending in .cache
202 | !*.[Cc]ache/
203 |
204 | # Others
205 | ClientBin/
206 | ~$*
207 | *~
208 | *.dbmdl
209 | *.dbproj.schemaview
210 | *.jfm
211 | *.pfx
212 | *.publishsettings
213 | orleans.codegen.cs
214 |
215 | # Since there are multiple workflows, uncomment next line to ignore bower_components
216 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
217 | #bower_components/
218 |
219 | # RIA/Silverlight projects
220 | Generated_Code/
221 |
222 | # Backup & report files from converting an old project file
223 | # to a newer Visual Studio version. Backup files are not needed,
224 | # because we have git ;-)
225 | _UpgradeReport_Files/
226 | Backup*/
227 | UpgradeLog*.XML
228 | UpgradeLog*.htm
229 |
230 | # SQL Server files
231 | *.mdf
232 | *.ldf
233 | *.ndf
234 |
235 | # Business Intelligence projects
236 | *.rdl.data
237 | *.bim.layout
238 | *.bim_*.settings
239 |
240 | # Microsoft Fakes
241 | FakesAssemblies/
242 |
243 | # GhostDoc plugin setting file
244 | *.GhostDoc.xml
245 |
246 | # Node.js Tools for Visual Studio
247 | .ntvs_analysis.dat
248 | node_modules/
249 |
250 | # TypeScript v1 declaration files
251 | typings/
252 |
253 | # Visual Studio 6 build log
254 | *.plg
255 |
256 | # Visual Studio 6 workspace options file
257 | *.opt
258 |
259 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
260 | *.vbw
261 |
262 | # Visual Studio LightSwitch build output
263 | **/*.HTMLClient/GeneratedArtifacts
264 | **/*.DesktopClient/GeneratedArtifacts
265 | **/*.DesktopClient/ModelManifest.xml
266 | **/*.Server/GeneratedArtifacts
267 | **/*.Server/ModelManifest.xml
268 | _Pvt_Extensions
269 |
270 | # Paket dependency manager
271 | .paket/paket.exe
272 | paket-files/
273 |
274 | # FAKE - F# Make
275 | .fake/
276 |
277 | # JetBrains Rider
278 | .idea/
279 | *.sln.iml
280 |
281 | # CodeRush
282 | .cr/
283 |
284 | # Python Tools for Visual Studio (PTVS)
285 | __pycache__/
286 | *.pyc
287 |
288 | # Cake - Uncomment if you are using it
289 | # tools/**
290 | # !tools/packages.config
291 |
292 | # Tabs Studio
293 | *.tss
294 |
295 | # Telerik's JustMock configuration file
296 | *.jmconfig
297 |
298 | # BizTalk build output
299 | *.btp.cs
300 | *.btm.cs
301 | *.odx.cs
302 | *.xsd.cs
303 |
304 | # OpenCover UI analysis results
305 | OpenCover/
--------------------------------------------------------------------------------
/WPF.MDI/WPF.MDI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 9.0.30729
7 | 2.0
8 | {BE1ED569-5E0B-4DF0-8964-33AD2AAE4C4A}
9 | library
10 | Properties
11 | WPF.MDI
12 | WPF.MDI
13 | v4.0
14 | 512
15 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
16 | 4
17 |
18 |
19 | 4.0
20 |
21 | SAK
22 | SAK
23 | SAK
24 | SAK
25 | publish\
26 | true
27 | Disk
28 | false
29 | Foreground
30 | 7
31 | Days
32 | false
33 | false
34 | true
35 | 0
36 | 1.0.0.%2a
37 | false
38 | false
39 | true
40 | Client
41 |
42 |
43 | true
44 | full
45 | false
46 | bin\Debug\
47 | DEBUG;TRACE
48 | prompt
49 | 4
50 | AllRules.ruleset
51 |
52 |
53 | pdbonly
54 | true
55 | bin\Release\
56 | TRACE
57 | prompt
58 | 4
59 | AllRules.ruleset
60 |
61 |
62 |
63 |
64 |
65 | 3.0
66 |
67 |
68 | 3.0
69 |
70 |
71 | 3.0
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | Code
82 |
83 |
84 |
85 |
86 |
87 | Designer
88 | MSBuild:Compile
89 | Designer
90 |
91 |
92 |
93 |
94 | Designer
95 | MSBuild:Compile
96 | Designer
97 |
98 |
99 |
100 |
101 | Designer
102 | MSBuild:Compile
103 | MSBuild:Compile
104 | Designer
105 |
106 |
107 |
108 |
109 | False
110 | .NET Framework 3.5 SP1 Client Profile
111 | false
112 |
113 |
114 | False
115 | .NET Framework 3.5 SP1
116 | true
117 |
118 |
119 | False
120 | Windows Installer 3.1
121 | true
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
187 |
--------------------------------------------------------------------------------
/Example/Main.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Media.Imaging;
4 | using Example.Controls;
5 | using WPF.MDI;
6 | using System.Windows.Controls;
7 |
8 | namespace Example
9 | {
10 | ///
11 | /// Interaction logic for Main.xaml
12 | ///
13 | public partial class Main : Window
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | public Main()
19 | {
20 | InitializeComponent();
21 | _original_title = Title;
22 | Container.Children.CollectionChanged += (o, e) => Menu_RefreshWindows();
23 | Container.MdiChildTitleChanged += Container_MdiChildTitleChanged;
24 |
25 | Container.Children.Add(new MdiChild
26 | {
27 | Title = "Empty Window Using Code",
28 | Icon = new BitmapImage(new Uri("OriginalLogo.png", UriKind.Relative))
29 | });
30 |
31 | Container.Children.Add(new MdiChild
32 | {
33 | Title = "Window Using Code",
34 | Content = new ExampleControl(),
35 | Width = 714,
36 | Height = 734,
37 | Position = new Point(300, 80)
38 | });
39 | }
40 |
41 | #region Mdi-like title
42 |
43 | string _original_title;
44 |
45 | void Container_MdiChildTitleChanged(object sender, RoutedEventArgs e)
46 | {
47 | if (Container.ActiveMdiChild != null && Container.ActiveMdiChild.WindowState == WindowState.Maximized)
48 | Title = _original_title + " - [" + Container.ActiveMdiChild.Title + "]";
49 | else
50 | Title = _original_title;
51 | }
52 |
53 | #endregion
54 |
55 | #region Theme Menu Events
56 |
57 | ///
58 | /// Handles the Click event of the Generic control.
59 | ///
60 | /// The source of the event.
61 | /// The instance containing the event data.
62 | private void Generic_Click(object sender, RoutedEventArgs e)
63 | {
64 | Generic.IsChecked = true;
65 | Luna.IsChecked = false;
66 | Aero.IsChecked = false;
67 |
68 | Container.Theme = ThemeType.Generic;
69 | }
70 |
71 | ///
72 | /// Handles the Click event of the Luna control.
73 | ///
74 | /// The source of the event.
75 | /// The instance containing the event data.
76 | private void Luna_Click(object sender, RoutedEventArgs e)
77 | {
78 | Generic.IsChecked = false;
79 | Luna.IsChecked = true;
80 | Aero.IsChecked = false;
81 |
82 | Container.Theme = ThemeType.Luna;
83 | }
84 |
85 | ///
86 | /// Handles the Click event of the Aero control.
87 | ///
88 | /// The source of the event.
89 | /// The instance containing the event data.
90 | private void Aero_Click(object sender, RoutedEventArgs e)
91 | {
92 | Generic.IsChecked = false;
93 | Luna.IsChecked = false;
94 | Aero.IsChecked = true;
95 |
96 | Container.Theme = ThemeType.Aero;
97 | }
98 |
99 | #endregion
100 |
101 | #region Menu Events
102 |
103 | int ooo = 1;
104 |
105 | ///
106 | /// Handles the Click event of the 'Normal window' menu item.
107 | ///
108 | /// The source of the event.
109 | /// The instance containing the event data.
110 | private void AddWindow_Click(object sender, RoutedEventArgs e)
111 | {
112 | Container.Children.Add(new MdiChild { Content = new Label { Content = "Normal window" }, Title = "Window " + ooo++ });
113 | }
114 |
115 | ///
116 | /// Handles the Click event of the 'Fixed window' menu item.
117 | ///
118 | /// The source of the event.
119 | /// The instance containing the event data.
120 | private void AddFixedWindow_Click(object sender, RoutedEventArgs e)
121 | {
122 | Container.Children.Add(new MdiChild { Content = new Label { Content = "Fixed width window" }, Title = "Window " + ooo++, Resizable = false });
123 | }
124 |
125 | ///
126 | /// Handles the Click event of the 'Scroll window' menu item.
127 | ///
128 | /// The source of the event.
129 | /// The instance containing the event data.
130 | private void AddScrollWindow_Click(object sender, RoutedEventArgs e)
131 | {
132 | StackPanel sp = new StackPanel { Orientation = Orientation.Vertical };
133 | sp.Children.Add(new TextBlock { Text = "Window with scroll", Margin = new Thickness(5) });
134 | sp.Children.Add(new ComboBox { Margin = new Thickness(20), Width = 300 });
135 | ScrollViewer sv = new ScrollViewer { Content = sp, HorizontalScrollBarVisibility = ScrollBarVisibility.Auto };
136 |
137 | Container.Children.Add(new MdiChild { Content = sv, Title = "Window " + ooo++ });
138 | }
139 |
140 | ///
141 | /// Refresh windows list
142 | ///
143 | void Menu_RefreshWindows()
144 | {
145 | WindowsMenu.Items.Clear();
146 | MenuItem mi;
147 | for (int i = 0; i < Container.Children.Count; i++)
148 | {
149 | MdiChild child = Container.Children[i];
150 | mi = new MenuItem { Header = child.Title };
151 | mi.Click += (o, e) => child.Focus();
152 | WindowsMenu.Items.Add(mi);
153 | }
154 | WindowsMenu.Items.Add(new Separator());
155 | WindowsMenu.Items.Add(mi = new MenuItem { Header = "Cascade" });
156 | mi.Click += (o, e) => Container.MdiLayout = MdiLayout.Cascade;
157 | WindowsMenu.Items.Add(mi = new MenuItem { Header = "Horizontally" });
158 | mi.Click += (o, e) => Container.MdiLayout = MdiLayout.TileHorizontal;
159 | WindowsMenu.Items.Add(mi = new MenuItem { Header = "Vertically" });
160 | mi.Click += (o, e) => Container.MdiLayout = MdiLayout.TileVertical;
161 |
162 | WindowsMenu.Items.Add(new Separator());
163 | WindowsMenu.Items.Add(mi = new MenuItem { Header = "Close all" });
164 | mi.Click += (o, e) => Container.Children.Clear();
165 | }
166 |
167 | #endregion
168 |
169 | #region Content Button Events
170 |
171 | ///
172 | /// Handles the Click event of the DisableMinimize control.
173 | ///
174 | /// The source of the event.
175 | /// The instance containing the event data.
176 | private void DisableMinimize_Click(object sender, RoutedEventArgs e)
177 | {
178 | Window1.MinimizeBox = false;
179 | }
180 |
181 | ///
182 | /// Handles the Click event of the EnableMinimize control.
183 | ///
184 | /// The source of the event.
185 | /// The instance containing the event data.
186 | private void EnableMinimize_Click(object sender, RoutedEventArgs e)
187 | {
188 | Window1.MinimizeBox = true;
189 | }
190 |
191 | ///
192 | /// Handles the Click event of the DisableMaximize control.
193 | ///
194 | /// The source of the event.
195 | /// The instance containing the event data.
196 | private void DisableMaximize_Click(object sender, RoutedEventArgs e)
197 | {
198 | Window1.MaximizeBox = false;
199 | }
200 |
201 | ///
202 | /// Handles the Click event of the EnableMaximize control.
203 | ///
204 | /// The source of the event.
205 | /// The instance containing the event data.
206 | private void EnableMaximize_Click(object sender, RoutedEventArgs e)
207 | {
208 | Window1.MaximizeBox = true;
209 | }
210 |
211 | ///
212 | /// Handles the Click event of the DisableClose control.
213 | ///
214 | /// The source of the event.
215 | /// The instance containing the event data.
216 | private void DisableClose_Click(object sender, RoutedEventArgs e)
217 | {
218 | Window1.CloseBox = false;
219 | }
220 |
221 | ///
222 | /// Handles the Click event of the EnableClose control.
223 | ///
224 | /// The source of the event.
225 | /// The instance containing the event data.
226 | private void EnableClose_Click(object sender, RoutedEventArgs e)
227 | {
228 | Window1.CloseBox = true;
229 | }
230 |
231 | ///
232 | /// Handles the Click event of the ShowIcon control.
233 | ///
234 | /// The source of the event.
235 | /// The instance containing the event data.
236 | private void ShowIcon_Click(object sender, RoutedEventArgs e)
237 | {
238 | Window1.ShowIcon = true;
239 | }
240 |
241 | ///
242 | /// Handles the Click event of the HideIcon control.
243 | ///
244 | /// The source of the event.
245 | /// The instance containing the event data.
246 | private void HideIcon_Click(object sender, RoutedEventArgs e)
247 | {
248 | Window1.ShowIcon = false;
249 | }
250 | #endregion
251 | }
252 | }
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/WPF.MDI/MdiContainer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.ObjectModel;
3 | using System.Collections.Specialized;
4 | using System.Windows;
5 | using System.Windows.Controls;
6 | using System.Windows.Markup;
7 | using System.Windows.Media;
8 | using System.Collections.Generic;
9 | using System.Windows.Input;
10 | using System.Windows.Data;
11 |
12 | namespace WPF.MDI
13 | {
14 | [ContentProperty("Children")]
15 | public class MdiContainer : UserControl
16 | {
17 | #region Constants
18 |
19 | ///
20 | /// Offset for iniial placement of window, and for cascade mode.
21 | ///
22 | const int WindowOffset = 25;
23 |
24 | #endregion
25 |
26 | #region Static Members
27 |
28 | private static ResourceDictionary currentResourceDictionary;
29 |
30 | #endregion
31 |
32 | #region Dependency Properties
33 |
34 | ///
35 | /// Identifies the WPF.MDI.MdiContainer.Theme dependency property.
36 | ///
37 | /// The identifier for the WPF.MDI.MdiContainer.Theme property.
38 | public static readonly DependencyProperty ThemeProperty =
39 | DependencyProperty.Register("Theme", typeof(ThemeType), typeof(MdiContainer),
40 | new UIPropertyMetadata(ThemeType.Aero, new PropertyChangedCallback(ThemeValueChanged)));
41 |
42 | ///
43 | /// Identifies the WPF.MDI.MdiContainer.Menu dependency property.
44 | ///
45 | /// The identifier for the WPF.MDI.MdiContainer.Menu property.
46 | public static readonly DependencyProperty MenuProperty =
47 | DependencyProperty.Register("Menu", typeof(UIElement), typeof(MdiContainer),
48 | new UIPropertyMetadata(null, new PropertyChangedCallback(MenuValueChanged)));
49 |
50 | ///
51 | /// Identifies the WPF.MDI.MdiContainer.MdiLayout dependency property.
52 | ///
53 | /// The identifier for the WPF.MDI.MdiContainer.MdiLayout property.
54 | public static readonly DependencyProperty MdiLayoutProperty =
55 | DependencyProperty.Register("MdiLayout", typeof(MdiLayout), typeof(MdiContainer),
56 | new UIPropertyMetadata(MdiLayout.ArrangeIcons, new PropertyChangedCallback(MdiLayoutValueChanged)));
57 |
58 | ///
59 | /// Identifies the WPF.MDI.MdiContainer.ActiveMdiChild dependency property.
60 | ///
61 | /// The identifier for the WPF.MDI.ActiveMdiChild.MdiLayout property.
62 | public static readonly DependencyProperty ActiveMdiChildProperty =
63 | DependencyProperty.Register("ActiveMdiChild", typeof(MdiChild), typeof(MdiContainer),
64 | new UIPropertyMetadata(null, new PropertyChangedCallback(ActiveMdiChildValueChanged)));
65 |
66 | ///
67 | /// Identifies the WPF.MDI.MdiContainer.Buttons dependency property.
68 | ///
69 | /// The identifier for the WPF.MDI.ActiveMdiChild.Buttons property.
70 | internal static readonly DependencyProperty ButtonsProperty =
71 | DependencyProperty.Register("Buttons", typeof(Panel), typeof(MdiContainer),
72 | new UIPropertyMetadata(null, new PropertyChangedCallback(ButtonsValueChanged)));
73 |
74 | #endregion
75 |
76 | #region Property Accessors
77 |
78 | ///
79 | /// Gets or sets the container theme.
80 | /// The default is determined by the operating system.
81 | /// This is a dependency property.
82 | ///
83 | /// The container theme.
84 | public ThemeType Theme
85 | {
86 | get { return (ThemeType)GetValue(ThemeProperty); }
87 | set { SetValue(ThemeProperty, value); }
88 | }
89 |
90 | ///
91 | /// Gets or sets the element to display as menu.
92 | /// Window buttons in maximized mode will be on the same level.
93 | /// This is a dependency property.
94 | ///
95 | /// Element to be placed in menu row.
96 | public UIElement Menu
97 | {
98 | get { return (UIElement)GetValue(MenuProperty); }
99 | set { SetValue(MenuProperty, value); }
100 | }
101 |
102 | ///
103 | /// Gets or sets the element to display as menu.
104 | /// Window buttons in maximized mode will be on the same level.
105 | /// This is a dependency property.
106 | ///
107 | /// Mdi layout.
108 | public MdiLayout MdiLayout
109 | {
110 | get { return (MdiLayout)GetValue(MdiLayoutProperty); }
111 | set { SetValue(MdiLayoutProperty, value); }
112 | }
113 |
114 | ///
115 | /// Gets active MDI child. Null if no one.
116 | /// This is a dependency property.
117 | ///
118 | /// Active Mdi Child.
119 | public MdiChild ActiveMdiChild
120 | {
121 | get { return (MdiChild)GetValue(ActiveMdiChildProperty); }
122 | internal set { SetValue(ActiveMdiChildProperty, value); }
123 | }
124 |
125 | ///
126 | /// Buttons on top; null for non-maximized mode;
127 | ///
128 | /// Buttons panel.
129 | internal Panel Buttons
130 | {
131 | get { return (Panel)GetValue(ButtonsProperty); }
132 | set { SetValue(ButtonsProperty, value); }
133 | }
134 |
135 | ///
136 | /// Gets correct canvas height for internal usage.
137 | ///
138 | internal double InnerHeight
139 | {
140 | get { return ActualHeight - _topPanel.ActualHeight; }
141 | }
142 |
143 | #endregion
144 |
145 | #region Member Declarations
146 |
147 | ///
148 | /// Gets or sets the child elements.
149 | ///
150 | /// The child elements.
151 | public ObservableCollection Children { get; set; }
152 |
153 | private Canvas _windowCanvas;
154 |
155 | ///
156 | /// Contains user-specified element.
157 | ///
158 | private Border _menu;
159 |
160 | ///
161 | /// Contains window buttons in maximized mode.
162 | ///
163 | private Border _buttons;
164 |
165 | ///
166 | /// Container for _buttons and _menu.
167 | ///
168 | private Panel _topPanel;
169 |
170 | ///
171 | /// Offset for new window.
172 | ///
173 | private double _windowOffset;
174 |
175 | #endregion
176 |
177 | #region Constructor
178 |
179 | ///
180 | /// Initializes a new instance of the class.
181 | ///
182 | public MdiContainer()
183 | {
184 | Background = Brushes.DarkGray;
185 | Focusable = IsTabStop = false;
186 |
187 | Children = new ObservableCollection();
188 | Children.CollectionChanged += Children_CollectionChanged;
189 |
190 | Grid gr = new Grid();
191 | gr.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
192 | gr.RowDefinitions.Add(new RowDefinition());
193 |
194 | _topPanel = new DockPanel { Background = SystemColors.MenuBrush };
195 | _topPanel.Children.Add(_menu = new Border());
196 | DockPanel.SetDock(_menu, Dock.Left);
197 | _topPanel.Children.Add(_buttons = new Border());
198 | DockPanel.SetDock(_buttons, Dock.Right);
199 | _topPanel.SizeChanged += MdiContainer_SizeChanged;
200 | _topPanel.Children.Add(new UIElement());
201 | gr.Children.Add(_topPanel);
202 |
203 | ScrollViewer sv = new ScrollViewer {
204 | Content = _windowCanvas = new Canvas(),
205 | HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
206 | VerticalScrollBarVisibility = ScrollBarVisibility.Auto
207 | };
208 | gr.Children.Add(sv);
209 | Grid.SetRow(sv, 1);
210 | Content = gr;
211 |
212 | if (Environment.OSVersion.Version.Major > 5)
213 | ThemeValueChanged(this, new DependencyPropertyChangedEventArgs(ThemeProperty, Theme, ThemeType.Aero));
214 | else
215 | ThemeValueChanged(this, new DependencyPropertyChangedEventArgs(ThemeProperty, Theme, ThemeType.Luna));
216 |
217 | Loaded += MdiContainer_Loaded;
218 | SizeChanged += MdiContainer_SizeChanged;
219 | KeyDown += new System.Windows.Input.KeyEventHandler(MdiContainer_KeyDown);
220 | }
221 |
222 | static void MdiContainer_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
223 | {
224 | MdiContainer mdiContainer = (MdiContainer)sender;
225 | if (mdiContainer.Children.Count < 2)
226 | return;
227 | switch (e.Key)
228 | {
229 | case Key.Tab:
230 | if (e.KeyboardDevice.Modifiers == ModifierKeys.Control)
231 | {
232 | int minZindex = Panel.GetZIndex(mdiContainer.Children[0]);
233 | foreach (MdiChild mdiChild in mdiContainer.Children)
234 | if (Panel.GetZIndex(mdiChild) < minZindex)
235 | minZindex = Panel.GetZIndex(mdiChild);
236 | Panel.SetZIndex(mdiContainer.GetTopChild(), minZindex - 1);
237 | mdiContainer.GetTopChild().Focus();
238 | e.Handled = true;
239 | }
240 | break;
241 | }
242 | }
243 |
244 | #endregion
245 |
246 | #region Container Events
247 |
248 | ///
249 | /// Handles the Loaded event of the MdiContainer control.
250 | ///
251 | /// The source of the event.
252 | /// The instance containing the event data.
253 | private void MdiContainer_Loaded(object sender, RoutedEventArgs e)
254 | {
255 | Window wnd = Window.GetWindow(this);
256 | if (wnd != null)
257 | {
258 | wnd.Activated += MdiContainer_Activated;
259 | wnd.Deactivated += MdiContainer_Deactivated;
260 | }
261 |
262 | _windowCanvas.Width = _windowCanvas.ActualWidth;
263 | _windowCanvas.Height = _windowCanvas.ActualHeight;
264 |
265 | _windowCanvas.VerticalAlignment = VerticalAlignment.Top;
266 | _windowCanvas.HorizontalAlignment = HorizontalAlignment.Left;
267 |
268 | InvalidateSize();
269 | }
270 |
271 | ///
272 | /// Handles the Activated event of the MdiContainer control.
273 | ///
274 | /// The source of the event.
275 | /// The instance containing the event data.
276 | private void MdiContainer_Activated(object sender, EventArgs e)
277 | {
278 | if (ActiveMdiChild == null)
279 | return;
280 | ActiveMdiChild.Focused = true;
281 | }
282 |
283 | ///
284 | /// Handles the Deactivated event of the MdiContainer control.
285 | ///
286 | /// The source of the event.
287 | /// The instance containing the event data.
288 | private void MdiContainer_Deactivated(object sender, EventArgs e)
289 | {
290 | if (Children.Count == 0)
291 | return;
292 |
293 | for (int i = 0; i < Children.Count; i++)
294 | if (Children[i].WindowState != WindowState.Maximized)
295 | Children[i].Focused = false;
296 | }
297 |
298 | ///
299 | /// Handles the SizeChanged event of the MdiContainer control.
300 | ///
301 | /// The source of the event.
302 | /// The instance containing the event data.
303 | private void MdiContainer_SizeChanged(object sender, SizeChangedEventArgs e)
304 | {
305 | if (Children.Count == 0)
306 | return;
307 |
308 | for (int i = 0; i < Children.Count; i++)
309 | {
310 | MdiChild mdiChild = Children[i];
311 | if (mdiChild.WindowState == WindowState.Maximized)
312 | {
313 | mdiChild.Width = ActualWidth;
314 | mdiChild.Height = ActualHeight;
315 | }
316 | if (mdiChild.WindowState == WindowState.Minimized)
317 | {
318 | mdiChild.Position = new Point(mdiChild.Position.X, mdiChild.Position.Y + e.NewSize.Height - e.PreviousSize.Height);
319 | }
320 | }
321 | }
322 |
323 | #endregion
324 |
325 | #region ObservableCollection Events
326 |
327 | ///
328 | /// Handles the CollectionChanged event of the Children control.
329 | ///
330 | /// The source of the event.
331 | /// The instance containing the event data.
332 | private void Children_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
333 | {
334 | switch (e.Action)
335 | {
336 | case NotifyCollectionChangedAction.Add:
337 | {
338 | MdiChild mdiChild = Children[e.NewStartingIndex],
339 | topChild = ActiveMdiChild;
340 |
341 | if (topChild != null && topChild.WindowState == WindowState.Maximized)
342 | mdiChild.Loaded += (s, a) => mdiChild.WindowState = WindowState.Maximized;
343 | mdiChild.Loaded += (s, a) => ActiveMdiChild = mdiChild;
344 |
345 | if (mdiChild.Position.X < 0 || mdiChild.Position.Y < 0)
346 | mdiChild.Position = new Point(_windowOffset, _windowOffset);
347 | _windowCanvas.Children.Add(mdiChild);
348 |
349 | _windowOffset += WindowOffset;
350 | if (_windowOffset + mdiChild.Width > ActualWidth)
351 | _windowOffset = 0;
352 | if (_windowOffset + mdiChild.Height > ActualHeight)
353 | _windowOffset = 0;
354 | }
355 | break;
356 | case NotifyCollectionChangedAction.Remove:
357 | {
358 | MdiChild oldChild = (MdiChild)e.OldItems[0];
359 | _windowCanvas.Children.Remove(oldChild);
360 | MdiChild newChild = GetTopChild();
361 |
362 | ActiveMdiChild = newChild;
363 | if (newChild != null && oldChild.WindowState == WindowState.Maximized)
364 | newChild.WindowState = WindowState.Maximized;
365 | }
366 | break;
367 | case NotifyCollectionChangedAction.Reset:
368 | _windowCanvas.Children.Clear();
369 | break;
370 | }
371 | InvalidateSize();
372 | }
373 |
374 | #endregion
375 |
376 | ///
377 | /// Invalidates the size checking to see if the furthest
378 | /// child point exceeds the current height and width.
379 | ///
380 | internal void InvalidateSize()
381 | {
382 | Point largestPoint = new Point(0, 0);
383 |
384 | for (int i = 0; i < Children.Count; i++)
385 | {
386 | MdiChild mdiChild = Children[i];
387 |
388 | Point farPosition = new Point(mdiChild.Position.X + mdiChild.Width, mdiChild.Position.Y + mdiChild.Height);
389 |
390 | if (farPosition.X > largestPoint.X)
391 | largestPoint.X = farPosition.X;
392 |
393 | if (farPosition.Y > largestPoint.Y)
394 | largestPoint.Y = farPosition.Y;
395 | }
396 |
397 | if (_windowCanvas.Width != largestPoint.X)
398 | _windowCanvas.Width = largestPoint.X;
399 |
400 | if (_windowCanvas.Height != largestPoint.Y)
401 | _windowCanvas.Height = largestPoint.Y;
402 | }
403 |
404 | ///
405 | /// Gets MdiChild with maximum ZIndex.
406 | ///
407 | internal MdiChild GetTopChild()
408 | {
409 | if (Children.Count < 1)
410 | return null;
411 |
412 | int index = 0, maxZindex = Panel.GetZIndex(Children[0]);
413 | for (int i = 1, zindex; i < Children.Count; i++)
414 | {
415 | zindex = Panel.GetZIndex(Children[i]);
416 | if (zindex > maxZindex)
417 | {
418 | maxZindex = zindex;
419 | index = i;
420 | }
421 | }
422 | return Children[index];
423 | }
424 |
425 | #region Dependency Property Events
426 |
427 | ///
428 | /// Dependency property event once the theme value has changed.
429 | ///
430 | /// The sender.
431 | /// The instance containing the event data.
432 | private static void ThemeValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
433 | {
434 | MdiContainer mdiContainer = (MdiContainer)sender;
435 | ThemeType themeType = (ThemeType)e.NewValue;
436 |
437 | bool max_mode = mdiContainer.ActiveMdiChild != null && mdiContainer.ActiveMdiChild.WindowState == WindowState.Maximized;
438 | if (max_mode)
439 | mdiContainer.ActiveMdiChild.WindowState = WindowState.Normal;
440 |
441 | if (currentResourceDictionary != null)
442 | Application.Current.Resources.MergedDictionaries.Remove(currentResourceDictionary);
443 |
444 | switch (themeType)
445 | {
446 | case ThemeType.Luna:
447 | Application.Current.Resources.MergedDictionaries.Add(currentResourceDictionary = new ResourceDictionary { Source = new Uri(@"/WPF.MDI;component/Themes/Luna.xaml", UriKind.Relative) });
448 | break;
449 | case ThemeType.Aero:
450 | Application.Current.Resources.MergedDictionaries.Add(currentResourceDictionary = new ResourceDictionary { Source = new Uri(@"/WPF.MDI;component/Themes/Aero.xaml", UriKind.Relative) });
451 | break;
452 | }
453 |
454 | //if (max_mode)
455 | // mdiContainer.ActiveMdiChild.WindowState = WindowState.Maximized;
456 | }
457 |
458 | ///
459 | /// Dependency property event once the menu element has changed.
460 | ///
461 | /// The sender.
462 | /// The instance containing the event data.
463 | private static void MenuValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
464 | {
465 | MdiContainer mdiContainer = (MdiContainer)sender;
466 | UIElement menu = (UIElement)e.NewValue;
467 |
468 | mdiContainer._menu.Child = menu;
469 | }
470 |
471 | ///
472 | /// Dependency property event once the MDI layout value has changed.
473 | ///
474 | /// The sender.
475 | /// The instance containing the event data.
476 | private static void MdiLayoutValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
477 | {
478 | MdiContainer mdiContainer = (MdiContainer)sender;
479 | MdiLayout value = (MdiLayout)e.NewValue;
480 |
481 | if (value == MdiLayout.ArrangeIcons ||
482 | mdiContainer.Children.Count < 1)
483 | return;
484 |
485 | // 1. WindowState.Maximized -> WindowState.Normal
486 | List minimizedWindows = new List(),
487 | normalWindows = new List();
488 | foreach (MdiChild mdiChild in mdiContainer.Children)
489 | switch (mdiChild.WindowState)
490 | {
491 | case WindowState.Minimized:
492 | minimizedWindows.Add(mdiChild);
493 | break;
494 | case WindowState.Maximized:
495 | mdiChild.WindowState = WindowState.Normal;
496 | normalWindows.Add(mdiChild);
497 | break;
498 | default:
499 | normalWindows.Add(mdiChild);
500 | break;
501 | }
502 |
503 | minimizedWindows.Sort(new MdiChildComparer());
504 | normalWindows.Sort(new MdiChildComparer());
505 |
506 | // 2. Arrange minimized windows
507 | double containerHeight = mdiContainer.InnerHeight;
508 | for (int i = 0; i < minimizedWindows.Count; i++)
509 | {
510 | MdiChild mdiChild = minimizedWindows[i];
511 | int capacity = Convert.ToInt32(mdiContainer.ActualWidth) / MdiChild.MinimizedWidth,
512 | row = i / capacity + 1,
513 | col = i % capacity;
514 | containerHeight = mdiContainer.InnerHeight - MdiChild.MinimizedHeight * row;
515 | double newLeft = MdiChild.MinimizedWidth * col;
516 | mdiChild.Position = new Point(newLeft, containerHeight);
517 | }
518 |
519 | // 3. Resize & arrange normal windows
520 | switch (value)
521 | {
522 | case MdiLayout.Cascade:
523 | {
524 | double newWidth = mdiContainer.ActualWidth * 0.58, // should be non-linear formula here
525 | newHeight = containerHeight * 0.67,
526 | windowOffset = 0;
527 | foreach (MdiChild mdiChild in normalWindows)
528 | {
529 | if (mdiChild.Resizable)
530 | {
531 | mdiChild.Width = newWidth;
532 | mdiChild.Height = newHeight;
533 | }
534 | mdiChild.Position = new Point(windowOffset, windowOffset);
535 |
536 | windowOffset += WindowOffset;
537 | if (windowOffset + mdiChild.Width > mdiContainer.ActualWidth)
538 | windowOffset = 0;
539 | if (windowOffset + mdiChild.Height > containerHeight)
540 | windowOffset = 0;
541 | }
542 | }
543 | break;
544 | case MdiLayout.TileHorizontal:
545 | {
546 | int cols = (int)Math.Sqrt(normalWindows.Count),
547 | rows = normalWindows.Count / cols;
548 |
549 | List col_count = new List(); // windows per column
550 | for (int i = 0; i < cols; i++)
551 | {
552 | if (normalWindows.Count % cols > cols - i - 1)
553 | col_count.Add(rows + 1);
554 | else
555 | col_count.Add(rows);
556 | }
557 |
558 | double newWidth = mdiContainer.ActualWidth / cols,
559 | newHeight = containerHeight / col_count[0],
560 | offsetTop = 0,
561 | offsetLeft = 0;
562 |
563 | for (int i = 0, col_index = 0, prev_count = 0; i < normalWindows.Count; i++)
564 | {
565 | if (i >= prev_count + col_count[col_index])
566 | {
567 | prev_count += col_count[col_index++];
568 | offsetLeft += newWidth;
569 | offsetTop = 0;
570 | newHeight = containerHeight / col_count[col_index];
571 | }
572 |
573 | MdiChild mdiChild = normalWindows[i];
574 | if (mdiChild.Resizable)
575 | {
576 | mdiChild.Width = newWidth;
577 | mdiChild.Height = newHeight;
578 | }
579 | mdiChild.Position = new Point(offsetLeft, offsetTop);
580 | offsetTop += newHeight;
581 | }
582 | }
583 | break;
584 | case MdiLayout.TileVertical:
585 | {
586 | int rows = (int)Math.Sqrt(normalWindows.Count),
587 | cols = normalWindows.Count / rows;
588 |
589 | List col_count = new List(); // windows per column
590 | for (int i = 0; i < cols; i++)
591 | {
592 | if (normalWindows.Count % cols > cols - i - 1)
593 | col_count.Add(rows + 1);
594 | else
595 | col_count.Add(rows);
596 | }
597 |
598 | double newWidth = mdiContainer.ActualWidth / cols,
599 | newHeight = containerHeight / col_count[0],
600 | offsetTop = 0,
601 | offsetLeft = 0;
602 |
603 | for (int i = 0, col_index = 0, prev_count = 0; i < normalWindows.Count; i++)
604 | {
605 | if (i >= prev_count + col_count[col_index])
606 | {
607 | prev_count += col_count[col_index++];
608 | offsetLeft += newWidth;
609 | offsetTop = 0;
610 | newHeight = containerHeight / col_count[col_index];
611 | }
612 |
613 | MdiChild mdiChild = normalWindows[i];
614 | if (mdiChild.Resizable)
615 | {
616 | mdiChild.Width = newWidth;
617 | mdiChild.Height = newHeight;
618 | }
619 | mdiChild.Position = new Point(offsetLeft, offsetTop);
620 | offsetTop += newHeight;
621 | }
622 | }
623 | break;
624 | }
625 | mdiContainer.InvalidateSize();
626 | mdiContainer.MdiLayout = MdiLayout.ArrangeIcons;
627 | }
628 |
629 | ///
630 | /// Dependency property event once the focused mdi child has changed.
631 | ///
632 | /// The sender.
633 | /// The instance containing the event data.
634 | private static void ActiveMdiChildValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
635 | {
636 | MdiContainer mdiContainer = (MdiContainer)sender;
637 | MdiChild newChild = (MdiChild)e.NewValue,
638 | oldChild = (MdiChild)e.OldValue;
639 |
640 | if (newChild == null || newChild == oldChild)
641 | return;
642 |
643 | if (oldChild != null && oldChild.WindowState == WindowState.Maximized)
644 | newChild.WindowState = WindowState.Maximized;
645 |
646 | int maxZindex = 0;
647 | for (int i = 0; i < mdiContainer.Children.Count; i++)
648 | {
649 | int zindex = Panel.GetZIndex(mdiContainer.Children[i]);
650 | if (zindex > maxZindex)
651 | maxZindex = zindex;
652 | if (mdiContainer.Children[i] != newChild)
653 | mdiContainer.Children[i].Focused = false;
654 | else
655 | newChild.Focused = true;
656 | }
657 |
658 | Panel.SetZIndex(newChild, maxZindex + 1);
659 |
660 | if (mdiContainer.MdiChildTitleChanged != null)
661 | mdiContainer.MdiChildTitleChanged(mdiContainer, new RoutedEventArgs());
662 | }
663 |
664 | ///
665 | /// Dependency property event once the MdiChild's Buttons property has changed.
666 | ///
667 | /// The sender.
668 | /// The instance containing the event data.
669 | private static void ButtonsValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
670 | {
671 | MdiContainer mdiContainer = (MdiContainer)sender;
672 | Panel panel = (Panel)e.NewValue;
673 |
674 | mdiContainer._buttons.Child = panel;
675 |
676 | if (mdiContainer.MdiChildTitleChanged != null)
677 | mdiContainer.MdiChildTitleChanged(mdiContainer, new RoutedEventArgs());
678 | }
679 |
680 | #endregion
681 |
682 | #region Nested MdiChild comparerer
683 |
684 | internal class MdiChildComparer : IComparer
685 | {
686 | #region IComparer Members
687 |
688 | public int Compare(MdiChild x, MdiChild y)
689 | {
690 | return -1 * Canvas.GetZIndex(x).CompareTo(Canvas.GetZIndex(y));
691 | }
692 |
693 | #endregion
694 | }
695 |
696 | #endregion
697 |
698 | ///
699 | /// Occurs when a multiple-document interface (MDI) child form is activated or closed within an MDI application.
700 | ///
701 | public event RoutedEventHandler MdiChildTitleChanged;
702 | }
703 | }
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Aero.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
481 |
--------------------------------------------------------------------------------
/WPF.MDI/Themes/Luna.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
461 |
--------------------------------------------------------------------------------
/WPF.MDI/MdiChild.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 | using System.Windows.Controls.Primitives;
6 | using System.Windows.Input;
7 | using System.Windows.Markup;
8 | using System.Windows.Media;
9 | using System.Collections.Generic;
10 |
11 | namespace WPF.MDI
12 | {
13 | [ContentProperty("Content")]
14 | public class MdiChild : Control
15 | {
16 | #region Constants
17 |
18 | ///
19 | /// Width of minimized window.
20 | ///
21 | internal const int MinimizedWidth = 160;
22 |
23 | ///
24 | /// Height of minimized window.
25 | ///
26 | internal const int MinimizedHeight = 29;
27 |
28 | #endregion
29 |
30 | #region Dependency Properties
31 |
32 | ///
33 | /// Identifies the WPF.MDI.MdiChild.ContentProperty dependency property.
34 | ///
35 | /// The identifier for the WPF.MDI.MdiChild.ContentProperty property.
36 | public static readonly DependencyProperty ContentProperty =
37 | DependencyProperty.Register("Content", typeof(UIElement), typeof(MdiChild));
38 |
39 | ///
40 | /// Identifies the WPF.MDI.MdiChild.TitleProperty dependency property.
41 | ///
42 | /// The identifier for the WPF.MDI.MdiChild.TitleProperty property.
43 | public static readonly DependencyProperty TitleProperty =
44 | DependencyProperty.Register("Title", typeof(string), typeof(MdiChild));
45 |
46 | ///
47 | /// Identifies the WPF.MDI.MdiChild.IconProperty dependency property.
48 | ///
49 | /// The identifier for the WPF.MDI.MdiChild.IconProperty property.
50 | public static readonly DependencyProperty IconProperty =
51 | DependencyProperty.Register("Icon", typeof(ImageSource), typeof(MdiChild));
52 |
53 | ///
54 | /// Identifies the WPF.MDI.MdiChild.ShowIconProperty dependency property.
55 | ///
56 | /// The identifier for the WPF.MDI.MdiChild.ShowIconProperty property.
57 | public static readonly DependencyProperty ShowIconProperty =
58 | DependencyProperty.Register("ShowIcon", typeof(bool), typeof(MdiChild),
59 | new UIPropertyMetadata(true));
60 |
61 | ///
62 | /// Identifies the WPF.MDI.MdiChild.ResizableProperty dependency property.
63 | ///
64 | /// The identifier for the WPF.MDI.MdiChild.ResizableProperty property.
65 | public static readonly DependencyProperty ResizableProperty =
66 | DependencyProperty.Register("Resizable", typeof(bool), typeof(MdiChild),
67 | new UIPropertyMetadata(true));
68 |
69 | ///
70 | /// Identifies the WPF.MDI.MdiChild.FocusedProperty dependency property.
71 | ///
72 | /// The identifier for the WPF.MDI.MdiChild.FocusedProperty property.
73 | public static readonly DependencyProperty FocusedProperty =
74 | DependencyProperty.Register("Focused", typeof(bool), typeof(MdiChild),
75 | new UIPropertyMetadata(false, new PropertyChangedCallback(FocusedValueChanged)));
76 |
77 | ///
78 | /// Identifies the WPF.MDI.MdiChild.MinimizeBoxProperty dependency property.
79 | ///
80 | /// The identifier for the WPF.MDI.MdiChild.MinimizeBoxProperty property.
81 | public static readonly DependencyProperty MinimizeBoxProperty =
82 | DependencyProperty.Register("MinimizeBox", typeof(bool), typeof(MdiChild),
83 | new UIPropertyMetadata(true, new PropertyChangedCallback(MinimizeBoxValueChanged)));
84 |
85 | ///
86 | /// Identifies the WPF.MDI.MdiChild.MaximizeBoxProperty dependency property.
87 | ///
88 | /// The identifier for the WPF.MDI.MdiChild.MaximizeBoxProperty property.
89 | public static readonly DependencyProperty MaximizeBoxProperty =
90 | DependencyProperty.Register("MaximizeBox", typeof(bool), typeof(MdiChild),
91 | new UIPropertyMetadata(true, new PropertyChangedCallback(MaximizeBoxValueChanged)));
92 |
93 | ///
94 | /// Identifies the WPF.MDI.MdiChild.CloseBoxProperty dependency property.
95 | ///
96 | /// The identifier for the WPF.MDI.MdiChild.CloseBoxProperty property.
97 | public static readonly DependencyProperty CloseBoxProperty =
98 | DependencyProperty.Register("CloseBox", typeof(bool), typeof(MdiChild),
99 | new UIPropertyMetadata(true, new PropertyChangedCallback(CloseBoxValueChanged)));
100 |
101 | ///
102 | /// Identifies the WPF.MDI.MdiChild.WindowStateProperty dependency property.
103 | ///
104 | /// The identifier for the WPF.MDI.MdiChild.WindowStateProperty property.
105 | public static readonly DependencyProperty WindowStateProperty =
106 | DependencyProperty.Register("WindowState", typeof(WindowState), typeof(MdiChild),
107 | new UIPropertyMetadata(WindowState.Normal, new PropertyChangedCallback(WindowStateValueChanged)));
108 |
109 | ///
110 | /// Identifies the WPF.MDI.MdiChild.PositionProperty dependency property.
111 | ///
112 | /// The identifier for the WPF.MDI.MdiChild.PositionProperty property.
113 | public static readonly DependencyProperty PositionProperty =
114 | DependencyProperty.Register("Position", typeof(Point), typeof(MdiChild),
115 | new UIPropertyMetadata(new Point(-1, -1), new PropertyChangedCallback(PositionValueChanged)));
116 |
117 | /////
118 | ///// Identifies the WPF.MDI.MdiChild.ButtonsProperty dependency property.
119 | /////
120 | ///// The identifier for the WPF.MDI.MdiChild.ButtonsProperty property.
121 | //public static readonly DependencyProperty ButtonsProperty =
122 | // DependencyProperty.Register("Buttons", typeof(Panel), typeof(MdiChild),
123 | // new UIPropertyMetadata(null));
124 |
125 |
126 | #endregion
127 |
128 | #region Dependency Events
129 |
130 | ///
131 | /// Identifies the WPF.MDI.MdiChild.ClosingEvent routed event.
132 | ///
133 | /// The identifier for the WPF.MDI.MdiChild.ClosingEvent routed event.
134 | public static readonly RoutedEvent ClosingEvent =
135 | EventManager.RegisterRoutedEvent("Closing", RoutingStrategy.Bubble, typeof(ClosingEventArgs), typeof(MdiChild));
136 |
137 | ///
138 | /// Identifies the WPF.MDI.MdiChild.ClosedEvent routed event.
139 | ///
140 | /// The identifier for the WPF.MDI.MdiChild.ClosedEvent routed event.
141 | public static readonly RoutedEvent ClosedEvent =
142 | EventManager.RegisterRoutedEvent("Closed", RoutingStrategy.Bubble, typeof(RoutedEventArgs), typeof(MdiChild));
143 |
144 | #endregion
145 |
146 | #region Property Accessors
147 |
148 | ///
149 | /// Gets or sets the content.
150 | /// This is a dependency property.
151 | ///
152 | /// The content.
153 | public UIElement Content
154 | {
155 | get { return (UIElement)GetValue(ContentProperty); }
156 | set { SetValue(ContentProperty, value); }
157 | }
158 |
159 | ///
160 | /// Gets or sets the window title.
161 | /// This is a dependency property.
162 | ///
163 | /// The window title.
164 | public string Title
165 | {
166 | get { return (string)GetValue(TitleProperty); }
167 | set { SetValue(TitleProperty, value); }
168 | }
169 |
170 | ///
171 | /// Gets or sets the window icon.
172 | /// This is a dependency property.
173 | ///
174 | /// The window icon.
175 | public ImageSource Icon
176 | {
177 | get { return (ImageSource)GetValue(IconProperty); }
178 | set { SetValue(IconProperty, value); }
179 | }
180 |
181 | ///
182 | /// Gets or sets a value indicating whether to [show the window icon].
183 | /// This is a dependency property.
184 | ///
185 | /// true if [show the window icon]; otherwise, false.
186 | public bool ShowIcon
187 | {
188 | get { return (bool)GetValue(ShowIconProperty); }
189 | set { SetValue(ShowIconProperty, value); }
190 | }
191 |
192 | ///
193 | /// Gets or sets a value indicating whether the [window is resizable].
194 | /// This is a dependency property.
195 | ///
196 | /// true if [window is resizable]; otherwise, false.
197 | public bool Resizable
198 | {
199 | get { return (bool)GetValue(ResizableProperty); }
200 | set { SetValue(ResizableProperty, value); }
201 | }
202 |
203 | ///
204 | /// Gets or sets a value indicating whether the [window is focused].
205 | /// This is a dependency property.
206 | ///
207 | /// true if [window is focused]; otherwise, false.
208 | public bool Focused
209 | {
210 | get { return (bool)GetValue(FocusedProperty); }
211 | set { SetValue(FocusedProperty, value); }
212 | }
213 |
214 | ///
215 | /// Gets or sets a value indicating whether to [show the minimize box button].
216 | /// This is a dependency property.
217 | ///
218 | /// true if [show the minimize box button]; otherwise, false.
219 | public bool MinimizeBox
220 | {
221 | get { return (bool)GetValue(MinimizeBoxProperty); }
222 | set { SetValue(MinimizeBoxProperty, value); }
223 | }
224 |
225 | ///
226 | /// Gets or sets a value indicating whether to [show the maximize box button].
227 | /// This is a dependency property.
228 | ///
229 | /// true if [show the maximize box button]; otherwise, false.
230 | public bool MaximizeBox
231 | {
232 | get { return (bool)GetValue(MaximizeBoxProperty); }
233 | set { SetValue(MaximizeBoxProperty, value); }
234 | }
235 |
236 | ///
237 | /// Gets or sets a value indicating whether to [show the close box button].
238 | /// This is a dependency property.
239 | ///
240 | /// true if [show the close box button]; otherwise, false.
241 | public bool CloseBox
242 | {
243 | get { return (bool)GetValue(CloseBoxProperty); }
244 | set { SetValue(CloseBoxProperty, value); }
245 | }
246 |
247 | ///
248 | /// Gets or sets the state of the window.
249 | /// This is a dependency property.
250 | ///
251 | /// The state of the window.
252 | public WindowState WindowState
253 | {
254 | get { return (WindowState)GetValue(WindowStateProperty); }
255 | set { SetValue(WindowStateProperty, value); }
256 | }
257 |
258 | ///
259 | /// Gets or sets position of top left corner of window.
260 | /// This is a dependency property.
261 | ///
262 | public Point Position
263 | {
264 | get { return (Point)GetValue(PositionProperty); }
265 | set { SetValue(PositionProperty, value); }
266 | }
267 |
268 | ///
269 | /// Gets buttons for window in maximized state.
270 | ///
271 | public Panel Buttons
272 | {
273 | //get { return (Panel)GetValue(ButtonsProperty); }
274 | //private set { SetValue(ButtonsProperty, value); }
275 | get;
276 | private set;
277 | }
278 |
279 | ///
280 | /// Force user not to use Margin property.
281 | ///
282 | private new Thickness Margin { set { } }
283 |
284 | #endregion
285 |
286 | #region Event Accessors
287 |
288 | public event RoutedEventHandler Closing
289 | {
290 | add { AddHandler(ClosingEvent, value); }
291 | remove { RemoveHandler(ClosingEvent, value); }
292 | }
293 |
294 | public event RoutedEventHandler Closed
295 | {
296 | add { AddHandler(ClosedEvent, value); }
297 | remove { RemoveHandler(ClosedEvent, value); }
298 | }
299 |
300 | #endregion
301 |
302 | #region Member Declarations
303 |
304 | #region Top Buttons
305 |
306 | private Button minimizeButton;
307 |
308 | private Button maximizeButton;
309 |
310 | private Button closeButton;
311 |
312 | private StackPanel buttonsPanel;
313 |
314 | #endregion
315 |
316 | ///
317 | /// Gets or sets the container.
318 | ///
319 | /// The container.
320 | public MdiContainer Container { get; private set; }
321 |
322 | ///
323 | /// Dimensions of window in Normal state.
324 | ///
325 | private Rect originalDimension;
326 |
327 | ///
328 | /// Position of window in Minimized state.
329 | ///
330 | private Point minimizedPosition = new Point(-1, -1);
331 |
332 | ///
333 | /// Previous non-maximized state of maximized window.
334 | ///
335 | WindowState NonMaximizedState { get; set; }
336 |
337 | #endregion
338 |
339 | #region Constructor
340 |
341 | ///
342 | /// Initializes the class.
343 | ///
344 | static MdiChild()
345 | {
346 | DefaultStyleKeyProperty.OverrideMetadata(typeof(MdiChild), new FrameworkPropertyMetadata(typeof(MdiChild)));
347 | }
348 |
349 | ///
350 | /// Initializes a new instance of the class.
351 | ///
352 | public MdiChild()
353 | {
354 | Focusable = IsTabStop = false;
355 |
356 | Loaded += MdiChild_Loaded;
357 | GotFocus += MdiChild_GotFocus;
358 | KeyDown += MdiChild_KeyDown;
359 | }
360 |
361 | static void MdiChild_KeyDown(object sender, KeyEventArgs e)
362 | {
363 | MdiChild mdiChild = (MdiChild)sender;
364 | switch (e.Key)
365 | {
366 | case Key.F4:
367 | if (e.KeyboardDevice.Modifiers == ModifierKeys.Control)
368 | {
369 | mdiChild.Close();
370 | e.Handled = true;
371 | }
372 | break;
373 | }
374 | }
375 |
376 | #endregion
377 |
378 | #region Control Events
379 |
380 | ///
381 | /// Handles the Loaded event of the MdiChild control.
382 | ///
383 | /// The source of the event.
384 | /// The instance containing the event data.
385 | private void MdiChild_Loaded(object sender, RoutedEventArgs e)
386 | {
387 | FrameworkElement currentControl = this;
388 |
389 | while (currentControl != null && currentControl.GetType() != typeof(MdiContainer))
390 | currentControl = (FrameworkElement)currentControl.Parent;
391 |
392 | if (currentControl != null)
393 | Container = (MdiContainer)currentControl;
394 | //else throw new Exception("Unable to find MdiContainer parent.");
395 | }
396 |
397 | ///
398 | /// Handles the GotFocus event of the MdiChild control.
399 | ///
400 | /// The source of the event.
401 | /// The instance containing the event data.
402 | private void MdiChild_GotFocus(object sender, RoutedEventArgs e)
403 | {
404 | Focus();
405 | }
406 |
407 | #endregion
408 |
409 | #region Control Overrides
410 |
411 | ///
412 | /// When overridden in a derived class, is invoked whenever application code or internal processes call .
413 | ///
414 | public override void OnApplyTemplate()
415 | {
416 | base.OnApplyTemplate();
417 |
418 | minimizeButton = (Button)Template.FindName("MinimizeButton", this);
419 | maximizeButton = (Button)Template.FindName("MaximizeButton", this);
420 | closeButton = (Button)Template.FindName("CloseButton", this);
421 | buttonsPanel = (StackPanel)Template.FindName("ButtonsPanel", this);
422 |
423 | if (minimizeButton != null)
424 | minimizeButton.Click += minimizeButton_Click;
425 |
426 | if (maximizeButton != null)
427 | maximizeButton.Click += maximizeButton_Click;
428 |
429 | if (closeButton != null)
430 | closeButton.Click += closeButton_Click;
431 |
432 | Thumb dragThumb = (Thumb)Template.FindName("DragThumb", this);
433 |
434 | if (dragThumb != null)
435 | {
436 | dragThumb.DragStarted += Thumb_DragStarted;
437 | dragThumb.DragDelta += dragThumb_DragDelta;
438 |
439 | dragThumb.MouseDoubleClick += (sender, e) =>
440 | {
441 | if (WindowState == WindowState.Minimized)
442 | minimizeButton_Click(null, null);
443 | else if (WindowState == WindowState.Normal)
444 | maximizeButton_Click(null, null);
445 | };
446 | }
447 |
448 | Thumb resizeLeft = (Thumb)Template.FindName("ResizeLeft", this);
449 | Thumb resizeTopLeft = (Thumb)Template.FindName("ResizeTopLeft", this);
450 | Thumb resizeTop = (Thumb)Template.FindName("ResizeTop", this);
451 | Thumb resizeTopRight = (Thumb)Template.FindName("ResizeTopRight", this);
452 | Thumb resizeRight = (Thumb)Template.FindName("ResizeRight", this);
453 | Thumb resizeBottomRight = (Thumb)Template.FindName("ResizeBottomRight", this);
454 | Thumb resizeBottom = (Thumb)Template.FindName("ResizeBottom", this);
455 | Thumb resizeBottomLeft = (Thumb)Template.FindName("ResizeBottomLeft", this);
456 |
457 | if (resizeLeft != null)
458 | {
459 | resizeLeft.DragStarted += Thumb_DragStarted;
460 | resizeLeft.DragDelta += ResizeLeft_DragDelta;
461 | }
462 |
463 | if (resizeTop != null)
464 | {
465 | resizeTop.DragStarted += Thumb_DragStarted;
466 | resizeTop.DragDelta += ResizeTop_DragDelta;
467 | }
468 |
469 | if (resizeRight != null)
470 | {
471 | resizeRight.DragStarted += Thumb_DragStarted;
472 | resizeRight.DragDelta += ResizeRight_DragDelta;
473 | }
474 |
475 | if (resizeBottom != null)
476 | {
477 | resizeBottom.DragStarted += Thumb_DragStarted;
478 | resizeBottom.DragDelta += ResizeBottom_DragDelta;
479 | }
480 |
481 | if (resizeTopLeft != null)
482 | {
483 | resizeTopLeft.DragStarted += Thumb_DragStarted;
484 |
485 | resizeTopLeft.DragDelta += (sender, e) =>
486 | {
487 | ResizeTop_DragDelta(null, e);
488 | ResizeLeft_DragDelta(null, e);
489 |
490 | Container.InvalidateSize();
491 | };
492 | }
493 |
494 | if (resizeTopRight != null)
495 | {
496 | resizeTopRight.DragStarted += Thumb_DragStarted;
497 |
498 | resizeTopRight.DragDelta += (sender, e) =>
499 | {
500 | ResizeTop_DragDelta(null, e);
501 | ResizeRight_DragDelta(null, e);
502 |
503 | Container.InvalidateSize();
504 | };
505 | }
506 |
507 | if (resizeBottomRight != null)
508 | {
509 | resizeBottomRight.DragStarted += Thumb_DragStarted;
510 |
511 | resizeBottomRight.DragDelta += (sender, e) =>
512 | {
513 | ResizeBottom_DragDelta(null, e);
514 | ResizeRight_DragDelta(null, e);
515 |
516 | Container.InvalidateSize();
517 | };
518 | }
519 |
520 | if (resizeBottomLeft != null)
521 | {
522 | resizeBottomLeft.DragStarted += Thumb_DragStarted;
523 |
524 | resizeBottomLeft.DragDelta += (sender, e) =>
525 | {
526 | ResizeBottom_DragDelta(null, e);
527 | ResizeLeft_DragDelta(null, e);
528 |
529 | Container.InvalidateSize();
530 | };
531 | }
532 |
533 | MinimizeBoxValueChanged(this, new DependencyPropertyChangedEventArgs(MinimizeBoxProperty, true, MinimizeBox));
534 | MaximizeBoxValueChanged(this, new DependencyPropertyChangedEventArgs(MaximizeBoxProperty, true, MaximizeBox));
535 | CloseBoxValueChanged(this, new DependencyPropertyChangedEventArgs(CloseBoxProperty, true, CloseBox));
536 | }
537 |
538 | ///
539 | /// Invoked when an unhandled attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
540 | ///
541 | /// The that contains the event data. This event data reports details about the mouse button that was pressed and the handled state.
542 | protected override void OnMouseDown(MouseButtonEventArgs e)
543 | {
544 | base.OnMouseDown(e);
545 |
546 | Focused = true;
547 | }
548 |
549 | #endregion
550 |
551 | #region Top Button Events
552 |
553 | ///
554 | /// Handles the Click event of the minimizeButton control.
555 | ///
556 | /// The source of the event.
557 | /// The instance containing the event data.
558 | private void minimizeButton_Click(object sender, RoutedEventArgs e)
559 | {
560 | if (WindowState == WindowState.Minimized)
561 | WindowState = WindowState.Normal;
562 | else
563 | WindowState = WindowState.Minimized;
564 | }
565 |
566 | ///
567 | /// Handles the Click event of the maximizeButton control.
568 | ///
569 | /// The source of the event.
570 | /// The instance containing the event data.
571 | private void maximizeButton_Click(object sender, RoutedEventArgs e)
572 | {
573 | if (WindowState == WindowState.Maximized)
574 | WindowState = WindowState.Normal;
575 | else
576 | WindowState = WindowState.Maximized;
577 | }
578 |
579 | ///
580 | /// Handles the Click event of the closeButton control.
581 | ///
582 | /// The source of the event.
583 | /// The instance containing the event data.
584 | private void closeButton_Click(object sender, RoutedEventArgs e)
585 | {
586 | ClosingEventArgs eventArgs = new ClosingEventArgs(ClosingEvent);
587 | RaiseEvent(eventArgs);
588 |
589 | if (eventArgs.Cancel)
590 | return;
591 |
592 | Close();
593 |
594 | RaiseEvent(new RoutedEventArgs(ClosedEvent));
595 | }
596 |
597 | #endregion
598 |
599 | #region Thumb Events
600 |
601 | ///
602 | /// Handles the DragStarted event of the Thumb control.
603 | ///
604 | /// The source of the event.
605 | /// The instance containing the event data.
606 | private void Thumb_DragStarted(object sender, DragStartedEventArgs e)
607 | {
608 | if (!Focused)
609 | Focused = true;
610 | }
611 |
612 | ///
613 | /// Handles the DragDelta event of the ResizeLeft control.
614 | ///
615 | /// The source of the event.
616 | /// The instance containing the event data.
617 | private void ResizeLeft_DragDelta(object sender, DragDeltaEventArgs e)
618 | {
619 | if (Width - e.HorizontalChange < MinWidth)
620 | return;
621 |
622 | double newLeft = e.HorizontalChange;
623 |
624 | if (Position.X + newLeft < 0)
625 | newLeft = 0 - Position.X;
626 |
627 | Width -= newLeft;
628 | Position = new Point(Position.X + newLeft, Position.Y);
629 |
630 | if (sender != null)
631 | Container.InvalidateSize();
632 | }
633 |
634 | ///
635 | /// Handles the DragDelta event of the ResizeTop control.
636 | ///
637 | /// The source of the event.
638 | /// The instance containing the event data.
639 | private void ResizeTop_DragDelta(object sender, DragDeltaEventArgs e)
640 | {
641 | if (Height - e.VerticalChange < MinHeight)
642 | return;
643 |
644 | double newTop = e.VerticalChange;
645 |
646 | if (Position.Y + newTop < 0)
647 | newTop = 0 - Position.Y;
648 |
649 | Height -= newTop;
650 | Position = new Point(Position.X, Position.Y + newTop);
651 |
652 | if (sender != null)
653 | Container.InvalidateSize();
654 | }
655 |
656 | ///
657 | /// Handles the DragDelta event of the ResizeRight control.
658 | ///
659 | /// The source of the event.
660 | /// The instance containing the event data.
661 | private void ResizeRight_DragDelta(object sender, DragDeltaEventArgs e)
662 | {
663 | if (Width + e.HorizontalChange < MinWidth)
664 | return;
665 |
666 | Width += e.HorizontalChange;
667 |
668 | if (sender != null)
669 | Container.InvalidateSize();
670 | }
671 |
672 | ///
673 | /// Handles the DragDelta event of the ResizeBottom control.
674 | ///
675 | /// The source of the event.
676 | /// The instance containing the event data.
677 | private void ResizeBottom_DragDelta(object sender, DragDeltaEventArgs e)
678 | {
679 | if (Height + e.VerticalChange < MinHeight)
680 | return;
681 |
682 | Height += e.VerticalChange;
683 |
684 | if (sender != null)
685 | Container.InvalidateSize();
686 | }
687 |
688 | #endregion
689 |
690 | #region Control Drag Event
691 |
692 | ///
693 | /// Handles the DragDelta event of the dragThumb control.
694 | ///
695 | /// The source of the event.
696 | /// The instance containing the event data.
697 | private void dragThumb_DragDelta(object sender, DragDeltaEventArgs e)
698 | {
699 | if (WindowState == WindowState.Maximized)
700 | return;
701 |
702 | double newLeft = Position.X + e.HorizontalChange,
703 | newTop = Position.Y + e.VerticalChange;
704 |
705 | if (newLeft < 0)
706 | newLeft = 0;
707 | if (newTop < 0)
708 | newTop = 0;
709 |
710 | Position = new Point(newLeft, newTop);
711 |
712 | Container.InvalidateSize();
713 | }
714 |
715 | #endregion
716 |
717 | #region Dependency Property Events
718 |
719 | ///
720 | /// Dependency property event once the position value has changed.
721 | ///
722 | /// The sender.
723 | /// The instance containing the event data.
724 | private static void PositionValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
725 | {
726 | if ((Point)e.NewValue == (Point)e.OldValue)
727 | return;
728 |
729 | MdiChild mdiChild = (MdiChild)sender;
730 | Point newPosition = (Point)e.NewValue;
731 |
732 | Canvas.SetTop(mdiChild, newPosition.Y < 0 ? 0 : newPosition.Y);
733 | Canvas.SetLeft(mdiChild, newPosition.X < 0 ? 0 : newPosition.X);
734 | }
735 |
736 | ///
737 | /// Dependency property event once the focused value has changed.
738 | ///
739 | /// The sender.
740 | /// The instance containing the event data.
741 | private static void FocusedValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
742 | {
743 | if ((bool)e.NewValue == (bool)e.OldValue)
744 | return;
745 |
746 | MdiChild mdiChild = (MdiChild)sender;
747 | if ((bool)e.NewValue)
748 | {
749 | mdiChild.Dispatcher.BeginInvoke(new Func(Keyboard.Focus), System.Windows.Threading.DispatcherPriority.ApplicationIdle, mdiChild.Content);
750 | mdiChild.RaiseEvent(new RoutedEventArgs(GotFocusEvent, mdiChild));
751 | }
752 | else
753 | {
754 | if (mdiChild.WindowState == WindowState.Maximized)
755 | mdiChild.Unmaximize();
756 | mdiChild.RaiseEvent(new RoutedEventArgs(LostFocusEvent, mdiChild));
757 | }
758 | }
759 |
760 | ///
761 | /// Dependency property event once the minimize box value has changed.
762 | ///
763 | /// The sender.
764 | /// The instance containing the event data.
765 | private static void MinimizeBoxValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
766 | {
767 | MdiChild mdiChild = (MdiChild)sender;
768 | bool visible = (bool)e.NewValue;
769 |
770 | if (visible)
771 | {
772 | bool maximizeVisible = true;
773 |
774 | if (mdiChild.maximizeButton != null)
775 | maximizeVisible = mdiChild.maximizeButton.Visibility == Visibility.Visible;
776 |
777 | if (mdiChild.minimizeButton != null)
778 | mdiChild.minimizeButton.IsEnabled = true;
779 |
780 | if (!maximizeVisible)
781 | {
782 | if (mdiChild.maximizeButton != null)
783 | mdiChild.minimizeButton.Visibility = Visibility.Visible;
784 |
785 | if (mdiChild.maximizeButton != null)
786 | mdiChild.maximizeButton.Visibility = Visibility.Visible;
787 | }
788 | }
789 | else
790 | {
791 | bool maximizeEnabled = true;
792 |
793 | if (mdiChild.maximizeButton != null)
794 | maximizeEnabled = mdiChild.maximizeButton.IsEnabled;
795 |
796 | if (mdiChild.minimizeButton != null)
797 | mdiChild.minimizeButton.IsEnabled = false;
798 |
799 | if (!maximizeEnabled)
800 | {
801 | if (mdiChild.minimizeButton != null)
802 | mdiChild.minimizeButton.Visibility = Visibility.Hidden;
803 |
804 | if (mdiChild.maximizeButton != null)
805 | mdiChild.maximizeButton.Visibility = Visibility.Hidden;
806 | }
807 | }
808 | }
809 |
810 | ///
811 | /// Dependency property event once the maximize box value has changed.
812 | ///
813 | /// The sender.
814 | /// The instance containing the event data.
815 | private static void MaximizeBoxValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
816 | {
817 | MdiChild mdiChild = (MdiChild)sender;
818 | bool visible = (bool)e.NewValue;
819 |
820 | if (visible)
821 | {
822 | bool minimizeVisible = true;
823 |
824 | if (mdiChild.minimizeButton != null)
825 | minimizeVisible = mdiChild.minimizeButton.Visibility == Visibility.Visible;
826 |
827 | if (mdiChild.maximizeButton != null)
828 | mdiChild.maximizeButton.IsEnabled = true;
829 |
830 | if (!minimizeVisible)
831 | {
832 | if (mdiChild.maximizeButton != null)
833 | mdiChild.minimizeButton.Visibility = Visibility.Visible;
834 |
835 | if (mdiChild.maximizeButton != null)
836 | mdiChild.maximizeButton.Visibility = Visibility.Visible;
837 | }
838 | }
839 | else
840 | {
841 | bool minimizeEnabled = true;
842 |
843 | if (mdiChild.minimizeButton != null)
844 | minimizeEnabled = mdiChild.minimizeButton.IsEnabled;
845 |
846 | if (mdiChild.maximizeButton != null)
847 | mdiChild.maximizeButton.IsEnabled = false;
848 |
849 | if (!minimizeEnabled)
850 | {
851 | if (mdiChild.maximizeButton != null)
852 | mdiChild.minimizeButton.Visibility = Visibility.Hidden;
853 |
854 | if (mdiChild.maximizeButton != null)
855 | mdiChild.maximizeButton.Visibility = Visibility.Hidden;
856 | }
857 | }
858 | }
859 |
860 | ///
861 | /// Dependency property event once the close box value has changed.
862 | ///
863 | /// The sender.
864 | /// The instance containing the event data.
865 | private static void CloseBoxValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
866 | {
867 | MdiChild mdiChild = (MdiChild)sender;
868 | bool visible = (bool)e.NewValue;
869 |
870 | if (visible)
871 | {
872 | if ((mdiChild.closeButton != null) && (mdiChild.closeButton.Visibility != Visibility.Visible))
873 | mdiChild.closeButton.Visibility = Visibility.Visible;
874 | }
875 | else
876 | {
877 | if ((mdiChild.closeButton != null) && (mdiChild.closeButton.Visibility == Visibility.Visible))
878 | mdiChild.closeButton.Visibility = Visibility.Collapsed;
879 | }
880 | }
881 |
882 | ///
883 | /// Dependency property event once the windows state value has changed.
884 | ///
885 | /// The sender.
886 | /// The instance containing the event data.
887 | private static void WindowStateValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
888 | {
889 | MdiChild mdiChild = (MdiChild)sender;
890 | MdiContainer mdiContainer = mdiChild.Container;
891 |
892 | WindowState previousWindowState = (WindowState)e.OldValue;
893 | WindowState windowState = (WindowState)e.NewValue;
894 |
895 | if (mdiChild.Container == null ||
896 | previousWindowState == windowState)
897 | return;
898 |
899 | if (previousWindowState == WindowState.Maximized)
900 | {
901 | if (mdiContainer.ActiveMdiChild.WindowState != WindowState.Maximized)
902 | {
903 | for (int i = 0; i < mdiContainer.Children.Count; i++)
904 | {
905 | if (mdiContainer.Children[i] != mdiChild &&
906 | mdiContainer.Children[i].WindowState == WindowState.Maximized &&
907 | mdiContainer.Children[i].MaximizeBox)
908 | mdiContainer.Children[i].WindowState = WindowState.Normal;
909 | }
910 |
911 | ScrollViewer sv = (ScrollViewer)((Grid)mdiContainer.Content).Children[1];
912 | sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
913 | sv.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
914 | }
915 |
916 | mdiChild.Buttons.Children.Clear();
917 | mdiChild.Buttons = null;
918 | mdiChild.buttonsPanel.Children.Add(mdiChild.minimizeButton);
919 | mdiChild.buttonsPanel.Children.Add(mdiChild.maximizeButton);
920 | mdiChild.buttonsPanel.Children.Add(mdiChild.closeButton);
921 | }
922 |
923 | if (previousWindowState == WindowState.Minimized)
924 | mdiChild.minimizedPosition = mdiChild.Position;
925 |
926 | switch (windowState)
927 | {
928 | case WindowState.Normal:
929 | {
930 | mdiChild.Position = new Point(mdiChild.originalDimension.X, mdiChild.originalDimension.Y);
931 | mdiChild.Width = mdiChild.originalDimension.Width;
932 | mdiChild.Height = mdiChild.originalDimension.Height;
933 | }
934 | break;
935 | case WindowState.Minimized:
936 | {
937 | if (previousWindowState == WindowState.Normal)
938 | mdiChild.originalDimension = new Rect(mdiChild.Position.X, mdiChild.Position.Y, mdiChild.ActualWidth, mdiChild.ActualHeight);
939 |
940 | double newLeft, newTop;
941 | if (mdiChild.minimizedPosition.X >= 0 || mdiChild.minimizedPosition.Y >= 0)
942 | {
943 | newLeft = mdiChild.minimizedPosition.X;
944 | newTop = mdiChild.minimizedPosition.Y;
945 | }
946 | else
947 | {
948 | List minimizedWindows = new List();
949 | for (int i = 0; i < mdiContainer.Children.Count; i++)
950 | {
951 | MdiChild child = mdiContainer.Children[i];
952 | if (child != mdiChild &&
953 | child.WindowState == WindowState.Minimized)
954 | minimizedWindows.Add(new Rect(child.Position.X, mdiContainer.InnerHeight - child.Position.Y, child.Width, child.Height));
955 | }
956 | Rect newWindowPlace;
957 | bool occupied = true;
958 | int count = 0,
959 | capacity = Convert.ToInt32(mdiContainer.ActualWidth) / MdiChild.MinimizedWidth;
960 | do
961 | {
962 | int row = count / capacity + 1,
963 | col = count % capacity;
964 | newTop = MdiChild.MinimizedHeight * row;
965 | newLeft = MdiChild.MinimizedWidth * col;
966 |
967 | newWindowPlace = new Rect(newLeft, newTop, MdiChild.MinimizedWidth, MdiChild.MinimizedHeight);
968 | occupied = false;
969 | foreach (Rect rect in minimizedWindows)
970 | {
971 | Rect intersection = rect;
972 | intersection.Intersect(newWindowPlace);
973 | if (intersection != Rect.Empty && intersection.Width > 0 && intersection.Height > 0)
974 | {
975 | occupied = true;
976 | break;
977 | }
978 | }
979 | count++;
980 |
981 | // TODO: handle negative Canvas coordinates somehow.
982 | if (newTop < 0)
983 | {
984 | // ugly workaround for now.
985 | newTop = 0;
986 | occupied = false;
987 | }
988 |
989 | } while (occupied);
990 |
991 | newTop = mdiContainer.InnerHeight - newTop;
992 | }
993 |
994 | mdiChild.Position = new Point(newLeft, newTop);
995 |
996 | mdiChild.Width = MdiChild.MinimizedWidth;
997 | mdiChild.Height = MdiChild.MinimizedHeight;
998 | }
999 | break;
1000 | case WindowState.Maximized:
1001 | {
1002 | if (previousWindowState == WindowState.Normal)
1003 | mdiChild.originalDimension = new Rect(mdiChild.Position.X, mdiChild.Position.Y, mdiChild.ActualWidth, mdiChild.ActualHeight);
1004 | mdiChild.NonMaximizedState = previousWindowState;
1005 |
1006 | mdiChild.buttonsPanel.Children.Clear();
1007 | StackPanel sp = new StackPanel { Orientation = Orientation.Horizontal };
1008 | sp.Children.Add(mdiChild.minimizeButton);
1009 | sp.Children.Add(mdiChild.maximizeButton);
1010 | sp.Children.Add(mdiChild.closeButton);
1011 | mdiChild.Buttons = sp;
1012 |
1013 | mdiChild.Position = new Point(0, 0);
1014 | mdiChild.Width = mdiContainer.ActualWidth;
1015 | mdiChild.Height = mdiContainer.InnerHeight - 2; // ContentBorder.BorderThickness="1" in template
1016 |
1017 | ScrollViewer sv = (ScrollViewer)((Grid)mdiContainer.Content).Children[1];
1018 | sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
1019 | sv.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
1020 | }
1021 | break;
1022 | }
1023 | if (mdiContainer.ActiveMdiChild == mdiChild)
1024 | mdiContainer.Buttons = mdiChild.Buttons;
1025 | mdiContainer.InvalidateSize();
1026 | }
1027 |
1028 | #endregion
1029 |
1030 | ///
1031 | /// Set focus to the child window and brings into view.
1032 | ///
1033 | public new void Focus()
1034 | {
1035 | Container.ActiveMdiChild = this;
1036 | }
1037 |
1038 | ///
1039 | /// Sets WindowState to previous non-maximized value.
1040 | ///
1041 | internal void Unmaximize()
1042 | {
1043 | if (WindowState == WindowState.Maximized)
1044 | WindowState = NonMaximizedState;
1045 | }
1046 |
1047 | ///
1048 | /// Manually closes the child window.
1049 | ///
1050 | public void Close()
1051 | {
1052 | if (Buttons != null)
1053 | Buttons.Children.Clear();
1054 | Container.Children.Remove(this);
1055 | }
1056 | }
1057 | }
--------------------------------------------------------------------------------