├── 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 | 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 | -------------------------------------------------------------------------------- /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 | } --------------------------------------------------------------------------------