├── DropDownButtonLibLogo.png
├── source
├── DropDownButtonLib_Source.txt
├── DropDownButtonTest
│ ├── App.config
│ ├── Properties
│ │ ├── Settings.settings
│ │ ├── Settings.Designer.cs
│ │ ├── AssemblyInfo.cs
│ │ ├── Resources.Designer.cs
│ │ └── Resources.resx
│ ├── App.xaml.cs
│ ├── MainWindow.xaml.cs
│ ├── MainWindow.xaml
│ ├── Views
│ │ ├── DemoView.xaml.cs
│ │ ├── BindingProxy.cs
│ │ ├── DemoViewModel.cs
│ │ └── DemoView.xaml
│ ├── ViewModels
│ │ └── AppViewModel.cs
│ ├── App.xaml
│ └── DropDownButtonTest.csproj
├── DropDownButtonLib
│ ├── Themes
│ │ ├── MetroDark.xaml
│ │ ├── MetroLight.xaml
│ │ ├── Generic.xaml
│ │ ├── LightBrushes.xaml
│ │ ├── DarkBrushes.xaml
│ │ └── ResourceKeys.cs
│ ├── AssemblyInfo.cs
│ ├── Readme.md
│ ├── DropDownButtonLib.csproj.user
│ ├── ViewModels
│ │ ├── Items
│ │ │ └── ItemsItemViewModel.cs
│ │ ├── Base
│ │ │ └── BaseViewModel.cs
│ │ ├── DropDownItemsButtonViewModel.cs
│ │ ├── SplitItemsButtonViewModel.cs
│ │ ├── DropDownButtonViewModel.cs
│ │ └── SplitButtonViewModel.cs
│ ├── Utilities
│ │ └── KeyboardUtilities.cs
│ ├── Controls
│ │ ├── SplitItemsButton.xaml.cs
│ │ ├── SplitButton.xaml.cs
│ │ ├── DropDownButton.xaml
│ │ ├── Chromes
│ │ │ ├── ButtonChrome_Metro.xaml
│ │ │ ├── ButtonChrome.cs
│ │ │ └── ButtonChrome.xaml
│ │ ├── DropDownItemsButton.xaml
│ │ ├── SplitButton.xaml
│ │ ├── SplitItemsButton.xaml
│ │ └── DropDownButton.xaml.cs
│ ├── Converters
│ │ └── InverseBoolConverter.cs
│ ├── DropDownButtonLib.csproj
│ └── Command
│ │ └── RelayCommand.cs
├── CleanAll.bat
└── DropDownButtonTest.sln
├── .gitignore
├── appveyor.yml
├── LICENSE.md
└── README.md
/DropDownButtonLibLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dirkster99/DropDownButtonLib/HEAD/DropDownButtonLibLogo.png
--------------------------------------------------------------------------------
/source/DropDownButtonLib_Source.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 | DropDownButtonLib
4 | -----------------
5 |
6 | The source code and project description for the DropDownButtonLib.dll is here:
7 | https://github.com/Dirkster99/DropDownButtonLib
8 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | 00_Release/
2 | 01_Nuget/
3 | debug/
4 | release/
5 | source/.vs
6 | build/
7 | bin/
8 | obj/
9 | cache/
10 | log/
11 | tmp/
12 |
13 | *~
14 | *.lock
15 | *.DS_Store
16 | *.swp
17 | *.out
18 | *.sou
19 | *.suo
20 | *.sqlite
21 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace DropDownButtonTest
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonTest
2 | {
3 | using System.Windows;
4 | using DropDownButtonTest.ViewModels;
5 |
6 | ///
7 | /// Interaction logic for MainWindow.xaml
8 | ///
9 | public partial class MainWindow : Window
10 | {
11 | public MainWindow()
12 | {
13 | this.InitializeComponent();
14 |
15 | this.DataContext = new AppViewModel();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 1.1.{build}
2 |
3 | configuration: Release
4 |
5 | platform: Any CPU
6 |
7 | image: Visual Studio 2019 Preview
8 |
9 | install:
10 | - cmd: choco install dotnetcore-sdk --pre
11 |
12 | before_build:
13 | - cmd: nuget restore source/DropDownButtonTest.sln
14 |
15 | build:
16 | verbosity: minimal
17 |
18 | artifacts:
19 |
20 | - path: source\DropDownButtonTest\bin\Release
21 | name: DropDownButtonTest
22 |
23 | - path: source\DropDownButtonLib\bin\Release
24 | name: DropDownButtonLib
25 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Themes/MetroDark.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Themes/MetroLight.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/Views/DemoView.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonTest.Views
2 | {
3 | using System.Windows;
4 | using System.Windows.Controls;
5 |
6 | ///
7 | /// Interaction logic for DemoView.xaml
8 | ///
9 | public partial class DemoView : UserControl
10 | {
11 | public DemoView()
12 | {
13 | this.InitializeComponent();
14 | }
15 |
16 | private void DropDownButton_Click(object sender, System.Windows.RoutedEventArgs e)
17 | {
18 | }
19 |
20 | private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
21 | {
22 | // this._dropDownButton.IsOpen = false;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Themes/Generic.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/source/CleanAll.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 | pushd "%~dp0"
3 | ECHO.
4 | ECHO.
5 | ECHO This script deletes all temporary build files in their
6 | ECHO corresponding BIN and OBJ Folder contained in the following projects
7 | ECHO.
8 | ECHO DropDownButtonLib
9 | ECHO DropDownButtonTest
10 | ECHO.
11 | REM Ask the user if hes really sure to continue beyond this point XXXXXXXX
12 | set /p choice=Are you sure to continue (Y/N)?
13 | if not '%choice%'=='Y' Goto EndOfBatch
14 | REM Script does not continue unless user types 'Y' in upper case letter
15 | ECHO.
16 | ECHO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
17 | ECHO.
18 | ECHO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
19 |
20 | ECHO.
21 | ECHO Deleting .vs and BIN, OBJ Folders in project folder
22 | ECHO.
23 | RMDIR .vs /S /Q
24 |
25 | RMDIR /S /Q DropDownButtonLib\bin
26 | RMDIR /S /Q DropDownButtonLib\obj
27 |
28 | RMDIR /S /Q DropDownButtonTest\bin
29 | RMDIR /S /Q DropDownButtonTest\obj
30 |
31 | PAUSE
32 |
33 | :EndOfBatch
34 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2015-2017 Dirk Bahle
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Readme.md:
--------------------------------------------------------------------------------
1 |
2 | #Overview#
3 |
4 | This project includes some bugfixes to the original implementation and extends the original controls:
5 |
6 | - DropDownButton, SplitButton
7 |
8 | with:
9 |
10 | - DropDownItemsButton, SplitItemsButton
11 |
12 | controls. The original implementation (DropDownButton, SplitButton) can be used to drop down and interact with
13 | single drop down items, while the extended controls (DropDownItemsButton, SplittItemsButton) are based on an
14 | an *ItemsControl* and can thus be used with multiple drop down items (in a similar fashion as a *ComboBox* or *ListBox*).
15 |
16 | #Contributors and Licenses#
17 |
18 | The DropDownButtonLib project is based on the Extended WPF Toolkit.
19 |
20 | Copyright (C) 2007-2013 Xceed Software Inc.
21 |
22 | This program is provided to you under the terms of the Microsoft Public
23 | License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
24 |
25 | For more features, controls, and fast professional support,
26 | pick up the Plus Edition at http://xceed.com/wpf_toolkit
27 |
28 | Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
29 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.18408
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace DropDownButtonTest.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/Views/BindingProxy.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonTest.Views
2 | {
3 | using System.Windows;
4 |
5 | ///
6 | /// Implements an XAML proxy which can be used to bind items (TreeViewItem, ListViewItem etc)
7 | /// with a viewmodel that manages the collecrions.
8 | ///
9 | /// Source: http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
10 | /// Issue: http://stackoverflow.com/questions/9994241/mvvm-binding-command-to-contextmenu-item
11 | ///
12 | public class BindingProxy : Freezable
13 | {
14 | public static readonly DependencyProperty DataProperty =
15 | DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
16 |
17 | ///
18 | /// Gets the data object this class is forwarding to everyone
19 | /// who has a reference to this object.
20 | ///
21 | public object Data
22 | {
23 | get { return (object)this.GetValue(DataProperty); }
24 | set { this.SetValue(DataProperty, value); }
25 | }
26 |
27 | ///
28 | /// Overrides of Freezable
29 | ///
30 | ///
31 | protected override Freezable CreateInstanceCore()
32 | {
33 | return new BindingProxy();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/ViewModels/AppViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonTest.ViewModels
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using DropDownButtonLib.ViewModels;
8 | using DropDownButtonTest.Views;
9 |
10 | ///
11 | /// Implements an application viewmodel that can be used
12 | /// to drive the entire behaviour of the main application view.
13 | ///
14 | public class AppViewModel : DropDownButtonLib.ViewModels.Base.BaseViewModel
15 | {
16 | #region fields
17 | private readonly DemoViewModel mDemo;
18 | #endregion fields
19 |
20 | #region constructor
21 | ///
22 | /// Class constructor
23 | ///
24 | public AppViewModel()
25 | {
26 | this.mDemo = new DemoViewModel();
27 | }
28 | #endregion constructor
29 |
30 | #region properties
31 | ///
32 | /// Gets an instance of a
33 | /// which can be bound to the
34 | /// control to test functions implemented in the DropDownButtonLib.
35 | ///
36 | public DemoViewModel Demo
37 | {
38 | get
39 | {
40 | return this.mDemo;
41 | }
42 | }
43 | #endregion properties
44 |
45 | #region methods
46 | #endregion methods
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/DropDownButtonLib.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Designer
7 |
8 |
9 | Designer
10 |
11 |
12 | Designer
13 |
14 |
15 | Designer
16 |
17 |
18 | Designer
19 |
20 |
21 | Designer
22 |
23 |
24 | Designer
25 |
26 |
27 | Designer
28 |
29 |
30 | Designer
31 |
32 |
33 | Designer
34 |
35 |
36 | Designer
37 |
38 |
39 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/ViewModels/Items/ItemsItemViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonLib.ViewModels.Items
2 | {
3 | ///
4 | /// Implements a viewmodel that drives the
5 | /// the control.
6 | ///
7 | public class ItemsItemViewModel : DropDownButtonLib.ViewModels.Base.BaseViewModel
8 | {
9 | #region fields
10 | private string mDisplayItemName;
11 | #endregion fields
12 |
13 | #region constructor
14 | ///
15 | /// Parmeterized class constructor
16 | ///
17 | public ItemsItemViewModel(string displayName)
18 | : this()
19 | {
20 | this.mDisplayItemName = displayName;
21 | }
22 |
23 | ///
24 | /// Class constructor
25 | ///
26 | protected ItemsItemViewModel()
27 | {
28 | this.mDisplayItemName = null;
29 | }
30 | #endregion constructor
31 |
32 | #region properties
33 | ///
34 | /// Gets the string that represents a name for display purposes.
35 | ///
36 | public string DisplayItemName
37 | {
38 | get
39 | {
40 | return this.mDisplayItemName;
41 | }
42 |
43 | private set
44 | {
45 | if (this.mDisplayItemName != value)
46 | {
47 | this.mDisplayItemName = value;
48 | this.NotifyPropertyChanged(() => this.DisplayItemName);
49 | }
50 | }
51 | }
52 | #endregion properties
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Utilities/KeyboardUtilities.cs:
--------------------------------------------------------------------------------
1 | /*************************************************************************************
2 |
3 | Extended WPF Toolkit
4 |
5 | Copyright (C) 2007-2013 Xceed Software Inc.
6 |
7 | This program is provided to you under the terms of the Microsoft Public
8 | License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
9 |
10 | For more features, controls, and fast professional support,
11 | pick up the Plus Edition at http://xceed.com/wpf_toolkit
12 |
13 | Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
14 |
15 | ***********************************************************************************/
16 | namespace DropDownButtonLib.Utilities
17 | {
18 | using System.Windows.Input;
19 |
20 | internal class KeyboardUtilities
21 | {
22 | ///
23 | /// Determine whether the parameter represents a keyboard short-cut
24 | /// that should modify the pop-up state of the drop-down button and return
25 | /// true if so, otherwise false.
26 | ///
27 | ///
28 | /// true if keyboard short-cut should modify the pop-up state, otherwise false.
29 | internal static bool IsKeyModifyingPopupState(KeyEventArgs e)
30 | {
31 | return ((((Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt) &&
32 | ((e.SystemKey == Key.Down) || (e.SystemKey == Key.Up)))
33 | || (e.Key == Key.F4));
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 | #ff3399ff
11 |
12 |
13 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Controls/SplitItemsButton.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonLib.Controls
2 | {
3 | using System.Windows;
4 | using System.Windows.Controls;
5 | using System.Windows.Controls.Primitives;
6 |
7 | ///
8 | /// Implements a look-less WPF SplitItemsButton control.
9 | ///
10 | [TemplatePart(Name = PART_ActionButton, Type = typeof(Button))]
11 | [TemplatePart(Name = DropDownItemsButton.PART_DropDownButton, Type = typeof(ToggleButton))]
12 | [TemplatePart(Name = DropDownItemsButton.PART_ItemsControl, Type = typeof(ContentPresenter))]
13 | [TemplatePart(Name = DropDownItemsButton.PART_Popup, Type = typeof(Popup))]
14 | public class SplitItemsButton : DropDownItemsButton
15 | {
16 | #region fields
17 | ///
18 | /// Const string of the required additional button element in the control.
19 | ///
20 | public const string PART_ActionButton = "PART_ActionButton";
21 | #endregion fields
22 |
23 | #region constructors
24 | ///
25 | /// Static class constructor
26 | ///
27 | static SplitItemsButton()
28 | {
29 | DefaultStyleKeyProperty.OverrideMetadata(typeof(SplitItemsButton),
30 | new FrameworkPropertyMetadata(typeof(SplitItemsButton)));
31 | }
32 | #endregion constructors
33 |
34 | #region methods
35 | ///
36 | ///
37 | ///
38 | public override void OnApplyTemplate()
39 | {
40 | base.OnApplyTemplate();
41 | this.Button = GetTemplateChild(PART_ActionButton) as Button;
42 | }
43 | #endregion methods
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Controls/SplitButton.xaml.cs:
--------------------------------------------------------------------------------
1 | /*************************************************************************************
2 |
3 | Extended WPF Toolkit
4 |
5 | Copyright (C) 2007-2013 Xceed Software Inc.
6 |
7 | This program is provided to you under the terms of the Microsoft Public
8 | License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
9 |
10 | For more features, controls, and fast professional support,
11 | pick up the Plus Edition at http://xceed.com/wpf_toolkit
12 |
13 | Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
14 |
15 | ***********************************************************************************/
16 | namespace DropDownButtonLib.Controls
17 | {
18 | using System.Windows;
19 | using System.Windows.Controls;
20 | using System.Windows.Controls.Primitives;
21 |
22 | ///
23 | /// Implements a look-less WPF SplitButton control.
24 | ///
25 | [TemplatePart(Name = SplitButton.PART_ActionButton, Type = typeof(Button))]
26 | [TemplatePart(Name = SplitButton.PART_DropDownButton, Type = typeof(ToggleButton))]
27 | [TemplatePart(Name = SplitButton.PART_ContentPresenter, Type = typeof(ContentPresenter))]
28 | [TemplatePart(Name = SplitButton.PART_Popup, Type = typeof(Popup))]
29 | public class SplitButton : DropDownButton
30 | {
31 | #region fields
32 | ///
33 | /// Const string of the required additional button element in the control.
34 | ///
35 | public const string PART_ActionButton = "PART_ActionButton";
36 | #endregion fields
37 |
38 | #region constructors
39 | ///
40 | /// Static class constructor
41 | ///
42 | static SplitButton()
43 | {
44 | DefaultStyleKeyProperty.OverrideMetadata(typeof(SplitButton),
45 | new FrameworkPropertyMetadata(typeof(SplitButton)));
46 | }
47 | #endregion constructors
48 |
49 | #region methods
50 | ///
51 | ///
52 | ///
53 | public override void OnApplyTemplate()
54 | {
55 | base.OnApplyTemplate();
56 | this.Button = GetTemplateChild(PART_ActionButton) as Button;
57 | }
58 | #endregion methods
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/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("DropDownButtonTest")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("DropDownButtonTest")]
15 | [assembly: AssemblyCopyright("Copyright © Open Source 2014")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Converters/InverseBoolConverter.cs:
--------------------------------------------------------------------------------
1 | /*************************************************************************************
2 |
3 | Extended WPF Toolkit
4 |
5 | Copyright (C) 2007-2013 Xceed Software Inc.
6 |
7 | This program is provided to you under the terms of the Microsoft Public
8 | License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
9 |
10 | For more features, controls, and fast professional support,
11 | pick up the Plus Edition at http://xceed.com/wpf_toolkit
12 |
13 | Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
14 |
15 | ***********************************************************************************/
16 | namespace DropDownButtonLib.Converters
17 | {
18 | using System;
19 | using System.Windows.Data;
20 |
21 | ///
22 | /// Implements a WPF that converts an input
23 | /// boolean value into an inverted boolean value (true to false, and vice versa).
24 | ///
25 | [ValueConversion(typeof(bool), typeof(bool))]
26 | public class InverseBoolConverter : IValueConverter
27 | {
28 | #region IValueConverter Members
29 | ///
30 | /// Standard Convert method of the interface.
31 | ///
32 | ///
33 | ///
34 | ///
35 | ///
36 | ///
37 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
38 | {
39 | if (value == null)
40 | return Binding.DoNothing;
41 |
42 | if ((value is bool) == false)
43 | return Binding.DoNothing;
44 |
45 | return !(bool)value;
46 | }
47 |
48 | ///
49 | /// Standard ConvertBack method of the interface.
50 | ///
51 | ///
52 | ///
53 | ///
54 | ///
55 | ///
56 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
57 | {
58 | if (value == null)
59 | return Binding.DoNothing;
60 |
61 | if ((value is bool) == false)
62 | return Binding.DoNothing;
63 |
64 | return !(bool)value;
65 | }
66 | #endregion
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29209.152
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DropDownButtonTest", "DropDownButtonTest\DropDownButtonTest.csproj", "{E5F032E0-CC7A-40A0-B11D-98D1F5A67775}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DE2DCFE5-1E33-4BBA-B76E-90B88BD3A5B3}"
9 | ProjectSection(SolutionItems) = preProject
10 | DropDownButtonLib_Source.txt = DropDownButtonLib_Source.txt
11 | EndProjectSection
12 | EndProject
13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DropDownButtonLib", "DropDownButtonLib\DropDownButtonLib.csproj", "{C9B8C80D-60CB-44CE-8A22-06010C62FD74}"
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Debug|x86 = Debug|x86
19 | Release|Any CPU = Release|Any CPU
20 | Release|x86 = Release|x86
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {E5F032E0-CC7A-40A0-B11D-98D1F5A67775}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {E5F032E0-CC7A-40A0-B11D-98D1F5A67775}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {E5F032E0-CC7A-40A0-B11D-98D1F5A67775}.Debug|x86.ActiveCfg = Debug|x86
26 | {E5F032E0-CC7A-40A0-B11D-98D1F5A67775}.Debug|x86.Build.0 = Debug|x86
27 | {E5F032E0-CC7A-40A0-B11D-98D1F5A67775}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {E5F032E0-CC7A-40A0-B11D-98D1F5A67775}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {E5F032E0-CC7A-40A0-B11D-98D1F5A67775}.Release|x86.ActiveCfg = Release|x86
30 | {E5F032E0-CC7A-40A0-B11D-98D1F5A67775}.Release|x86.Build.0 = Release|x86
31 | {C9B8C80D-60CB-44CE-8A22-06010C62FD74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {C9B8C80D-60CB-44CE-8A22-06010C62FD74}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {C9B8C80D-60CB-44CE-8A22-06010C62FD74}.Debug|x86.ActiveCfg = Debug|Any CPU
34 | {C9B8C80D-60CB-44CE-8A22-06010C62FD74}.Debug|x86.Build.0 = Debug|Any CPU
35 | {C9B8C80D-60CB-44CE-8A22-06010C62FD74}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {C9B8C80D-60CB-44CE-8A22-06010C62FD74}.Release|Any CPU.Build.0 = Release|Any CPU
37 | {C9B8C80D-60CB-44CE-8A22-06010C62FD74}.Release|x86.ActiveCfg = Release|Any CPU
38 | {C9B8C80D-60CB-44CE-8A22-06010C62FD74}.Release|x86.Build.0 = Release|Any CPU
39 | EndGlobalSection
40 | GlobalSection(SolutionProperties) = preSolution
41 | HideSolutionNode = FALSE
42 | EndGlobalSection
43 | GlobalSection(ExtensibilityGlobals) = postSolution
44 | SolutionGuid = {D92C3282-83F7-4190-B9B4-44F86C16727A}
45 | EndGlobalSection
46 | EndGlobal
47 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/Views/DemoViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonTest.Views
2 | {
3 | using DropDownButtonLib.ViewModels;
4 |
5 | ///
6 | /// Implements an application viewmodel that can be used
7 | /// to drive the entire behaviour of the main application view.
8 | ///
9 | public class DemoViewModel : DropDownButtonLib.ViewModels.Base.BaseViewModel
10 | {
11 | #region fields
12 | private readonly SplitButtonViewModel mSplitButtonTest;
13 | private readonly DropDownItemsButtonViewModel mDropDownItemsButtonTest;
14 | private readonly DropDownButtonViewModel mDropDownButtonTest;
15 | private readonly SplitItemsButtonViewModel mSplitItemsButtonTest;
16 | #endregion fields
17 |
18 | #region constructor
19 | ///
20 | /// Class constructor
21 | ///
22 | public DemoViewModel()
23 | {
24 | this.mDropDownButtonTest = new DropDownButtonViewModel();
25 | this.mSplitButtonTest = new SplitButtonViewModel();
26 | this.mDropDownItemsButtonTest = new DropDownItemsButtonViewModel();
27 | this.mSplitItemsButtonTest = new SplitItemsButtonViewModel();
28 | }
29 | #endregion constructor
30 |
31 | #region properties
32 | ///
33 | /// Gets an instance of a
34 | /// which can be bound to a
35 | /// control to test it.
36 | ///
37 | public DropDownButtonViewModel DropDownButtonTest
38 | {
39 | get
40 | {
41 | return this.mDropDownButtonTest;
42 | }
43 | }
44 |
45 | ///
46 | /// Gets an instance of a
47 | /// which can be bound to a
48 | /// control to test it.
49 | ///
50 | public SplitButtonViewModel SplitButtonTest
51 | {
52 | get
53 | {
54 | return this.mSplitButtonTest;
55 | }
56 | }
57 |
58 | ///
59 | /// Gets an instance of a
60 | /// which can be bound to a
61 | /// control to test it.
62 | ///
63 | public DropDownItemsButtonViewModel DropDownItemsButtonTest
64 | {
65 | get
66 | {
67 | return this.mDropDownItemsButtonTest;
68 | }
69 | }
70 |
71 | public SplitItemsButtonViewModel SplitItemsButtonTest
72 | {
73 | get
74 | {
75 | return this.mSplitItemsButtonTest;
76 | }
77 | }
78 | #endregion properties
79 |
80 | #region methods
81 | #endregion methods
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.18408
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace DropDownButtonTest.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DropDownButtonTest.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/ViewModels/Base/BaseViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonLib.ViewModels.Base
2 | {
3 | using System;
4 | using System.ComponentModel;
5 | using System.Linq.Expressions;
6 | using System.Windows;
7 |
8 | ///
9 | /// Every ViewModel class is required to implement the INotifyPropertyChanged
10 | /// interface in order to tell WPF when a property changed (for instance, when
11 | /// a method or setter is executed).
12 | ///
13 | /// Therefore, the PropertyChanged methode has to be called when data changes,
14 | /// because the relevant properties may or may not be bound to GUI elements,
15 | /// which in turn have to refresh their display.
16 | ///
17 | /// The PropertyChanged method is to be called by the members and properties of
18 | /// the class that derives from this class. Each call contains the name of the
19 | /// property that has to be refreshed.
20 | ///
21 | /// The BaseViewModel is derived from from System.Windows.DependencyObject to allow
22 | /// resulting ViewModels the implemantion of dependency properties. Dependency properties
23 | /// in turn are useful when working with IValueConverter and ConverterParameters.
24 | ///
25 | public class BaseViewModel : INotifyPropertyChanged
26 | {
27 | ///
28 | /// Standard event handler of the interface
29 | ///
30 | public event PropertyChangedEventHandler PropertyChanged;
31 |
32 | ///
33 | /// Tell bound controls (via WPF binding) to refresh their display.
34 | ///
35 | /// Sample call: this.NotifyPropertyChanged(() => this.IsSelected);
36 | /// where 'this' is derived from
37 | /// and IsSelected is a property.
38 | ///
39 | ///
40 | ///
41 | public void NotifyPropertyChanged(Expression> property)
42 | {
43 | var lambda = (LambdaExpression)property;
44 | MemberExpression memberExpression;
45 |
46 | if (lambda.Body is UnaryExpression)
47 | {
48 | var unaryExpression = (UnaryExpression)lambda.Body;
49 | memberExpression = (MemberExpression)unaryExpression.Operand;
50 | }
51 | else
52 | memberExpression = (MemberExpression)lambda.Body;
53 |
54 | this.OnPropertyChanged(memberExpression.Member.Name);
55 | }
56 |
57 | ///
58 | /// Tell bound controls (via WPF binding) to refresh their display.
59 | ///
60 | /// Sample call: this.OnPropertyChanged("IsSelected");
61 | /// where 'this' is derived from
62 | /// and IsSelected is a property.
63 | ///
64 | /// Name of property to refresh
65 | public void OnPropertyChanged(string propertyName)
66 | {
67 | try
68 | {
69 | if (this.PropertyChanged != null)
70 | this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
71 | }
72 | catch
73 | {
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/DropDownButtonLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net4;netcoreapp3.0
5 | true
6 |
7 | true
8 | 1.1.0.0
9 | 1.1.0.0
10 | 1.1.0.0
11 | Open Source
12 | DropDownButtonLib
13 | 2014-2019
14 | Provides a .Net implementation of a WPF drop down button control.
15 | https://github.com/Dirkster99/DropDownButtonLib
16 | https://github.com/Dirkster99/DropDownButtonLib
17 | Dirkster.DropDownButtonLib
18 | https://github.com/Dirkster99/DropDownButtonLib
19 | MIT
20 | wpf mvvm c# .net metro dark light themed dropdown button dropdownbutton control library
21 | This control is now supported in NetCore 3 (with Preview 8) and .Net 4.
22 | en
23 | https://raw.githubusercontent.com/Dirkster99/DropDownButtonLib/master/DropDownButtonLibLogo.png
24 |
25 |
26 |
27 |
28 |
29 | ButtonChrome.xaml
30 |
31 |
32 | DropDownButton.xaml
33 |
34 |
35 | DropDownItemsButton.xaml
36 |
37 |
38 | SplitButton.xaml
39 |
40 |
41 | SplitItemsButton.xaml
42 |
43 |
44 |
45 |
46 |
47 | Designer
48 |
49 |
50 | Designer
51 |
52 |
53 | Designer
54 |
55 |
56 | Designer
57 |
58 |
59 | Designer
60 |
61 |
62 | Designer
63 |
64 |
65 | Designer
66 |
67 |
68 | Designer
69 | MSBuild:Compile
70 |
71 |
72 | Designer
73 |
74 |
75 | Designer
76 |
77 |
78 | Designer
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://ci.appveyor.com/project/Dirkster99/dropdownbuttonlib)
2 | [](https://github.com/Dirkster99/DropDownButtonLib/releases/latest)
3 | [](http://nuget.org/packages/Dirkster.DropDownButtonLib)
4 |
5 |  
6 |
7 | Overview
8 | The DropDownButtonLib project supplies MVVM/WPF drop down controls that are based on a button.
9 |
10 | There are sample screenshot on the Codeplex site from were this project is migrated from:
11 | https://dropdownbuttonlib.codeplex.com/
12 |
13 | This project is based on the drop down control contained in the
14 | Extended WPF Toolkit™ Community Edition:https://wpftoolkit.codeplex.com/ from Xceed.
15 | It includes some bugfixes to the original implementation and extends the original controls with a:
16 |
17 | - DropDownButton, SplitButton
18 | with:
19 | - DropDownItemsButton, SplitItemsButton
20 |
21 | controls. The original implementation (DropDownButton, SplitButton) can be used to drop down and interact with single drop down items, while the extended controls (DropDownItemsButton, SplittItemsButton) are based on an ItemsControl and can thus be with multiple drop down items (in a similar fashion as a standard WPF ComboBox or ListBox control).
22 |
23 | ## DropDownButton
24 |
25 | The DropDown button shows a drop down element that gives users a way of editing something and confirming it with Cancel or OK (this works similar to a dialog but in a drop down scenario).
26 |
27 | ## SplitButton
28 |
29 | The Split button has a drop down section and a button.
30 | The drop down element gives you a way of editing/selecting in a similar scenario as in the DropDownButton shown above, while the button itself can be used like a shortcut that refers to the last selected element.
31 |
32 | ## DropDownItemsButton
33 |
34 | The DropDown button shows a drop down element which can be used to select one element out of many. This could also be implemented with the DropDownButton control but it is much easier with this control since it already contains an ItemsControl inside the drop down element.
35 |
36 | ## SplitItemsButton
37 |
38 | The Split button has a drop down section and a button.
39 | The drop down element gives you a way of selecting from among many elements while the button itself can be used like a shortcut that refers to the last selected element.
40 |
41 | ## Demo Application
42 |
43 | This is a screenshot of the MainWindow of the included Test Application. The complete implementation is MVVM compliant and all controls are fully themeable (look-less controls).
44 |
45 | ## Theming
46 |
47 | Load *Light* or *Dark* brush resources in you resource dictionary to take advantage of existing definitions.
48 |
49 | ```XAML
50 |
51 |
52 |
53 | ```
54 |
55 | ```XAML
56 |
57 |
58 |
59 | ```
60 |
61 | These definitions do not theme all controls used within this library. You should use a standard theming library, such as:
62 | - [MahApps.Metro](https://github.com/MahApps/MahApps.Metro),
63 | - [MLib](https://github.com/Dirkster99/MLib), or
64 | - [MUI](https://github.com/firstfloorsoftware/mui)
65 |
66 | to also theme standard elements, such as, button and textblock etc.
67 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Themes/LightBrushes.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
8 | #FF2C628B
10 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Themes/DarkBrushes.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 | #FF2C628B
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
38 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Controls/DropDownButton.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Command/RelayCommand.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonLib.Command
2 | {
3 | using System;
4 | using System.Diagnostics;
5 | using System.Windows.Input;
6 |
7 | ///
8 | /// A command whose sole purpose is to
9 | /// relay its functionality to other
10 | /// objects by invoking delegates. The
11 | /// default return value for the CanExecute
12 | /// method is 'true'.
13 | ///
14 | /// Source: http://www.codeproject.com/Articles/31837/Creating-an-Internationalized-Wizard-in-WPF
15 | ///
16 | internal class RelayCommand : ICommand
17 | {
18 | #region Fields
19 | private readonly Action mExecute = null;
20 | private readonly Predicate mCanExecute = null;
21 | #endregion // Fields
22 |
23 | #region Constructors
24 | ///
25 | /// Class constructor
26 | ///
27 | ///
28 | public RelayCommand(Action execute)
29 | : this(execute, null)
30 | {
31 | }
32 |
33 | ///
34 | /// Creates a new command.
35 | ///
36 | /// The execution logic.
37 | /// The execution status logic.
38 | public RelayCommand(Action execute, Predicate canExecute)
39 | {
40 | if (execute == null)
41 | throw new ArgumentNullException("execute");
42 |
43 | this.mExecute = execute;
44 | this.mCanExecute = canExecute;
45 | }
46 |
47 | #endregion // Constructors
48 |
49 | #region events
50 | ///
51 | /// Eventhandler to re-evaluate whether this command can execute or not
52 | ///
53 | public event EventHandler CanExecuteChanged
54 | {
55 | add
56 | {
57 | if (this.mCanExecute != null)
58 | CommandManager.RequerySuggested += value;
59 | }
60 |
61 | remove
62 | {
63 | if (this.mCanExecute != null)
64 | CommandManager.RequerySuggested -= value;
65 | }
66 | }
67 | #endregion
68 |
69 | #region methods
70 | ///
71 | /// Determine whether this pre-requisites to execute this command are given or not.
72 | ///
73 | ///
74 | ///
75 | [DebuggerStepThrough]
76 | public bool CanExecute(object parameter)
77 | {
78 | return this.mCanExecute == null ? true : this.mCanExecute((T)parameter);
79 | }
80 |
81 | ///
82 | /// Execute the command method managed in this class.
83 | ///
84 | ///
85 | public void Execute(object parameter)
86 | {
87 | this.mExecute((T)parameter);
88 | }
89 | #endregion methods
90 | }
91 |
92 | ///
93 | /// A command whose sole purpose is to
94 | /// relay its functionality to other
95 | /// objects by invoking delegates. The
96 | /// default return value for the CanExecute
97 | /// method is 'true'.
98 | ///
99 | internal class RelayCommand : ICommand
100 | {
101 | #region Fields
102 | private readonly Action mExecute;
103 | private readonly Func mCanExecute;
104 | #endregion Fields
105 |
106 | #region Constructors
107 |
108 | ///
109 | /// Creates a new command that can always execute.
110 | ///
111 | /// The execution logic.
112 | public RelayCommand(Action execute)
113 | : this(execute, null)
114 | {
115 | }
116 |
117 | ///
118 | /// Copy constructor
119 | ///
120 | ///
121 | public RelayCommand(RelayCommand inputRC)
122 | : this(inputRC.mExecute, inputRC.mCanExecute)
123 | {
124 | }
125 |
126 | ///
127 | /// Creates a new command.
128 | ///
129 | /// The execution logic.
130 | /// The execution status logic.
131 | public RelayCommand(Action execute, Func canExecute)
132 | {
133 | if (execute == null)
134 | throw new ArgumentNullException("execute");
135 |
136 | this.mExecute = execute;
137 | this.mCanExecute = canExecute;
138 | }
139 |
140 | #endregion Constructors
141 |
142 | #region Events
143 | ///
144 | /// Eventhandler to re-evaluate whether this command can execute or not
145 | ///
146 | public event EventHandler CanExecuteChanged
147 | {
148 | add
149 | {
150 | if (this.mCanExecute != null)
151 | CommandManager.RequerySuggested += value;
152 | }
153 |
154 | remove
155 | {
156 | if (this.mCanExecute != null)
157 | CommandManager.RequerySuggested -= value;
158 | }
159 | }
160 | #endregion Events
161 |
162 | #region Methods
163 | ///
164 | /// Execute the attached CanExecute methode delegate (or always return true)
165 | /// to determine whether the command managed in this object can execute or not.
166 | ///
167 | ///
168 | ///
169 | [DebuggerStepThrough]
170 | public bool CanExecute(object parameter)
171 | {
172 | return this.mCanExecute == null ? true : this.mCanExecute();
173 | }
174 |
175 | ///
176 | /// Return the attached delegate method.
177 | ///
178 | ///
179 | public void Execute(object parameter)
180 | {
181 | this.mExecute();
182 | }
183 | #endregion Methods
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/ViewModels/DropDownItemsButtonViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonLib.ViewModels
2 | {
3 | using System;
4 | using System.Collections.ObjectModel;
5 | using System.Windows.Input;
6 | using DropDownButtonLib.Command;
7 | using DropDownButtonLib.ViewModels.Items;
8 |
9 | ///
10 | /// Implements a viewmodel that drives the
11 | /// the control.
12 | ///
13 | public class DropDownItemsButtonViewModel : Base.BaseViewModel
14 | {
15 | #region fields
16 | private readonly ObservableCollection mDropDownItems;
17 |
18 | private RelayCommand mDropDownButtonClickCommand;
19 | private RelayCommand mItemButtonClickCommand;
20 |
21 | private bool mIsOpen;
22 | private string mStatus;
23 | private bool mIsEnabled;
24 | #endregion fields
25 |
26 | #region constructor
27 | ///
28 | /// Class constructor
29 | ///
30 | public DropDownItemsButtonViewModel()
31 | {
32 | this.mIsOpen = false;
33 | this.mIsEnabled = true;
34 | this.mStatus = string.Empty;
35 | this.mDropDownItems = new ObservableCollection();
36 |
37 | for (int i = 0; i < 255; i++)
38 | this.mDropDownItems.Add(new ItemsItemViewModel("Drop Down Items Demo " + i));
39 | }
40 | #endregion constructor
41 |
42 | #region properties
43 | ///
44 | /// Command is invoked when user clicks on the DropDownButton
45 | /// (either on label part or DropDown arrow).
46 | ///
47 | public ICommand DropDownButtonClickCommand
48 | {
49 | get
50 | {
51 | if (this.mDropDownButtonClickCommand == null)
52 | this.mDropDownButtonClickCommand = new RelayCommand(
53 | (p) => this.DropDownButtonClickCommand_Executed(),
54 | (p) => this.IsEnabled);
55 |
56 | return this.mDropDownButtonClickCommand;
57 | }
58 | }
59 |
60 | ///
61 | /// Command is invoked when user clicks on the DropDownButton
62 | /// (user clicked a button or hyperlink in DropDown part).
63 | ///
64 | public ICommand ItemButtonClickCommand
65 | {
66 | get
67 | {
68 | if (this.mItemButtonClickCommand == null)
69 | this.mItemButtonClickCommand = new RelayCommand((p) =>
70 | {
71 | var param = p as ItemsItemViewModel;
72 |
73 | if (param != null)
74 | this.ItemButtonClickCommand_Executed(param);
75 | },
76 | (p) => this.IsEnabled);
77 |
78 | return this.mItemButtonClickCommand;
79 | }
80 | }
81 |
82 | ///
83 | /// Gets the list of drives and folders for display in treeview structure control.
84 | ///
85 | public ObservableCollection DropDownItems
86 | {
87 | get
88 | {
89 | return this.mDropDownItems;
90 | }
91 | }
92 |
93 | ///
94 | /// Gets the caption of the dropdown button.
95 | ///
96 | public string ButtonLabel
97 | {
98 | get
99 | {
100 | return "Select an item";
101 | }
102 | }
103 |
104 | ///
105 | /// Gets/sets bound property to determine whether
106 | /// drop-down/pop-up element is open or not.
107 | ///
108 | public bool IsOpen
109 | {
110 | get
111 | {
112 | return this.mIsOpen;
113 | }
114 |
115 | set
116 | {
117 | if (this.mIsOpen != value)
118 | {
119 | this.mIsOpen = value;
120 | this.NotifyPropertyChanged(() => this.IsOpen);
121 | }
122 | }
123 | }
124 |
125 | ///
126 | /// Gets/sets Boolean value to determine whether attached dropdown view is enabled or not.
127 | ///
128 | public bool IsEnabled
129 | {
130 | get
131 | {
132 | return this.mIsEnabled;
133 | }
134 |
135 | set
136 | {
137 | if (this.mIsEnabled != value)
138 | {
139 | this.mIsEnabled = value;
140 | this.NotifyPropertyChanged(() => this.IsEnabled);
141 | }
142 | }
143 | }
144 |
145 | ///
146 | /// Gets the status description of this viewmodel
147 | /// (this property is present for testing/demo/debugging purposes only
148 | /// since it gives us the ability to give state feedback without using
149 | /// MessageBoxes, which steals the focus and thus influence the pop-up element)
150 | ///
151 | public string Status
152 | {
153 | get
154 | {
155 | return this.mStatus;
156 | }
157 |
158 | private set
159 | {
160 | if (this.mStatus != value)
161 | {
162 | this.mStatus = value;
163 | this.NotifyPropertyChanged(() => this.Status);
164 | }
165 | }
166 | }
167 | #endregion properties
168 |
169 | #region methods
170 | private void DropDownButtonClickCommand_Executed()
171 | {
172 | this.Status = "Thanks for clicking the DropDownItemsButton!";
173 | }
174 |
175 | private void ItemButtonClickCommand_Executed(ItemsItemViewModel p)
176 | {
177 | if (p == null)
178 | return;
179 |
180 | // This is the only button specific logic there is -> the rest is demo
181 | this.IsOpen = false;
182 |
183 | string source = "DropDownItemsButton";
184 |
185 | this.Status += Environment.NewLine +
186 | string.Format("Thanks for clicking: '{0} -> {1}'!", source, p.DisplayItemName);
187 | }
188 | #endregion methods
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/DropDownButtonTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {E5F032E0-CC7A-40A0-B11D-98D1F5A67775}
8 | WinExe
9 | Properties
10 | DropDownButtonTest
11 | DropDownButtonTest
12 | v4.0
13 | 512
14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 | 4
16 | Client
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | AnyCPU
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 | true
39 | bin\x86\Debug\
40 | DEBUG;TRACE
41 | full
42 | x86
43 | prompt
44 | ManagedMinimumRules.ruleset
45 |
46 |
47 | bin\x86\Release\
48 | TRACE
49 | true
50 | pdbonly
51 | x86
52 | prompt
53 | ManagedMinimumRules.ruleset
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | 4.0
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | MSBuild:Compile
73 | Designer
74 |
75 |
76 |
77 |
78 | DemoView.xaml
79 |
80 |
81 |
82 | MSBuild:Compile
83 | Designer
84 |
85 |
86 | App.xaml
87 | Code
88 |
89 |
90 | MainWindow.xaml
91 | Code
92 |
93 |
94 | MSBuild:Compile
95 | Designer
96 |
97 |
98 |
99 |
100 | Code
101 |
102 |
103 | True
104 | True
105 | Resources.resx
106 |
107 |
108 | True
109 | Settings.settings
110 | True
111 |
112 |
113 | ResXFileCodeGenerator
114 | Resources.Designer.cs
115 |
116 |
117 | SettingsSingleFileGenerator
118 | Settings.Designer.cs
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | {c9b8c80d-60cb-44ce-8a22-06010c62fd74}
128 | DropDownButtonLib
129 |
130 |
131 |
132 |
139 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/ViewModels/SplitItemsButtonViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonLib.ViewModels
2 | {
3 | using System;
4 | using System.Collections.ObjectModel;
5 | using System.Windows.Input;
6 | using DropDownButtonLib.Command;
7 | using DropDownButtonLib.ViewModels.Items;
8 |
9 | ///
10 | /// Implements a viewmodel for a split button that can display multiple items.
11 | /// The user experience is similar to a combobox with the difference that a
12 | /// splitbutton allows a re-apply of the last selected item.
13 | ///
14 | public class SplitItemsButtonViewModel : Base.BaseViewModel
15 | {
16 | #region fields
17 | private readonly ObservableCollection mDropDownItems;
18 |
19 | private RelayCommand mDropDownButtonClickCommand;
20 | private RelayCommand mItemButtonClickCommand;
21 |
22 | private bool mIsOpen;
23 | private string mStatus;
24 | private bool mIsEnabled;
25 | private ItemsItemViewModel mSelectedItem;
26 | #endregion fields
27 |
28 | #region constructor
29 | ///
30 | /// Class constructor
31 | ///
32 | public SplitItemsButtonViewModel()
33 | {
34 | this.mIsOpen = false;
35 | this.mIsEnabled = true;
36 | this.mStatus = string.Empty;
37 | this.mDropDownItems = new ObservableCollection();
38 |
39 | this.mSelectedItem = new ItemsItemViewModel("Drop Down Items Demo 1");
40 |
41 | this.mDropDownItems.Add(this.mSelectedItem);
42 |
43 | for (int i = 2; i < 255; i++)
44 | this.mDropDownItems.Add(new ItemsItemViewModel("Drop Down Items Demo " + i));
45 | }
46 | #endregion constructor
47 |
48 | #region properties
49 | ///
50 | /// Command is invoked when user clicks on the DropDownButton
51 | /// (either on label part or DropDown arrow).
52 | ///
53 | public ICommand DropDownButtonClickCommand
54 | {
55 | get
56 | {
57 | if (this.mDropDownButtonClickCommand == null)
58 | this.mDropDownButtonClickCommand = new RelayCommand(
59 | (p) =>
60 | {
61 | var param = p as ItemsItemViewModel;
62 |
63 | if (param != null)
64 | this.DropDownButtonClickCommand_Executed(param);
65 | },
66 | (p) => this.IsEnabled);
67 |
68 | return this.mDropDownButtonClickCommand;
69 | }
70 | }
71 |
72 | ///
73 | /// Command is invoked when user clicks on the DropDownButton
74 | /// (user clicked a button or hyperlink in DropDown part).
75 | ///
76 | public ICommand ItemButtonClickCommand
77 | {
78 | get
79 | {
80 | if (this.mItemButtonClickCommand == null)
81 | this.mItemButtonClickCommand = new RelayCommand((p) =>
82 | {
83 | var param = p as ItemsItemViewModel;
84 |
85 | if (param != null)
86 | this.ItemButtonClickCommand_Executed(param);
87 | },
88 | (p) => this.IsEnabled);
89 |
90 | return this.mItemButtonClickCommand;
91 | }
92 | }
93 |
94 | ///
95 | /// Gets the list of drives and folders for display in treeview structure control.
96 | ///
97 | public ObservableCollection DropDownItems
98 | {
99 | get
100 | {
101 | return this.mDropDownItems;
102 | }
103 | }
104 |
105 | ///
106 | /// Gets/sets the selected (current) item of this button viewmodel.
107 | ///
108 | public ItemsItemViewModel SelectedItem
109 | {
110 | get
111 | {
112 | return this.mSelectedItem;
113 | }
114 |
115 | set
116 | {
117 | if (this.mSelectedItem != value)
118 | {
119 | this.mSelectedItem = value;
120 | this.NotifyPropertyChanged(() => this.SelectedItem);
121 | }
122 | }
123 | }
124 |
125 | ///
126 | /// Gets/sets bound property to determine whether
127 | /// drop-down/pop-up element is open or not.
128 | ///
129 | public bool IsOpen
130 | {
131 | get
132 | {
133 | return this.mIsOpen;
134 | }
135 |
136 | set
137 | {
138 | if (this.mIsOpen != value)
139 | {
140 | this.mIsOpen = value;
141 | this.NotifyPropertyChanged(() => this.IsOpen);
142 | }
143 | }
144 | }
145 |
146 | ///
147 | /// Gets/sets Boolean value to determine whether attached dropdown view is enabled or not.
148 | ///
149 | public bool IsEnabled
150 | {
151 | get
152 | {
153 | return this.mIsEnabled;
154 | }
155 |
156 | set
157 | {
158 | if (this.mIsEnabled != value)
159 | {
160 | this.mIsEnabled = value;
161 | this.NotifyPropertyChanged(() => this.IsEnabled);
162 | }
163 | }
164 | }
165 |
166 | ///
167 | /// Gets the status description of this viewmodel
168 | /// (this property is present for testing/demo/debugging purposes only
169 | /// since it gives us the ability to give state feedback without using
170 | /// MessageBoxes, which steals the focus and thus influence the pop-up element)
171 | ///
172 | public string Status
173 | {
174 | get
175 | {
176 | return this.mStatus;
177 | }
178 |
179 | private set
180 | {
181 | if (this.mStatus != value)
182 | {
183 | this.mStatus = value;
184 | this.NotifyPropertyChanged(() => this.Status);
185 | }
186 | }
187 | }
188 | #endregion properties
189 |
190 | #region methods
191 | private void DropDownButtonClickCommand_Executed(ItemsItemViewModel p)
192 | {
193 | if (p == null)
194 | return;
195 |
196 | string source = "SplitItemsButton -> DropDownButtonClickCommand";
197 |
198 | this.Status = string.Format("Thanks for clicking: '{0} -> {1}'!", source, p.DisplayItemName);
199 | }
200 |
201 | private void ItemButtonClickCommand_Executed(ItemsItemViewModel p)
202 | {
203 | if (p == null)
204 | return;
205 |
206 | this.IsOpen = false;
207 | this.SelectedItem = p;
208 |
209 | string source = "SplitItemsButton -> ItemButtonClickCommand";
210 |
211 | this.Status += Environment.NewLine +
212 | string.Format("Thanks for clicking: '{0} -> {1}'!", source, p.DisplayItemName);
213 | }
214 | #endregion methods
215 | }
216 | }
217 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/ViewModels/DropDownButtonViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonLib.ViewModels
2 | {
3 | using System.Windows.Input;
4 | using DropDownButtonLib.Command;
5 |
6 | ///
7 | /// Implements a viewmodel that drives the
8 | /// the control.
9 | ///
10 | public class DropDownButtonViewModel : Base.BaseViewModel
11 | {
12 | #region fields
13 | private RelayCommand mDropDownButtonClickCommand;
14 | private RelayCommand mItemButtonClickCommand;
15 | private RelayCommand mItemCancelCommand;
16 |
17 | private bool mIsOpen;
18 | private bool mIsEnabled;
19 | private int mSliderValue;
20 | private string mStatus;
21 | private int mBackupSliderValue;
22 | #endregion fields
23 |
24 | #region constructor
25 | ///
26 | /// Class constructor
27 | ///
28 | public DropDownButtonViewModel()
29 | {
30 | this.mStatus = string.Empty;
31 | this.mBackupSliderValue = this.mSliderValue = 50;
32 |
33 | this.mIsEnabled = true;
34 | this.mIsOpen = false;
35 | }
36 | #endregion constructor
37 |
38 | #region properties
39 | #region commands
40 | ///
41 | /// Command is invoked when user clicks on the DropDownButton
42 | /// (either on label part or DropDown arrow).
43 | ///
44 | public ICommand DropDownButtonClickCommand
45 | {
46 | get
47 | {
48 | if (this.mDropDownButtonClickCommand == null)
49 | this.mDropDownButtonClickCommand = new RelayCommand(
50 | (p) =>
51 | {
52 | if ((p is int) == false)
53 | return;
54 |
55 | var param = (int)p;
56 |
57 | this.DropDownButtonClickCommand_Executed(param);
58 | },
59 | (p) =>
60 | {
61 | return (this.IsEnabled == true);
62 | });
63 |
64 | return this.mDropDownButtonClickCommand;
65 | }
66 | }
67 |
68 | ///
69 | /// Command is invoked when user clicks on the DropDownButton
70 | /// (user clicked a button or hyperlink in DropDown part).
71 | ///
72 | public ICommand ItemButtonClickCommand
73 | {
74 | get
75 | {
76 | if (this.mItemButtonClickCommand == null)
77 | this.mItemButtonClickCommand = new RelayCommand(
78 | (p) =>
79 | {
80 | if ((p is int) == false)
81 | return;
82 |
83 | var param = (int)p;
84 |
85 | this.ItemButtonClickCommand_Executed(param);
86 | });
87 |
88 | return this.mItemButtonClickCommand;
89 | }
90 | }
91 |
92 | ///
93 | /// Gets a command that is executed to cancel a dropdown action.
94 | /// This command closes the drop down and rolls back edited values (if any).
95 | ///
96 | public ICommand ItemCancelCommand
97 | {
98 | get
99 | {
100 | if (this.mItemCancelCommand == null)
101 | this.mItemCancelCommand = new RelayCommand(
102 | () =>
103 | {
104 | this.ItemCancelCommand_Executed();
105 | });
106 |
107 | return this.mItemCancelCommand;
108 | }
109 | }
110 | #endregion commands
111 |
112 | ///
113 | /// Gets the selected item of the DropDown viewmodel.
114 | ///
115 | public string ButtonLabel
116 | {
117 | get
118 | {
119 | return "Select a Value";
120 | }
121 | }
122 |
123 | ///
124 | /// Gets/sets bound property to determine whether
125 | /// drop-down/pop-up element is open or not.
126 | ///
127 | public bool IsOpen
128 | {
129 | get
130 | {
131 | return this.mIsOpen;
132 | }
133 |
134 | set
135 | {
136 | if (this.mIsOpen != value)
137 | {
138 | this.mIsOpen = value;
139 | this.NotifyPropertyChanged(() => this.IsOpen);
140 | }
141 | }
142 | }
143 |
144 | ///
145 | /// Gets/sets Boolean value to determine whether attached dropdown view is enabled or not.
146 | ///
147 | public bool IsEnabled
148 | {
149 | get
150 | {
151 | return this.mIsEnabled;
152 | }
153 |
154 | set
155 | {
156 | if (this.mIsEnabled != value)
157 | {
158 | this.mIsEnabled = value;
159 | this.NotifyPropertyChanged(() => this.IsEnabled);
160 | }
161 | }
162 | }
163 |
164 | ///
165 | /// Gets/sets the current value displayed in the slider control.
166 | ///
167 | public int SliderValue
168 | {
169 | get
170 | {
171 | return this.mSliderValue;
172 | }
173 |
174 | set
175 | {
176 | if (this.mSliderValue != value)
177 | {
178 | this.mSliderValue = value;
179 | this.NotifyPropertyChanged(() => this.SliderValue);
180 | }
181 | }
182 | }
183 |
184 | ///
185 | /// Gets the status description of this viewmodel
186 | /// (this property is present for testing/demo/debugging purposes only
187 | /// since it gives us the ability to give state feedback without using
188 | /// MessageBoxes, which steals the focus and thus influence the pop-up element)
189 | ///
190 | public string Status
191 | {
192 | get
193 | {
194 | return this.mStatus;
195 | }
196 |
197 | private set
198 | {
199 | if (this.mStatus != value)
200 | {
201 | this.mStatus = value;
202 | this.NotifyPropertyChanged(() => this.Status);
203 | }
204 | }
205 | }
206 | #endregion properties
207 |
208 | #region methods
209 | private void DropDownButtonClickCommand_Executed(int value)
210 | {
211 | string source = "SplitButton";
212 |
213 | this.Status = string.Format("Thanks for clicking me: '{0} -> {1}'!", source, value);
214 | }
215 |
216 | private void ItemButtonClickCommand_Executed(int value)
217 | {
218 | this.mBackupSliderValue = this.SliderValue;
219 | this.IsOpen = false;
220 |
221 | string source = "OK from SplitButtonItem";
222 |
223 | this.Status = string.Format("Thanks for clicking me: '{0} -> {1}'!", source, value);
224 | }
225 |
226 | private void ItemCancelCommand_Executed()
227 | {
228 | this.IsOpen = false;
229 |
230 | string source = "Cancel from SplitButtonItem";
231 |
232 | this.Status = string.Format("Cancel -> roll back from '{0} to {1} ({2})'!", this.SliderValue, this.mBackupSliderValue, source);
233 |
234 | this.SliderValue = this.mBackupSliderValue;
235 | }
236 | #endregion methods
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/ViewModels/SplitButtonViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonLib.ViewModels
2 | {
3 | using System.Windows.Input;
4 | using DropDownButtonLib.Command;
5 |
6 | ///
7 | /// Implements a viewmodel that drives the
8 | /// the control.
9 | ///
10 | public class SplitButtonViewModel : Base.BaseViewModel
11 | {
12 | #region fields
13 | private RelayCommand mDropDownButtonClickCommand;
14 | private RelayCommand mItemButtonClickCommand;
15 | private RelayCommand mItemCancelCommand;
16 |
17 | private bool mIsOpen;
18 | private bool mIsEnabled;
19 | private int mSliderValue, mBackupSliderValue;
20 | private string mStatus;
21 | #endregion fields
22 |
23 | #region constructor
24 | ///
25 | /// Class constructor
26 | ///
27 | public SplitButtonViewModel()
28 | {
29 | this.mStatus = string.Empty;
30 | this.mBackupSliderValue = this.mSliderValue = 50;
31 |
32 | this.mIsEnabled = true;
33 | this.mIsOpen = false;
34 | }
35 | #endregion constructor
36 |
37 | #region properties
38 | #region commands
39 | ///
40 | /// Command is invoked when user clicks on the DropDownButton
41 | /// (either on label part or DropDown arrow).
42 | ///
43 | public ICommand DropDownButtonClickCommand
44 | {
45 | get
46 | {
47 | if (this.mDropDownButtonClickCommand == null)
48 | this.mDropDownButtonClickCommand = new RelayCommand(
49 | (p) =>
50 | {
51 | if ((p is int) == false)
52 | return;
53 |
54 | var param = (int)p;
55 |
56 | this.DropDownButtonClickCommand_Executed(param);
57 | },
58 | (p) =>
59 | {
60 | return (this.IsEnabled == true);
61 | });
62 |
63 | return this.mDropDownButtonClickCommand;
64 | }
65 | }
66 |
67 | ///
68 | /// Command is invoked when user clicks on the DropDownButton
69 | /// (user clicked a button or hyperlink in DropDown part).
70 | ///
71 | public ICommand ItemButtonClickCommand
72 | {
73 | get
74 | {
75 | if (this.mItemButtonClickCommand == null)
76 | this.mItemButtonClickCommand = new RelayCommand(
77 | (p) =>
78 | {
79 | if ((p is int) == false)
80 | return;
81 |
82 | var param = (int)p;
83 |
84 | this.ItemButtonClickCommand_Executed(param);
85 | });
86 |
87 | return this.mItemButtonClickCommand;
88 | }
89 | }
90 |
91 | ///
92 | /// Gets a command that is executed to cancel a dropdown action.
93 | /// This command closes the drop down and rolls back edited values (if any).
94 | ///
95 | public ICommand ItemCancelCommand
96 | {
97 | get
98 | {
99 | if (this.mItemCancelCommand == null)
100 | this.mItemCancelCommand = new RelayCommand(
101 | () =>
102 | {
103 | this.ItemCancelCommand_Executed();
104 | });
105 |
106 | return this.mItemCancelCommand;
107 | }
108 | }
109 | #endregion commands
110 |
111 | ///
112 | /// Gets the selected item of the DropDown viewmodel.
113 | ///
114 | public string SelectedItem
115 | {
116 | get
117 | {
118 | return "Demo Value " + this.mSliderValue;
119 | }
120 | }
121 |
122 | ///
123 | /// Gets/sets bound property to determine whether
124 | /// drop-down/pop-up element is open or not.
125 | ///
126 | public bool IsOpen
127 | {
128 | get
129 | {
130 | return this.mIsOpen;
131 | }
132 |
133 | set
134 | {
135 | if (this.mIsOpen != value)
136 | {
137 | this.mIsOpen = value;
138 | this.NotifyPropertyChanged(() => this.IsOpen);
139 | }
140 | }
141 | }
142 |
143 | ///
144 | /// Gets/sets Boolean value to determine whether attached dropdown view is enabled or not.
145 | ///
146 | public bool IsEnabled
147 | {
148 | get
149 | {
150 | return this.mIsEnabled;
151 | }
152 |
153 | set
154 | {
155 | if (this.mIsEnabled != value)
156 | {
157 | this.mIsEnabled = value;
158 | this.NotifyPropertyChanged(() => this.IsEnabled);
159 | }
160 | }
161 | }
162 |
163 | ///
164 | /// Gets/sets the current value displayed in the slider control.
165 | ///
166 | public int SliderValue
167 | {
168 | get
169 | {
170 | return this.mSliderValue;
171 | }
172 |
173 | set
174 | {
175 | if (this.mSliderValue != value)
176 | {
177 | this.mSliderValue = value;
178 | this.NotifyPropertyChanged(() => this.SliderValue);
179 | this.NotifyPropertyChanged(() => this.SelectedItem);
180 | }
181 | }
182 | }
183 |
184 | ///
185 | /// Gets the status description of this viewmodel
186 | /// (this property is present for testing/demo/debugging purposes only
187 | /// since it gives us the ability to give state feedback without using
188 | /// MessageBoxes, which steals the focus and thus influence the pop-up element)
189 | ///
190 | public string Status
191 | {
192 | get
193 | {
194 | return this.mStatus;
195 | }
196 |
197 | private set
198 | {
199 | if (this.mStatus != value)
200 | {
201 | this.mStatus = value;
202 | this.NotifyPropertyChanged(() => this.Status);
203 | }
204 | }
205 | }
206 | #endregion properties
207 |
208 | #region methods
209 | private void DropDownButtonClickCommand_Executed(int value)
210 | {
211 | string source = "SplitButton";
212 |
213 | this.Status = string.Format("Thanks for clicking me: '{0} -> {1}'!", source, value);
214 | }
215 |
216 | private void ItemButtonClickCommand_Executed(int value)
217 | {
218 | this.mBackupSliderValue = this.mSliderValue;
219 | this.IsOpen = false;
220 |
221 | string source = "SplitButtonItem";
222 |
223 | this.Status = string.Format("Thanks for clicking me: '{0} -> {1}'!", source, value);
224 | }
225 |
226 | private void ItemCancelCommand_Executed()
227 | {
228 | this.IsOpen = false;
229 |
230 | string source = "Cancel from SplitButtonItem";
231 |
232 | this.Status = string.Format("Cancel -> roll back from '{0} to {1} ({2})'!", this.SliderValue, this.mBackupSliderValue, source);
233 |
234 | this.SliderValue = this.mBackupSliderValue;
235 | }
236 | #endregion methods
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Controls/Chromes/ButtonChrome_Metro.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Controls/DropDownItemsButton.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Controls/SplitButton.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Themes/ResourceKeys.cs:
--------------------------------------------------------------------------------
1 | namespace DropDownButtonLib.Themes
2 | {
3 | using System.Windows;
4 |
5 | ///
6 | /// Resource key management class to keep track of all resources
7 | /// that can be re-styled in applications that make use of the implemented controls.
8 | ///
9 | public static class ResourceKeys
10 | {
11 | #region Accent Keys
12 | ///
13 | /// Accent Color Key - This Color key is used to accent elements in the UI
14 | /// (e.g.: Color of Activated Normal Window Frame, ResizeGrip, Focus or MouseOver input elements)
15 | ///
16 | public static readonly ComponentResourceKey ControlAccentColorKey = new ComponentResourceKey(typeof(ResourceKeys), "ControlAccentColorKey");
17 |
18 | ///
19 | /// Accent Brush Key - This Brush key is used to accent elements in the UI
20 | /// (e.g.: Color of Activated Normal Window Frame, ResizeGrip, Focus or MouseOver input elements)
21 | ///
22 | public static readonly ComponentResourceKey ControlAccentBrushKey = new ComponentResourceKey(typeof(ResourceKeys), "ControlAccentBrushKey");
23 | #endregion Accent Keys
24 |
25 | #region Brush Keys
26 | ///
27 | /// Resource key of the controls normal background brush key.
28 | ///
29 | public static readonly ComponentResourceKey ControlNormalBackgroundKey = new ComponentResourceKey(typeof(ResourceKeys), "ControlNormalBackgroundKey");
30 |
31 | ///
32 | /// Resource key of the controls disabled background brush key.
33 | ///
34 | public static readonly ComponentResourceKey ControlDisabledBackgroundKey = new ComponentResourceKey(typeof(ResourceKeys), "ControlDisabledBackgroundKey");
35 |
36 | ///
37 | /// Resource key of the controls normal background brush key.
38 | ///
39 | public static readonly ComponentResourceKey ControlNormalBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ControlNormalBorderKey");
40 |
41 | ///
42 | /// Resource key of the controls mouse over border brush key.
43 | ///
44 | public static readonly ComponentResourceKey ControlMouseOverBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ControlMouseOverBorderKey");
45 |
46 | ///
47 | /// Resource key of the controls selected border brush key.
48 | ///
49 | public static readonly ComponentResourceKey ControlSelectedBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ControlSelectedBorderKey");
50 |
51 | ///
52 | /// Resource key of the controls focused border brush key.
53 | ///
54 | public static readonly ComponentResourceKey ControlFocusedBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ControlFocusedBorderKey");
55 |
56 | ///
57 | /// Resource key of the button's normal outer border brush key.
58 | ///
59 | public static readonly ComponentResourceKey ButtonNormalOuterBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonNormalOuterBorderKey");
60 |
61 | ///
62 | /// Resource key of the button's normal inner border brush key.
63 | ///
64 | public static readonly ComponentResourceKey ButtonNormalInnerBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonNormalInnerBorderKey");
65 |
66 | ///
67 | /// Resource key of the button's normal background brush key.
68 | ///
69 | public static readonly ComponentResourceKey ButtonNormalBackgroundKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonNormalBackgroundKey");
70 |
71 | ///
72 | /// Resource key of the button's mouse over background brush key.
73 | ///
74 | public static readonly ComponentResourceKey ButtonMouseOverBackgroundKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonMouseOverBackgroundKey");
75 |
76 | ///
77 | /// Resource key of the button's mouse over outer border brush key.
78 | ///
79 | public static readonly ComponentResourceKey ButtonMouseOverOuterBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonMouseOverOuterBorderKey");
80 |
81 | ///
82 | /// Resource key of the button's mouse over inner border brush key.
83 | ///
84 | public static readonly ComponentResourceKey ButtonMouseOverInnerBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonMouseOverInnerBorderKey");
85 |
86 | ///
87 | /// Resource key of the button's pressed outer border brush key.
88 | ///
89 | public static readonly ComponentResourceKey ButtonPressedOuterBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonPressedOuterBorderKey");
90 |
91 | ///
92 | /// Resource key of the button's pressed inner border brush key.
93 | ///
94 | public static readonly ComponentResourceKey ButtonPressedInnerBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonPressedInnerBorderKey");
95 |
96 | ///
97 | /// Resource key of the button's pressed background brush key.
98 | ///
99 | public static readonly ComponentResourceKey ButtonPressedBackgroundKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonPressedBackgroundKey");
100 |
101 | ///
102 | /// Resource key of the button's focused outer border brush key.
103 | ///
104 | public static readonly ComponentResourceKey ButtonFocusedOuterBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonFocusedOuterBorderKey");
105 |
106 | ///
107 | /// Resource key of the button's focused inner border brush key.
108 | ///
109 | public static readonly ComponentResourceKey ButtonFocusedInnerBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonFocusedInnerBorderKey");
110 |
111 | ///
112 | /// Resource key of the button's focused background brush key.
113 | ///
114 | public static readonly ComponentResourceKey ButtonFocusedBackgroundKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonFocusedBackgroundKey");
115 |
116 | ///
117 | /// Resource key of the button's disbled outer border brush key.
118 | ///
119 | public static readonly ComponentResourceKey ButtonDisabledOuterBorderKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonDisabledOuterBorderKey");
120 |
121 | ///
122 | /// Resource key of the button's disabled inner border brush key.
123 | ///
124 | public static readonly ComponentResourceKey ButtonInnerBorderDisabledKey = new ComponentResourceKey(typeof(ResourceKeys), "ButtonInnerBorderDisabledKey");
125 |
126 | ///
127 | /// Resource key of the drop down list item background key.
128 | ///
129 | public static readonly ComponentResourceKey DropDownList_MouseOverBackgroundKey = new ComponentResourceKey(typeof(ResourceKeys), "DropDownList_MouseOverBackgroundKey");
130 |
131 | ///
132 | /// Resource key of the drop down background key.
133 | ///
134 | public static readonly ComponentResourceKey DropDownList_BackgroundKey = new ComponentResourceKey(typeof(ResourceKeys), "DropDownList_BackgroundKey");
135 |
136 | ///
137 | /// Resource key of the drop down border key.
138 | ///
139 | public static readonly ComponentResourceKey DropDownList_BorderForegroundKey = new ComponentResourceKey(typeof(ResourceKeys), "DropDownList_BorderForegroundKey");
140 | #endregion Brush Keys
141 |
142 | ///
143 | /// Resource key object of the normal glyph color.
144 | ///
145 | public static readonly ComponentResourceKey GlyphNormalForegroundKey = new ComponentResourceKey(typeof(ResourceKeys), "GlyphNormalForegroundKey");
146 |
147 | ///
148 | /// Resource key object of the mouseover foreground glyph color.
149 | ///
150 | public static readonly ComponentResourceKey GlyphMouseOverForegroundKey = new ComponentResourceKey(typeof(ResourceKeys), "GlyphMouseOverForegroundKey");
151 |
152 | ///
153 | /// Resource key object of the disabled foreground glyph color.
154 | ///
155 | public static readonly ComponentResourceKey GlyphDisabledForegroundKey = new ComponentResourceKey(typeof(ResourceKeys), "GlyphDisabledForegroundKey");
156 |
157 | ///
158 | /// Resource key object of the corner radius property assigned in different UI elements (not just SpinButton).
159 | ///
160 | public static readonly ComponentResourceKey SpinButtonCornerRadiusKey = new ComponentResourceKey(typeof(ResourceKeys), "SpinButtonCornerRadiusKey");
161 |
162 | ///
163 | /// Resource style key of the repeat button.
164 | ///
165 | public static readonly ComponentResourceKey SpinnerButtonStyleKey = new ComponentResourceKey(typeof(ResourceKeys), "SpinnerButtonStyleKey");
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Controls/SplitItemsButton.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
164 |
165 |
166 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Controls/Chromes/ButtonChrome.cs:
--------------------------------------------------------------------------------
1 | /*************************************************************************************
2 |
3 | Extended WPF Toolkit
4 |
5 | Copyright (C) 2007-2013 Xceed Software Inc.
6 |
7 | This program is provided to you under the terms of the Microsoft Public
8 | License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
9 |
10 | For more features, controls, and fast professional support,
11 | pick up the Plus Edition at http://xceed.com/wpf_toolkit
12 |
13 | Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
14 |
15 | ***********************************************************************************/
16 | namespace DropDownButtonLib.Controls.Chromes
17 | {
18 | using System;
19 | using System.Windows;
20 | using System.Windows.Controls;
21 |
22 | ///
23 | /// Implements a ButtonChrome which is a kind of frame that
24 | /// determines the look and feel of a button.
25 | ///
26 | public class ButtonChrome : ContentControl
27 | {
28 | #region fields
29 | ///
30 | /// Backing store for corner radius dependency property of button chrome.
31 | ///
32 | public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(ButtonChrome), new UIPropertyMetadata(default(CornerRadius), new PropertyChangedCallback(OnCornerRadiusChanged)));
33 |
34 | ///
35 | /// Backing store for inner corner radius dependency property of button chrome.
36 | ///
37 | public static readonly DependencyProperty InnerCornerRadiusProperty = DependencyProperty.Register("InnerCornerRadius", typeof(CornerRadius), typeof(ButtonChrome), new UIPropertyMetadata(default(CornerRadius), new PropertyChangedCallback(OnInnerCornerRadiusChanged)));
38 |
39 | ///
40 | /// Backing store for render checked dependency property of button chrome.
41 | ///
42 | public static readonly DependencyProperty RenderCheckedProperty = DependencyProperty.Register("RenderChecked", typeof(bool), typeof(ButtonChrome), new UIPropertyMetadata(false, OnRenderCheckedChanged));
43 |
44 | ///
45 | /// Backing store for render enabled dependency property of button chrome.
46 | ///
47 | public static readonly DependencyProperty RenderEnabledProperty = DependencyProperty.Register("RenderEnabled", typeof(bool), typeof(ButtonChrome), new UIPropertyMetadata(true, OnRenderEnabledChanged));
48 |
49 | ///
50 | /// Backing store for render focused dependency property of button chrome.
51 | ///
52 | public static readonly DependencyProperty RenderFocusedProperty = DependencyProperty.Register("RenderFocused", typeof(bool), typeof(ButtonChrome), new UIPropertyMetadata(false, OnRenderFocusedChanged));
53 |
54 | ///
55 | /// Backing store for render mouse over dependency property of button chrome.
56 | ///
57 | public static readonly DependencyProperty RenderMouseOverProperty = DependencyProperty.Register("RenderMouseOver", typeof(bool), typeof(ButtonChrome), new UIPropertyMetadata(false, OnRenderMouseOverChanged));
58 |
59 | ///
60 | /// Backing store for render normal dependency property of button chrome.
61 | ///
62 | public static readonly DependencyProperty RenderNormalProperty = DependencyProperty.Register("RenderNormal", typeof(bool), typeof(ButtonChrome), new UIPropertyMetadata(true, OnRenderNormalChanged));
63 |
64 | ///
65 | /// Backing store for render pressed dependency property of button chrome.
66 | ///
67 | public static readonly DependencyProperty RenderPressedProperty = DependencyProperty.Register("RenderPressed", typeof(bool), typeof(ButtonChrome), new UIPropertyMetadata(false, OnRenderPressedChanged));
68 | #endregion fields
69 |
70 | #region constructors
71 | ///
72 | /// Static class constructor
73 | ///
74 | static ButtonChrome()
75 | {
76 | DefaultStyleKeyProperty.OverrideMetadata(typeof(ButtonChrome), new FrameworkPropertyMetadata(typeof(ButtonChrome)));
77 | }
78 | #endregion constructors
79 |
80 | #region properties
81 | #region dependency properties
82 | ///
83 | /// Gets/sets corner radius dependency property of button chrome.
84 | ///
85 | public CornerRadius CornerRadius
86 | {
87 | get
88 | {
89 | return (CornerRadius)GetValue(CornerRadiusProperty);
90 | }
91 |
92 | set
93 | {
94 | this.SetValue(CornerRadiusProperty, value);
95 | }
96 | }
97 |
98 | ///
99 | /// Gets/sets inner corner radius dependency property of button chrome.
100 | ///
101 | public CornerRadius InnerCornerRadius
102 | {
103 | get
104 | {
105 | return (CornerRadius)GetValue(InnerCornerRadiusProperty);
106 | }
107 |
108 | set
109 | {
110 | this.SetValue(InnerCornerRadiusProperty, value);
111 | }
112 | }
113 |
114 | ///
115 | /// Gets/sets render checked dependency property of button chrome.
116 | ///
117 | public bool RenderChecked
118 | {
119 | get
120 | {
121 | return (bool)GetValue(RenderCheckedProperty);
122 | }
123 |
124 | set
125 | {
126 | this.SetValue(RenderCheckedProperty, value);
127 | }
128 | }
129 |
130 | ///
131 | /// Gets/sets render enabled dependency property of button chrome.
132 | ///
133 | public bool RenderEnabled
134 | {
135 | get
136 | {
137 | return (bool)GetValue(RenderEnabledProperty);
138 | }
139 |
140 | set
141 | {
142 | this.SetValue(RenderEnabledProperty, value);
143 | }
144 | }
145 |
146 | ///
147 | /// Gets/sets render focused dependency property of button chrome.
148 | ///
149 | public bool RenderFocused
150 | {
151 | get
152 | {
153 | return (bool)GetValue(RenderFocusedProperty);
154 | }
155 |
156 | set
157 | {
158 | this.SetValue(RenderFocusedProperty, value);
159 | }
160 | }
161 |
162 | ///
163 | /// Gets/sets render mouseover dependency property of button chrome.
164 | ///
165 | public bool RenderMouseOver
166 | {
167 | get
168 | {
169 | return (bool)GetValue(RenderMouseOverProperty);
170 | }
171 |
172 | set
173 | {
174 | this.SetValue(RenderMouseOverProperty, value);
175 | }
176 | }
177 |
178 | ///
179 | /// Gets/sets render normal dependency property of button chrome.
180 | ///
181 | public bool RenderNormal
182 | {
183 | get
184 | {
185 | return (bool)GetValue(RenderNormalProperty);
186 | }
187 |
188 | set
189 | {
190 | this.SetValue(RenderNormalProperty, value);
191 | }
192 | }
193 |
194 | ///
195 | /// Gets/sets render pressed dependency property of button chrome.
196 | ///
197 | public bool RenderPressed
198 | {
199 | get
200 | {
201 | return (bool)GetValue(RenderPressedProperty);
202 | }
203 |
204 | set
205 | {
206 | this.SetValue(RenderPressedProperty, value);
207 | }
208 | }
209 | #endregion dependency properties
210 | #endregion properties
211 |
212 | #region methods
213 | ///
214 | /// Method executes when the corner radius dependency property is changed.
215 | /// It re-computes the inner corner radius since it always needs to be 1
216 | /// less than the outer radius.
217 | ///
218 | ///
219 | ///
220 | protected virtual void OnCornerRadiusChanged(CornerRadius oldValue, CornerRadius newValue)
221 | {
222 | // we always want the InnerBorderRadius to be one less than the CornerRadius
223 | CornerRadius newInnerCornerRadius = new CornerRadius(Math.Max(0, newValue.TopLeft - 1),
224 | Math.Max(0, newValue.TopRight - 1),
225 | Math.Max(0, newValue.BottomRight - 1),
226 | Math.Max(0, newValue.BottomLeft - 1));
227 |
228 | this.InnerCornerRadius = newInnerCornerRadius;
229 | }
230 |
231 | ///
232 | /// Method executes when the inner corner radius dependency property is changed.
233 | ///
234 | /// TODO: Add your property changed side-effects. Descendants can override as well.
235 | ///
236 | ///
237 | ///
238 | protected virtual void OnInnerCornerRadiusChanged(CornerRadius oldValue, CornerRadius newValue)
239 | {
240 |
241 | }
242 |
243 | ///
244 | /// Method executes when the render checked dependency property is changed.
245 | ///
246 | /// TODO: Add your property changed side-effects. Descendants can override as well.
247 | ///
248 | ///
249 | ///
250 | protected virtual void OnRenderCheckedChanged(bool oldValue, bool newValue)
251 | {
252 | }
253 |
254 | ///
255 | /// Method executes when the render enabled dependency property is changed.
256 | ///
257 | /// TODO: Add your property changed side-effects. Descendants can override as well.
258 | ///
259 | ///
260 | ///
261 | protected virtual void OnRenderEnabledChanged(bool oldValue, bool newValue)
262 | {
263 | }
264 |
265 | ///
266 | /// Method executes when the render focused dependency property is changed.
267 | ///
268 | /// TODO: Add your property changed side-effects. Descendants can override as well.
269 | ///
270 | ///
271 | ///
272 | protected virtual void OnRenderFocusedChanged(bool oldValue, bool newValue)
273 | {
274 | }
275 |
276 | ///
277 | /// Method executes when the render mouseover dependency property is changed.
278 | ///
279 | /// TODO: Add your property changed side-effects. Descendants can override as well.
280 | ///
281 | ///
282 | ///
283 | protected virtual void OnRenderMouseOverChanged(bool oldValue, bool newValue)
284 | {
285 | }
286 |
287 | ///
288 | /// Method executes when the render normal dependency property is changed.
289 | ///
290 | /// TODO: Add your property changed side-effects. Descendants can override as well.
291 | ///
292 | ///
293 | ///
294 | protected virtual void OnRenderNormalChanged(bool oldValue, bool newValue)
295 | {
296 | }
297 |
298 | ///
299 | /// Method executes when the render pressed dependency property is changed.
300 | ///
301 | /// TODO: Add your property changed side-effects. Descendants can override as well.
302 | ///
303 | ///
304 | ///
305 | protected virtual void OnRenderPressedChanged(bool oldValue, bool newValue)
306 | {
307 | }
308 |
309 | ///
310 | /// Method executes when the corner radius dependency property is changed.
311 | ///
312 | ///
313 | ///
314 | private static void OnCornerRadiusChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
315 | {
316 | ButtonChrome buttonChrome = o as ButtonChrome;
317 |
318 | if (buttonChrome != null)
319 | buttonChrome.OnCornerRadiusChanged((CornerRadius)e.OldValue, (CornerRadius)e.NewValue);
320 | }
321 |
322 | ///
323 | /// Method executes when the inner corner radius dependency property is changed.
324 | ///
325 | ///
326 | ///
327 | private static void OnInnerCornerRadiusChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
328 | {
329 | ButtonChrome buttonChrome = o as ButtonChrome;
330 | if (buttonChrome != null)
331 | buttonChrome.OnInnerCornerRadiusChanged((CornerRadius)e.OldValue, (CornerRadius)e.NewValue);
332 | }
333 |
334 | ///
335 | /// Method executes when the render checked dependency property is changed.
336 | ///
337 | ///
338 | ///
339 | private static void OnRenderCheckedChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
340 | {
341 | ButtonChrome buttonChrome = o as ButtonChrome;
342 | if (buttonChrome != null)
343 | buttonChrome.OnRenderCheckedChanged((bool)e.OldValue, (bool)e.NewValue);
344 | }
345 |
346 | ///
347 | /// Method executes when the render enabled dependency property is changed.
348 | ///
349 | ///
350 | ///
351 | private static void OnRenderEnabledChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
352 | {
353 | ButtonChrome buttonChrome = o as ButtonChrome;
354 | if (buttonChrome != null)
355 | buttonChrome.OnRenderEnabledChanged((bool)e.OldValue, (bool)e.NewValue);
356 | }
357 |
358 | ///
359 | /// Method executes when the render focused dependency property is changed.
360 | ///
361 | ///
362 | ///
363 | private static void OnRenderFocusedChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
364 | {
365 | ButtonChrome buttonChrome = o as ButtonChrome;
366 | if (buttonChrome != null)
367 | buttonChrome.OnRenderFocusedChanged((bool)e.OldValue, (bool)e.NewValue);
368 | }
369 |
370 | ///
371 | /// Method executes when the render mouseover dependency property is changed.
372 | ///
373 | ///
374 | ///
375 | private static void OnRenderMouseOverChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
376 | {
377 | ButtonChrome buttonChrome = o as ButtonChrome;
378 | if (buttonChrome != null)
379 | buttonChrome.OnRenderMouseOverChanged((bool)e.OldValue, (bool)e.NewValue);
380 | }
381 |
382 | ///
383 | /// Method executes when the render normal dependency property is changed.
384 | ///
385 | ///
386 | ///
387 | private static void OnRenderNormalChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
388 | {
389 | ButtonChrome buttonChrome = o as ButtonChrome;
390 | if (buttonChrome != null)
391 | buttonChrome.OnRenderNormalChanged((bool)e.OldValue, (bool)e.NewValue);
392 | }
393 |
394 | ///
395 | /// Method executes when the render pressed dependency property is changed.
396 | ///
397 | ///
398 | ///
399 | private static void OnRenderPressedChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
400 | {
401 | ButtonChrome buttonChrome = o as ButtonChrome;
402 | if (buttonChrome != null)
403 | buttonChrome.OnRenderPressedChanged((bool)e.OldValue, (bool)e.NewValue);
404 | }
405 | #endregion methods
406 | }
407 | }
408 |
--------------------------------------------------------------------------------
/source/DropDownButtonTest/Views/DemoView.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | Click the DropDown and SplitButton below to see how these work.
22 |
23 | Insert a ResourceDictionary reference in App.xaml to activate a supported theme:
24 | DropDownButtonLib /Themes/Generic.xaml and
25 | DropDownButtonLib /Themes/MetroDark.xaml
26 | DropDownButtonLib /Themes/MetroLight.xaml
27 |
28 | Note: The Generic.xaml theme is the same as the MetroLight.xaml theme.
29 |
30 | Note: The Generic.xaml theme does not need explicit activation
31 | because WPF loads it by default when nothings else was defined.
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
73 |
75 |
76 |
77 |
78 |
79 |
83 |
84 |
88 |
89 |
90 |
91 |
92 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
119 |
120 |
121 |
123 |
124 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
152 |
153 |
158 |
159 |
160 |
161 |
162 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
181 |
183 |
184 |
185 |
186 |
187 |
191 |
192 |
196 |
197 |
198 |
199 |
200 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
228 |
229 |
230 |
232 |
233 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
262 |
263 |
267 |
268 |
269 |
270 |
271 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Controls/Chromes/ButtonChrome.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
243 |
244 |
245 |
--------------------------------------------------------------------------------
/source/DropDownButtonLib/Controls/DropDownButton.xaml.cs:
--------------------------------------------------------------------------------
1 | /*************************************************************************************
2 |
3 | Extended WPF Toolkit
4 |
5 | Copyright (C) 2007-2013 Xceed Software Inc.
6 |
7 | This program is provided to you under the terms of the Microsoft Public
8 | License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
9 |
10 | For more features, controls, and fast professional support,
11 | pick up the Plus Edition at http://xceed.com/wpf_toolkit
12 |
13 | Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
14 |
15 | ***********************************************************************************/
16 | namespace DropDownButtonLib.Controls
17 | {
18 | using System;
19 | using System.ComponentModel;
20 | using System.Windows;
21 | using System.Windows.Controls;
22 | using System.Windows.Controls.Primitives;
23 | using System.Windows.Input;
24 | using DropDownButtonLib.Utilities;
25 |
26 | ///
27 | /// Implements a look-less WPF DropDownButton control.
28 | ///
29 | [TemplatePart(Name = DropDownButton.PART_DropDownButton, Type = typeof(ToggleButton))]
30 | [TemplatePart(Name = DropDownButton.PART_ContentPresenter, Type = typeof(ContentPresenter))]
31 | [TemplatePart(Name = DropDownButton.PART_Popup, Type = typeof(Popup))]
32 | public class DropDownButton : ContentControl, ICommandSource
33 | {
34 | #region fields
35 | ///
36 | /// Const string name of the required drop down button element in the control.
37 | ///
38 | public const string PART_DropDownButton = "PART_DropDownButton";
39 |
40 | ///
41 | /// Const string name of the required ContentPresenter element in the control.
42 | ///
43 | public const string PART_ContentPresenter = "PART_ContentPresenter";
44 |
45 | ///
46 | /// Const string name of the required PopUp element in the control.
47 | ///
48 | public const string PART_Popup = "PART_Popup";
49 |
50 | #region dependency properties
51 | ///
52 | /// Backing store of the DropDownContent dependency property.
53 | ///
54 | public static readonly DependencyProperty DropDownContentProperty = DependencyProperty.Register("DropDownContent", typeof(object), typeof(DropDownButton), new UIPropertyMetadata(null, OnDropDownContentChanged));
55 |
56 | ///
57 | /// Backing store of the IsOpen dependency property.
58 | ///
59 | public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register("IsOpen", typeof(bool), typeof(DropDownButton), new UIPropertyMetadata(false, OnIsOpenChanged));
60 |
61 | ///
62 | /// Backing store of the Command dependency property.
63 | ///
64 | public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(DropDownButton), new PropertyMetadata((ICommand)null, OnCommandChanged));
65 |
66 | ///
67 | /// Backing store of the CommandParameter dependency property.
68 | ///
69 | public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(DropDownButton), new PropertyMetadata(null));
70 |
71 | ///
72 | /// Backing store of the CommandTarget dependency property.
73 | ///
74 | public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(DropDownButton), new PropertyMetadata(null));
75 |
76 | #region events
77 | ///
78 | /// Backing store of the Click Event dependency property.
79 | ///
80 | public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DropDownButton));
81 |
82 | ///
83 | /// Backing store of the Opened Event dependency property.
84 | ///
85 | public static readonly RoutedEvent OpenedEvent = EventManager.RegisterRoutedEvent("Opened", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DropDownButton));
86 |
87 | ///
88 | /// Backing store of the Closed Event dependency property.
89 | ///
90 | public static readonly RoutedEvent ClosedEvent = EventManager.RegisterRoutedEvent("Closed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DropDownButton));
91 | #endregion events
92 | #endregion dependency properties
93 |
94 | private System.Windows.Controls.Primitives.ButtonBase mButton;
95 | private ContentPresenter mContentPresenter;
96 | private Popup mPopup;
97 |
98 | ///
99 | /// Keeps a copy of the CanExecuteChanged handler so it doesn't get garbage collected.
100 | ///
101 | private EventHandler mCanExecuteChangedHandler;
102 | #endregion fields
103 |
104 | #region constructors
105 | ///
106 | /// Static class constructor
107 | ///
108 | static DropDownButton()
109 | {
110 | DefaultStyleKeyProperty.OverrideMetadata(typeof(DropDownButton),
111 | new FrameworkPropertyMetadata(typeof(DropDownButton)));
112 | }
113 |
114 | ///
115 | /// Default class constructor
116 | ///
117 | public DropDownButton()
118 | {
119 | Keyboard.AddKeyDownHandler(this, this.OnKeyDown);
120 | Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(this, this.OnMouseDownOutsideCapturedElement);
121 | }
122 | #endregion constructors
123 |
124 | #region events
125 | ///
126 | /// Adds/removes a reference to a click event handler.
127 | ///
128 | public event RoutedEventHandler Click
129 | {
130 | add
131 | {
132 | this.AddHandler(ClickEvent, value);
133 | }
134 |
135 | remove
136 | {
137 | this.RemoveHandler(ClickEvent, value);
138 | }
139 | }
140 |
141 | ///
142 | /// Adds/removes a reference to a Opened event handler.
143 | ///
144 | public event RoutedEventHandler Opened
145 | {
146 | add
147 | {
148 | this.AddHandler(OpenedEvent, value);
149 | }
150 |
151 | remove
152 | {
153 | this.RemoveHandler(OpenedEvent, value);
154 | }
155 | }
156 |
157 | ///
158 | /// Adds/removes a reference to a Closed event handler.
159 | ///
160 | public event RoutedEventHandler Closed
161 | {
162 | add
163 | {
164 | this.AddHandler(ClosedEvent, value);
165 | }
166 |
167 | remove
168 | {
169 | this.RemoveHandler(ClosedEvent, value);
170 | }
171 | }
172 | #endregion events
173 |
174 | #region Properties
175 | ///
176 | /// Gets/sets part of the DropDownContent dependency property of this class.
177 | ///
178 | public object DropDownContent
179 | {
180 | get
181 | {
182 | return (object)GetValue(DropDownContentProperty);
183 | }
184 |
185 | set
186 | {
187 | this.SetValue(DropDownContentProperty, value);
188 | }
189 | }
190 |
191 | ///
192 | /// Gets/sets whether the DwropDownContent is currently open or not.
193 | ///
194 | public bool IsOpen
195 | {
196 | get
197 | {
198 | return (bool)GetValue(IsOpenProperty);
199 | }
200 |
201 | set
202 | {
203 | this.SetValue(IsOpenProperty, value);
204 | }
205 | }
206 |
207 | #region Commands
208 | ///
209 | /// Part of the Command dependency property.
210 | ///
211 | [TypeConverter(typeof(CommandConverter))]
212 | public ICommand Command
213 | {
214 | get
215 | {
216 | return (ICommand)GetValue(CommandProperty);
217 | }
218 |
219 | set
220 | {
221 | this.SetValue(CommandProperty, value);
222 | }
223 | }
224 |
225 | ///
226 | /// Gets/sets CommandParameter dependency property.
227 | ///
228 | public object CommandParameter
229 | {
230 | get
231 | {
232 | return this.GetValue(CommandParameterProperty);
233 | }
234 |
235 | set
236 | {
237 | this.SetValue(CommandParameterProperty, value);
238 | }
239 | }
240 |
241 | ///
242 | /// Gets/sets CommandTarget dependency property.
243 | ///
244 | public IInputElement CommandTarget
245 | {
246 | get
247 | {
248 | return (IInputElement)GetValue(CommandTargetProperty);
249 | }
250 |
251 | set
252 | {
253 | this.SetValue(CommandTargetProperty, value);
254 | }
255 | }
256 | #endregion Commands
257 |
258 | ///
259 | /// Gets/sets the templated PART_DropDownButton instance.
260 | ///
261 | protected System.Windows.Controls.Primitives.ButtonBase Button
262 | {
263 | get
264 | {
265 | return this.mButton;
266 | }
267 |
268 | set
269 | {
270 | if (this.mButton != value)
271 | {
272 | if (this.mButton != null)
273 | this.mButton.Click -= this.DropDownButton_Click;
274 |
275 | this.mButton = value;
276 |
277 | if (this.mButton != null)
278 | this.mButton.Click += this.DropDownButton_Click;
279 | }
280 | }
281 | }
282 | #endregion Properties
283 |
284 | #region methods
285 | ///
286 | ///
287 | ///
288 | public override void OnApplyTemplate()
289 | {
290 | base.OnApplyTemplate();
291 | this.Button = GetTemplateChild(PART_DropDownButton) as ToggleButton;
292 |
293 | this.mContentPresenter = GetTemplateChild(PART_ContentPresenter) as ContentPresenter;
294 |
295 | if (this.mPopup != null)
296 | this.mPopup.Opened -= this.Popup_Opened;
297 |
298 | this.mPopup = GetTemplateChild(PART_Popup) as Popup;
299 |
300 | if (this.mPopup != null)
301 | this.mPopup.Opened += this.Popup_Opened;
302 | }
303 |
304 | ///
305 | /// Method is invoked when the DropDownContent dependency property is changed.
306 | ///
307 | ///
308 | ///
309 | protected virtual void OnDropDownContentChanged(object oldValue, object newValue)
310 | {
311 | // TODO: Add your property changed side-effects. Descendants can override as well.
312 | }
313 |
314 | ///
315 | /// Method is invoked when the IsOpen dependency property is changed.
316 | ///
317 | ///
318 | ///
319 | protected virtual void OnIsOpenChanged(bool oldValue, bool newValue)
320 | {
321 | if (newValue == true)
322 | this.RaiseRoutedEvent(DropDownButton.OpenedEvent);
323 | else
324 | this.RaiseRoutedEvent(DropDownButton.ClosedEvent);
325 | }
326 |
327 | ///
328 | /// Method is invoked when the Command dependency property is changed.
329 | ///
330 | ///
331 | ///
332 | protected virtual void OnCommandChanged(ICommand oldValue, ICommand newValue)
333 | {
334 | // If old command is not null, then we need to remove the handlers.
335 | if (oldValue != null)
336 | this.UnhookCommand(oldValue, newValue);
337 |
338 | this.HookUpCommand(oldValue, newValue);
339 |
340 | // May need to call this when changing the command parameter or target.
341 | this.CanExecuteChanged();
342 | }
343 |
344 | ///
345 | /// Method executes when the drop down button is clicked.
346 | /// The method opens the drop-down/pop-up element.
347 | ///
348 | protected virtual void OnClick()
349 | {
350 | this.RaiseRoutedEvent(DropDownButton.ClickEvent);
351 | this.RaiseCommand();
352 | }
353 |
354 | ///
355 | /// Method is invoked when the DropDownContent dependency property is changed.
356 | ///
357 | ///
358 | ///
359 | private static void OnDropDownContentChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
360 | {
361 | var dropDownButton = o as DropDownButton;
362 |
363 | if (dropDownButton != null)
364 | dropDownButton.OnDropDownContentChanged((object)e.OldValue, (object)e.NewValue);
365 | }
366 |
367 | ///
368 | /// Method is invoked when the IsOpen dependency property is changed.
369 | ///
370 | ///
371 | ///
372 | private static void OnIsOpenChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
373 | {
374 | var dropDownButton = o as DropDownButton;
375 |
376 | if (dropDownButton != null)
377 | dropDownButton.OnIsOpenChanged((bool)e.OldValue, (bool)e.NewValue);
378 | }
379 |
380 | ///
381 | /// Method is invoked when the Command dependency property is changed.
382 | ///
383 | ///
384 | ///
385 | private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
386 | {
387 | var dropDownButton = d as DropDownButton;
388 |
389 | if (dropDownButton != null)
390 | dropDownButton.OnCommandChanged((ICommand)e.OldValue, (ICommand)e.NewValue);
391 | }
392 |
393 | #region Event Handlers
394 | ///
395 | /// Implements a keyboard event handler for the
396 | /// System.Windows.Input.Keyboard.KeyDown attached event.
397 | ///
398 | ///
399 | ///
400 | private void OnKeyDown(object sender, KeyEventArgs e)
401 | {
402 | if (this.IsOpen == false)
403 | {
404 | if (KeyboardUtilities.IsKeyModifyingPopupState(e))
405 | {
406 | this.IsOpen = true;
407 |
408 | // ContentPresenter items will get focus in Popup_Opened().
409 | e.Handled = true;
410 | }
411 | }
412 | else
413 | {
414 | if (KeyboardUtilities.IsKeyModifyingPopupState(e))
415 | {
416 | this.CloseDropDown(true);
417 | e.Handled = true;
418 | }
419 | else if (e.Key == Key.Escape)
420 | {
421 | this.CloseDropDown(true);
422 | e.Handled = true;
423 | }
424 | }
425 | }
426 |
427 | ///
428 | /// Closes the drop-down content element when user clicks
429 | /// the mouse outside of the pop-up/drop down element.
430 | ///
431 | ///
432 | ///
433 | private void OnMouseDownOutsideCapturedElement(object sender, MouseButtonEventArgs e)
434 | {
435 | if( !IsMouseOver )
436 | CloseDropDown( true );
437 | }
438 |
439 | ///
440 | /// Executes when the user clicks on the drop-down button.
441 | /// System opens the drop-down/pop-up element.
442 | ///
443 | ///
444 | ///
445 | private void DropDownButton_Click(object sender, RoutedEventArgs e)
446 | {
447 | this.OnClick();
448 | }
449 |
450 | private void CanExecuteChanged(object sender, EventArgs e)
451 | {
452 | this.CanExecuteChanged();
453 | }
454 |
455 | private void Popup_Opened(object sender, EventArgs e)
456 | {
457 | // Set the focus on the content of the ContentPresenter.
458 | if (this.mContentPresenter != null)
459 | this.mContentPresenter.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
460 | }
461 | #endregion Event Handlers
462 |
463 | private void CanExecuteChanged()
464 | {
465 | if (this.Command != null)
466 | {
467 | var command = this.Command as RoutedCommand;
468 |
469 | // If a RoutedCommand.
470 | if (command != null)
471 | {
472 | if (this.CommandTarget != null)
473 | this.IsEnabled = command.CanExecute(this.CommandParameter, this.CommandTarget) ? true : false;
474 | else
475 | this.IsEnabled = command.CanExecute(this.CommandParameter, this) ? true : false;
476 | }
477 | else
478 | {
479 | // If a not RoutedCommand.
480 | this.IsEnabled = this.Command.CanExecute(this.CommandParameter) ? true : false;
481 | }
482 | }
483 | }
484 |
485 | ///
486 | /// Closes the drop down.
487 | /// Is executed when the user closes the drop down via keyboard (ESC or ALT-Cursor Up).
488 | /// Is executed when the user clicks outside of the open drop down element.
489 | ///
490 | private void CloseDropDown(bool isFocusOnButton)
491 | {
492 | if (this.IsOpen == true)
493 | this.IsOpen = false;
494 |
495 | this.ReleaseMouseCapture();
496 |
497 | if (isFocusOnButton == true)
498 | this.Button.Focus();
499 | }
500 |
501 | ///
502 | /// Raises routed events.
503 | ///
504 | private void RaiseRoutedEvent(RoutedEvent routedEvent)
505 | {
506 | RoutedEventArgs args = new RoutedEventArgs(routedEvent, this);
507 | this.RaiseEvent(args);
508 | }
509 |
510 | ///
511 | /// Raises the command's Execute event.
512 | ///
513 | private void RaiseCommand()
514 | {
515 | if (this.Command != null)
516 | {
517 | RoutedCommand routedCommand = this.Command as RoutedCommand;
518 |
519 | if (routedCommand == null)
520 | ((ICommand)this.Command).Execute(this.CommandParameter);
521 | else
522 | routedCommand.Execute(this.CommandParameter, this.CommandTarget);
523 | }
524 | }
525 |
526 | ///
527 | /// Unhooks a command from the Command property.
528 | ///
529 | /// The old command.
530 | /// The new command.
531 | private void UnhookCommand(ICommand oldCommand, ICommand newCommand)
532 | {
533 | EventHandler handler = this.CanExecuteChanged;
534 | oldCommand.CanExecuteChanged -= handler;
535 | }
536 |
537 | ///
538 | /// Hooks up a command to the CanExecuteChnaged event handler.
539 | ///
540 | /// The old command.
541 | /// The new command.
542 | private void HookUpCommand(ICommand oldCommand, ICommand newCommand)
543 | {
544 | EventHandler handler = new EventHandler(this.CanExecuteChanged);
545 | this.mCanExecuteChangedHandler = handler;
546 |
547 | if (newCommand != null)
548 | newCommand.CanExecuteChanged += this.mCanExecuteChangedHandler;
549 | }
550 | #endregion methods
551 | }
552 | }
553 |
--------------------------------------------------------------------------------