Repository: Ruris/PanuonUI
Branch: master
Commit: 6a28a8f41551
Files: 234
Total size: 3.2 MB
Directory structure:
gitextract_d18lroo2/
├── .gitignore
├── LICENSE
├── Panuon.UI/
│ ├── 0_Base/
│ │ ├── DragableThumb.cs
│ │ ├── NotTopMostPopup.cs
│ │ ├── PUResizeContainer.cs
│ │ ├── PUResizeGrid.cs
│ │ ├── PUResizeThumb.cs
│ │ └── PUWindow.cs
│ ├── 2_Button/
│ │ ├── PUButton.cs
│ │ └── PURepeatButton.cs
│ ├── 3_TextBox/
│ │ └── PUTextBox.cs
│ ├── 4_PasswordBox/
│ │ └── PUPasswordBox.cs
│ ├── 5_ComboBox/
│ │ ├── PUComboBox.cs
│ │ └── PUComboBoxItem.cs
│ ├── 6_CheckBox/
│ │ └── PUCheckBox.cs
│ ├── 7_RadioButton/
│ │ └── PURadioButton.cs
│ ├── 8_ProgressBar/
│ │ └── PUProgressBar.cs
│ ├── 9_Special/
│ │ ├── Countdown.cs
│ │ ├── DateTimePicker.cs
│ │ ├── DropDown.cs
│ │ ├── PUCard.cs
│ │ ├── PUImageCuter.xaml
│ │ ├── PUImageCuter.xaml.cs
│ │ ├── PUIndicator.xaml
│ │ ├── PUIndicator.xaml.cs
│ │ ├── PULoading.xaml
│ │ ├── PULoading.xaml.cs
│ │ ├── PUMessageBox.xaml
│ │ ├── PUMessageBox.xaml.cs
│ │ ├── PUSlideShow.xaml
│ │ ├── PUSlideShow.xaml.cs
│ │ └── PUSplitLine.cs
│ ├── A0_TreeView/
│ │ ├── PUTreeView.cs
│ │ └── PUTreeViewItem.cs
│ ├── A1_Slider/
│ │ ├── PUSlider.xaml
│ │ └── PUSlider.xaml.cs
│ ├── A2_TabControl/
│ │ ├── PUTabControl.cs
│ │ └── PUTabItem.cs
│ ├── A3_ListBox/
│ │ ├── PUListBox.cs
│ │ └── PUListBoxItem.cs
│ ├── A4_DatePicker/
│ │ ├── PUDatePicker.xaml
│ │ └── PUDatePicker.xaml.cs
│ ├── A5_PagingNav/
│ │ ├── PUPagingNav.xaml
│ │ └── PUPagingNav.xaml.cs
│ ├── A6_ContextMenu/
│ │ ├── PUContextMenu.cs
│ │ └── PUContextMenuItem.cs
│ ├── A7_Bubble/
│ │ └── PUBubble.cs
│ ├── Helper/
│ │ └── Helper.cs
│ ├── Others/
│ │ └── Enums.cs
│ ├── Panuon.UI.csproj
│ ├── Properties/
│ │ ├── AssemblyInfo.cs
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.resx
│ │ ├── Settings.Designer.cs
│ │ └── Settings.settings
│ ├── Themes/
│ │ ├── Control.xaml
│ │ ├── Generic.xaml
│ │ └── Resources.xaml
│ ├── Utils/
│ │ ├── Converters.cs
│ │ ├── Extends.cs
│ │ └── Utils.cs
│ ├── Z_Helper/
│ │ └── Helper.cs
│ ├── Z_Models/
│ │ ├── PUComboBoxItemModel.cs
│ │ ├── PUListBoxItemModel.cs
│ │ ├── PUTabItemModel.cs
│ │ └── PUTreeViewItemModel.cs
│ ├── Z_Others/
│ │ ├── Converters.cs
│ │ ├── Enums.cs
│ │ └── SkipCompareAttribute.cs
│ └── Z_Utils/
│ ├── Extends.cs
│ └── Utils.cs
├── Panuon.UI.Charts/
│ ├── 0_Base/
│ │ ├── PUChartPoint.cs
│ │ ├── PUChartToolTip.xaml
│ │ └── PUChartToolTip.xaml.cs
│ ├── 1_LineChart/
│ │ ├── PULineChart.cs
│ │ ├── PULineChart.xaml
│ │ └── PULineChart.xaml.cs
│ ├── Others/
│ │ └── Enums.cs
│ ├── Panuon.UI.Charts.csproj
│ └── Properties/
│ └── AssemblyInfo.cs
├── Panuon.UI.sln
├── Panuon.UIBrowser/
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── AppBootstrapper.cs
│ ├── IShell.cs
│ ├── Models/
│ │ └── DataSourceModel.cs
│ ├── Panuon.UIBrowser.csproj
│ ├── Properties/
│ │ ├── AssemblyInfo.cs
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.resx
│ │ ├── Settings.Designer.cs
│ │ └── Settings.settings
│ ├── ViewModels/
│ │ ├── Chart/
│ │ │ └── LineChartViewModel.cs
│ │ ├── Control/
│ │ │ ├── ButtonViewModel.cs
│ │ │ ├── CheckBoxViewModel.cs
│ │ │ ├── ComboBoxViewModel.cs
│ │ │ ├── ContextMenuViewModel.cs
│ │ │ ├── DatePickerViewModel.cs
│ │ │ ├── ListBoxViewModel.cs
│ │ │ ├── PasswordBoxViewModel.cs
│ │ │ ├── ProgressBarViewModel.cs
│ │ │ ├── RadioButtonViewModel.cs
│ │ │ ├── SliderViewModel.cs
│ │ │ ├── TabControlViewModel.cs
│ │ │ ├── TextBoxViewModel.cs
│ │ │ ├── TreeViewViewModel.cs
│ │ │ └── WindowViewModel.cs
│ │ ├── Example.cs
│ │ ├── IntroductionViewModel.cs
│ │ ├── MainWindowViewModel.cs
│ │ ├── OverviewViewModel.cs
│ │ ├── Partial/
│ │ │ ├── BubblesViewModel.cs
│ │ │ ├── ButtonsViewModel.cs
│ │ │ ├── CheckBoxsViewModel.cs
│ │ │ ├── ComboBoxsViewModel.cs
│ │ │ ├── ContextMenusViewModel.cs
│ │ │ ├── DataGridsViewModel.cs
│ │ │ ├── DatePickersViewModel.cs
│ │ │ ├── GridsViewModel.cs
│ │ │ ├── ImageCuterViewModel.cs
│ │ │ ├── IntroductionViewModel.cs
│ │ │ ├── LineChartsViewModel.cs
│ │ │ ├── ListBoxsViewModel.cs
│ │ │ ├── PagingNavsViewModel.cs
│ │ │ ├── PasswordBoxsViewModel.cs
│ │ │ ├── ProgressBarsViewModel.cs
│ │ │ ├── RadioButtonsViewModel.cs
│ │ │ ├── SlidersViewModel.cs
│ │ │ ├── SpecialViewModel.cs
│ │ │ ├── TabControlsViewModel.cs
│ │ │ ├── TextBoxsViewModel.cs
│ │ │ ├── TreeViewsViewModel.cs
│ │ │ ├── UtilsViewModel.cs
│ │ │ └── WindowsViewModel.cs
│ │ ├── ShellWindowViewModel.cs
│ │ └── Special/
│ │ ├── BubbleViewModel.cs
│ │ ├── DropDownViewModel.cs
│ │ ├── ImageCuterViewModel.cs
│ │ ├── LoadingViewModel.cs
│ │ ├── PagingNavViewModel.cs
│ │ ├── ResizeGridViewModel.cs
│ │ └── SplitLineViewModel.cs
│ ├── Views/
│ │ ├── Chart/
│ │ │ └── LineChartView.xaml
│ │ ├── Controls/
│ │ │ ├── ButtonView.xaml
│ │ │ ├── CheckBoxView.xaml
│ │ │ ├── ComboBoxView.xaml
│ │ │ ├── ContextMenuView.xaml
│ │ │ ├── DatePickerView.xaml
│ │ │ ├── Examples/
│ │ │ │ ├── ChatWindow.xaml
│ │ │ │ ├── ChatWindow.xaml.cs
│ │ │ │ ├── LoginWindow.xaml
│ │ │ │ ├── LoginWindow.xaml.cs
│ │ │ │ ├── MultiNavWindow.xaml
│ │ │ │ └── MultiNavWindow.xaml.cs
│ │ │ ├── ListBoxView.xaml
│ │ │ ├── PasswordBoxView.xaml
│ │ │ ├── ProgressBarView.xaml
│ │ │ ├── RadioButtonView.xaml
│ │ │ ├── SliderView.xaml
│ │ │ ├── TabControlView.xaml
│ │ │ ├── TextBoxView.xaml
│ │ │ ├── TreeViewView.xaml
│ │ │ └── WindowView.xaml
│ │ ├── MainWindowView.xaml
│ │ ├── OverviewView.xaml
│ │ ├── Partial/
│ │ │ ├── BubblesView.xaml
│ │ │ ├── ButtonsView.xaml
│ │ │ ├── CheckBoxsView.xaml
│ │ │ ├── ComboBoxsView.xaml
│ │ │ ├── ContextMenusView.xaml
│ │ │ ├── DataGridsView.xaml
│ │ │ ├── DatePickersView.xaml
│ │ │ ├── HelpersView.xaml
│ │ │ ├── ImageCuterView.xaml
│ │ │ ├── IntroductionView.xaml
│ │ │ ├── LineChartsView.xaml
│ │ │ ├── ListBoxsView.xaml
│ │ │ ├── PagingNavsView.xaml
│ │ │ ├── PasswordBoxsView.xaml
│ │ │ ├── ProgressBarsView.xaml
│ │ │ ├── RadioButtonsView.xaml
│ │ │ ├── SlidersView.xaml
│ │ │ ├── SpecialView.xaml
│ │ │ ├── TabControlsView.xaml
│ │ │ ├── TextBoxsView.xaml
│ │ │ ├── TreeViewsView.xaml
│ │ │ ├── UtilsView.xaml
│ │ │ └── WindowsView.xaml
│ │ ├── ShellWindowView.xaml
│ │ └── Special/
│ │ ├── BubbleView.xaml
│ │ ├── DropDownView.xaml
│ │ ├── ImageCuterView.xaml
│ │ ├── IndicatorView.xaml
│ │ ├── LoadingView.xaml
│ │ ├── PagingNavView.xaml
│ │ ├── ResizeGridView.xaml
│ │ └── SplitLineView.xaml
│ ├── app.config
│ └── packages.config
├── README.md
└── packages/
├── Caliburn.Micro.3.2.0/
│ ├── Caliburn.Micro.3.2.0.nupkg
│ └── lib/
│ ├── MonoAndroid10/
│ │ ├── Caliburn.Micro.Platform.Core.xml
│ │ └── Caliburn.Micro.Platform.xml
│ ├── MonoTouch10/
│ │ ├── Caliburn.Micro.Platform.Core.dll.mdb
│ │ ├── Caliburn.Micro.Platform.Core.xml
│ │ ├── Caliburn.Micro.Platform.xml
│ │ └── Caliburn.Micro.dll.mdb
│ ├── Xamarin.iOS10/
│ │ ├── Caliburn.Micro.Platform.Core.dll.mdb
│ │ ├── Caliburn.Micro.Platform.Core.xml
│ │ ├── Caliburn.Micro.Platform.xml
│ │ └── Caliburn.Micro.dll.mdb
│ ├── net40/
│ │ ├── Caliburn.Micro.Platform.xml
│ │ └── System.Windows.Interactivity.xml
│ ├── net45/
│ │ ├── Caliburn.Micro.Platform.Core.xml
│ │ └── Caliburn.Micro.Platform.xml
│ ├── sl5/
│ │ └── Caliburn.Micro.Platform.xml
│ ├── uap10.0/
│ │ ├── Caliburn.Micro.Platform.Core.xml
│ │ ├── Caliburn.Micro.Platform.UWP/
│ │ │ └── Properties/
│ │ │ └── Caliburn.Micro.Platform.UWP.rd.xml
│ │ ├── Caliburn.Micro.Platform.UWP.XML
│ │ └── Caliburn.Micro.Platform.UWP.pri
│ ├── win81/
│ │ ├── Caliburn.Micro.Platform.Core.xml
│ │ ├── Caliburn.Micro.Platform.XML
│ │ └── Caliburn.Micro.Platform.pri
│ ├── wp8/
│ │ ├── Caliburn.Micro.Platform.Core.xml
│ │ └── Caliburn.Micro.Platform.xml
│ └── wpa81/
│ ├── Caliburn.Micro.Platform.Core.xml
│ ├── Caliburn.Micro.Platform.pri
│ └── Caliburn.Micro.Platform.xml
└── Caliburn.Micro.Core.3.2.0/
├── Caliburn.Micro.Core.3.2.0.nupkg
└── lib/
├── net40/
│ └── Caliburn.Micro.XML
├── net45/
│ └── Caliburn.Micro.xml
├── portable-net45+win8+wp8+wpa81+MonoAndroid10+Xamarin.iOS10+MonoTouch10+uap10.0/
│ ├── Caliburn.Micro.XML
│ └── Caliburn.Micro.dll.mdb
└── sl5/
└── Caliburn.Micro.XML
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.suo
*.user
*.userosscache
*.sln.docstates
*.userprefs
*.pdb
*.dll
*.cache
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
.vs/
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Panuon.UI/0_Base/DragableThumb.cs
================================================
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Interop;
using System.Windows.Media;
namespace Panuon.UI
{
internal class DragableThumb : Thumb
{
static DragableThumb()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DragableThumb), new FrameworkPropertyMetadata(typeof(DragableThumb)));
}
public DragableThumb()
{
DragDelta += new DragDeltaEventHandler(this.ResizeThumb_DragDelta);
}
private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
var element = DragTarget as FrameworkElement;
if (double.IsNaN(Canvas.GetLeft(element)))
Canvas.SetLeft(element, 0);
if (double.IsNaN(Canvas.GetTop(element)))
Canvas.SetTop(element, 0);
var width = element.ActualWidth;
var height = element.ActualHeight;
var left = Canvas.GetLeft(element);
var targetLeft = left + e.HorizontalChange;
var top = Canvas.GetTop(element);
var targetTop = top + e.VerticalChange;
var parentCanvas = element.Parent as Canvas;
if (LimitInParent && parentCanvas != null)
{
if (targetLeft < 0)
targetLeft = 0;
else if (targetLeft + width > parentCanvas.ActualWidth)
targetLeft = parentCanvas.ActualWidth - width;
if (targetTop < 0)
targetTop = 0;
else if (targetTop + height > parentCanvas.ActualHeight)
targetTop = parentCanvas.ActualHeight - height;
}
Canvas.SetLeft(element, targetLeft);
Canvas.SetTop(element, targetTop);
}
#region Property
public DependencyObject DragTarget
{
get { return (DependencyObject)GetValue(DragTargetProperty); }
set { SetValue(DragTargetProperty, value); }
}
public static readonly DependencyProperty DragTargetProperty =
DependencyProperty.Register("DragTarget", typeof(DependencyObject), typeof(DragableThumb));
public bool LimitInParent
{
get { return (bool)GetValue(LimitInParentProperty); }
set { SetValue(LimitInParentProperty, value); }
}
public static readonly DependencyProperty LimitInParentProperty =
DependencyProperty.Register("LimitInParent", typeof(bool), typeof(DragableThumb));
#endregion
}
}
================================================
FILE: Panuon.UI/0_Base/NotTopMostPopup.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interop;
namespace Panuon.UI
{
internal class NotTopMostPopup : Popup
{
private Window _window;
protected override void OnOpened(EventArgs e)
{
var hwnd = ((HwndSource)PresentationSource.FromVisual(this.Child)).Handle;
RECT rect;
if (GetWindowRect(hwnd, out rect))
{
SetWindowPos(hwnd, -2, rect.Left, rect.Top, (int)this.Width, (int)this.Height, 0);
}
_window = Window.GetWindow(this);
_window.PreviewMouseDown -= Window_PreviewMouseDown;
_window.PreviewMouseDown += Window_PreviewMouseDown;
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
_window.PreviewMouseDown -= Window_PreviewMouseDown;
}
private void Window_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var element = Tag as FrameworkElement;
if (!IsMouseOver && !element.IsMouseOver)
IsOpen = false;
}
#region P/Invoke imports & definitions
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32", EntryPoint = "SetWindowPos")]
private static extern int SetWindowPos(IntPtr hWnd, int hwndInsertAfter, int x, int y, int cx, int cy, int wFlags);
#endregion
}
}
================================================
FILE: Panuon.UI/0_Base/PUResizeContainer.cs
================================================
using System.Windows;
using System.Windows.Controls;
namespace Panuon.UI
{
internal class PUResizeContainer : ContentControl
{
static PUResizeContainer()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUResizeContainer), new FrameworkPropertyMetadata(typeof(PUResizeContainer)));
}
#region Property
public bool IsSquare
{
get { return (bool)GetValue(IsSquareProperty); }
set { SetValue(IsSquareProperty, value); }
}
public static readonly DependencyProperty IsSquareProperty =
DependencyProperty.Register("IsSquare", typeof(bool), typeof(PUResizeContainer));
public bool LimitInParent
{
get { return (bool)GetValue(LimitInParentProperty); }
set { SetValue(LimitInParentProperty, value); }
}
public static readonly DependencyProperty LimitInParentProperty =
DependencyProperty.Register("LimitInParent", typeof(bool), typeof(PUResizeContainer));
public bool CanResize
{
get { return (bool)GetValue(CanResizeProperty); }
set { SetValue(CanResizeProperty, value); }
}
public static readonly DependencyProperty CanResizeProperty =
DependencyProperty.Register("CanResize", typeof(bool), typeof(PUResizeContainer), new PropertyMetadata(true));
#endregion
}
}
================================================
FILE: Panuon.UI/0_Base/PUResizeGrid.cs
================================================
using System.Windows;
using System.Windows.Controls;
namespace Panuon.UI
{
public class PUResizeGrid : UserControl
{
static PUResizeGrid()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUResizeGrid), new FrameworkPropertyMetadata(typeof(PUResizeGrid)));
}
#region Property
public bool IsSquare
{
get { return (bool)GetValue(IsSquareProperty); }
set { SetValue(IsSquareProperty, value); }
}
public static readonly DependencyProperty IsSquareProperty =
DependencyProperty.Register("IsSquare", typeof(bool), typeof(PUResizeGrid), new PropertyMetadata(false));
#endregion
}
}
================================================
FILE: Panuon.UI/0_Base/PUResizeThumb.cs
================================================
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Interop;
namespace Panuon.UI
{
internal class ResizeThumb : Thumb
{
public ResizeThumb()
{
DragDelta += new DragDeltaEventHandler(this.ResizeThumb_DragDelta);
}
#region Property
public bool IsSquare
{
get { return (bool)GetValue(IsSquareProperty); }
set { SetValue(IsSquareProperty, value); }
}
public static readonly DependencyProperty IsSquareProperty =
DependencyProperty.Register("IsSquare", typeof(bool), typeof(ResizeThumb));
public bool LimitInParent
{
get { return (bool)GetValue(LimitInParentProperty); }
set { SetValue(LimitInParentProperty, value); }
}
public static readonly DependencyProperty LimitInParentProperty =
DependencyProperty.Register("LimitInParent", typeof(bool), typeof(ResizeThumb));
#endregion
#region Event
private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
var element = this.DataContext as FrameworkElement;
if (double.IsNaN(Canvas.GetLeft(element)))
Canvas.SetLeft(element, 0);
if (double.IsNaN(Canvas.GetTop(element)))
Canvas.SetTop(element, 0);
var parentCanvas = element.Parent as Canvas;
double width = 0.0;
double height = 0.0;
var left = Canvas.GetLeft(element);
var top = Canvas.GetTop(element);
if (HorizontalAlignment == HorizontalAlignment.Left || HorizontalAlignment == HorizontalAlignment.Right)
{
if (HorizontalAlignment == HorizontalAlignment.Left)
{
width = element.ActualWidth - e.HorizontalChange;
if (LimitInParent && parentCanvas != null)
{
if (left + e.HorizontalChange < 0 && element.ActualWidth != element.MaxWidth)
width = element.ActualWidth + left;
}
}
else
{
width = element.ActualWidth + e.HorizontalChange;
if (LimitInParent && parentCanvas != null)
{
if (left + element.ActualWidth + e.HorizontalChange > parentCanvas.ActualWidth && element.ActualWidth != element.MaxWidth)
width = parentCanvas.ActualWidth - left;
}
}
width = width > element.MaxWidth ? element.MaxWidth : width;
width = width < element.MinWidth ? element.MinWidth : width;
}
if (VerticalAlignment == VerticalAlignment.Top || VerticalAlignment == VerticalAlignment.Bottom)
{
if (VerticalAlignment == VerticalAlignment.Top)
{
height = element.ActualHeight - e.VerticalChange;
if (LimitInParent && parentCanvas != null)
{
if (top + e.VerticalChange < 0 && element.ActualHeight != element.MaxHeight)
height = element.ActualHeight + top;
}
}
else
{
height = element.ActualHeight + e.VerticalChange;
if (LimitInParent && parentCanvas != null)
{
if (top + element.ActualHeight + e.VerticalChange > parentCanvas.ActualHeight && element.ActualHeight != element.MaxHeight)
height = parentCanvas.ActualHeight - top;
}
}
height = height > element.MaxHeight ? element.MaxHeight : height;
height = height < element.MinHeight ? element.MinHeight : height;
}
if (!IsSquare)
{
if (width != 0)
SetElementWidth(element, width, left);
if (height != 0)
SetElementHeight(element, height, top);
}
else
{
if (width != 0)
{
if (!LimitInParent)
{
SetElementWidth(element, width, left);
SetElementHeight(element, width, top);
}
if (LimitInParent)
{
if (width + top < parentCanvas.ActualHeight)
{
SetElementWidth(element, width, left);
SetElementHeight(element, width, top);
}
}
}
else if (height != 0)
{
if (!LimitInParent)
{
SetElementWidth(element, height, left);
SetElementHeight(element, height, top);
}
if (LimitInParent)
{
if (height + left <= parentCanvas.ActualWidth)
{
SetElementWidth(element, height, left);
SetElementHeight(element, height, top);
}
}
}
}
}
#endregion
#region Function
private void SetElementWidth(FrameworkElement element, double width, double left)
{
if (HorizontalAlignment == HorizontalAlignment.Left)
{
var delta = element.ActualWidth - width;
Canvas.SetLeft(element, left + delta);
}
element.Width = width;
}
private void SetElementHeight(FrameworkElement element, double height, double top)
{
if (VerticalAlignment == VerticalAlignment.Top)
{
var delta = element.ActualHeight - height;
Canvas.SetTop(element, Canvas.GetTop(element) + delta);
}
element.Height = height;
}
#endregion
}
}
================================================
FILE: Panuon.UI/0_Base/PUWindow.cs
================================================
using System;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace Panuon.UI
{
public class PUWindow : Window
{
#region Import
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam);
#endregion
#region Identify
private enum ResizeDirection
{
Left = 1,
Right = 2,
Top = 3,
TopLeft = 4,
TopRight = 5,
Bottom = 6,
BottomLeft = 7,
BottomRight = 8,
}
private HwndSource _hwndSource;
private PUButton _btnClose;
private StackPanel _stkNav;
private bool _animateOutHandle = true;
private bool? _dialogResult;
private bool _needToSetDialogResult;
#endregion
#region Constructor
static PUWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUWindow), new FrameworkPropertyMetadata(typeof(PUWindow)));
}
///
/// 初始化一个窗体实例。
/// 若您期望从当前窗体中连续Show出多个窗体,请务必分别指定这些子窗体的Owner,否则将出现显示问题。
///
public PUWindow()
{
PreviewMouseMove += OnPreviewMouseMove;
}
#endregion
#region Sys
public override void OnApplyTemplate()
{
var auto = Owner;
Loaded += delegate
{
if (AllowAutoCoverMask && (Owner as PUWindow) != null)
{
(Owner as PUWindow).IsCoverMaskShow = true;
}
if (AnimateIn)
OnBeginLoadStoryboard();
else
OnSkipLoadStoryboard();
if (!AllowForcingClose)
{
DisableAltF4(this);
}
};
var grdResize = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(this, 0), 1) as Grid;
if (grdResize != null)
{
foreach (Rectangle resizeRectangle in grdResize.Children)
{
resizeRectangle.PreviewMouseDown += ResizeRectangle_PreviewMouseDown;
resizeRectangle.MouseMove += ResizeRectangle_MouseMove;
}
}
var grdNavbar = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(this, 0), 0), 0), 0), 0) as Grid;
_stkNav = VisualTreeHelper.GetChild(grdNavbar, 1) as StackPanel;
grdNavbar.MouseLeftButtonDown += delegate
{
this.DragMove();
};
_btnClose = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(grdNavbar, 1), 2) as PUButton;
}
protected override void OnClosing(CancelEventArgs e)
{
if(_animateOutHandle)
base.OnClosing(e);
if (e.Cancel)
return;
if (AllowAutoCoverMask && (Owner as PUWindow) != null)
{
var owner = Owner as PUWindow;
if (owner.OwnedWindows.Count == 1)
{
owner.IsCoverMaskShow = false;
}
else
{
var closeMask = true;
foreach (var window in owner.OwnedWindows)
{
var puwindow = window as PUWindow;
if (puwindow != null)
{
if (puwindow.AllowAutoCoverMask)
{
closeMask = true;
break;
}
}
}
if (closeMask)
owner.IsCoverMaskShow = false;
}
}
if (AnimateOut && _animateOutHandle)
{
if (IsModal(this))
{
_dialogResult = DialogResult;
_needToSetDialogResult = true;
}
OnBeginCloseStoryboard();
_animateOutHandle = false;
DispatcherTimer timer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(0.4) };
timer.Tick += delegate { Close(); timer.Stop(); };
timer.Start();
e.Cancel = true;
return;
}
if (AnimateOut)
{
if (_needToSetDialogResult)
{
DialogResult = _dialogResult;
}
}
}
private void ResizeRectangle_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
Rectangle rectangle = sender as Rectangle;
if (rectangle != null)
{
switch (rectangle.Name)
{
case "Top":
Cursor = Cursors.SizeNS;
ResizeWindow(ResizeDirection.Top);
break;
case "Bottom":
Cursor = Cursors.SizeNS;
ResizeWindow(ResizeDirection.Bottom);
break;
case "Left":
Cursor = Cursors.SizeWE;
ResizeWindow(ResizeDirection.Left);
break;
case "Right":
Cursor = Cursors.SizeWE;
ResizeWindow(ResizeDirection.Right);
break;
case "TopLeft":
Cursor = Cursors.SizeNWSE;
ResizeWindow(ResizeDirection.TopLeft);
break;
case "TopRight":
Cursor = Cursors.SizeNESW;
ResizeWindow(ResizeDirection.TopRight);
break;
case "BottomLeft":
Cursor = Cursors.SizeNESW;
ResizeWindow(ResizeDirection.BottomLeft);
break;
case "BottomRight":
Cursor = Cursors.SizeNWSE;
ResizeWindow(ResizeDirection.BottomRight);
break;
default:
break;
}
}
}
private void ResizeWindow(ResizeDirection direction)
{
SendMessage(_hwndSource.Handle, 0x112, (IntPtr)(61440 + direction), IntPtr.Zero);
}
protected override void OnInitialized(EventArgs e)
{
SourceInitialized += MainWindow_SourceInitialized;
base.OnInitialized(e);
}
private void MainWindow_SourceInitialized(object sender, EventArgs e)
{
_hwndSource = (HwndSource)PresentationSource.FromVisual(this);
}
protected void OnPreviewMouseMove(object sender, MouseEventArgs e)
{
if (ResizeMode != ResizeMode.CanResize)
return;
if (Mouse.LeftButton != MouseButtonState.Pressed)
Cursor = Cursors.Arrow;
}
private void ResizeRectangle_MouseMove(object sender, MouseEventArgs e)
{
Rectangle rectangle = sender as Rectangle;
if (rectangle != null)
{
switch (rectangle.Name)
{
case "Top":
Cursor = Cursors.SizeNS;
break;
case "Bottom":
Cursor = Cursors.SizeNS;
break;
case "Left":
Cursor = Cursors.SizeWE;
break;
case "Right":
Cursor = Cursors.SizeWE;
break;
case "TopLeft":
Cursor = Cursors.SizeNWSE;
break;
case "TopRight":
Cursor = Cursors.SizeNESW;
break;
case "BottomLeft":
Cursor = Cursors.SizeNESW;
break;
case "BottomRight":
Cursor = Cursors.SizeNWSE;
break;
default:
break;
}
}
}
///
/// Alt + F4 无效化处理
///
private static Action DisableAltF4(Window window)
{
var source = HwndSource.FromHwnd(new WindowInteropHelper(window).Handle);
source.AddHook(DisableAltF4WndHookProc);
return () => source.RemoveHook(DisableAltF4WndHookProc);
}
///
/// Alt + F4无效化窗口消息
///
private static IntPtr DisableAltF4WndHookProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
const int WM_SYSKEYDOWN = 0x0104;
const int VK_F4 = 0x73;
if (msg == WM_SYSKEYDOWN && wParam.ToInt32() == VK_F4)
{
handled = true;
}
return IntPtr.Zero;
}
#endregion
#region RoutedEvent
///
/// 使用动画打开窗体。
///
internal static readonly RoutedEvent BeginLoadStoryboardEvent = EventManager.RegisterRoutedEvent("BeginLoadStoryboard", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUWindow));
internal event RoutedPropertyChangedEventHandler BeginLoadStoryboard
{
add { AddHandler(BeginLoadStoryboardEvent, value); }
remove { RemoveHandler(BeginLoadStoryboardEvent, value); }
}
internal void OnBeginLoadStoryboard()
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(null, this, BeginLoadStoryboardEvent);
RaiseEvent(arg);
}
///
/// 不使用动画打开窗体。
///
internal static readonly RoutedEvent SkipLoadStoryboardEvent = EventManager.RegisterRoutedEvent("SkipLoadStoryboard", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUWindow));
internal event RoutedPropertyChangedEventHandler SkipLoadStoryboard
{
add { AddHandler(SkipLoadStoryboardEvent, value); }
remove { RemoveHandler(SkipLoadStoryboardEvent, value); }
}
internal void OnSkipLoadStoryboard()
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(null, this, SkipLoadStoryboardEvent);
RaiseEvent(arg);
}
///
/// 使用动画关闭窗体。
///
internal static readonly RoutedEvent BeginCloseStoryboardEvent = EventManager.RegisterRoutedEvent("BeginCloseStoryboard", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUWindow));
internal event RoutedPropertyChangedEventHandler BeginCloseStoryboard
{
add { AddHandler(BeginCloseStoryboardEvent, value); }
remove { RemoveHandler(BeginCloseStoryboardEvent, value); }
}
internal void OnBeginCloseStoryboard()
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(null, this, BeginCloseStoryboardEvent);
RaiseEvent(arg);
}
#endregion
#region Property
///
/// 获取或设置窗体的返回结果,不会对前端显示造成影响。默认值为Null
///
public object Result
{
get { return (object)GetValue(ResultProperty); }
set { SetValue(ResultProperty, value); }
}
public static readonly DependencyProperty ResultProperty =
DependencyProperty.Register("Result", typeof(object), typeof(PUWindow));
///
///获取或设置是否打开窗体的遮罩层。默认值为False。
///
public bool IsCoverMaskShow
{
get { return (bool)GetValue(IsCoverMaskShowProperty); }
set { SetValue(IsCoverMaskShowProperty, value); }
}
public static readonly DependencyProperty IsCoverMaskShowProperty =
DependencyProperty.Register("IsCoverMaskShow", typeof(bool), typeof(PUWindow));
///
/// 获取或设置是否允许延迟显示内容。当页面内容较为复杂时,启用此选项有助于减少启动动画卡顿。默认值为False。
///
public bool AllowShowDelay
{
get { return (bool)GetValue(AllowShowDelayProperty); }
set { SetValue(AllowShowDelayProperty, value); }
}
public static readonly DependencyProperty AllowShowDelayProperty =
DependencyProperty.Register("AllowShowDelay", typeof(bool), typeof(PUWindow));
///
/// 获取或设置右侧标题栏按钮的显示状态。默认值为Visible。
///
public Visibility NavButtonVisibility
{
get { return (Visibility)GetValue(NavButtonVisibilityProperty); }
set { SetValue(NavButtonVisibilityProperty, value); }
}
public static readonly DependencyProperty NavButtonVisibilityProperty =
DependencyProperty.Register("NavButtonVisibility", typeof(Visibility), typeof(PUWindow), new PropertyMetadata(Visibility.Visible));
///
/// 获取或设置是否在窗体打开时使用动画。默认值为True。
///
public bool AnimateIn
{
get { return (bool)GetValue(AnimateInProperty); }
set { SetValue(AnimateInProperty, value); }
}
public static readonly DependencyProperty AnimateInProperty =
DependencyProperty.Register("AnimateIn", typeof(bool), typeof(PUWindow), new PropertyMetadata(true));
///
/// 获取或设置是否在窗体关闭时使用动画,默认值为True。
///
public bool AnimateOut
{
get { return (bool)GetValue(AnimateOutProperty); }
set { SetValue(AnimateOutProperty, value); }
}
public static readonly DependencyProperty AnimateOutProperty =
DependencyProperty.Register("AnimateOut", typeof(bool), typeof(PUWindow), new PropertyMetadata(true));
///
/// 获取或设置窗体动画类型。默认值为Gradual(一个从上到下的渐变显示)。
///
public AnimationStyles AnimationStyle
{
get { return (AnimationStyles)GetValue(AnimationStyleProperty); }
set { SetValue(AnimationStyleProperty, value); }
}
public static readonly DependencyProperty AnimationStyleProperty =
DependencyProperty.Register("AnimationStyle", typeof(AnimationStyles), typeof(PUWindow), new PropertyMetadata(AnimationStyles.Scale));
///
/// 获取或设置窗体的圆角大小,默认值为0。
///
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static readonly DependencyProperty BorderCornerRadiusProperty =
DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(PUWindow));
///
/// 左上角标题,默认值为null。
/// 当该属性为null时,将采用Title属性来填充左上角标题。
///
public object Header
{
get { return (object)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(object), typeof(PUWindow));
///
/// 左上角图标,默认值为null。
///
public new object Icon
{
get { return (object)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public new static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(object), typeof(PUWindow));
///
/// 控制栏背景色,默认值为White(白色)。
///
public Brush NavbarBackground
{
get { return (Brush)GetValue(NavbarBackgroundProperty); }
set { SetValue(NavbarBackgroundProperty, value); }
}
public static readonly DependencyProperty NavbarBackgroundProperty =
DependencyProperty.Register("NavbarBackground", typeof(Brush), typeof(PUWindow));
///
/// 控制栏高度,默认值为30。
///
public double NavbarHeight
{
get { return (double)GetValue(NavbarHeightProperty); }
set { SetValue(NavbarHeightProperty, value); }
}
public static readonly DependencyProperty NavbarHeightProperty =
DependencyProperty.Register("NavbarHeight", typeof(double), typeof(PUWindow));
///
/// 控制按钮高度,默认值为30。
///
public double NavButtonHeight
{
get { return (double)GetValue(NavButtonHeightProperty); }
set { SetValue(NavButtonHeightProperty, value); }
}
public static readonly DependencyProperty NavButtonHeightProperty =
DependencyProperty.Register("NavButtonHeight", typeof(double), typeof(PUWindow));
///
/// 控制按钮宽度,默认值为40。
///
public double NavButtonWidth
{
get { return (double)GetValue(NavButtonWidthProperty); }
set { SetValue(NavButtonWidthProperty, value); }
}
public static readonly DependencyProperty NavButtonWidthProperty =
DependencyProperty.Register("NavButtonWidth", typeof(double), typeof(PUWindow));
///
/// 是否打开遮罩层并显示等待控件。
///
public bool IsAwaitShow
{
get { return (bool)GetValue(IsAwaitShowProperty); }
set { SetValue(IsAwaitShowProperty, value); }
}
public static readonly DependencyProperty IsAwaitShowProperty =
DependencyProperty.Register("IsAwaitShow", typeof(bool), typeof(PUWindow));
///
/// 获取或设置是否允许在调用Show或ShowDialog方法时自动打开父窗体的遮罩层,并在Close时将其关闭。
/// 若没有父窗体或父窗体不是PUWindow类型,则不会触发任何效果。
///
public bool AllowAutoCoverMask
{
get { return (bool)GetValue(AllowAutoCoverMaskProperty); }
set { SetValue(AllowAutoCoverMaskProperty, value); }
}
public static readonly DependencyProperty AllowAutoCoverMaskProperty =
DependencyProperty.Register("AllowAutoCoverMask", typeof(bool), typeof(PUWindow), new PropertyMetadata(false));
///
/// 获取或设置是否允许用户使用Alt + F4按键组合强制关闭窗体。该属性在窗体加载后的更改将无效。默认值为True(允许)。
///
public bool AllowForcingClose
{
get { return (bool)GetValue(AllowForcingCloseProperty); }
set { SetValue(AllowForcingCloseProperty, value); }
}
public static readonly DependencyProperty AllowForcingCloseProperty =
DependencyProperty.Register("AllowForcingClose", typeof(bool), typeof(PUWindow), new PropertyMetadata(true));
///
/// 获取或设置是否允许自动将当前的活动窗口设置为自己的Owner。默认值为True。
///
public bool AllowAutoOwner
{
get { return (bool)GetValue(AllowAutoOwnerProperty); }
set { SetValue(AllowAutoOwnerProperty, value); }
}
public static readonly DependencyProperty AllowAutoOwnerProperty =
DependencyProperty.Register("AllowAutoOwner", typeof(bool), typeof(PUWindow), new PropertyMetadata(false, OnAllowAutoOwnerChanged));
private static void OnAllowAutoOwnerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var window = d as PUWindow;
if (window.AllowAutoOwner == true)
{
try
{
window.Owner = GetOwnerWindow();
}
catch (Exception ex) { }
}
}
#endregion
#region Internal APIs
#endregion
#region Command
///
/// 关闭命令
///
public ICommand CloseCommand
{
get
{ return _closeCommad; }
}
private ICommand _closeCommad = new CloseWindowCommand();
///
/// 最大化命令
///
public ICommand MaxCommand
{
get
{ return _maxCommand; }
}
private ICommand _maxCommand = new MaxWindowCommand();
///
/// 最小化命令
///
public ICommand MinCommand
{
get
{ return _minCommand; }
}
private ICommand _minCommand = new MinWindowCommand();
#endregion
#region APIs
///
/// 向控制栏的左侧添加一个新的按钮。
/// 警告:当Window的前景色发生改变时,该按钮的前景色不会随之变化。
///
/// 按钮的内容
/// 点击按钮时应该触发的事件。
public void AppendNavButton(object content, RoutedEventHandler clickHandler, bool isIconFont = true, object tooltip = null)
{
var btn = new PUButton()
{
Content = content,
ButtonStyle = ButtonStyles.Hollow,
Foreground = Foreground,
BorderBrush = new SolidColorBrush(Colors.Transparent),
CoverBrush = new SolidColorBrush(((Color)ColorConverter.ConvertFromString("#99999999"))),
HorizontalAlignment = HorizontalAlignment.Right,
};
if (isIconFont)
btn.FontFamily = FindResource("IconFont") as FontFamily;
if (tooltip != null)
btn.ToolTip = tooltip;
var visibility = new Binding() { Path = new PropertyPath("NavButtonVisibility"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, Source = this, Mode = BindingMode.OneWay };
BindingOperations.SetBinding(btn, VisibilityProperty, visibility);
var width = new Binding() { Path = new PropertyPath("NavButtonWidth"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, Source = this, Mode = BindingMode.OneWay };
BindingOperations.SetBinding(btn, WidthProperty, width);
var height = new Binding() { Path = new PropertyPath("NavButtonHeight"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, Source = this, Mode = BindingMode.OneWay };
BindingOperations.SetBinding(btn, HeightProperty, height);
var fontsize = new Binding() { Path = new PropertyPath("FontSize"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, Source = this, Mode = BindingMode.OneWay };
BindingOperations.SetBinding(btn, FontSizeProperty, fontsize);
btn.Click += clickHandler;
if (IsLoaded)
_stkNav.Children.Insert(0, btn);
else
{
Loaded += delegate
{
_stkNav.Children.Insert(0, btn);
};
}
}
#endregion
#region Function
private static bool IsModal(Window window)
{
return (bool)typeof(Window).GetField("_showingAsDialog", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(window);
}
private static PUWindow GetWindowFromHwnd(IntPtr hwnd)
{
var visual = HwndSource.FromHwnd(hwnd).RootVisual;
return visual as PUWindow;
}
private static PUWindow GetOwnerWindow()
{
var hwnd = GetForegroundWindow();
if (hwnd == null)
return null;
return GetWindowFromHwnd(hwnd);
}
#endregion
}
internal class CloseWindowCommand : ICommand
{
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var window = (parameter as PUWindow);
window.Close();
}
}
internal class MaxWindowCommand : ICommand
{
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var window = (parameter as PUWindow);
if (window.WindowState == WindowState.Maximized)
window.WindowState = WindowState.Normal;
else
window.WindowState = WindowState.Maximized;
}
}
internal class MinWindowCommand : ICommand
{
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
(parameter as PUWindow).WindowState = WindowState.Minimized;
}
}
}
================================================
FILE: Panuon.UI/2_Button/PUButton.cs
================================================
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
public class PUButton : Button
{
static PUButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUButton), new FrameworkPropertyMetadata(typeof(PUButton)));
}
#region Property
///
/// 效果等同于Tag,无实际作用。
///
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(PUButton));
///
/// 获取或设置按钮的基本样式。默认值为标准样式(General)。
///
public ButtonStyles ButtonStyle
{
get { return (ButtonStyles)GetValue(ButtonStyleProperty); }
set { SetValue(ButtonStyleProperty, value); }
}
public static readonly DependencyProperty ButtonStyleProperty = DependencyProperty.Register("ButtonStyle", typeof(ButtonStyles), typeof(PUButton), new PropertyMetadata(ButtonStyles.General));
///
/// 获取或设置鼠标点击时按钮的效果。默认为无特殊效果(Classic)。
///
public ClickStyles ClickStyle
{
get { return (ClickStyles)GetValue(ClickStyleProperty); }
set { SetValue(ClickStyleProperty, value); }
}
public static readonly DependencyProperty ClickStyleProperty =
DependencyProperty.Register("ClickStyle", typeof(ClickStyles), typeof(PUButton), new PropertyMetadata(ClickStyles.Classic));
///
/// 获取或设置按钮的圆角大小。默认值为0。
///
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static readonly DependencyProperty BorderCornerRadiusProperty =
DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(PUButton));
///
/// 获取或设置鼠标悬浮时遮罩层的背景颜色(在Outline和Link样式下为前景色),默认值为#26FFFFFF(在Hollow、Outline和Link样式下为灰黑色)。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUButton));
#endregion
}
}
================================================
FILE: Panuon.UI/2_Button/PURepeatButton.cs
================================================
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace Panuon.UI
{
public class PURepeatButton : RepeatButton
{
static PURepeatButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PURepeatButton), new FrameworkPropertyMetadata(typeof(PURepeatButton)));
}
#region Property
///
/// 获取或设置按钮的基本样式。默认值为标准样式(General)。
///
public RepeatButtonStyles RepeatButtonStyle
{
get { return (RepeatButtonStyles)GetValue(RepeatButtonStyleProperty); }
set { SetValue(RepeatButtonStyleProperty, value); }
}
public static readonly DependencyProperty RepeatButtonStyleProperty = DependencyProperty.Register("RepeatButtonStyle", typeof(RepeatButtonStyles), typeof(PURepeatButton), new PropertyMetadata(RepeatButtonStyles.General));
///
/// 获取或设置鼠标点击时按钮的效果。默认为无效果(Classic)。
///
public ClickStyles ClickStyle
{
get { return (ClickStyles)GetValue(ClickStyleProperty); }
set { SetValue(ClickStyleProperty, value); }
}
public static readonly DependencyProperty ClickStyleProperty =
DependencyProperty.Register("ClickStyle", typeof(ClickStyles), typeof(PURepeatButton), new PropertyMetadata(ClickStyles.Classic));
///
/// 圆角大小,默认值为0。
///
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static readonly DependencyProperty BorderCornerRadiusProperty = DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(PURepeatButton), new PropertyMetadata(new CornerRadius(0)));
///
/// 鼠标悬浮时遮罩层的背景颜色(在Outline和Link样式下为前景色),默认值为白色(在Outline和Link样式下为灰色)。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty = DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PURepeatButton), new PropertyMetadata(new SolidColorBrush(Colors.White)));
#endregion
}
}
================================================
FILE: Panuon.UI/3_TextBox/PUTextBox.cs
================================================
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
public class PUTextBox : TextBox
{
static PUTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUTextBox), new FrameworkPropertyMetadata(typeof(PUTextBox)));
}
#region Sys
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
AddHandler(PUButton.ClickEvent, new RoutedEventHandler(OnClearButtonClick));
ScrollViewer scrollViewer = new ScrollViewer();
if (TextBoxStyle == TextBoxStyles.General)
{
scrollViewer = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(this, 0), 1), 0), 0) as ScrollViewer;
}
else if (TextBoxStyle == TextBoxStyles.IconGroup)
{
scrollViewer = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(this, 0), 1), 0), 1), 0) as ScrollViewer;
}
if(scrollViewer != null)
scrollViewer.MouseWheel += ScrollViewer_MouseWheel;
PreviewKeyDown += PUTextBox_PreviewKeyDown;
}
private void PUTextBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (TextType == TextTypes.Text)
return;
else
{
switch (e.Key)
{
case System.Windows.Input.Key.D0:
case System.Windows.Input.Key.D1:
case System.Windows.Input.Key.D2:
case System.Windows.Input.Key.D3:
case System.Windows.Input.Key.D4:
case System.Windows.Input.Key.D5:
case System.Windows.Input.Key.D6:
case System.Windows.Input.Key.D7:
case System.Windows.Input.Key.D8:
case System.Windows.Input.Key.D9:
case System.Windows.Input.Key.NumPad0:
case System.Windows.Input.Key.NumPad1:
case System.Windows.Input.Key.NumPad2:
case System.Windows.Input.Key.NumPad3:
case System.Windows.Input.Key.NumPad4:
case System.Windows.Input.Key.NumPad5:
case System.Windows.Input.Key.NumPad6:
case System.Windows.Input.Key.NumPad7:
case System.Windows.Input.Key.NumPad8:
case System.Windows.Input.Key.NumPad9:
case System.Windows.Input.Key.Enter:
case System.Windows.Input.Key.Back:
case System.Windows.Input.Key.Delete:
case System.Windows.Input.Key.Left:
case System.Windows.Input.Key.Right:
case System.Windows.Input.Key.Up:
case System.Windows.Input.Key.Down:
case System.Windows.Input.Key.Home:
case System.Windows.Input.Key.End:
case System.Windows.Input.Key.Tab:
break;
case System.Windows.Input.Key.OemPeriod:
if (TextType != TextTypes.Decimal)
e.Handled = true;
break;
default:
e.Handled = true;
break;
}
}
}
private void OnClearButtonClick(object sender, RoutedEventArgs e)
{
var btnClear = e.OriginalSource as PUButton;
if (btnClear.Tag == null || btnClear.Tag.ToString() != "Clear")
return;
Text = "";
}
private void ScrollViewer_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
var scrollViewer = sender as ScrollViewer;
if (e.Delta > 0)
if (scrollViewer.ComputedVerticalScrollBarVisibility == Visibility.Visible)
scrollViewer.LineUp();
else if (scrollViewer.ComputedHorizontalScrollBarVisibility == Visibility.Visible)
scrollViewer.LineLeft();
else
return;
else
if (scrollViewer.ComputedVerticalScrollBarVisibility == Visibility.Visible)
scrollViewer.LineDown();
else if (scrollViewer.ComputedHorizontalScrollBarVisibility == Visibility.Visible)
scrollViewer.LineRight();
else
return;
if (scrollViewer.ComputedVerticalScrollBarVisibility == Visibility.Visible || scrollViewer.ComputedHorizontalScrollBarVisibility == Visibility.Visible)
e.Handled = true;
}
#endregion
#region Property
///
/// 获取或设置文本框的基本样式。默认值为General。
///
public TextBoxStyles TextBoxStyle
{
get { return (TextBoxStyles)GetValue(TextBoxStyleProperty); }
set { SetValue(TextBoxStyleProperty, value); }
}
public static readonly DependencyProperty TextBoxStyleProperty =
DependencyProperty.Register("TextBoxStyle", typeof(TextBoxStyles), typeof(PUTextBox), new PropertyMetadata(TextBoxStyles.General));
///
/// 获取或设置文本框的圆角大小,默认值为0。
///
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static readonly DependencyProperty BorderCornerRadiusProperty =
DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(PUTextBox));
///
/// 获取或设置输入框获得焦点时阴影的颜色,默认值为#66888888。
///
public Color ShadowColor
{
get { return (Color)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("ShadowColor", typeof(Color), typeof(PUTextBox));
///
/// 获取或设置水印内容。默认值为空。
///
public string Watermark
{
get { return (string)GetValue(WatermarkProperty); }
set { SetValue(WatermarkProperty, value); }
}
public static readonly DependencyProperty WatermarkProperty =
DependencyProperty.Register("Watermark", typeof(string), typeof(PUTextBox));
///
/// 获取或设置i放置在输入框前的图标。
/// 仅当输入框样式为IconGroup时有效。
///
public object Icon
{
get { return (object)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(object), typeof(PUTextBox));
///
/// 获取或设置图标的宽度,默认值为30。
/// 仅当输入框样式为IconGroup时有效。
///
public double IconWidth
{
get { return (double)GetValue(IconWidthProperty); }
set { SetValue(IconWidthProperty, value); }
}
public static readonly DependencyProperty IconWidthProperty =
DependencyProperty.Register("IconWidth", typeof(double), typeof(PUTextBox), new PropertyMetadata((double)30));
///
/// 获取或设置当鼠标悬浮时是否显示清除按钮。默认值为False。
///
public bool IsClearButtonShow
{
get { return (bool)GetValue(IsClearButtonShowProperty); }
set { SetValue(IsClearButtonShowProperty, value); }
}
public static readonly DependencyProperty IsClearButtonShowProperty =
DependencyProperty.Register("IsClearButtonShow", typeof(bool), typeof(PUTextBox));
///
/// 获取或设置允许键入的类型。默认值为Text(全部内容)。
///
public TextTypes TextType
{
get { return (TextTypes)GetValue(TextTypeProperty); }
set { SetValue(TextTypeProperty, value); }
}
public static readonly DependencyProperty TextTypeProperty =
DependencyProperty.Register("TextType", typeof(TextTypes), typeof(PUTextBox), new PropertyMetadata(TextTypes.Text, OnTextTypeChanged));
private static void OnTextTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBox = d as PUTextBox;
if(textBox.TextType == TextTypes.Text)
{
System.Windows.Input.InputMethod.SetIsInputMethodEnabled(textBox, true);
}
else
{
System.Windows.Input.InputMethod.SetIsInputMethodEnabled(textBox, false);
}
}
#endregion
}
}
================================================
FILE: Panuon.UI/4_PasswordBox/PUPasswordBox.cs
================================================
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
namespace Panuon.UI
{
[ContentProperty(nameof(Password))]
public class PUPasswordBox : TextBox
{
/*严重警告:
*PasswordBox是一个密封类,因此控件无法直接从PasswordBox派生。
*该控件继承自TextBox,因此无法保证在装有恶意软件的计算机上的密码安全(恶意软件可以通过内存读取密码)。
*如果对密码安全有较高的需求,切勿使用此控件。*/
static PUPasswordBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUPasswordBox), new FrameworkPropertyMetadata(typeof(PUPasswordBox)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
AcceptsReturn = false;
PUButton btnShowPwd;
if(PasswordBoxStyle == PasswordBoxStyles.General)
btnShowPwd = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(this, 0), 1), 0), 2) as PUButton;
else
btnShowPwd = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(this, 0), 1), 0), 1), 2) as PUButton;
btnShowPwd.PreviewMouseLeftButtonDown += BtnShowPwd_MouseLeftButtonDown;
btnShowPwd.PreviewMouseLeftButtonUp += BtnShowPwd_MouseLeftButtonUp;
ContextMenu = null;
Text = "";
if (Password != null && Password != "")
for (int i = 0; i < Password.Length; i++)
Text += PasswordChar;
PreviewTextInput += PUPasswordBox_TextInput;
PreviewKeyDown += PUPasswordBox_PreviewKeyDown;
}
private void BtnShowPwd_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Text = "";
for (int i = 0; i < Password.Length; i++)
Text += PasswordChar;
}
private void BtnShowPwd_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Text = Password;
}
#region Sys
private void PUPasswordBox_TextInput(object sender, TextCompositionEventArgs e)
{
Password = Password ?? "";
if ((MaxLength != 0 && Password.Length >= MaxLength) && SelectionLength == 0)
{
e.Handled = true;
return;
}
if (e.Text == "\n" || e.Text == "\r" || e.Text == "\t")
return;
var currentCursor = SelectionStart;
if (SelectionLength != 0)
{
var length = SelectionLength;
Password = Password.Remove(currentCursor, length);
}
Password = Password.Insert(currentCursor, e.Text);
Select(currentCursor + 1, 0);
e.Handled = true;
}
private void PUPasswordBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
//禁止任何与Control键有关的事(除了全选)
if ((Keyboard.IsKeyDown(Key.LeftCtrl) && !Keyboard.IsKeyDown(Key.A)))
{
e.Handled = true;
return;
}
if (e.Key == Key.Enter)
return;
var currentCursor = SelectionStart;
switch (e.Key)
{
case Key.Back:
if (Text.Length > 0 && currentCursor > 0 && SelectionLength == 0)
{
Password = Password.Remove(currentCursor - 1, 1);
if (currentCursor > 0)
Select(currentCursor - 1, 0);
}
else if (SelectionLength > 0)
{
var length = SelectionLength;
Password = Password.Remove(currentCursor, length);
Select(currentCursor, 0);
}
//批量选择情况下
break;
case Key.Delete:
if (currentCursor < Text.Length)
{
Password = Password.Remove(currentCursor, 1);
Select(currentCursor, 0);
}
break;
case Key.Space:
if (SelectionLength != 0)
{
Password = Password.Remove(currentCursor, SelectionLength);
}
Password = Password.Insert(currentCursor, " ");
Select(currentCursor + 1, 0);
break;
default:
return;
}
e.Handled = true;
}
#endregion
#region RoutedEvent
///
/// 密码改变事件。
///
public static readonly RoutedEvent PasswordChangedEvent = EventManager.RegisterRoutedEvent("PasswordChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUPasswordBox));
public event RoutedPropertyChangedEventHandler PasswordChanged
{
add { AddHandler(PasswordChangedEvent, value); }
remove { RemoveHandler(PasswordChangedEvent, value); }
}
#endregion
#region Property
[Obsolete("不能对密码框的Text属性赋值。")]
public new string Text
{
get { return base.Text; }
private set { base.Text = value; }
}
///
/// 密码属性
///
public string Password
{
get { return (string)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.Register("Password", typeof(string), typeof(PUPasswordBox), new PropertyMetadata("", OnPasswordChanged));
private static void OnPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var pb = d as PUPasswordBox;
var val = (string)e.NewValue;
pb.Text = "";
if (pb.Password != null && pb.Password != "")
for (int i = 0; i < pb.Password.Length; i++)
pb.Text += pb.PasswordChar;
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(val, pb.Password, PasswordChangedEvent);
pb.RaiseEvent(arg);
}
///
/// 密码掩饰字符,默认值为●。
///
public char PasswordChar
{
get { return (char)GetValue(PasswordCharProperty); }
set { SetValue(PasswordCharProperty, value); }
}
public static readonly DependencyProperty PasswordCharProperty =
DependencyProperty.Register("PasswordChar", typeof(char), typeof(PUPasswordBox), new PropertyMetadata('●'));
///
/// 密码框样式,默认值为General。
///
public PasswordBoxStyles PasswordBoxStyle
{
get { return (PasswordBoxStyles)GetValue(PasswordBoxStyleProperty); }
set { SetValue(PasswordBoxStyleProperty, value); }
}
public static readonly DependencyProperty PasswordBoxStyleProperty =
DependencyProperty.Register("PasswordBoxStyle", typeof(PasswordBoxStyles), typeof(PUPasswordBox), new PropertyMetadata(PasswordBoxStyles.General));
///
/// 圆角大小,默认值为0。
///
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static readonly DependencyProperty BorderCornerRadiusProperty = DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(PUPasswordBox), new PropertyMetadata(new CornerRadius(0)));
///
/// 密码框激活时阴影的颜色,默认值为#888888。
///
public Color ShadowColor
{
get { return (Color)GetValue(ShadowColorProperty); }
set { SetValue(ShadowColorProperty, value); }
}
public static readonly DependencyProperty ShadowColorProperty = DependencyProperty.Register("ShadowColor", typeof(Color), typeof(PUPasswordBox), new PropertyMetadata((Color)ColorConverter.ConvertFromString("#888888")));
///
/// 水印内容,默认值为空。
///
public string Watermark
{
get { return (string)GetValue(WatermarkProperty); }
set { SetValue(WatermarkProperty, value); }
}
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register("Watermark", typeof(string), typeof(PUPasswordBox));
///
/// 放置在密码框前的图标。
/// 仅当密码框样式为IconGroup时有效。
///
public object Icon
{
get { return (object)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(object), typeof(PUPasswordBox));
///
/// 图标的宽度,默认值为30。
/// 仅当密码框样式为IconGroup时有效。
///
public double IconWidth
{
get { return (double)GetValue(IconWidthProperty); }
set { SetValue(IconWidthProperty, value); }
}
public static readonly DependencyProperty IconWidthProperty = DependencyProperty.Register("IconWidth", typeof(double), typeof(PUPasswordBox), new PropertyMetadata((double)30));
///
/// 获取或设置当鼠标悬浮时是否显示 显示密码 按钮。默认值为False。
///
public bool IsShowPwdButtonShow
{
get { return (bool)GetValue(IsShowPwdButtonShowProperty); }
set { SetValue(IsShowPwdButtonShowProperty, value); }
}
public static readonly DependencyProperty IsShowPwdButtonShowProperty =
DependencyProperty.Register("IsShowPwdButtonShow", typeof(bool), typeof(PUPasswordBox));
#endregion
}
}
================================================
FILE: Panuon.UI/5_ComboBox/PUComboBox.cs
================================================
using Panuon.UI.Utils;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
public class PUComboBox : ComboBox
{
static PUComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUComboBox), new FrameworkPropertyMetadata(typeof(PUComboBox)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (SearchMode == SearchModes.TextChanged)
{
AddHandler(PUTextBox.TextChangedEvent, new RoutedEventHandler(OnSearchTextChanged));
SearchBoxVisibility = Visibility.Visible;
}
else if (SearchMode == SearchModes.Enter)
{
AddHandler(PUTextBox.PreviewKeyDownEvent, new RoutedEventHandler(OnSearchKeyDown));
SearchBoxVisibility = Visibility.Visible;
}
else
{
SearchBoxVisibility = Visibility.Collapsed;
}
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
if (SelectedValuePath == SelectedValuePaths.Header)
SelectedValue = SelectedItem == null ? "" : (SelectedItem as PUComboBoxItem).Content;
else
SelectedValue = SelectedItem == null ? null : (SelectedItem as PUComboBoxItem).Value;
base.OnSelectionChanged(e);
}
private void OnSearchKeyDown(object sender, RoutedEventArgs e)
{
var eve = e as System.Windows.Input.KeyEventArgs;
if (eve.Key != System.Windows.Input.Key.Enter)
return;
var tbSearch = e.OriginalSource as PUTextBox;
if (tbSearch == null || tbSearch.Tag == null || tbSearch.Tag.ToString() != "Search")
return;
var text = tbSearch.Text;
foreach (var item in Items)
{
var comboItem = item as ComboBoxItem;
if (comboItem.Content.ToString().Contains(text))
comboItem.Visibility = Visibility.Visible;
else
comboItem.Visibility = Visibility.Collapsed;
}
e.Handled = true;
}
private void OnSearchTextChanged(object sender, RoutedEventArgs e)
{
var tbSearch = e.OriginalSource as PUTextBox;
if (tbSearch == null || tbSearch.Tag == null || tbSearch.Tag.ToString() != "Search")
return;
var text = tbSearch.Text;
foreach (var item in Items)
{
var comboItem = item as ComboBoxItem;
if (comboItem.Content.ToString().Contains(text))
comboItem.Visibility = Visibility.Visible;
else
comboItem.Visibility = Visibility.Collapsed;
}
}
#region RoutedEvent
///
/// 用户点击删除按钮事件。
///
public static readonly RoutedEvent DeleteItemEvent = EventManager.RegisterRoutedEvent("DeleteItem", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUComboBox));
public event RoutedPropertyChangedEventHandler DeleteItem
{
add { AddHandler(DeleteItemEvent, value); }
remove { RemoveHandler(DeleteItemEvent, value); }
}
internal void OnDeleteItem(PUComboBoxItem oldItem, PUComboBoxItem newItem)
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(oldItem, newItem, DeleteItemEvent);
RaiseEvent(arg);
}
#endregion
#region Property
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("该属性对此控件无效。请使用BindingItems属性替代。", true)]
public new IEnumerable ItemsSource
{
get { return base.ItemsSource; }
private set { base.ItemsSource = value; }
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("该属性对此控件无效。BindingItems属性中的Header属性即为要显示的内容。", true)]
public new string DisplayMemberPath
{
get { return base.DisplayMemberPath; }
private set { base.DisplayMemberPath = value; }
}
///
/// 获取或设置鼠标悬浮时子项的背景颜色。默认值为浅灰色(#EEEEEE)。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUComboBox), new PropertyMetadata(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#EEEEEE"))));
///
/// 获取或设置子项被选中时的背景颜色。默认值为浅灰色(#DDDDDD)。
///
public Brush SelectedBrush
{
get { return (Brush)GetValue(SelectedBrushProperty); }
set { SetValue(SelectedBrushProperty, value); }
}
// Using a DependencyProperty as the backing store for SelectedBrush. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectedBrushProperty =
DependencyProperty.Register("SelectedBrush", typeof(Brush), typeof(PUComboBox), new PropertyMetadata(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#DDDDDD"))));
///
/// 获取或设置显示框和下拉框的圆角大小。默认值为0。
///
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static readonly DependencyProperty BorderCornerRadiusProperty =
DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(PUComboBox), new PropertyMetadata(new CornerRadius(0)));
///
/// 获取或设置下拉框激活时阴影的颜色,默认值为#888888。
///
public Color ShadowColor
{
get { return (Color)GetValue(ShadowColorProperty); }
set { SetValue(ShadowColorProperty, value); }
}
public static readonly DependencyProperty ShadowColorProperty = DependencyProperty.Register("ShadowColor", typeof(Color), typeof(PUComboBox), new PropertyMetadata((Color)ColorConverter.ConvertFromString("#888888")));
///
/// 获取或设置当子项目可删除时,用户点击删除按钮后的操作。默认为删除项目并触发DeleteItem路由事件。
///
public DeleteModes DeleteMode
{
get { return (DeleteModes)GetValue(DeleteModeProperty); }
set { SetValue(DeleteModeProperty, value); }
}
public static readonly DependencyProperty DeleteModeProperty =
DependencyProperty.Register("DeleteMode", typeof(DeleteModes), typeof(PUComboBox), new PropertyMetadata(DeleteModes.Delete));
///
/// 若使用MVVM绑定,请使用此依赖属性。
///
public ObservableCollection BindingItems
{
get { return (ObservableCollection)GetValue(BindingItemsProperty); }
set { SetValue(BindingItemsProperty, value); }
}
public static readonly DependencyProperty BindingItemsProperty =
DependencyProperty.Register("BindingItems", typeof(ObservableCollection), typeof(PUComboBox), new PropertyMetadata(null, OnBindingItemsChanged));
private static void OnBindingItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var comboBox = d as PUComboBox;
if (comboBox.BindingItems != null)
{
comboBox.BindingItems.CollectionChanged -= comboBox.BindingItemChanged;
comboBox.BindingItems.CollectionChanged += comboBox.BindingItemChanged;
}
comboBox.GenerateBindindItems(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
private void BindingItemChanged(object sender, NotifyCollectionChangedEventArgs e)
{
GenerateBindindItems(e);
}
///
/// 获取或设置当子项目被选中时,SelectedValue应呈现子项目的哪一个值。(在ComboBox中,Header属性表示展现子项的Content属性)
/// 可选项为Header或Value,默认值为Header。
///
public new SelectedValuePaths SelectedValuePath
{
get { return (SelectedValuePaths)GetValue(SelectedValuePathProperty); }
set { SetValue(SelectedValuePathProperty, value); }
}
public new static readonly DependencyProperty SelectedValuePathProperty =
DependencyProperty.Register("SelectedValuePath", typeof(SelectedValuePaths), typeof(PUComboBox), new PropertyMetadata(SelectedValuePaths.Header));
///
/// 获取被选中PUComboBoxItem的Header或Value属性(这取决于SelectedValuePath),
/// 或根据设置的SelectedValue来选中子项目。
///
public new object SelectedValue
{
get { return (object)GetValue(SelectedValueProperty); }
set { SetValue(SelectedValueProperty, value); }
}
public new static readonly DependencyProperty SelectedValueProperty =
DependencyProperty.Register("SelectedValue", typeof(object), typeof(PUComboBox), new PropertyMetadata("", OnSelectedValueChanged));
private static void OnSelectedValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var comboBox = d as PUComboBox;
if (comboBox.SelectedValue == null)
{
return;
}
if (e.NewValue.Equals(e.OldValue))
return;
var selectedItem = comboBox.SelectedItem as PUComboBoxItem;
foreach (var item in comboBox.Items)
{
var comboBoxItem = item as PUComboBoxItem;
if ((comboBox.SelectedValuePath == SelectedValuePaths.Header ?
(comboBoxItem.Content == null ? false : comboBoxItem.Content.Equals(comboBox.SelectedValue)) :
(comboBoxItem.Value == null ? false : comboBoxItem.Value.Equals(comboBox.SelectedValue))))
{
if (!comboBoxItem.IsSelected)
comboBoxItem.IsSelected = true;
return;
}
}
}
///
/// 获取或设置搜索模式。默认为不显示搜索。
///
public SearchModes SearchMode
{
get { return (SearchModes)GetValue(SearchModeProperty); }
set { SetValue(SearchModeProperty, value); }
}
public static readonly DependencyProperty SearchModeProperty =
DependencyProperty.Register("SearchMode", typeof(SearchModes), typeof(PUComboBox), new PropertyMetadata(SearchModes.None, OnSearchModeChanged));
private static void OnSearchModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var comboBox = d as PUComboBox;
if (comboBox.IsLoaded)
{
comboBox.RemoveHandler(PUTextBox.TextChangedEvent, new RoutedEventHandler(comboBox.OnSearchTextChanged));
comboBox.RemoveHandler(PUTextBox.KeyDownEvent, new RoutedEventHandler(comboBox.OnSearchKeyDown));
if (comboBox.SearchMode == SearchModes.TextChanged)
{
comboBox.AddHandler(PUTextBox.TextChangedEvent, new RoutedEventHandler(comboBox.OnSearchTextChanged));
comboBox.SearchBoxVisibility = Visibility.Visible;
}
else if (comboBox.SearchMode == SearchModes.Enter)
{
comboBox.AddHandler(PUTextBox.PreviewKeyDownEvent, new RoutedEventHandler(comboBox.OnSearchKeyDown));
comboBox.SearchBoxVisibility = Visibility.Visible;
}
else
{
comboBox.SearchBoxVisibility = Visibility.Collapsed;
}
}
}
#endregion
#region Internal Property
internal Visibility SearchBoxVisibility
{
get { return (Visibility)GetValue(SearchBoxVisibilityProperty); }
set { SetValue(SearchBoxVisibilityProperty, value); }
}
internal static readonly DependencyProperty SearchBoxVisibilityProperty =
DependencyProperty.Register("SearchBoxVisibility", typeof(Visibility), typeof(PUComboBox), new PropertyMetadata(Visibility.Collapsed));
#endregion
#region APIs
///
/// 通过内容选中项目。
/// 若content不是值类型,则将逐一比较其中各个属性的值是否相等。
///
/// 要匹配的内容。
public void SelectItemByContent(object content)
{
var comboItem = GetItemByContent(content);
if (comboItem != null)
comboItem.IsSelected = true;
}
///
/// 通过Value选中项目。
/// 若value不是值类型,则将逐一比较其中各个属性的值是否相等。
///
/// 要匹配的value。
public void SelectItemByValue(object value)
{
var comboItem = GetItemByValue(value);
if (comboItem != null)
comboItem.IsSelected = true;
}
#endregion
#region Function
private void GenerateBindindItems(NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Reset:
var value = SelectedValue;
SelectedValue = null;
Items.Clear();
if (BindingItems == null)
break;
foreach (var item in BindingItems)
{
var comboBoxItem = GenerateComboBoxItem(item);
Items.Add(comboBoxItem);
}
SelectedValue = value;
break;
case NotifyCollectionChangedAction.Add:
foreach (var item in e.NewItems)
{
var comboBoxItem = GenerateComboBoxItem(item as PUComboBoxItemModel);
Items.Insert(e.NewStartingIndex, comboBoxItem);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (var item in e.OldItems)
{
Items.RemoveAt(e.OldStartingIndex);
}
break;
case NotifyCollectionChangedAction.Replace:
foreach (var item in e.NewItems)
{
var comboBoxItem = GenerateComboBoxItem(item as PUComboBoxItemModel);
Items[e.OldStartingIndex] = comboBoxItem;
}
break;
case NotifyCollectionChangedAction.Move:
{
var tabItem = Items[e.OldStartingIndex];
Items.RemoveAt(e.OldStartingIndex);
Items.Insert(e.NewStartingIndex, tabItem);
}
break;
}
if (SelectedValue != null)
{
if (SelectedValuePath == SelectedValuePaths.Header)
SelectItemByContent(SelectedValue);
else
SelectItemByValue(SelectedValue);
}
}
private PUComboBoxItem GenerateComboBoxItem(PUComboBoxItemModel model)
{
var comboBoxItem = new PUComboBoxItem()
{
Uid = model.Uid,
Content = model.Header,
Value = model.Value,
CanDelete = model.CanDelete,
};
model.PropertyChanged += delegate
{
comboBoxItem.Content = model.Header;
comboBoxItem.Value = model.Value;
comboBoxItem.CanDelete = model.CanDelete;
};
return comboBoxItem;
}
private PUComboBoxItem GetItemByContent(object content)
{
foreach (var item in Items)
{
var comboItem = item as PUComboBoxItem;
if (comboItem == null)
throw new Exception("PUComboBox的子项必须是PUComboBoxItem。");
if (comboItem.Content.IsEqual(content))
return comboItem;
}
return null;
}
private PUComboBoxItem GetItemByValue(object value)
{
foreach (var item in Items)
{
var comboItem = item as PUComboBoxItem;
if (comboItem == null)
throw new Exception("PUComboBox的子项必须是PUComboBoxItem。");
if (comboItem.Value.IsEqual(value))
return comboItem;
}
return null;
}
#endregion
}
}
================================================
FILE: Panuon.UI/5_ComboBox/PUComboBoxItem.cs
================================================
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Panuon.UI
{
public class PUComboBoxItem : ComboBoxItem
{
public PUComboBoxItem()
{
}
static PUComboBoxItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUComboBoxItem), new FrameworkPropertyMetadata(typeof(PUComboBoxItem)));
}
#region Property
///
/// 获取或设置是否显示删除按钮,默认值为False(不显示)。
///
public bool CanDelete
{
get { return (bool)GetValue(CanDeleteProperty); }
set { SetValue(CanDeleteProperty, value); }
}
public static readonly DependencyProperty CanDeleteProperty =
DependencyProperty.Register("CanDelete", typeof(bool), typeof(PUComboBoxItem));
///
/// 获取或设置用以标记该项目的值。默认值为Null。
///
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(PUComboBoxItem));
#endregion
public ICommand DeleteCommand
{
get
{ return _deleteCommand; }
}
private ICommand _deleteCommand = new PUComboBoxDeleteCommand();
}
internal sealed class PUComboBoxDeleteCommand : ICommand
{
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var comItem = (parameter as PUComboBoxItem);
var combox = comItem.Parent as PUComboBox;
if (combox.DeleteMode == DeleteModes.Delete)
{
if (combox.BindingItems != null && !String.IsNullOrEmpty((comItem.Uid)))
{
var model = combox.BindingItems.FirstOrDefault(x => x.Uid == comItem.Uid);
if (model != null)
combox.BindingItems.Remove(model);
else
combox.Items.Remove(comItem);
}
else
{
combox.Items.Remove(comItem);
}
}
combox.OnDeleteItem(null, comItem);
}
}
}
================================================
FILE: Panuon.UI/6_CheckBox/PUCheckBox.cs
================================================
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
public class PUCheckBox : CheckBox
{
static PUCheckBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUCheckBox), new FrameworkPropertyMetadata(typeof(PUCheckBox)));
}
#region Property
///
/// 获取或设置选择框的基本样式。默认值为General。
///
public CheckBoxStyles CheckBoxStyle
{
get { return (CheckBoxStyles)GetValue(CheckBoxStyleProperty); }
set { SetValue(CheckBoxStyleProperty, value); }
}
public static readonly DependencyProperty CheckBoxStyleProperty = DependencyProperty.Register("CheckBoxStyle", typeof(CheckBoxStyles), typeof(PUCheckBox), new PropertyMetadata(CheckBoxStyles.General));
///
/// 获取或设置选择框的圆角大小。默认值为0。
///
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static readonly DependencyProperty BorderCornerRadiusProperty = DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(PUCheckBox), new PropertyMetadata(new CornerRadius(0)));
///
/// 获取或设置选择框的宽度。默认值为20(Switch样式下为30)。
///
public double InnerWidth
{
get { return (double)GetValue(InnerWidthProperty); }
set
{ SetValue(InnerWidthProperty, value); }
}
public static readonly DependencyProperty InnerWidthProperty =
DependencyProperty.Register("InnerWidth", typeof(double), typeof(PUCheckBox), new PropertyMetadata((double)20));
///
/// 获取或设置选择框的高度。默认值为20。
///
public double InnerHeight
{
get { return (double)GetValue(InnerHeightProperty); }
set { SetValue(InnerHeightProperty, value); }
}
public static readonly DependencyProperty InnerHeightProperty =
DependencyProperty.Register("InnerHeight", typeof(double), typeof(PUCheckBox), new PropertyMetadata((double)20));
///
/// Check时对号的背景颜色(或前景色),默认值为白色。
/// 仅当按钮样式为General时生效。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUCheckBox));
#endregion
}
}
================================================
FILE: Panuon.UI/7_RadioButton/PURadioButton.cs
================================================
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
public class PURadioButton : RadioButton
{
static PURadioButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PURadioButton), new FrameworkPropertyMetadata(typeof(PURadioButton)));
}
#region Property
///
/// 选择框样式,默认值为General。
///
public RadioButtonStyles RadioButtonStyle
{
get { return (RadioButtonStyles)GetValue(RadioButtonStyleProperty); }
set { SetValue(RadioButtonStyleProperty, value); }
}
public static readonly DependencyProperty RadioButtonStyleProperty = DependencyProperty.Register("RadioButtonStyle", typeof(RadioButtonStyles), typeof(PURadioButton), new PropertyMetadata(RadioButtonStyles.General));
///
/// 圆角大小,默认值为0。
///
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static readonly DependencyProperty BorderCornerRadiusProperty = DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(PURadioButton), new PropertyMetadata(new CornerRadius(0)));
///
/// 内部选择框的宽度,默认值为20。
/// Switch样式下默认值为30。
///
public double InnerWidth
{
get { return (double)GetValue(InnerWidthProperty); }
set
{ SetValue(InnerWidthProperty, value); }
}
public static readonly DependencyProperty InnerWidthProperty = DependencyProperty.Register("InnerWidth", typeof(double), typeof(PURadioButton), new PropertyMetadata((double)20));
///
/// 内部选择框的高度,默认值为20。
///
public double InnerHeight
{
get { return (double)GetValue(InnerHeightProperty); }
set { SetValue(InnerHeightProperty, value); }
}
public static readonly DependencyProperty InnerHeightProperty =
DependencyProperty.Register("InnerHeight", typeof(double), typeof(PURadioButton), new PropertyMetadata((double)20));
///
/// Check时对号的背景颜色(或前景色),默认值为白色。
/// 仅当按钮样式为General时生效。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PURadioButton), new PropertyMetadata(new SolidColorBrush(Colors.White)));
#endregion
}
}
================================================
FILE: Panuon.UI/8_ProgressBar/PUProgressBar.cs
================================================
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace Panuon.UI
{
public class PUProgressBar : Control
{
static PUProgressBar()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUProgressBar), new FrameworkPropertyMetadata(typeof(PUProgressBar)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Loaded += delegate
{
PercentString = Percent * 100 + "%";
Change();
};
}
#region RoutedEvent
///
/// 进度改变事件。
///
public static readonly RoutedEvent PercentChangedEvent = EventManager.RegisterRoutedEvent("PercentChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUProgressBar));
public event RoutedPropertyChangedEventHandler PercentChanged
{
add { AddHandler(PercentChangedEvent, value); }
remove { RemoveHandler(PercentChangedEvent, value); }
}
internal void OnPercentChanged(double oldValue, double newValue)
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(oldValue, newValue, PercentChangedEvent);
RaiseEvent(arg);
}
#endregion
#region Property
///
/// 获取或设置进度条的基本样式。默认值为General。
///
public ProgressBarStyles ProgressBarStyle
{
get { return (ProgressBarStyles)GetValue(ProgressBarStyleProperty); }
set { SetValue(ProgressBarStyleProperty, value); }
}
public static readonly DependencyProperty ProgressBarStyleProperty =
DependencyProperty.Register("ProgressBarStyle", typeof(ProgressBarStyles), typeof(PUProgressBar), new PropertyMetadata(ProgressBarStyles.General));
///
/// 获取或设置进度条的填充动画持续时间。默认值为0.4秒。
///
public TimeSpan AnimationDuration
{
get { return (TimeSpan)GetValue(AnimationDurationProperty); }
set { SetValue(AnimationDurationProperty, value); }
}
public static readonly DependencyProperty AnimationDurationProperty =
DependencyProperty.Register("AnimationDuration", typeof(TimeSpan), typeof(PUProgressBar), new PropertyMetadata(TimeSpan.FromSeconds(0.6)));
///
/// 获取或设置进度条的填充颜色。默认值为灰黑色。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUProgressBar));
///
/// 获取或设置进度条的圆角大小,默认值为0。
///
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static readonly DependencyProperty BorderCornerRadiusProperty =
DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(PUProgressBar));
///
/// 获取或设置进度条填充方向,默认值为LeftToRight。
///
public ProgressDirections ProgressDirection
{
get { return (ProgressDirections)GetValue(ProgressDirectionroperty); }
set { SetValue(ProgressDirectionroperty, value); }
}
public static readonly DependencyProperty ProgressDirectionroperty =
DependencyProperty.Register("ProgressDirection", typeof(ProgressDirections), typeof(PUProgressBar), new PropertyMetadata(ProgressDirections.LeftToRight));
///
/// 获取或设置是否显示百分比。默认值为False。
///
public bool IsPercentShow
{
get { return (bool)GetValue(IsPercentShowProperty); }
set { SetValue(IsPercentShowProperty, value); }
}
public static readonly DependencyProperty IsPercentShowProperty =
DependencyProperty.Register("IsPercentShow", typeof(bool), typeof(PUProgressBar));
///
/// 获取或设置当前进度条的百分比,从0~1的值。默认值为0。
///
public double Percent
{
get { return (double)GetValue(PercentProperty); }
set { SetValue(PercentProperty, value); }
}
public static readonly DependencyProperty PercentProperty =
DependencyProperty.Register("Percent", typeof(double), typeof(PUProgressBar), new PropertyMetadata(OnPercentChanged));
private static void OnPercentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var pgBar = d as PUProgressBar;
if (pgBar.Percent < 0)
{
pgBar.Percent = 0;
return;
}
else if (pgBar.Percent > 1)
{
pgBar.Percent = 1;
return;
}
pgBar.PercentString = pgBar.Percent * 100 + "%";
pgBar.OnPercentChanged((double)e.OldValue, (double)e.NewValue);
if (!pgBar.IsLoaded)
return;
pgBar.Change();
}
public new Thickness BorderThickness
{
get { return (Thickness)GetValue(BorderThicknessProperty); }
set { SetValue(BorderThicknessProperty, value); }
}
public new static readonly DependencyProperty BorderThicknessProperty =
DependencyProperty.Register("BorderThickness", typeof(Thickness), typeof(PUProgressBar), new PropertyMetadata(OnBorderThicknessChanged));
private static void OnBorderThicknessChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var bar = d as PUProgressBar;
bar.StrokeThickness = bar.BorderThickness.Left;
}
#endregion
#region Internal Property
internal string PercentString
{
get { return (string)GetValue(PercentStringProperty); }
set { SetValue(PercentStringProperty, value); }
}
internal static readonly DependencyProperty PercentStringProperty =
DependencyProperty.Register("PercentString", typeof(string), typeof(PUProgressBar));
internal double InnerWidth
{
get { return (double)GetValue(InnerWidthProperty); }
set { SetValue(InnerWidthProperty, value); }
}
internal static readonly DependencyProperty InnerWidthProperty =
DependencyProperty.Register("InnerWidth", typeof(double), typeof(PUProgressBar));
internal double InnerPercent
{
get { return (double)GetValue(InnerPercentProperty); }
set { SetValue(InnerPercentProperty, value); }
}
internal static readonly DependencyProperty InnerPercentProperty =
DependencyProperty.Register("InnerPercent", typeof(double), typeof(PUProgressBar));
internal double StrokeThickness
{
get { return (double)GetValue(StrokeThicknessProperty); }
set { SetValue(StrokeThicknessProperty, value); }
}
internal static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register("StrokeThickness", typeof(double), typeof(PUProgressBar));
#endregion
#region Function
private void Change()
{
var toValue = ActualWidth * Percent;
if (ProgressDirection == ProgressDirections.TopToBottom || ProgressDirection == ProgressDirections.BottomToTop)
{
toValue = ActualHeight * Percent;
}
var anima = new DoubleAnimation()
{
To = toValue,
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut },
Duration = AnimationDuration,
};
BeginAnimation(InnerWidthProperty, anima);
var anima2 = new DoubleAnimation()
{
To = Percent,
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut },
Duration = AnimationDuration,
};
BeginAnimation(InnerPercentProperty, anima2);
}
#endregion
}
}
================================================
FILE: Panuon.UI/9_Special/Countdown.cs
================================================
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
namespace Panuon.UI
{
public class Countdown : Control
{
#region Identity
private DispatcherTimer _timer;
#endregion
static Countdown()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Countdown), new FrameworkPropertyMetadata(typeof(Countdown)));
}
public Countdown()
{
_timer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(1) };
_timer.Tick += CountdownTimer_Tick;
}
#region RoutedEvent
public static readonly RoutedEvent TimeChangedEvent = EventManager.RegisterRoutedEvent("TimeChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(Countdown));
public event RoutedPropertyChangedEventHandler TimeChanged
{
add { AddHandler(TimeChangedEvent, value); }
remove { RemoveHandler(TimeChangedEvent, value); }
}
void RaiseTimeChanged(int oldValue, int newValue)
{
var arg = new RoutedPropertyChangedEventArgs(oldValue, newValue, TimeChangedEvent);
RaiseEvent(arg);
}
public static readonly RoutedEvent StopedEvent = EventManager.RegisterRoutedEvent("Stoped", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Countdown));
public event RoutedEventHandler Stoped
{
add { AddHandler(StopedEvent, value); }
remove { RemoveHandler(StopedEvent, value); }
}
void RaiseStoped()
{
var arg = new RoutedEventArgs(StopedEvent);
RaiseEvent(arg);
}
#endregion
#region Property
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(Countdown));
public int Second
{
get { return (int)GetValue(SecondProperty); }
set { SetValue(SecondProperty, value); }
}
public static readonly DependencyProperty SecondProperty =
DependencyProperty.Register("Second", typeof(int), typeof(Countdown), new PropertyMetadata(OnSecondChanged));
private static void OnSecondChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var countDown = d as Countdown;
if(countDown.Second < 0)
{
countDown.Second = 0;
return;
}
countDown.RaiseTimeChanged(e.OldValue as int? ?? 0, e.NewValue as int? ?? 0);
}
public bool IsRunning
{
get { return (bool)GetValue(IsRunningProperty); }
set { SetValue(IsRunningProperty, value); }
}
public static readonly DependencyProperty IsRunningProperty =
DependencyProperty.Register("IsRunning", typeof(bool), typeof(Countdown), new PropertyMetadata(OnIsRunningChanged));
private static void OnIsRunningChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var countdown = d as Countdown;
if (countdown.IsRunning)
{
countdown._timer.Start();
}
else
{
countdown.RaiseStoped();
countdown._timer.Stop();
}
}
#endregion
#region Event
private void CountdownTimer_Tick(object sender, EventArgs e)
{
if (Second <= 0)
{
RaiseStoped();
_timer.Stop();
}
Second--;
}
#endregion
}
}
================================================
FILE: Panuon.UI/9_Special/DateTimePicker.cs
================================================
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
public class PUDateTimeSelector : Control
{
#region Constructor
static PUDateTimeSelector()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUDateTimeSelector), new FrameworkPropertyMetadata(typeof(PUDateTimeSelector)));
}
public PUDateTimeSelector()
{
Loaded += delegate
{
UpdateText();
};
}
#endregion
#region Property
public DatePickerModes DatePickerMode
{
get { return (DatePickerModes)GetValue(DatePickerModeProperty); }
set { SetValue(DatePickerModeProperty, value); }
}
public static readonly DependencyProperty DatePickerModeProperty =
DependencyProperty.Register("DatePickerMode", typeof(DatePickerModes), typeof(PUDateTimeSelector), new PropertyMetadata(DatePickerModes.DateTime));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(PUDateTimeSelector));
public Color ShadowColor
{
get { return (Color)GetValue(ShadowColorProperty); }
set { SetValue(ShadowColorProperty, value); }
}
public static readonly DependencyProperty ShadowColorProperty =
DependencyProperty.Register("ShadowColor", typeof(Color), typeof(PUDateTimeSelector));
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUDateTimeSelector));
public DateTime SelectedDateTime
{
get { return (DateTime)GetValue(SelectedDateTimeProperty); }
set { SetValue(SelectedDateTimeProperty, value); }
}
public static readonly DependencyProperty SelectedDateTimeProperty =
DependencyProperty.Register("SelectedDateTime", typeof(DateTime), typeof(PUDateTimeSelector), new PropertyMetadata(new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 0, 0, 0), OnSelectedDateTimeChanged));
private static void OnSelectedDateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var picker = d as PUDateTimeSelector;
picker.UpdateText();
}
public DateTime? MaxDate
{
get { return (DateTime?)GetValue(MaxDateProperty); }
set { SetValue(MaxDateProperty, value); }
}
public static readonly DependencyProperty MaxDateProperty =
DependencyProperty.Register("MaxDate", typeof(DateTime?), typeof(PUDateTimeSelector));
public DateTime? MinDate
{
get { return (DateTime?)GetValue(MinDateProperty); }
set { SetValue(MinDateProperty, value); }
}
public static readonly DependencyProperty MinDateProperty =
DependencyProperty.Register("MinDate", typeof(DateTime?), typeof(PUDateTimeSelector));
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(PUDateTimeSelector));
public object Icon
{
get { return (object)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(object), typeof(PUDateTimeSelector));
#endregion
#region Function
private void UpdateText()
{
switch (DatePickerMode)
{
case DatePickerModes.DateTime:
Text = SelectedDateTime.ToString("yyyy-MM-dd HH:mm:ss");
break;
case DatePickerModes.DateOnly:
Text = SelectedDateTime.ToString("yyyy-MM-dd");
break;
case DatePickerModes.TimeOnly:
Text = SelectedDateTime.ToString("HH:mm:ss");
break;
}
}
#endregion
}
}
================================================
FILE: Panuon.UI/9_Special/DropDown.cs
================================================
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace Panuon.UI
{
public class DropDown : ContentControl
{
static DropDown()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DropDown), new FrameworkPropertyMetadata(typeof(DropDown)));
}
#region Property
public Color ShadowColor
{
get { return (Color)GetValue(ShadowColorProperty); }
set { SetValue(ShadowColorProperty, value); }
}
public static readonly DependencyProperty ShadowColorProperty =
DependencyProperty.Register("ShadowColor", typeof(Color), typeof(DropDown));
public UIElement Child
{
get { return (UIElement)GetValue(ChildProperty); }
set { SetValue(ChildProperty, value); }
}
public static readonly DependencyProperty ChildProperty =
DependencyProperty.Register("Child", typeof(UIElement), typeof(DropDown));
public DropDownPlacement DropDownPlacement
{
get { return (DropDownPlacement)GetValue(DropDownPlacementProperty); }
set { SetValue(DropDownPlacementProperty, value); }
}
public static readonly DependencyProperty DropDownPlacementProperty =
DependencyProperty.Register("DropDownPlacement", typeof(DropDownPlacement), typeof(DropDown), new PropertyMetadata(DropDownPlacement.LeftBottom));
public double CornerRadius
{
get { return (double)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register("CornerRadius", typeof(double), typeof(DropDown));
public bool IsOpen
{
get { return (bool)GetValue(IsOpenProperty); }
set { SetValue(IsOpenProperty, value); }
}
public static readonly DependencyProperty IsOpenProperty =
DependencyProperty.Register("IsOpen", typeof(bool), typeof(DropDown));
#endregion
}
}
================================================
FILE: Panuon.UI/9_Special/PUCard.cs
================================================
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
public class PUCard : UserControl
{
#region Constructor
static PUCard()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUCard), new FrameworkPropertyMetadata(typeof(PUCard)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
AddHandler(PUButton.ClickEvent, new RoutedEventHandler(OnDetailButtonClicked));
}
private void OnDetailButtonClicked(object sender, RoutedEventArgs e)
{
var btnDetail = (sender as PUButton);
if (btnDetail == null || btnDetail.Tag == null || btnDetail.Tag.ToString() != "PART_Detail")
return;
OnDetail();
}
#endregion
#region RoutedEvent
///
/// 点击详情事件。
///
public static readonly RoutedEvent DetailEvent = EventManager.RegisterRoutedEvent("Detail", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUCard));
public event RoutedPropertyChangedEventHandler Detail
{
add { AddHandler(DetailEvent, value); }
remove { RemoveHandler(DetailEvent, value); }
}
internal void OnDetail()
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(this, this, DetailEvent);
RaiseEvent(arg);
}
#endregion
#region Property
///
/// 获取或设置是否显示详情按钮。默认值为False。
///
public bool IsDetailButtonShow
{
get { return (bool)GetValue(IsDetailButtonShowProperty); }
set { SetValue(IsDetailButtonShowProperty, value); }
}
public static readonly DependencyProperty IsDetailButtonShowProperty =
DependencyProperty.Register("IsDetailButtonShow", typeof(bool), typeof(PUCard));
///
/// 获取或设置标题的内容。默认值为Null。
///
public object Header
{
get { return (object)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(object), typeof(PUCard));
///
/// 获取或设置标题前的图标按钮。默认值为Null。
///
public object Icon
{
get { return (object)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(object), typeof(PUCard));
///
/// 获取或设置阴影颜色。默认值为透明。
///
public Color ShadowColor
{
get { return (Color)GetValue(ShadowColorProperty); }
set { SetValue(ShadowColorProperty, value); }
}
public static readonly DependencyProperty ShadowColorProperty =
DependencyProperty.Register("ShadowColor", typeof(Color), typeof(PUCard));
///
/// 获取或设置卡片的圆角大小。默认值为0。
///
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static readonly DependencyProperty BorderCornerRadiusProperty =
DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(PUCard));
///
/// 获取或设置卡片的标题高度(包含标题和详情按钮)。默认值为30。
///
public double HeaderHeight
{
get { return (double)GetValue(HeaderHeightProperty); }
set { SetValue(HeaderHeightProperty, value); }
}
public static readonly DependencyProperty HeaderHeightProperty =
DependencyProperty.Register("HeaderHeight", typeof(double), typeof(PUCard));
#endregion
}
}
================================================
FILE: Panuon.UI/9_Special/PUImageCuter.xaml
================================================
================================================
FILE: Panuon.UI/9_Special/PUImageCuter.xaml.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Panuon.UI
{
///
/// ImageCuter.xaml 的交互逻辑
///
public partial class PUImageCuter : UserControl
{
public PUImageCuter()
{
InitializeComponent();
}
#region Property
public BitmapImage ImageSource
{
get { return (BitmapImage)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(BitmapImage), typeof(PUImageCuter));
public ImageType ImageType
{
get { return (ImageType)GetValue(ImageTypeProperty); }
set { SetValue(ImageTypeProperty, value); }
}
public static readonly DependencyProperty ImageTypeProperty =
DependencyProperty.Register("ImageType", typeof(ImageType), typeof(PUImageCuter), new PropertyMetadata(ImageType.Rectangle, OnImageTypeChanged));
private static void OnImageTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var cuter = d as PUImageCuter;
cuter.ResizeContainer.IsSquare = cuter.ImageType == ImageType.Square;
}
public double ImageMinHeight
{
get { return (double)GetValue(ImageMinHeightProperty); }
set { SetValue(ImageMinHeightProperty, value); }
}
public static readonly DependencyProperty ImageMinHeightProperty =
DependencyProperty.Register("ImageMinHeight", typeof(double), typeof(PUImageCuter), new PropertyMetadata(50.0));
public double ImageMinWidth
{
get { return (double)GetValue(ImageMinWidthProperty); }
set { SetValue(ImageMinWidthProperty, value); }
}
public static readonly DependencyProperty ImageMinWidthProperty =
DependencyProperty.Register("ImageMinWidth", typeof(double), typeof(PUImageCuter), new PropertyMetadata(50.0));
public double ImageMaxHeight
{
get { return (double)GetValue(ImageMaxHeightProperty); }
set { SetValue(ImageMaxHeightProperty, value); }
}
public static readonly DependencyProperty ImageMaxHeightProperty =
DependencyProperty.Register("ImageMaxHeight", typeof(double), typeof(PUImageCuter), new PropertyMetadata(double.NaN));
public double ImageMaxWidth
{
get { return (double)GetValue(ImageMaxWidthProperty); }
set { SetValue(ImageMaxWidthProperty, value); }
}
public static readonly DependencyProperty ImageMaxWidthProperty =
DependencyProperty.Register("ImageMaxWidth", typeof(double), typeof(PUImageCuter), new PropertyMetadata(double.NaN));
#endregion
#region Event
private void Img_SizeChanged(object sender, SizeChangedEventArgs e)
{
var image = sender as Image;
CvaMain.Width = image.ActualWidth;
CvaMain.Height = image.ActualHeight;
CvaMain.Margin = new Thickness((ActualWidth - image.ActualWidth) / 2, (ActualHeight - image.ActualHeight) / 2, (ActualWidth - image.ActualWidth) / 2, (ActualHeight - image.ActualHeight) / 2);
ResizeContainer.Visibility = Visibility.Visible;
}
#endregion
#region APIs
public BitmapSource GetCutedImage()
{
if (ImageSource == null)
return null;
var widthScale = ImageSource.PixelWidth / CvaMain.ActualWidth;
var heightScale = ImageSource.PixelHeight / CvaMain.ActualHeight;
return new CroppedBitmap(BitmapFrame.Create(ImageSource), new Int32Rect((int)(Canvas.GetLeft(ResizeContainer) * widthScale), (int)(Canvas.GetTop(ResizeContainer) * heightScale), (int)(ResizeContainer.ActualWidth * widthScale), (int)(ResizeContainer.ActualHeight * heightScale)));
}
#endregion
}
}
================================================
FILE: Panuon.UI/9_Special/PUIndicator.xaml
================================================
================================================
FILE: Panuon.UI/9_Special/PUIndicator.xaml.cs
================================================
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace Panuon.UI
{
///
/// PUIndicator.xaml 的交互逻辑
///
public partial class PUIndicator : UserControl
{
public PUIndicator()
{
InitializeComponent();
Background = new SolidColorBrush(Colors.Transparent);
MouseEnter += delegate
{
var anima = new DoubleAnimation()
{
To = 1,
Duration = TimeSpan.FromSeconds(0.2),
};
this.BeginAnimation(OpacityProperty, anima);
};
MouseLeave += delegate
{
var anima = new DoubleAnimation()
{
To = 0.8,
Duration = TimeSpan.FromSeconds(0.2),
};
this.BeginAnimation(OpacityProperty, anima);
};
}
#region RoutedEvent
///
/// 索引变更事件。
///
public static readonly RoutedEvent IndexChangedEvent = EventManager.RegisterRoutedEvent("IndexChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUIndicator));
public event RoutedPropertyChangedEventHandler IndexChanged
{
add { AddHandler(IndexChangedEvent, value); }
remove { RemoveHandler(IndexChangedEvent, value); }
}
internal void OnIndexChanged(int oldValue, int newValue)
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(oldValue, newValue, IndexChangedEvent);
RaiseEvent(arg);
}
#endregion
#region Property
///
/// 排列方式,默认值为Horizontal(横向)。
/// 若排列方式为横向,需要设置控件的Height属性来计算球体大小;若排列方式为纵向,则需要设置控件的Width属性来计算球体大小。
///
public Orientation Dircetion
{
get { return (Orientation)GetValue(DircetionProperty); }
set { SetValue(DircetionProperty, value); }
}
public static readonly DependencyProperty DircetionProperty =
DependencyProperty.Register("Dircetion", typeof(Orientation), typeof(PUIndicator), new PropertyMetadata(Orientation.Horizontal, OnDircetionDircetionChanged));
private static void OnDircetionDircetionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var indicator = d as PUIndicator;
indicator.StkMain.Orientation = indicator.Dircetion;
}
///
/// 指示小球的颜色,默认值为灰色。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUIndicator), new PropertyMetadata(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#666666"))));
///
/// 索引总数。 默认值为1,最小值为1。
///
public int TotalIndex
{
get { return (int)GetValue(TotalIndexProperty); }
set { SetValue(TotalIndexProperty, value); }
}
public static readonly DependencyProperty TotalIndexProperty =
DependencyProperty.Register("TotalIndex", typeof(int), typeof(PUIndicator), new PropertyMetadata(1));
///
/// 当前索引。默认值为1,最小值为1。
///
public int Index
{
get { return (int)GetValue(IndexProperty); }
set { SetValue(IndexProperty, value); }
}
public static readonly DependencyProperty IndexProperty =
DependencyProperty.Register("Index", typeof(int), typeof(PUIndicator), new PropertyMetadata(1, OnIndexChanged));
private static void OnIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var indicator = d as PUIndicator;
indicator.OnIndexChanged((int?)e.OldValue ?? 0, (int?)e.NewValue ?? 0);
if (!indicator.IsLoaded)
return;
indicator.ChangeIndex(true);
}
///
/// 左右滑动动画的持续时间(单位:毫秒),若为0,则滑动时不使用动画。默认值为500毫秒。
///
public int AnimationDuration
{
get { return (int)GetValue(AnimationDurationProperty); }
set { SetValue(AnimationDurationProperty, value); }
}
public static readonly DependencyProperty AnimationDurationProperty =
DependencyProperty.Register("AnimationDuration", typeof(int), typeof(PUIndicator), new PropertyMetadata(0));
#endregion
#region Private APIs
private void Draw()
{
if (TotalIndex < 1)
TotalIndex = 1;
var radius = 0.0;
if (Dircetion == Orientation.Horizontal)
radius = this.ActualHeight;
else
radius = this.ActualWidth;
StkMain.Children.Clear();
EllIndicator.Height = (int)(radius * 0.6);
EllIndicator.Width = (int)(radius * 0.6);
EllIndicator.Background = CoverBrush;
EllIndicator.CornerRadius = new CornerRadius(EllIndicator.Height / 2);
if (Dircetion == Orientation.Horizontal)
EllIndicator.Margin = new Thickness((radius - ((int)(radius * 0.6))) / 2, EllIndicator.Height / 2, 0, 0);
else
EllIndicator.Margin = new Thickness(EllIndicator.Height / 2, (radius - ((int)(radius * 0.6))) / 2, 0, 0);
EllIndicator.Opacity = 0.8;
EllIndicator.MouseEnter += delegate
{
var anima = new DoubleAnimation()
{
To = 1,
Duration = TimeSpan.FromSeconds(0.2),
};
EllIndicator.BeginAnimation(OpacityProperty, anima);
};
EllIndicator.MouseLeave += delegate
{
var anima = new DoubleAnimation()
{
To = 0.8,
Duration = TimeSpan.FromSeconds(0.2),
};
EllIndicator.BeginAnimation(OpacityProperty, anima);
};
for (int i = 1; i <= TotalIndex; i++)
{
var ellipse = new Border()
{
Margin = Dircetion == Orientation.Horizontal ? new Thickness(0, 0, (int)(radius * 0.3), 0) : new Thickness(0, 0, 0, (int)(radius * 0.3)),
Height = (int)radius,
Width = (int)radius,
CornerRadius = new CornerRadius(radius / 2),
BorderBrush = BorderBrush,
Background = new SolidColorBrush(Colors.Transparent),
BorderThickness = new Thickness(1),
Opacity = 0.6,
Tag = i,
Cursor = Cursors.Hand,
};
ellipse.MouseEnter += delegate
{
var anima = new DoubleAnimation()
{
To = 1,
Duration = TimeSpan.FromSeconds(0.2),
};
ellipse.BeginAnimation(OpacityProperty, anima);
};
ellipse.MouseLeave += delegate
{
var anima = new DoubleAnimation()
{
To = 0.6,
Duration = TimeSpan.FromSeconds(0.2),
};
ellipse.BeginAnimation(OpacityProperty, anima);
};
ellipse.MouseLeftButtonDown += delegate
{
Index = (int)ellipse.Tag;
};
StkMain.Children.Add(ellipse);
}
}
private void ChangeIndex(bool usingAnima)
{
var radius = 0.0;
if (Dircetion == Orientation.Horizontal)
radius = this.ActualHeight;
else
radius = this.ActualWidth;
var left = (Index - 1) * ((int)(radius * 1.3)) + (radius - ((int)(radius * 0.6))) / 2;
if (!usingAnima || AnimationDuration == 0)
{
if(Dircetion == Orientation.Horizontal)
EllIndicator.Margin = new Thickness(left, radius * 0.2, 0, 0);
else
EllIndicator.Margin = new Thickness(radius * 0.2, left, 0, 0);
}
else
{
if (Dircetion == Orientation.Horizontal)
{
var anima = new ThicknessAnimation()
{
To = new Thickness(left, radius * 0.2, 0, 0),
Duration = TimeSpan.FromMilliseconds(AnimationDuration),
EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseInOut },
};
EllIndicator.BeginAnimation(MarginProperty, anima);
}
else
{
var anima = new ThicknessAnimation()
{
To = new Thickness(radius * 0.2, left, 0, 0),
Duration = TimeSpan.FromMilliseconds(AnimationDuration),
EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseInOut },
};
EllIndicator.BeginAnimation(MarginProperty, anima);
}
}
}
#endregion
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
Draw();
ChangeIndex(false);
}
}
}
================================================
FILE: Panuon.UI/9_Special/PULoading.xaml
================================================
================================================
FILE: Panuon.UI/9_Special/PULoading.xaml.cs
================================================
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace Panuon.UI
{
///
/// Loading.xaml 的交互逻辑
///
public partial class PULoading : UserControl
{
private Storyboard _storyboard;
public PULoading()
{
InitializeComponent();
Loaded += PULoading_Loaded;
}
private void PULoading_Loaded(object sender, RoutedEventArgs e)
{
if (IsRunning)
Draw();
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
}
#region Property
public bool IsRunning
{
get { return (bool)GetValue(IsRunningProperty); }
set { SetValue(IsRunningProperty, value); }
}
public static readonly DependencyProperty IsRunningProperty = DependencyProperty.Register("IsRunning", typeof(bool), typeof(PULoading), new PropertyMetadata(false, OnIsRunningChanged));
private static void OnIsRunningChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var load = d as PULoading;
if (!load.IsLoaded)
return;
var run = (bool)e.NewValue;
if (run)
load.Draw();
else
load.Clear();
}
#endregion
#region Internal APIs
internal void Draw()
{
_storyboard = new Storyboard()
{
RepeatBehavior = RepeatBehavior.Forever,
};
double canvasHeight = 0;
if (double.IsNaN(Height))
{
if (ActualHeight == 0)
{
return;
}
else
{
canvasHeight = ActualHeight;
}
}
else
{
canvasHeight = this.Height;
}
var ellipseHeight = canvasHeight * 0.1;
var rollHeight = canvasHeight * 0.75;
var rollRadius = rollHeight / 2;
for (int i = 0; i < 6; i++)
{
var ellipse = new Ellipse()
{
Fill = Foreground,
Width = ellipseHeight,
Height = ellipseHeight,
Margin = new Thickness(-ellipseHeight / 2, -ellipseHeight / 2, 0, 0),
Opacity = 0,
};
Canvas.SetTop(ellipse, canvasHeight * 0.125);
Canvas.SetLeft(ellipse, canvasHeight / 2);
var path = $"M{canvasHeight / 2},{canvasHeight * 0.125} A {rollRadius},{rollRadius} 0 0 1 {canvasHeight / 2},{rollHeight + canvasHeight * 0.125} A {rollRadius},{rollRadius} 0 0 1 {canvasHeight / 2},{canvasHeight * 0.125} A {rollRadius},{rollRadius} 0 0 1 {canvasHeight / 2},{rollHeight + canvasHeight * 0.125} A {rollRadius},{rollRadius} 0 0 1 {canvasHeight / 2},{canvasHeight * 0.125}";
var anima1 = GetDoubleAnimation(1, (i + i * 0.3) * 0.1, 0.01);
Storyboard.SetTarget(anima1, ellipse);
Storyboard.SetTargetProperty(anima1, new PropertyPath("Opacity"));
_storyboard.Children.Add(anima1);
var animaX = GetDoubleAnimationUsingPath(path, (i + i * 0.3) * 0.1, 1.5, PathAnimationSource.X);
Storyboard.SetTarget(animaX, ellipse);
Storyboard.SetTargetProperty(animaX, new PropertyPath("(Canvas.Left)"));
_storyboard.Children.Add(animaX);
var animaY = GetDoubleAnimationUsingPath(path, (i + i * 0.3) * 0.1, 1.5, PathAnimationSource.Y);
Storyboard.SetTarget(animaY, ellipse);
Storyboard.SetTargetProperty(animaY, new PropertyPath("(Canvas.Top)"));
_storyboard.Children.Add(animaY);
var anima2 = GetDoubleAnimation(0, 1.05 + 0.1 * i, 0.5);
Storyboard.SetTarget(anima2, ellipse);
Storyboard.SetTargetProperty(anima2, new PropertyPath("Opacity"));
_storyboard.Children.Add(anima2);
cvaMain.Children.Add(ellipse);
}
_storyboard.Begin();
}
internal void Clear()
{
_storyboard.Stop();
cvaMain.Children.Clear();
}
#endregion
#region Function
private DoubleAnimation GetDoubleAnimation(double to, double beginTime, double duration, IEasingFunction easingFunction = null)
{
return new DoubleAnimation()
{
To = to,
BeginTime = TimeSpan.FromSeconds(beginTime),
Duration = TimeSpan.FromSeconds(duration),
EasingFunction = easingFunction,
};
}
private DoubleAnimationUsingPath GetDoubleAnimationUsingPath(string path, double beginTime, double duration, PathAnimationSource source)
{
return new DoubleAnimationUsingPath()
{
BeginTime = TimeSpan.FromSeconds(beginTime),
PathGeometry = Geometry.Parse(path).GetFlattenedPathGeometry(),
Duration = TimeSpan.FromSeconds(duration),
Source = source,
};
}
#endregion
}
}
================================================
FILE: Panuon.UI/9_Special/PUMessageBox.xaml
================================================
================================================
FILE: Panuon.UI/9_Special/PUMessageBox.xaml.cs
================================================
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
namespace Panuon.UI
{
///
/// PUMessageBox.xaml 的交互逻辑
///
public partial class PUMessageBox : UI.PUWindow
{
#region Identity
RoutedEventHandler _cancel;
static PUMessageBox _instance;
#endregion
private PUMessageBox(string title, string content, bool isConfirm, bool showInTaskBar, AnimationStyles animateStyle)
{
InitializeComponent();
Title = title;
txtContent.Text = content;
if (isConfirm)
{
groupTip.Visibility = Visibility.Collapsed;
groupConfirm.Visibility = Visibility.Visible;
}
ShowInTaskbar = showInTaskBar;
AnimationStyle = animateStyle;
if(Owner != null)
{
WindowStartupLocation = WindowStartupLocation.CenterOwner;
}
}
#region APIs
///
/// 打开一个消息提示对话框,并打开父窗体的遮罩层。
///
/// 要显示的内容。
/// 标题内容。
/// 按钮内容,默认为“好”
/// 是否在任务栏中显示,默认为True。
public static void ShowDialog(string content, string title = "提示", Buttons buttons = Buttons.Sure, bool showInTaskBar = true, AnimationStyles animateStyle = AnimationStyles.Scale)
{
var mbox = new PUMessageBox(title, content, false, showInTaskBar, animateStyle);
mbox.CheckButtonContent(buttons);
if (!showInTaskBar)
mbox.ShowInTaskbar = false;
mbox.ShowDialog();
}
///
/// 打开一个消息确认对话框,并打开父窗体的遮罩层。
///
/// 要显示的内容。
/// 标题内容。
/// 按钮内容,默认为“是/否”
/// 是否在任务栏中显示,默认为True。
public static bool? ShowConfirm(string content, string title = "提示", Buttons buttons = Buttons.YesOrNo, bool showInTaskBar = true, AnimationStyles animateStyle = AnimationStyles.Scale)
{
var mbox = new PUMessageBox(title, content, true, showInTaskBar, animateStyle);
mbox.CheckButtonContent(buttons);
if (!showInTaskBar)
mbox.ShowInTaskbar = false;
mbox.ShowDialog();
return mbox.DialogResult;
}
///
/// 打开一个等待界面,并打开父窗体的遮罩层。该界面将以Show的方式打开,但用户不能使用Alt+F4强制关闭此页面。若要关闭此界面,请调用PUMessageBox.CloseAwait()方法。
///
/// 要显示的内容
public static void ShowAwait(string content)
{
var mbox = new PUMessageBox("", "", false, false, AnimationStyles.Scale);
mbox.AllowForcingClose = false;
_instance = mbox;
mbox.txtAwait.Text = content;
mbox.btnOK.IsEnabled = false;
mbox.CheckButtonContent(Buttons.Cancel);
mbox.Topmost = true;
mbox.loading.IsRunning = true;
mbox.grdAwait.Visibility = Visibility.Visible;
mbox.Show();
}
///
/// 打开一个等待界面,并打开父窗体的遮罩层。该界面将以Show的方式打开,但用户不能使用Alt+F4强制关闭此页面。若要关闭此界面,请调用PUMessageBox.CloseAwait()方法。
///
/// 要显示的内容
/// 若允许用户取消等待,则必须指定点击取消按钮后的后续处理。用户点击了取消按钮,该窗体需要您手动关闭。若不指定后续处理,取消按钮将被禁用。
public static void ShowAwait(string content, RoutedEventHandler cancelCallback = null)
{
var mbox = new PUMessageBox("", "", false, false, AnimationStyles.Scale);
mbox.AllowForcingClose = false;
_instance = mbox;
mbox.txtAwait.Text = content;
mbox.CheckButtonContent(Buttons.Cancel);
mbox._cancel = cancelCallback;
mbox.Topmost = true;
mbox.loading.IsRunning = true;
mbox.grdAwait.Visibility = Visibility.Visible;
mbox.Show();
}
///
/// 打开一个等待界面,并打开父窗体的遮罩层。该界面将以Show的方式打开,但用户不能使用Alt+F4强制关闭此页面。若要关闭此界面,请调用PUMessageBox.CloseAwait()方法。
///
/// 要显示的内容
/// 标题内容。
/// 若允许用户取消等待,则必须指定点击取消按钮后的后续处理。用户点击了取消按钮,该窗体需要您手动关闭。若不指定后续处理,取消按钮将被禁用。
public static void ShowAwait(string content, string title = "提示", RoutedEventHandler cancelCallback = null, AnimationStyles animateStyle = AnimationStyles.Scale)
{
var mbox = new PUMessageBox(title, "", false, false, animateStyle);
mbox.AllowForcingClose = false;
_instance = mbox;
mbox.CheckButtonContent(Buttons.Cancel);
mbox._cancel = cancelCallback;
mbox.Topmost = true;
mbox.grdAwait.Visibility = Visibility.Visible;
mbox.loading.IsRunning = true;
mbox.txtAwait.Text = content;
mbox.Show();
}
///
/// 尝试关闭最后打开的一个等待界面。
/// 若要在其关闭之后立即打开另一个PUMessageBox,请使用另一个重载方法,或等待400ms后再打开。
///
public static void CloseAwait()
{
if (_instance != null)
{
_instance.Closed += delegate
{
_instance = null;
};
_instance.Close();
}
}
///
/// 尝试关闭最后打开的一个等待界面。
/// 若要关闭之后立即打开另一个PUMessageBox,请指定关闭事件后的回调处理。
///
public static void CloseAwait(EventHandler closedCallback)
{
if (_instance != null)
{
_instance.Closed += delegate
{
_instance = null;
closedCallback(null, null);
};
_instance.Close();
}
}
#endregion
#region Sys
private void CheckButtonContent(Buttons buttons)
{
switch (buttons)
{
case Buttons.Sure:
btnOK.Content = "好";
break;
case Buttons.Yes:
btnOK.Content = "是";
break;
case Buttons.OK:
btnOK.Content = "确定";
break;
case Buttons.Cancel:
btnOK.Content = "取消";
break;
case Buttons.YesOrNo:
BtnYes.Content = "是";
BtnNo.Content = "否";
break;
case Buttons.YesOrCancel:
BtnYes.Content = "是";
BtnNo.Content = "取消";
break;
case Buttons.OKOrCancel:
BtnYes.Content = "确定";
BtnNo.Content = "取消";
break;
case Buttons.AcceptOrRefused:
BtnYes.Content = "接受";
BtnNo.Content = "拒绝";
break;
case Buttons.AcceptOrCancel:
BtnYes.Content = "接受";
BtnNo.Content = "取消";
break;
}
}
private void PUButton_Click(object sender, RoutedEventArgs e)
{
if (_cancel != null)
{
txtAwait.Text = "正在取消";
btnOK.IsEnabled = false;
loading.IsRunning = false;
_cancel(null, null);
}
else
{
Close();
}
}
private void PUButtonYes_Click(object sender, RoutedEventArgs e)
{
DialogResult = true;
}
private void PUButtonNo_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
}
#endregion
}
}
================================================
FILE: Panuon.UI/9_Special/PUSlideShow.xaml
================================================
================================================
FILE: Panuon.UI/9_Special/PUSlideShow.xaml.cs
================================================
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace Panuon.UI
{
///
/// PUSlideShow.xaml 的交互逻辑
///
[ContentProperty(nameof(Content))]
public partial class PUSlideShow : UserControl
{
#region Identity
private bool isFirstTime = true;
#endregion
public PUSlideShow()
{
InitializeComponent();
Content = PART_STKMAIN.Children;
PART_INDICATOR.IndexChanged += delegate
{
Index = PART_INDICATOR.Index;
};
if (Index == 1 && !Recyclable)
PART_BTNLEFT.IsEnabled = false;
else
PART_BTNLEFT.IsEnabled = true;
if (Index == Content.Count && !Recyclable)
PART_BTNRIGHT.IsEnabled = false;
else
PART_BTNRIGHT.IsEnabled = true;
PART_INDICATOR.AnimationDuration = AnimationDuration;
}
#region Property
public new UIElementCollection Content
{
get { return (UIElementCollection)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public new static readonly DependencyProperty ContentProperty =
DependencyProperty.Register("Content", typeof(UIElementCollection), typeof(PUSlideShow), new PropertyMetadata(OnContentChanged));
private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var slideShow = d as PUSlideShow;
if (!slideShow.IsLoaded || slideShow.Content == null)
return;
slideShow.Draw();
slideShow.PART_INDICATOR.TotalIndex = slideShow.Content.Count;
}
///
/// 索引,表示当前的位置。从1开始。
/// 当你试图将Index的值设置为大于Content数量上限或小于1的数字时,Index会被重设为Content的数量或1
/// (若Recyclable为True,则会被重设为1或Content的数量)。
///
public int Index
{
get { return (int)GetValue(IndexProperty); }
set { SetValue(IndexProperty, value); }
}
public static readonly DependencyProperty IndexProperty =
DependencyProperty.Register("Index", typeof(int), typeof(PUSlideShow), new PropertyMetadata(1, OnIndexChanged));
private static void OnIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var slideShow = d as PUSlideShow;
if (!slideShow.IsLoaded || slideShow.Content == null)
return;
slideShow.PART_INDICATOR.Index = slideShow.Index;
slideShow.ChangeIndex();
}
///
/// 滑动方向。默认值为Horizontal(横向)。
///
public Orientation SlideDirection
{
get { return (Orientation)GetValue(SlideDirectionProperty); }
set { SetValue(SlideDirectionProperty, value); }
}
public static readonly DependencyProperty SlideDirectionProperty =
DependencyProperty.Register("SlideDirection", typeof(Orientation), typeof(PUSlideShow), new PropertyMetadata(Orientation.Horizontal, OnSlideDirectionChanged));
private static void OnSlideDirectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var slideShow = d as PUSlideShow;
slideShow.PART_STKMAIN.Orientation = slideShow.SlideDirection;
if (slideShow.SlideDirection == Orientation.Horizontal)
{
slideShow.PART_BTNLEFT.Content = "";
slideShow.PART_BTNRIGHT.Content = "";
slideShow.PART_BTNLEFT.VerticalAlignment = VerticalAlignment.Center;
slideShow.PART_BTNLEFT.HorizontalAlignment = HorizontalAlignment.Left;
slideShow.PART_BTNRIGHT.VerticalAlignment = VerticalAlignment.Center;
slideShow.PART_BTNRIGHT.HorizontalAlignment = HorizontalAlignment.Right;
slideShow.PART_BTNLEFT.Margin = new Thickness(20, 0, 0, 0);
slideShow.PART_BTNRIGHT.Margin = new Thickness(0, 0, 20, 0);
slideShow.PART_INDICATOR.Dircetion = Orientation.Horizontal;
slideShow.PART_INDICATOR.Height = 15;
slideShow.PART_INDICATOR.Width = double.NaN;
slideShow.PART_INDICATOR.VerticalAlignment = VerticalAlignment.Bottom;
slideShow.PART_INDICATOR.HorizontalAlignment = HorizontalAlignment.Center;
slideShow.PART_INDICATOR.Margin = new Thickness(0, 0, 0, 20);
}
else
{
slideShow.PART_BTNLEFT.Content = "";
slideShow.PART_BTNRIGHT.Content = "";
slideShow.PART_BTNLEFT.VerticalAlignment = VerticalAlignment.Top;
slideShow.PART_BTNLEFT.HorizontalAlignment = HorizontalAlignment.Center;
slideShow.PART_BTNRIGHT.VerticalAlignment = VerticalAlignment.Bottom;
slideShow.PART_BTNRIGHT.HorizontalAlignment = HorizontalAlignment.Center;
slideShow.PART_BTNLEFT.Margin = new Thickness(0, 20, 0, 0);
slideShow.PART_BTNRIGHT.Margin = new Thickness(0, 0, 0, 20);
slideShow.PART_INDICATOR.Dircetion = Orientation.Vertical;
slideShow.PART_INDICATOR.Height = double.NaN;
slideShow.PART_INDICATOR.Width =15 ;
slideShow.PART_INDICATOR.VerticalAlignment = VerticalAlignment.Center;
slideShow.PART_INDICATOR.HorizontalAlignment = HorizontalAlignment.Left;
slideShow.PART_INDICATOR.Margin = new Thickness(20, 0, 0, 0);
}
}
///
/// 是否显示左右滑动按钮。
///
public bool IsSlideButtonShow
{
get { return (bool)GetValue(IsSlideButtonShowProperty); }
set { SetValue(IsSlideButtonShowProperty, value); }
}
public static readonly DependencyProperty IsSlideButtonShowProperty =
DependencyProperty.Register("IsSlideButtonShow", typeof(bool), typeof(PUSlideShow), new PropertyMetadata(true, OnIsSlideButtonShowChanged));
private static void OnIsSlideButtonShowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var slideShow = d as PUSlideShow;
if (slideShow.IsSlideButtonShow)
{
slideShow.PART_BTNLEFT.Visibility = Visibility.Visible;
slideShow.PART_BTNRIGHT.Visibility = Visibility.Visible;
}
else
{
slideShow.PART_BTNLEFT.Visibility = Visibility.Collapsed;
slideShow.PART_BTNRIGHT.Visibility = Visibility.Collapsed;
}
}
///
/// 滑动按钮的颜色,默认为灰黑色。
///
public Brush SlideButtonBrush
{
get { return (Brush)GetValue(SlideButtonBrushProperty); }
set { SetValue(SlideButtonBrushProperty, value); }
}
public static readonly DependencyProperty SlideButtonBrushProperty =
DependencyProperty.Register("SlideButtonBrush", typeof(Brush), typeof(PUSlideShow), new PropertyMetadata(OnSlideButtonBrushChanged));
private static void OnSlideButtonBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var slideShow = d as PUSlideShow;
if (slideShow.SlideButtonBrush != null)
{
slideShow.PART_BTNLEFT.Foreground = slideShow.SlideButtonBrush;
slideShow.PART_BTNLEFT.Background = slideShow.SlideButtonBrush;
slideShow.PART_BTNLEFT.CoverBrush = slideShow.SlideButtonBrush;
slideShow.PART_BTNRIGHT.Foreground = slideShow.SlideButtonBrush;
slideShow.PART_BTNRIGHT.Background = slideShow.SlideButtonBrush;
slideShow.PART_BTNRIGHT.CoverBrush = slideShow.SlideButtonBrush;
}
}
///
/// 左右滑动动画的持续时间(单位:毫秒),若为0,则滑动时不使用动画。默认值为500毫秒。
///
public int AnimationDuration
{
get { return (int)GetValue(AnimationDurationProperty); }
set { SetValue(AnimationDurationProperty, value); }
}
public static readonly DependencyProperty AnimationDurationProperty =
DependencyProperty.Register("AnimationDuration", typeof(int), typeof(PUSlideShow), new PropertyMetadata(500, OnAnimationDurationChanged));
private static void OnAnimationDurationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var slideShow = d as PUSlideShow;
slideShow.PART_INDICATOR.AnimationDuration = slideShow.AnimationDuration;
}
///
/// 是否允许滑动无限循环。
///
public bool Recyclable
{
get { return (bool)GetValue(RecyclableProperty); }
set { SetValue(RecyclableProperty, value); }
}
public static readonly DependencyProperty RecyclableProperty =
DependencyProperty.Register("Recyclable", typeof(bool), typeof(PUSlideShow), new PropertyMetadata(false));
///
/// 是否显示指示器。
///
public bool IsIndicatorShow
{
get { return (bool)GetValue(IsIndicatorShowProperty); }
set { SetValue(IsIndicatorShowProperty, value); }
}
public static readonly DependencyProperty IsIndicatorShowProperty =
DependencyProperty.Register("IsIndicatorShow", typeof(bool), typeof(PUSlideShow), new PropertyMetadata(true, OnIsIndicatorShowChanged));
private static void OnIsIndicatorShowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var slide = d as PUSlideShow;
if (slide.IsIndicatorShow)
slide.PART_INDICATOR.Visibility = Visibility.Visible;
else
slide.PART_INDICATOR.Visibility = Visibility.Hidden;
}
///
/// 指示器颜色。
///
public Brush IndicatorBrush
{
get { return (Brush)GetValue(IndicatorBrushProperty); }
set { SetValue(IndicatorBrushProperty, value); }
}
public static readonly DependencyProperty IndicatorBrushProperty =
DependencyProperty.Register("IndicatorBrush", typeof(Brush), typeof(PUSlideShow), new PropertyMetadata(new SolidColorBrush(Colors.DimGray), OnIndicatorBrushChanged));
private static void OnIndicatorBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var slideShow = d as PUSlideShow;
slideShow.PART_INDICATOR.BorderBrush = slideShow.IndicatorBrush;
slideShow.PART_INDICATOR.CoverBrush = slideShow.IndicatorBrush;
}
#endregion
#region APIs
private void Draw()
{
PART_INDICATOR.TotalIndex = Content.Count;
foreach (var item in Content)
{
var grid = item as FrameworkElement;
grid.Width = ActualWidth;
grid.Height = ActualHeight;
}
}
private void ChangeIndex()
{
if (Index < 1)
{
if (!Recyclable)
{
Index = 1;
return;
}
else
{
Index = Content.Count;
return;
}
}
else if (Index > Content.Count)
{
if (!Recyclable)
{
Index = Content.Count;
return;
}
else
{
Index = 1;
return;
}
}
if (Index == 1 && !Recyclable)
PART_BTNLEFT.IsEnabled = false;
else
PART_BTNLEFT.IsEnabled = true;
if (Index == Content.Count && !Recyclable)
PART_BTNRIGHT.IsEnabled = false;
else
PART_BTNRIGHT.IsEnabled = true;
if (isFirstTime || AnimationDuration == 0)
{
if (SlideDirection == Orientation.Horizontal)
PART_STKMAIN.Margin = new Thickness(-1 * (Index - 1) * ActualWidth, 0, 0, 0);
else
PART_STKMAIN.Margin = new Thickness(0, -1 * (Index - 1) * ActualHeight, 0, 0);
}
else
{
if (SlideDirection == Orientation.Horizontal)
{
var anima = new ThicknessAnimation()
{
To = new Thickness(-1 * (Index - 1) * ActualWidth, 0, 0, 0),
Duration = TimeSpan.FromMilliseconds(AnimationDuration),
EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseInOut },
};
PART_STKMAIN.BeginAnimation(MarginProperty, anima);
}
else
{
var anima = new ThicknessAnimation()
{
To = new Thickness(0, -1 * (Index - 1) * ActualHeight, 0, 0),
Duration = TimeSpan.FromMilliseconds(AnimationDuration),
EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseInOut },
};
PART_STKMAIN.BeginAnimation(MarginProperty, anima);
}
}
isFirstTime = false;
}
#endregion
#region Sys
private void BtnLeft_Click(object sender, RoutedEventArgs e)
{
Index--;
}
private void BtnRight_Click(object sender, RoutedEventArgs e)
{
Index++;
}
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
Draw();
ChangeIndex();
}
#endregion
}
}
================================================
FILE: Panuon.UI/9_Special/PUSplitLine.cs
================================================
using System.Windows;
using System.Windows.Controls;
namespace Panuon.UI
{
public class PUSplitLine : Control
{
static PUSplitLine()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUSplitLine), new FrameworkPropertyMetadata(typeof(PUSplitLine)));
}
#region Property
///
/// 分割线的停靠方向,默认为Bottom(底部)。
///
public Alignments Alignment
{
get { return (Alignments)GetValue(AlignmentProperty); }
set { SetValue(AlignmentProperty, value); }
}
public static readonly DependencyProperty AlignmentProperty =
DependencyProperty.Register("Alignment", typeof(Alignments), typeof(PUSplitLine), new PropertyMetadata(Alignments.Bottom));
public enum Alignments
{
Left,Top,Right,Bottom
}
#endregion
}
}
================================================
FILE: Panuon.UI/A0_TreeView/PUTreeView.cs
================================================
using Panuon.UI.Utils;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
public class PUTreeView : TreeView
{
static PUTreeView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUTreeView), new FrameworkPropertyMetadata(typeof(PUTreeView)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
}
#region Event
///
/// 选择了新项目事件。
///
public static readonly RoutedEvent ChoosedItemChangedEvent = EventManager.RegisterRoutedEvent("ChoosedItemChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUTreeView));
public event RoutedPropertyChangedEventHandler ChoosedItemChanged
{
add { AddHandler(ChoosedItemChangedEvent, value); }
remove { RemoveHandler(ChoosedItemChangedEvent, value); }
}
internal void OnChoosedItemChanged(PUTreeViewItem oldItem, PUTreeViewItem newItem)
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(oldItem, newItem, ChoosedItemChangedEvent); RaiseEvent(arg);
}
#endregion
#region Property
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("该属性对此控件无效。请使用BindingItems属性替代。", true)]
public new IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
private set { SetValue(ItemsSourceProperty, value); }
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("该属性对此控件无效。请该用ChoosedValuePath属性替代。", true)]
public new string SelectedValuePath
{
get { return base.SelectedValuePath; }
private set { base.SelectedValuePath = value; }
}
[EditorBrowsable(EditorBrowsableState.Never)]
[ObsoleteAttribute("该属性对此控件无效。请该用ChoosedValue属性替代。", true)]
public new object SelectedValue
{
get { return base.SelectedValue; }
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("该属性对此控件无效。BindingItems属性中的Header属性即为要显示的内容。", true)]
public new string DisplayMemberPath
{
get { return base.DisplayMemberPath; }
private set { base.DisplayMemberPath = value; }
}
///
/// 获取或设置树视图的基本样式,默认值为General。
///
public TreeViewStyles TreeViewStyle
{
get { return (TreeViewStyles)GetValue(TreeViewStyleProperty); }
set { SetValue(TreeViewStyleProperty, value); }
}
public static readonly DependencyProperty TreeViewStyleProperty =
DependencyProperty.Register("TreeViewStyle", typeof(TreeViewStyles), typeof(PUTreeView), new PropertyMetadata(TreeViewStyles.General));
///
/// 获取或设置子项目的单行元素高度,默认值为40。
///
public double InnerHeight
{
get { return (double)GetValue(InnerHeightProperty); }
set { SetValue(InnerHeightProperty, value); }
}
public static readonly DependencyProperty InnerHeightProperty =
DependencyProperty.Register("InnerHeight", typeof(double), typeof(PUTreeView), new PropertyMetadata((double)40));
///
/// 获取或设置鼠标悬浮时遮罩层的背景颜色,默认值为#22666666。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUTreeView));
///
/// 鼠标悬浮时遮罩层的背景颜色,默认值为#44666666。
///
public Brush ChoosedBrush
{
get { return (Brush)GetValue(ChoosedBrushProperty); }
set { SetValue(ChoosedBrushProperty, value); }
}
public static readonly DependencyProperty ChoosedBrushProperty =
DependencyProperty.Register("ChoosedBrush", typeof(Brush), typeof(PUTreeView));
///
/// 获取被选中的元素。
///
public PUTreeViewItem ChoosedItem
{
get { return (PUTreeViewItem)GetValue(ChoosedItemProperty); }
internal set { SetValue(ChoosedItemProperty, value); }
}
public static readonly DependencyProperty ChoosedItemProperty =
DependencyProperty.Register("ChoosedItem", typeof(PUTreeViewItem), typeof(PUTreeView), new PropertyMetadata(OnChoosedItemChanged));
private static void OnChoosedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var treeView = d as PUTreeView;
if (treeView.ChoosedItem == null)
{
treeView.ChoosedValue = null;
}
else
{
var value = treeView.ChoosedValuePath == ChoosedValuePaths.Header ? treeView.ChoosedItem.Header : treeView.ChoosedItem.Value;
if (treeView.ChoosedValue != value)
{
treeView.isInternalSetChoosedValue = true;
treeView.ChoosedValue = value;
}
}
treeView.OnChoosedItemChanged(e.OldValue as PUTreeViewItem, e.NewValue as PUTreeViewItem);
}
///
/// 获取或设置是否需要展开父项的方式,默认为Click。
///
public ExpandModes ExpandMode
{
get { return (ExpandModes)GetValue(ExpandModeProperty); }
set { SetValue(ExpandModeProperty, value); }
}
public static readonly DependencyProperty ExpandModeProperty =
DependencyProperty.Register("ExpandMode", typeof(ExpandModes), typeof(PUTreeView), new PropertyMetadata(ExpandModes.Click));
///
/// 该属性指定了当子项目被选中时,ChoosedValue应呈现子项目的哪一个值。
/// 可选项为Header或Value,默认值为Header。
///
public ChoosedValuePaths ChoosedValuePath
{
get { return (ChoosedValuePaths)GetValue(ChoosedValuePathProperty); }
set { SetValue(ChoosedValuePathProperty, value); }
}
public static readonly DependencyProperty ChoosedValuePathProperty =
DependencyProperty.Register("ChoosedValuePath", typeof(ChoosedValuePaths), typeof(PUTreeView), new PropertyMetadata(ChoosedValuePaths.Header));
///
/// 获取被选中PUTreeViewItem的Header或Value属性(这取决于SelectedValuePath),
/// 或根据设置的ChoosedValue来选中子项目。
///
public object ChoosedValue
{
get { return (object)GetValue(ChoosedValueProperty); }
set { SetValue(ChoosedValueProperty, value); }
}
public static readonly DependencyProperty ChoosedValueProperty =
DependencyProperty.Register("ChoosedValue", typeof(object), typeof(PUTreeView), new PropertyMetadata(OnChoosedValueChanged));
internal bool isInternalSetChoosedValue = false;
private static void OnChoosedValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var treeView = d as PUTreeView;
if (treeView.ChoosedValue == null)
return;
if (treeView.isInternalSetChoosedValue)
{
treeView.isInternalSetChoosedValue = false;
return;
}
var tvi = treeView.ChoosedValuePath == ChoosedValuePaths.Header ? treeView.GetItemByHeader(treeView.ChoosedValue, true, false) : treeView.GetItemByValue(treeView.ChoosedValue, true, false);
if (tvi != null)
{
if (!tvi.IsChoosed)
tvi.IsChoosed = true;
}
else
{
if (treeView.ChoosedItem != null)
{
treeView.ChoosedItem.IsChoosed = false;
treeView.ChoosedItem = null;
}
}
}
///
/// 用于TreeView的绑定。
///
public ObservableCollection BindingItems
{
get { return (ObservableCollection)GetValue(BindingItemsProperty); }
set { SetValue(BindingItemsProperty, value); }
}
public static readonly DependencyProperty BindingItemsProperty =
DependencyProperty.Register("BindingItems", typeof(ObservableCollection), typeof(PUTreeView), new PropertyMetadata(OnBindingItemsChanged));
private static void OnBindingItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var treeView = d as PUTreeView;
if (treeView.BindingItems != null)
{
treeView.BindingItems.CollectionChanged -= treeView.BindingItemChanged;
treeView.BindingItems.CollectionChanged += treeView.BindingItemChanged;
}
treeView.GenerateBindindItems(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
private void BindingItemChanged(object sender, NotifyCollectionChangedEventArgs e)
{
GenerateBindindItems(e);
}
#endregion
#region APIs
///
/// 通过标题选中子项。
/// 若标题不是值类型,则将逐一比较每一个可写属性的值是否相等。
///
/// 要匹配的标题。
public void ChooseItemByHeader(object header)
{
var tvi = GetItemByHeader(header, true, false);
if (tvi != null)
{
if (!tvi.IsChoosed && !tvi.HasItems)
tvi.IsChoosed = true;
}
else if (tvi == null)
{
if (ChoosedItem != null)
{
ChoosedItem.IsChoosed = false;
ChoosedItem = null;
}
ChoosedValue = null;
}
}
///
/// 通过Value获取子项。
/// 若Value不是值类型,则将逐一比较每一个可写属性的值是否相等。
///
/// 要匹配的值。
public void ChooseItemByValue(object value)
{
var tvi = GetItemByValue(value, true, false);
if (tvi != null)
{
if (!tvi.IsChoosed && !tvi.HasItems)
tvi.IsChoosed = true;
}
else if (tvi == null)
{
if (ChoosedItem != null)
{
ChoosedItem.IsChoosed = false;
ChoosedItem = null;
}
ChoosedValue = null;
}
}
#endregion
#region Function
///
/// 通过标题获取Item。
///
/// 要匹配的标题。
/// 在检索过程中是否自动折叠不是目标项的项目,并将目标项的父PUTreeViewItem展开。
/// 返回结果中是否包含含有子项的项目。
///
private PUTreeViewItem GetItemByHeader(object header, bool autoExpand = false, bool includeParent = true)
{
foreach (var item in Items)
{
var tvi = item as PUTreeViewItem;
if (autoExpand)
tvi.IsExpanded = false;
var tvix = GetTreeViewItemByHeader(tvi, header, autoExpand, includeParent);
if (tvix != null)
{
if (autoExpand)
{
var parent = tvix.Parent as PUTreeViewItem;
if (parent != null)
parent.IsExpanded = true;
}
return tvix;
}
}
return null;
}
///
/// 通过Value获取Item。
///
/// 要匹配的Value。
/// 在检索过程中是否自动折叠不是目标项的项目,并将目标项的父PUTreeViewItem展开。
/// 返回结果中是否包含含有子项的项目。
///
private PUTreeViewItem GetItemByValue(object value, bool autoExpand = false, bool includeParent = true)
{
foreach (var item in Items)
{
var tvi = item as PUTreeViewItem;
if (autoExpand)
tvi.IsExpanded = false;
var tvix = GetTreeViewItemByValue(tvi, value, autoExpand, includeParent);
if (tvix != null)
{
if (autoExpand)
{
var parent = tvix.Parent as PUTreeViewItem;
if (parent != null)
parent.IsExpanded = true;
}
return tvix;
}
}
return null;
}
private PUTreeViewItem GetTreeViewItemByHeader(PUTreeViewItem item, object header, bool autoExpand, bool includeParent)
{
if ((includeParent || !item.HasItems) && item.Header != null && item.Header.IsEqual(header))
return item;
if (item.HasItems)
{
foreach (var tvi in item.Items)
{
if (autoExpand)
(tvi as PUTreeViewItem).IsExpanded = false;
var tvix = GetTreeViewItemByHeader(tvi as PUTreeViewItem, header, autoExpand, includeParent);
if (tvix != null)
{
if (autoExpand)
(tvi as PUTreeViewItem).IsExpanded = true;
return tvix;
}
}
}
return null;
}
private PUTreeViewItem GetTreeViewItemByValue(PUTreeViewItem item, object value, bool autoExpand, bool includeParent)
{
if ((includeParent || !item.HasItems) && item.Value != null && item.Value.IsEqual(value))
return item;
if (item.HasItems)
{
foreach (var tvi in item.Items)
{
if (autoExpand)
(tvi as PUTreeViewItem).IsExpanded = false;
var tvix = GetTreeViewItemByValue(tvi as PUTreeViewItem, value, autoExpand, includeParent);
if (tvix != null)
{
if (autoExpand)
(tvi as PUTreeViewItem).IsExpanded = true;
return tvix;
}
}
}
return null;
}
private void GenerateBindindItems(NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Reset:
var _choosedValue = ChoosedValue;
ChoosedValue = null;
Items.Clear();
if (BindingItems == null)
break;
foreach (var item in BindingItems)
{
var treeViewItem = GenerateTreeViewItem(item);
Items.Add(treeViewItem);
}
ChoosedValue = _choosedValue;
break;
case NotifyCollectionChangedAction.Add:
foreach (var item in e.NewItems)
{
var treeViewItem = GenerateTreeViewItem(item as PUTreeViewItemModel);
Items.Insert(e.NewStartingIndex, treeViewItem);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (var item in e.OldItems)
{
Items.RemoveAt(e.OldStartingIndex);
}
break;
case NotifyCollectionChangedAction.Replace:
foreach (var item in e.NewItems)
{
var tabItem = GenerateTreeViewItem(item as PUTreeViewItemModel);
Items[e.OldStartingIndex] = tabItem;
}
break;
case NotifyCollectionChangedAction.Move:
{
var tabItem = Items[e.OldStartingIndex];
Items.RemoveAt(e.OldStartingIndex);
Items.Insert(e.NewStartingIndex, tabItem);
}
break;
}
if (ChoosedValue != null)
{
if (ChoosedValuePath == ChoosedValuePaths.Header)
ChooseItemByHeader(ChoosedValue);
else
ChooseItemByValue(ChoosedValue);
}
}
private PUTreeViewItem GenerateTreeViewItem(PUTreeViewItemModel model)
{
var treeViewItem = new PUTreeViewItem()
{
Uid = model.Uid,
Header = model.Header,
Value = model.Value,
Padding = model.Padding,
};
if (model.ToolTip != null)
treeViewItem.ToolTip = model.ToolTip;
foreach (var child in Generate(model.Items))
{
treeViewItem.Items.Add(child);
}
model.PropertyChanged += delegate
{
treeViewItem.Header = model.Header;
treeViewItem.Value = model.Value;
treeViewItem.Padding = model.Padding;
if (model.ToolTip != null)
treeViewItem.ToolTip = model.ToolTip;
treeViewItem.Items.Clear();
foreach (var child in Generate(model.Items))
{
treeViewItem.Items.Add(child);
}
};
return treeViewItem;
}
private IEnumerable Generate(IList models)
{
if (models == null || models.Count == 0)
yield break;
foreach (var model in models)
{
var item = new UI.PUTreeViewItem()
{
Uid = model.Uid,
Header = model.Header,
Value = model.Value,
Padding = model.Padding,
};
if (model.ToolTip != null)
item.ToolTip = model.ToolTip;
foreach (var child in Generate(model.Items))
{
item.Items.Add(child);
}
yield return item;
}
}
#endregion
}
}
================================================
FILE: Panuon.UI/A0_TreeView/PUTreeViewItem.cs
================================================
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
public class PUTreeViewItem : TreeViewItem
{
#region Identity
private PUTreeView ParentTreeView
{
get
{
if (_parentTreeView == null)
{
var parent = this.Parent;
while (parent != null && parent.GetType() != typeof(PUTreeView))
{
parent = (parent as PUTreeViewItem).Parent;
}
_parentTreeView = (parent as PUTreeView);
}
return _parentTreeView;
}
}
private PUTreeView _parentTreeView;
#endregion
static PUTreeViewItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUTreeViewItem), new FrameworkPropertyMetadata(typeof(PUTreeViewItem)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (IsChoosed)
{
ParentTreeView.ChoosedItem = this;
}
var stk = VisualTreeHelper.GetChild(this, 0) as StackPanel;
stk.MouseLeftButtonDown += Stk_MouseLeftButtonDown;
}
#region Property
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("请使用IsChoosed属性。")]
public new bool IsSelected
{
get { return base.IsSelected; }
internal set { base.IsSelected = value; }
}
///
/// 获取或设置该子项是否已被选中,含有子项目的行项目无法被选中。
///
public bool IsChoosed
{
get { return (bool)GetValue(IsChoosedProperty); }
set { SetValue(IsChoosedProperty, value); }
}
public static readonly DependencyProperty IsChoosedProperty =
DependencyProperty.Register("IsChoosed", typeof(bool), typeof(PUTreeViewItem), new PropertyMetadata(false, OnIsChoosedChanged));
private static void OnIsChoosedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var item = d as PUTreeViewItem;
if (item.IsChoosed)
{
if(item.ParentTreeView.ChoosedItem != null)
item.ParentTreeView.ChoosedItem.IsChoosed = false;
item.ParentTreeView.ChoosedItem = item;
}
}
///
/// 获取或设置该子项可以携带的值,不会对前端显示造成影响。
///
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(PUTreeViewItem));
#endregion
#region Sys
private void Stk_MouseLeftButtonDown(object sender, RoutedEventArgs e)
{
if (!HasItems)
{
IsSelected = true;
if (IsChoosed == false)
{
IsChoosed = true;
}
else
{
e.Handled = true;
return;
}
}
else
{
IsSelected = false;
if (ParentTreeView.ExpandMode == ExpandModes.Click)
IsExpanded = !IsExpanded;
}
}
#endregion
}
}
================================================
FILE: Panuon.UI/A1_Slider/PUSlider.xaml
================================================
================================================
FILE: Panuon.UI/A1_Slider/PUSlider.xaml.cs
================================================
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
///
/// PUSlider.xaml 的交互逻辑
///
public partial class PUSlider : UserControl
{
private double _delta = 0.0;
private double _totalWidth = 0.0;
public PUSlider()
{
InitializeComponent();
Foreground = new SolidColorBrush(Colors.LightGray);
Loaded += delegate
{
RecheckSlideBar();
};
}
private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
var left = 0.0;
if (e.HorizontalChange >= _delta/2)
{
var per = (int)(e.HorizontalChange / _delta) + 1;
left = Canvas.GetLeft(tmbToggle) + _delta * per;
if (Value < Maximuim - per)
Value += per;
else
Value = Maximuim;
if (left > canvas.ActualWidth - tmbToggle.ActualWidth)
{
left = canvas.ActualWidth - tmbToggle.ActualWidth;
Value = Maximuim;
}
}
else if (e.HorizontalChange <= -_delta/2)
{
var per = (int)(e.HorizontalChange / -_delta) + 1;
left = Canvas.GetLeft(tmbToggle) - _delta * per;
if(Value > Minimuim + per)
Value -= per;
else
Value = Minimuim;
if (left < 0)
{
left = 0;
Value = Minimuim;
}
}
else
return;
bdrCover.Width = left;
Canvas.SetLeft(tmbToggle, left);
}
#region RoutedEvent
///
/// 进度改变事件。
///
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUSlider));
public event RoutedPropertyChangedEventHandler ValueChanged
{
add { AddHandler(ValueChangedEvent, value); }
remove { RemoveHandler(ValueChangedEvent, value); }
}
internal void OnValueChanged(int oldValue, int newValue)
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(oldValue, newValue, ValueChangedEvent);
RaiseEvent(arg);
}
#endregion
#region Property
///
/// 获取或设置滑块覆盖区域(左侧)的颜色。默认值为#696969。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUSlider), new PropertyMetadata(new SolidColorBrush(Colors.DimGray)));
///
/// 获取或设置滑块的最大值。默认值为100。
///
public int Maximuim
{
get { return (int)GetValue(MaximuimProperty); }
set { SetValue(MaximuimProperty, value); }
}
public static readonly DependencyProperty MaximuimProperty =
DependencyProperty.Register("Maximuim", typeof(int), typeof(PUSlider), new PropertyMetadata(100, OnValuesChanged));
///
/// 获取或设置滑块的最小值。默认值为0。
///
public int Minimuim
{
get { return (int)GetValue(MinimuimProperty); }
set { SetValue(MinimuimProperty, value); }
}
public static readonly DependencyProperty MinimuimProperty =
DependencyProperty.Register("Minimuim", typeof(int), typeof(PUSlider), new PropertyMetadata(0, OnValuesChanged));
///
/// 获取或设置滑块当前选择的值。默认值为0。
///
public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(int), typeof(PUSlider), new PropertyMetadata(0,OnValuesChanged));
private static void OnValuesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var slider = d as PUSlider;
if (!slider.IsLoaded)
return;
if (slider.RecheckSlideBar())
{
slider.OnValueChanged((int)e.OldValue, (int)e.NewValue);
}
}
#endregion
private bool RecheckSlideBar()
{
if (Value < Minimuim)
{
Value = Minimuim;
return false;
}
if (Value > Maximuim)
{
Value = Maximuim;
return false;
}
canvas.Width = this.ActualWidth;
_totalWidth = (canvas.ActualWidth - tmbToggle.ActualWidth);
_delta = _totalWidth / (Maximuim - Minimuim);
bdrCover.Width = (Value - Minimuim) * _delta;
Canvas.SetLeft(tmbToggle, (Value - Minimuim) * _delta);
return true;
}
private void slider_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (Minimuim > Maximuim)
Minimuim = Maximuim - 1;
RecheckSlideBar();
}
}
}
================================================
FILE: Panuon.UI/A2_TabControl/PUTabControl.cs
================================================
using Panuon.UI.Utils;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
namespace Panuon.UI
{
public class PUTabControl : TabControl
{
#region Identity
private TabPanel tabPanel
{
get
{
if (_tabPanel == null)
{
var scrollViewer = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(this, 0), 0), 1), 0) as ScrollViewer;
_tabPanel = (scrollViewer.Content as VirtualizingStackPanel).Children[0] as TabPanel;
}
return _tabPanel;
}
}
private TabPanel _tabPanel;
#endregion
static PUTabControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUTabControl), new FrameworkPropertyMetadata(typeof(PUTabControl)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
tabPanel.SizeChanged += delegate
{
CheckSideButton();
};
tabPanel.MouseWheel += ScrollViewer_MouseWheel;
}
#region Sys
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
if (SelectedValuePath == SelectedValuePaths.Header)
SelectedValue = SelectedItem == null ? "" : (SelectedItem as PUTabItem).Header.ToString();
else
SelectedValue = SelectedItem == null ? null : (SelectedItem as PUTabItem).Value;
base.OnSelectionChanged(e);
}
private void ScrollViewer_MouseWheel(object sender, MouseWheelEventArgs e)
{
var tabPanel = sender as TabPanel;
var scrollViewer = (tabPanel.Parent as VirtualizingStackPanel).Parent as ScrollViewer;
if(TabStripPlacement == Dock.Top || TabStripPlacement == Dock.Bottom)
{
if (e.Delta > 0)
scrollViewer.LineLeft();
else
scrollViewer.LineRight();
}
else
{
if (e.Delta > 0)
scrollViewer.LineUp();
else
scrollViewer.LineDown();
}
if (scrollViewer.ComputedVerticalScrollBarVisibility == Visibility.Visible || scrollViewer.ComputedHorizontalScrollBarVisibility == Visibility.Visible)
e.Handled = true;
}
#endregion
#region RoutedEvent
///
/// 用户点击删除按钮事件。
///
public static readonly RoutedEvent DeleteItemEvent = EventManager.RegisterRoutedEvent("DeleteItem", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUTabControl));
public event RoutedPropertyChangedEventHandler DeleteItem
{
add { AddHandler(DeleteItemEvent, value); }
remove { RemoveHandler(DeleteItemEvent, value); }
}
internal void OnDeleteItem(PUTabItem oldItem, PUTabItem newItem)
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(oldItem, newItem, DeleteItemEvent);
RaiseEvent(arg);
}
#endregion
#region Property
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("该属性对此控件无效。请使用BindingItems属性替代。", true)]
public new IEnumerable ItemsSource
{
get { return base.ItemsSource; }
private set { base.ItemsSource = value; }
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("该属性对此控件无效。BindingItems属性中的Header属性即为要显示的内容。", true)]
public new string DisplayMemberPath
{
get { return base.DisplayMemberPath; }
private set { base.DisplayMemberPath = value; }
}
///
/// 获取或设置选项卡的基础样式。默认值为General。
///
public TabControlStyles TabControlStyle
{
get { return (TabControlStyles)GetValue(TabControlStyleProperty); }
set { SetValue(TabControlStyleProperty, value); }
}
public static readonly DependencyProperty TabControlStyleProperty =
DependencyProperty.Register("TabControlStyle", typeof(TabControlStyles), typeof(PUTabControl), new PropertyMetadata(TabControlStyles.General));
///
/// 获取或设置当子项设置为可删除时,用户点击删除按钮后应执行的操作。默认为删除项目并触发DeleteItem路由事件。
///
public DeleteModes DeleteMode
{
get { return (DeleteModes)GetValue(DeleteModeProperty); }
set { SetValue(DeleteModeProperty, value); }
}
public static readonly DependencyProperty DeleteModeProperty =
DependencyProperty.Register("DeleteMode", typeof(DeleteModes), typeof(PUTabControl), new PropertyMetadata(DeleteModes.Delete));
///
/// 获取或设置当某个子项被选中时的前景色。默认值为灰黑色(#3E3E3E)。
///
public Brush SelectedBrush
{
get { return (Brush)GetValue(SelectedBrushProperty); }
set { SetValue(SelectedBrushProperty, value); }
}
public static readonly DependencyProperty SelectedBrushProperty =
DependencyProperty.Register("SelectedBrush", typeof(Brush), typeof(PUTabControl));
///
/// 该属性指定了当子项目被选中时,SelectedValue应呈现子项目的哪一个值。
/// 可选项为Header或Value,默认值为Header。
///
public new SelectedValuePaths SelectedValuePath
{
get { return (SelectedValuePaths)GetValue(SelectedValuePathProperty); }
set { SetValue(SelectedValuePathProperty, value); }
}
public new static readonly DependencyProperty SelectedValuePathProperty =
DependencyProperty.Register("SelectedValuePath", typeof(SelectedValuePaths), typeof(PUTabControl), new PropertyMetadata(SelectedValuePaths.Header));
///
/// 获取被选中PUTabItem的Header或Value属性(这取决于SelectedValuePath),或反向选中子项目。
///
public new object SelectedValue
{
get { return (object)GetValue(SelectedValueProperty); }
set { SetValue(SelectedValueProperty, value); }
}
public new static readonly DependencyProperty SelectedValueProperty =
DependencyProperty.Register("SelectedValue", typeof(object), typeof(PUTabControl), new PropertyMetadata("", OnSelectedValueChanged));
private static void OnSelectedValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var tabControl = d as PUTabControl;
if (tabControl.SelectedValue == null)
{
return;
}
if (e.NewValue == e.OldValue)
return;
var selectedItem = tabControl.SelectedItem as PUListBoxItem;
foreach (var item in tabControl.Items)
{
var tabItem = item as PUTabItem;
if ((tabControl.SelectedValuePath == SelectedValuePaths.Header ?
(tabItem.Content == null ? false : tabItem.Content.Equals(tabControl.SelectedValue)) :
(tabItem.Value == null ? false : tabItem.Value.Equals(tabControl.SelectedValue))))
{
if (!tabItem.IsSelected)
{
tabItem.IsSelected = true;
}
return;
}
}
}
///
/// 若使用MVVM绑定,请使用此依赖属性。
///
public ObservableCollection BindingItems
{
get { return (ObservableCollection)GetValue(BindingItemsProperty); }
set { SetValue(BindingItemsProperty, value); }
}
public static readonly DependencyProperty BindingItemsProperty =
DependencyProperty.Register("BindingItems", typeof(ObservableCollection), typeof(PUTabControl), new PropertyMetadata(OnBindingItemsChanged));
private static void OnBindingItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var tabControl = d as PUTabControl;
if(tabControl.BindingItems != null)
{
tabControl.BindingItems.CollectionChanged -= tabControl.BindingItemChanged;
tabControl.BindingItems.CollectionChanged += tabControl.BindingItemChanged;
}
tabControl.GenerateBindindItems(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
private void BindingItemChanged(object sender, NotifyCollectionChangedEventArgs e)
{
GenerateBindindItems(e);
}
#endregion
#region Internal Property
///
/// 是否允许显示选项卡两侧的按钮。
///
internal Visibility SideButtonVisibility
{
get { return (Visibility)GetValue(SideButtonVisibilityProperty); }
set { SetValue(SideButtonVisibilityProperty, value); }
}
internal static readonly DependencyProperty SideButtonVisibilityProperty =
DependencyProperty.Register("SideButtonVisibility", typeof(Visibility), typeof(PUTabControl), new PropertyMetadata(Visibility.Collapsed));
#endregion
#region Command
///
/// 向左命令
///
public ICommand LeftCommand
{
get
{ return _leftCommand; }
}
private ICommand _leftCommand = new PUTabControlLeftCommand();
///
/// 向右命令
///
public ICommand RightCommand
{
get
{ return _rightCommand; }
}
private ICommand _rightCommand = new PUTabControlRightCommand();
///
/// 向左命令
///
public ICommand UpCommand
{
get
{ return _upCommand; }
}
private ICommand _upCommand = new PUTabControlUpCommand();
///
/// 向左命令
///
public ICommand DownCommand
{
get
{ return _downCommand; }
}
private ICommand _downCommand = new PUTabControlDownCommand();
#endregion
#region APIs
public void SelectItemByContent(object content)
{
var tabItem = GetItemByContent(content);
if (tabItem != null)
tabItem.IsSelected = true;
}
public void SelectItemByValue(object value)
{
var tabItem = GetItemByValue(value);
if (tabItem != null)
tabItem.IsSelected = true;
}
#endregion
#region Function
private void CheckSideButton()
{
if (tabPanel == null)
return;
if(TabStripPlacement == Dock.Top || TabStripPlacement == Dock.Bottom)
{
if (ActualWidth <= tabPanel.ActualWidth)
{
SideButtonVisibility = Visibility.Visible;
}
else
{
SideButtonVisibility = Visibility.Collapsed;
}
}
else
{
if (ActualHeight <= tabPanel.ActualHeight)
{
SideButtonVisibility = Visibility.Visible;
}
else
{
SideButtonVisibility = Visibility.Collapsed;
}
}
}
private void GenerateBindindItems(NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Reset:
var _selectedValue = SelectedValue;
SelectedValue = null;
Items.Clear();
if (BindingItems == null)
break;
foreach (var item in BindingItems)
{
var tabItem = GenerateTabItem(item);
Items.Add(tabItem);
}
SelectedValue = _selectedValue;
break;
case NotifyCollectionChangedAction.Add:
foreach(var item in e.NewItems)
{
var tabItem = GenerateTabItem(item as PUTabItemModel);
Items.Insert(e.NewStartingIndex, tabItem);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (var item in e.OldItems)
{
Items.RemoveAt(e.OldStartingIndex);
}
break;
case NotifyCollectionChangedAction.Replace:
foreach (var item in e.NewItems)
{
var tabItem = GenerateTabItem(item as PUTabItemModel);
Items[e.OldStartingIndex] = tabItem;
}
break;
case NotifyCollectionChangedAction.Move:
{
var tabItem = Items[e.OldStartingIndex];
Items.RemoveAt(e.OldStartingIndex);
Items.Insert(e.NewStartingIndex, tabItem);
}
break;
}
if (SelectedValue != null)
{
if (SelectedValuePath == SelectedValuePaths.Header)
SelectItemByContent(SelectedValue);
else
SelectItemByValue(SelectedValue);
}
}
private PUTabItem GenerateTabItem(PUTabItemModel model)
{
var tabItem = new PUTabItem()
{
Uid = model.Uid,
Header = model.Header,
Content = model.Content,
Height = model.Height,
Icon = model.Icon,
Value = model.Value,
CanDelete = model.CanDelete,
};
if (Items.Count == 0)
tabItem.IsSelected = true;
model.PropertyChanged += delegate
{
tabItem.Header = model.Header;
tabItem.Content = model.Content;
tabItem.Height = model.Height;
tabItem.Icon = model.Icon;
tabItem.Value = model.Value;
tabItem.CanDelete = model.CanDelete;
};
return tabItem;
}
private PUTabItem GetItemByContent(object content)
{
foreach (var item in Items)
{
var tabItem = item as PUTabItem;
if (tabItem == null)
throw new Exception("PUTabControl的子项必须是PUTabItem。");
if (tabItem.Content.IsEqual(content))
return tabItem;
}
return null;
}
private PUTabItem GetItemByValue(object value)
{
foreach (var item in Items)
{
var tabItem = item as PUTabItem;
if (tabItem == null)
throw new Exception("PUTabControl的子项必须是PUTabItem。");
if (tabItem.Value.IsEqual(value))
return tabItem;
}
return null;
}
#endregion
}
internal sealed class PUTabControlLeftCommand : ICommand
{
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var stkMain = (parameter as ScrollViewer);
if (stkMain.HorizontalOffset >= 20)
stkMain.ScrollToHorizontalOffset(stkMain.HorizontalOffset - 20);
else
stkMain.ScrollToHorizontalOffset(0);
}
}
internal sealed class PUTabControlRightCommand : ICommand
{
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var scrollViewer = (parameter as ScrollViewer);
if (scrollViewer.HorizontalOffset <= scrollViewer.ActualWidth - 20)
scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + 20);
else
scrollViewer.ScrollToHorizontalOffset(scrollViewer.ActualWidth);
}
}
internal sealed class PUTabControlUpCommand : ICommand
{
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var stkMain = (parameter as ScrollViewer);
if (stkMain.VerticalOffset >= 20)
stkMain.ScrollToVerticalOffset(stkMain.VerticalOffset - 20);
else
stkMain.ScrollToVerticalOffset(0);
}
}
internal sealed class PUTabControlDownCommand : ICommand
{
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var scrollViewer = (parameter as ScrollViewer);
if (scrollViewer.VerticalOffset <= scrollViewer.ActualHeight - 20)
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + 20);
else
scrollViewer.ScrollToVerticalOffset(scrollViewer.ActualHeight);
}
}
}
================================================
FILE: Panuon.UI/A2_TabControl/PUTabItem.cs
================================================
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Panuon.UI
{
public class PUTabItem : TabItem
{
static PUTabItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUTabItem), new FrameworkPropertyMetadata(typeof(PUTabItem)));
}
#region Property
///
/// 获取或设置删除按钮的显示状态。
///
public bool CanDelete
{
get { return (bool)GetValue(CanDeleteProperty); }
set { SetValue(CanDeleteProperty, value); }
}
public static readonly DependencyProperty CanDeleteProperty =
DependencyProperty.Register("CanDelete", typeof(bool), typeof(PUTabItem), new PropertyMetadata(false));
///
/// 获取或设置显示在选项卡前的图标,默认值为空。
///
public object Icon
{
get { return (object)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(object), typeof(PUTabItem));
///
/// 获取或设置该子项可以携带的值,不会对前端显示造成影响。
///
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(PUTabItem));
#endregion
public ICommand DeleteCommand
{
get
{ return _deleteCommand; }
}
private ICommand _deleteCommand = new PUTabItemDeleteCommand();
internal sealed class PUTabItemDeleteCommand : ICommand
{
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
var tabItem = (parameter as PUTabItem);
var tabControl = tabItem.Parent as PUTabControl;
if (tabControl.DeleteMode == DeleteModes.Delete)
{
if (tabControl.BindingItems != null && !String.IsNullOrEmpty((tabItem.Uid)))
{
var model = tabControl.BindingItems.FirstOrDefault(x => x.Uid == tabItem.Uid);
if (model != null)
tabControl.BindingItems.Remove(model);
else
tabControl.Items.Remove(tabItem);
}
else
{
tabControl.Items.Remove(tabItem);
}
}
tabControl.OnDeleteItem(null, tabItem);
}
}
}
}
================================================
FILE: Panuon.UI/A3_ListBox/PUListBox.cs
================================================
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
public class PUListBox : ListBox
{
static PUListBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUListBox), new FrameworkPropertyMetadata(typeof(PUListBox)));
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
if (SelectedValuePath == SelectedValuePaths.Header)
SelectedValue = SelectedItem == null ? "" : (SelectedItem as PUListBoxItem).Content;
else
SelectedValue = SelectedItem == null ? null : (SelectedItem as PUListBoxItem).Value;
base.OnSelectionChanged(e);
}
#region Property
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("该属性对此控件无效。请使用BindingItems属性替代。",true)]
public new IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
private set { SetValue(ItemsSourceProperty, value); }
}
public new static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(PUListBox));
///
/// 该属性指定了当子项目被选中时,SelectedValue应呈现子项目的哪一个值。默认值为Header。
///
public new SelectedValuePaths SelectedValuePath
{
get { return (SelectedValuePaths)GetValue(SelectedValuePathProperty); }
set { SetValue(SelectedValuePathProperty, value); }
}
public new static readonly DependencyProperty SelectedValuePathProperty =
DependencyProperty.Register("SelectedValuePath", typeof(SelectedValuePaths), typeof(PUListBox), new PropertyMetadata(SelectedValuePaths.Header));
///
/// 获取被选中PUTabItem的Header(即ListBoxItem的Content属性)或Value属性(这取决于SelectedValuePath),或反向选中子项目。
///
public new object SelectedValue
{
get { return (object)GetValue(SelectedValueProperty); }
set { SetValue(SelectedValueProperty, value); }
}
public new static readonly DependencyProperty SelectedValueProperty =
DependencyProperty.Register("SelectedValue", typeof(object), typeof(PUListBox), new PropertyMetadata("", OnSelectedValueChanged));
private static void OnSelectedValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var listBox = d as PUListBox;
if (listBox.SelectedValue == null)
{
return;
}
if (e.NewValue == e.OldValue)
return;
var selectedItem = listBox.SelectedItem as PUListBoxItem;
foreach (var item in listBox.Items)
{
var listBoxItem = item as PUListBoxItem;
if ((listBox.SelectedValuePath == SelectedValuePaths.Header ?
(listBoxItem.Content == null ? false : listBoxItem.Content.Equals(listBox.SelectedValue)) :
(listBoxItem.Value == null ? false : listBoxItem.Value.Equals(listBox.SelectedValue))))
{
if (!listBoxItem.IsSelected)
{
listBoxItem.IsSelected = true;
listBox.ScrollIntoView(listBoxItem);
}
return;
}
}
}
///
/// 获取或设置当鼠标悬浮时ListBoxItem的背景色。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUListBox));
///
/// 获取或设置当ListBoxItem被选中时的背景色。
///
public Brush SelectedBrush
{
get { return (Brush)GetValue(SelectedBrushProperty); }
set { SetValue(SelectedBrushProperty, value); }
}
public static readonly DependencyProperty SelectedBrushProperty =
DependencyProperty.Register("SelectedBrush", typeof(Brush), typeof(PUListBox));
///
/// 获取或设置当搜索ListBoxItem时,ListBoxItem被找到时应呈现的背景色。
///
public Brush SearchBrush
{
get { return (Brush)GetValue(SearchBrushProperty); }
set { SetValue(SearchBrushProperty, value); }
}
public static readonly DependencyProperty SearchBrushProperty =
DependencyProperty.Register("SearchBrush", typeof(Brush), typeof(PUListBox));
///
/// 若使用MVVM绑定,请使用此依赖属性。
///
public ObservableCollection BindingItems
{
get { return (ObservableCollection)GetValue(BindingItemsProperty); }
set { SetValue(BindingItemsProperty, value); }
}
public static readonly DependencyProperty BindingItemsProperty =
DependencyProperty.Register("BindingItems", typeof(ObservableCollection), typeof(PUListBox), new PropertyMetadata(null, OnBindingItemsChanged));
private static void OnBindingItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var listBox = d as PUListBox;
if (listBox.BindingItems != null)
{
listBox.BindingItems.CollectionChanged -= listBox.BindingItemChanged;
listBox.BindingItems.CollectionChanged += listBox.BindingItemChanged;
}
listBox.GenerateBindindItems(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
private void BindingItemChanged(object sender, NotifyCollectionChangedEventArgs e)
{
GenerateBindindItems(e);
}
#endregion
#region APIs
///
/// 通过内容选中项目。
/// 若内容不是值类型,则将逐一比较其中每一个可写属性的值是否相等。
///
/// 要匹配的内容。
public void SelectItemByContent(object content)
{
var item = GetItemByContent(content);
if (!item.IsSelected)
item.IsSelected = true;
}
///
/// 通过Value选中项目。
/// 若Value不是值类型,则将逐一比较其中每一个可写属性的值是否相等。
///
/// 要匹配的Value
public void SelectItemByValue(object value)
{
var item = GetItemByValue(value);
if (!item.IsSelected)
item.IsSelected = true;
}
///
/// 通过内容查询符合条件的第一个子项,滚动到该项目并高亮(子项的内容须为string类型)。
///
/// 子项的内容。
/// 是否允许模糊查询。
public void SearchItemByContent(string content, bool allowFuzzySearch = true)
{
foreach (var item in Items)
{
var listBoxItem = item as PUListBoxItem;
if (listBoxItem.Content == null ? false : allowFuzzySearch ? listBoxItem.Content.ToString().Contains(content) : listBoxItem.Content.ToString() == content)
{
ScrollIntoView(listBoxItem);
listBoxItem.OnSearched();
return;
}
}
}
///
/// 通过Value查询符合条件的第一个子项,滚动到该项目并高亮。
///
public void SearchItemByValue(object value)
{
var item = GetItemByValue(value);
if (item == null)
return;
ScrollIntoView(item);
item.OnSearched();
}
#endregion
#region Function
///
/// 通过Value获取符合条件的第一个子项。
///
private PUListBoxItem GetItemByValue(object value)
{
foreach (var item in Items)
{
var listBoxItem = item as PUListBoxItem;
if (listBoxItem.Value == null ? false : listBoxItem.Value.Equals(value))
return listBoxItem;
}
return null;
}
///
/// 通过内容获取符合条件的第一个子项。
///
private PUListBoxItem GetItemByContent(object content)
{
foreach (var item in Items)
{
var listBoxItem = item as PUListBoxItem;
if (listBoxItem.Content == null ? false : listBoxItem.Content.Equals(content))
return listBoxItem;
}
return null;
}
private void GenerateBindindItems(NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Reset:
var selectedValue = SelectedValue;
SelectedValue = null;
Items.Clear();
if (BindingItems == null)
break;
foreach (var item in BindingItems)
{
var tabItem = GenerateComboBoxItem(item);
Items.Add(tabItem);
}
SelectedValue = selectedValue;
break;
case NotifyCollectionChangedAction.Add:
foreach (var item in e.NewItems)
{
var tabItem = GenerateComboBoxItem(item as PUListBoxItemModel);
Items.Insert(e.NewStartingIndex, tabItem);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (var item in e.OldItems)
{
Items.RemoveAt(e.OldStartingIndex);
}
break;
case NotifyCollectionChangedAction.Replace:
foreach (var item in e.NewItems)
{
var tabItem = GenerateComboBoxItem(item as PUListBoxItemModel);
Items[e.OldStartingIndex] = tabItem;
}
break;
case NotifyCollectionChangedAction.Move:
{
var tabItem = Items[e.OldStartingIndex];
Items.RemoveAt(e.OldStartingIndex);
Items.Insert(e.NewStartingIndex, tabItem);
}
break;
}
if(SelectedValue != null)
{
if (SelectedValuePath == SelectedValuePaths.Header)
SelectItemByContent(SelectedValue);
else
SelectItemByValue(SelectedValue);
}
}
private PUListBoxItem GenerateComboBoxItem(PUListBoxItemModel model)
{
var comboBoxItem = new PUListBoxItem()
{
Uid = model.Uid,
Content = model.Header,
Value = model.Value,
};
if (Items.Count == 0)
comboBoxItem.IsSelected = true;
model.PropertyChanged += delegate
{
comboBoxItem.Content = model.Header;
comboBoxItem.Value = model.Value;
};
return comboBoxItem;
}
#endregion
}
}
================================================
FILE: Panuon.UI/A3_ListBox/PUListBoxItem.cs
================================================
using System.Windows;
using System.Windows.Controls;
namespace Panuon.UI
{
public class PUListBoxItem : ListBoxItem
{
static PUListBoxItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUListBoxItem), new FrameworkPropertyMetadata(typeof(PUListBoxItem)));
}
#region RoutedEvent
///
/// 当子项被搜索到时,触发此事件。
///
public static readonly RoutedEvent SearchedEvent = EventManager.RegisterRoutedEvent("Searched", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUListBoxItem));
public event RoutedPropertyChangedEventHandler Searched
{
add { AddHandler(SearchedEvent, value); }
remove { RemoveHandler(SearchedEvent, value); }
}
internal void OnSearched()
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(null, this, SearchedEvent);
RaiseEvent(arg);
}
#endregion
#region Property
///
/// 获取或设置该子项可以携带的值,仅用于标记该子项的实际内容,不会对前端显示造成影响。
///
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(PUListBoxItem));
#endregion
}
}
================================================
FILE: Panuon.UI/A4_DatePicker/PUDatePicker.xaml
================================================
================================================
FILE: Panuon.UI/A4_DatePicker/PUDatePicker.xaml.cs
================================================
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
namespace Panuon.UI
{
///
/// DatePicker.xaml 的交互逻辑
///
public partial class PUDatePicker : UserControl
{
public PUDatePicker()
{
InitializeComponent();
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Loaded += delegate
{
ReLoad();
};
}
#region Property
///
/// 获取或设置主题颜色,默认值为#3E3E3E。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUDatePicker), new PropertyMetadata(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#3E3E3E"))));
///
/// 获取或设置可以选择的最大日期。该属性不能限制用户选择的时间,
///
public DateTime? MaxDateTime
{
get { return (DateTime?)GetValue(MaxDateTimeProperty); }
set { SetValue(MaxDateTimeProperty, value); }
}
public static readonly DependencyProperty MaxDateTimeProperty =
DependencyProperty.Register("MaxDateTime", typeof(DateTime?), typeof(PUDatePicker), new PropertyMetadata(OnMaxDateTimeChanged));
private static void OnMaxDateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var picker = d as PUDatePicker;
if (!picker.IsLoaded)
return;
picker.CheckDateTimeLimit();
}
///
/// 获取或设置可以选择的最小日期。该属性不能限制用户选择的时间,
///
public DateTime? MinDateTime
{
get { return (DateTime?)GetValue(MinDateTimeProperty); }
set { SetValue(MinDateTimeProperty, value); }
}
public static readonly DependencyProperty MinDateTimeProperty =
DependencyProperty.Register("MinDateTime", typeof(DateTime?), typeof(PUDatePicker), new PropertyMetadata(OnMinDateTimeChanged));
private static void OnMinDateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var picker = d as PUDatePicker;
if (!picker.IsLoaded)
return;
picker.CheckDateTimeLimit();
}
///
/// 获取或设置当前选中的日期和时间。
///
public DateTime SelectedDateTime
{
get { return (DateTime)GetValue(SelectedDateTimeProperty); }
set { SetValue(SelectedDateTimeProperty, value); }
}
public static readonly DependencyProperty SelectedDateTimeProperty =
DependencyProperty.Register("SelectedDateTime", typeof(DateTime), typeof(PUDatePicker), new PropertyMetadata(DateTime.Now.Date, OnSelectedDateTimeChanged));
private static void OnSelectedDateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == e.OldValue)
return;
var picker = d as PUDatePicker;
if (!picker.IsLoaded)
return;
var oldDate = (DateTime)e.OldValue;
var newDate = (DateTime)e.NewValue;
if (picker.MaxDateTime != null)
{
var max = (DateTime)picker.MaxDateTime;
if (newDate > max)
{
picker.SelectedDateTime = max;
return;
}
}
if (picker.MinDateTime != null)
{
var min = (DateTime)picker.MinDateTime;
if (newDate < min)
{
picker.SelectedDateTime = min;
return;
}
}
if (oldDate.Year != newDate.Year || (oldDate.Year == newDate.Year && oldDate.Month != newDate.Month))
{
picker.ResetAndSelectYear(newDate.Year);
picker.ResetAndSelectMonth(newDate.Month);
picker.ResetDate(newDate.Year, newDate.Month);
picker.CheckDateTimeLimit();
}
picker.SelectDate(newDate.Year, newDate.Month, newDate.Day);
picker.SelectTime(newDate.Hour, newDate.Minute, newDate.Second);
}
///
/// 获取或设置日期选择器的模式。默认值为日期和时间(DateTime)。
///
public DatePickerModes DatePickerMode
{
get { return (DatePickerModes)GetValue(DatePickerModeProperty); }
set { SetValue(DatePickerModeProperty, value); }
}
public static readonly DependencyProperty DatePickerModeProperty =
DependencyProperty.Register("DatePickerMode", typeof(DatePickerModes), typeof(PUDatePicker), new PropertyMetadata(DatePickerModes.DateTime, OnDatePickerModeChanged));
private static void OnDatePickerModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var picker = d as PUDatePicker;
if (!picker.IsLoaded)
return;
picker.ReLoad();
}
#endregion
#region Function
private void ReLoad()
{
GrdDate.Visibility = Visibility.Visible;
GrdTime.Visibility = Visibility.Hidden;
GrdYear.Visibility = Visibility.Hidden;
GrdMonth.Visibility = Visibility.Hidden;
switch (DatePickerMode)
{
case DatePickerModes.DateOnly:
ClearTimePanel();
LoadYearPanel();
LoadMonthPanel();
LoadDatePanel();
BtnBackToDate.Visibility = Visibility.Visible;
ResetDate(SelectedDateTime.Year, SelectedDateTime.Month);
SelectDate(SelectedDateTime.Year, SelectedDateTime.Month, SelectedDateTime.Day);
break;
case DatePickerModes.TimeOnly:
GrdDate.Visibility = Visibility.Hidden;
GrdTime.Visibility = Visibility.Visible;
LoadTimePanel();
ClearDatePanel();
ClearYearPanel();
ClearMonthPanel();
BtnBackToDate.Visibility = Visibility.Hidden;
SelectTime(SelectedDateTime.Hour, SelectedDateTime.Minute, SelectedDateTime.Second);
break;
case DatePickerModes.DateTime:
LoadYearPanel();
LoadMonthPanel();
LoadDatePanel();
LoadTimePanel();
BtnBackToDate.Visibility = Visibility.Visible;
ResetDate(SelectedDateTime.Year, SelectedDateTime.Month);
SelectDate(SelectedDateTime.Year, SelectedDateTime.Month, SelectedDateTime.Day);
SelectTime(SelectedDateTime.Hour, SelectedDateTime.Minute, SelectedDateTime.Second);
break;
}
CheckDateTimeLimit();
}
///
/// 清空并重新加载日期Panel。
///
private void LoadDatePanel()
{
ClearDatePanel();
for (int i = 0; i < 42; i++)
{
var radio = new PURadioButton
{
RadioButtonStyle = RadioButtonStyles.Button,
Content = i.ToString("00"),
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Center,
Padding = new Thickness(0),
};
Grid.SetRow(radio, (int)(i / 7));
Grid.SetColumn(radio, i % 7);
var fore = new Binding { Path = new PropertyPath("Foreground"), Source = this, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.ForegroundProperty, fore);
var cover = new Binding { Path = new PropertyPath("CoverBrush"), Source = this, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.CoverBrushProperty, cover);
radio.Click += DateRadioButton_Click;
GrdDatePanel.Children.Add(radio);
}
}
///
/// 清空日期Panel。
///
private void ClearDatePanel()
{
GrdDatePanel.Children.Clear();
}
///
/// 清空并重新加载时间Panel。
///
private void LoadTimePanel()
{
ClearTimePanel();
for (int i = 0; i < 24; i++)
{
var radio = new PURadioButton
{
RadioButtonStyle = RadioButtonStyles.Button,
Content = i.ToString("00"),
Height = 30,
HorizontalAlignment = HorizontalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Center,
Padding = new Thickness(0),
Tag = i,
};
Grid.SetRow(radio, i / 7);
Grid.SetColumn(radio, i % 7);
var fore = new Binding { Path = new PropertyPath("Foreground"), Source = this, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.ForegroundProperty, fore); var cover = new Binding { Path = new PropertyPath("CoverBrush"), Source = this, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.CoverBrushProperty, cover);
radio.Click += HourRadioButton_Click;
StkHour.Children.Add(radio);
}
for (int i = 0; i < 60; i++)
{
var radio = new PURadioButton
{
RadioButtonStyle = RadioButtonStyles.Button,
Height = 30,
HorizontalAlignment = HorizontalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Center,
Padding = new Thickness(0),
Content = i.ToString("00"),
Tag = i,
};
Grid.SetRow(radio, i / 7);
Grid.SetColumn(radio, i % 7);
var fore = new Binding { Path = new PropertyPath("Foreground"), Source = this, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.ForegroundProperty, fore); var cover = new Binding { Path = new PropertyPath("CoverBrush"), Source = this, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.CoverBrushProperty, cover);
radio.Click += MinuteRadioButton_Click;
StkMinute.Children.Add(radio);
}
for (int i = 0; i < 60; i++)
{
var radio = new PURadioButton
{
RadioButtonStyle = RadioButtonStyles.Button,
Height = 30,
HorizontalAlignment = HorizontalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Center,
Padding = new Thickness(0),
Content = i.ToString("00"),
Tag = i,
};
Grid.SetRow(radio, i / 7);
Grid.SetColumn(radio, i % 7);
var fore = new Binding { Path = new PropertyPath("Foreground"), Source = this, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.ForegroundProperty, fore); var cover = new Binding { Path = new PropertyPath("CoverBrush"), Source = this, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.CoverBrushProperty, cover);
radio.Click += SecondRadioButton_Click;
StkSecond.Children.Add(radio);
}
}
///
/// 清空时间Panel。
///
private void ClearTimePanel()
{
StkHour.Children.Clear();
StkMinute.Children.Clear();
StkSecond.Children.Clear();
}
///
/// 清空并重新加载年份Panel。
///
private void LoadYearPanel()
{
ClearYearPanel();
for (int i = 0; i < 15; i++)
{
var radio = new PURadioButton
{
RadioButtonStyle = RadioButtonStyles.Button,
Content = i.ToString("00"),
Height = 35,
HorizontalAlignment = HorizontalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Center,
Padding = new Thickness(0),
Tag = i,
};
Grid.SetRow(radio, i / 3);
Grid.SetColumn(radio, i % 3);
var fore = new Binding { Path = new PropertyPath("Foreground"), Source = this, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.ForegroundProperty, fore); var cover = new Binding { Path = new PropertyPath("CoverBrush"), Source = this, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.CoverBrushProperty, cover);
radio.Click += YearRadioButton_Click;
GrdYearPanel.Children.Add(radio);
}
}
///
/// 清空年份Panel。
///
private void ClearYearPanel()
{
GrdYearPanel.Children.Clear();
}
///
/// 清空并重新加载月份Panel。
///
private void LoadMonthPanel()
{
ClearMonthPanel();
for (int i = 1; i <= 12; i++)
{
var radio = new PURadioButton
{
RadioButtonStyle = RadioButtonStyles.Button,
Content = i + "月",
Height = 35,
HorizontalAlignment = HorizontalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Center,
Padding = new Thickness(0),
Tag = i,
};
Grid.SetRow(radio, (i - 1) / 4);
Grid.SetColumn(radio, (i - 1) % 4);
var fore = new Binding { Path = new PropertyPath("Foreground"), Source = this, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.ForegroundProperty, fore); var cover = new Binding { Path = new PropertyPath("CoverBrush"), Source = this, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.CoverBrushProperty, cover);
radio.Click += MonthRadioButton_Click;
GrdMonthPanel.Children.Add(radio);
}
}
///
/// 清空月份Panel。
///
private void ClearMonthPanel()
{
GrdMonthPanel.Children.Clear();
}
///
/// 重新设置RadioButton的日期。
///
private void ResetDate(int year, int month)
{
if (GrdDatePanel.Children.Count != 42)
return;
BtnYear.Content = year + "年";
BtnMonth.Content = month + "月";
var currentMonth = new DateTime(year, month, 1);
var lastMonth = currentMonth.AddMonths(-1);
var nextMonth = currentMonth.AddMonths(1);
//获取本月第一天是星期几
var firstDay = (int)currentMonth.DayOfWeek;
//获取上个月最后一天是几号。
var lastDay = DateTime.DaysInMonth(lastMonth.Year, lastMonth.Month);
//获取本月的天数。
var totalDay = DateTime.DaysInMonth(currentMonth.Year, currentMonth.Month);
for (int i = 0; i < firstDay; i++)
{
var date = new DateTime(lastMonth.Year, lastMonth.Month, lastDay - firstDay + i + 1);
var radio = GrdDatePanel.Children[i] as PURadioButton;
radio.Opacity = 0.5;
radio.Content = (lastDay - firstDay + i + 1).ToString();
radio.Tag = date;
if (MaxDateTime == null && MinDateTime == null)
{
radio.IsEnabled = true;
radio.Opacity = 0.5;
}
else if (MaxDateTime != null && MinDateTime != null)
{
if (date <= ((DateTime)MaxDateTime).Date && date >= ((DateTime)MinDateTime).Date)
{
radio.IsEnabled = true;
radio.Opacity = 0.5;
}
else
{
radio.IsEnabled = false;
radio.Opacity = 0.2;
}
}
else if (MaxDateTime != null && date <= ((DateTime)MaxDateTime).Date)
{
radio.IsEnabled = true;
radio.Opacity = 0.5;
}
else if (MinDateTime != null && date >= ((DateTime)MinDateTime).Date)
{
radio.IsEnabled = true;
radio.Opacity = 0.5;
}
else
{
radio.IsEnabled = false;
radio.Opacity = 0.2;
}
}
for (int i = firstDay; i < firstDay + totalDay; i++)
{
var date = new DateTime(currentMonth.Year, currentMonth.Month, i - firstDay + 1);
var radio = GrdDatePanel.Children[i] as PURadioButton;
radio.Opacity = 1;
radio.Content = i - firstDay + 1;
radio.Tag = date;
if (MaxDateTime == null && MinDateTime == null)
{
radio.IsEnabled = true;
radio.Opacity = 1;
}
else if (MaxDateTime != null && MinDateTime != null)
{
if (date <= ((DateTime)MaxDateTime).Date && date >= ((DateTime)MinDateTime).Date)
{
radio.IsEnabled = true;
radio.Opacity = 1;
}
else
{
radio.IsEnabled = false;
radio.Opacity = 0.2;
}
}
else if (MaxDateTime != null && date <= ((DateTime)MaxDateTime).Date)
{
radio.IsEnabled = true;
radio.Opacity = 1;
}
else if (MinDateTime != null && date >= ((DateTime)MinDateTime).Date)
{
radio.IsEnabled = true;
radio.Opacity = 1;
}
else
{
radio.IsEnabled = false;
radio.Opacity = 0.2;
}
}
for (int i = firstDay + totalDay; i < 42; i++)
{
var date = new DateTime(nextMonth.Year, nextMonth.Month, i - firstDay - totalDay + 1);
var radio = GrdDatePanel.Children[i] as PURadioButton;
radio.Opacity = 0.5;
radio.Content = i - firstDay - totalDay + 1;
radio.Tag = date;
if (MaxDateTime == null && MinDateTime == null)
{
radio.IsEnabled = true;
radio.Opacity = 0.5;
}
else if (MaxDateTime != null && MinDateTime != null)
{
if (date <= ((DateTime)MaxDateTime).Date && date >= ((DateTime)MinDateTime).Date)
{
radio.IsEnabled = true;
radio.Opacity = 0.5;
}
else
{
radio.IsEnabled = false;
radio.Opacity = 0.2;
}
}
else if (MaxDateTime != null && date <= ((DateTime)MaxDateTime).Date)
{
radio.IsEnabled = true;
radio.Opacity = 0.5;
}
else if (MinDateTime != null && date >= ((DateTime)MinDateTime).Date)
{
radio.IsEnabled = true;
radio.Opacity = 0.5;
}
else
{
radio.IsEnabled = false;
radio.Opacity = 0.2;
}
}
}
private void SelectDate(int year, int month, int day)
{
if (GrdDatePanel.Children.Count != 42)
return;
for (int i = 0; i < 42; i++)
{
var radio = GrdDatePanel.Children[i] as PURadioButton;
if (radio.Content.ToString() != day.ToString())
continue;
var date = (DateTime)radio.Tag;
if (date.Year == year && date.Month == month)
{
radio.IsChecked = true;
return;
}
}
}
///
/// 重新设置RadioButton的时间(如果必要),选中指定的时间。
///
private void SelectTime(int hour, int minute, int second)
{
if (StkHour.Children.Count != 24 || StkMinute.Children.Count != 60 || StkSecond.Children.Count != 60)
return;
{
var radio = StkHour.Children[hour] as PURadioButton;
radio.IsChecked = true;
ScrollHour.ScrollToVerticalOffset((hour - 2) * radio.Height);
}
{
var radio = StkMinute.Children[minute] as PURadioButton;
radio.IsChecked = true;
ScrollMinute.ScrollToVerticalOffset((minute - 2) * radio.Height);
}
{
var radio = StkSecond.Children[second] as PURadioButton;
radio.IsChecked = true;
ScrollSecond.ScrollToVerticalOffset((second - 2) * radio.Height);
}
}
private void ResetAndSelectYear(int year)
{
if (GrdYearPanel.Children.Count != 15)
return;
BtnYearInterval.Content = SelectedDateTime.AddYears(-7).Year + "年 - " + SelectedDateTime.AddYears(7).Year + "年";
for (int i = -7; i < 8; i++)
{
var radio = GrdYearPanel.Children[i + 7] as PURadioButton;
radio.Content = (year + i) + "年";
radio.Tag = year + i;
if (i == 0)
radio.IsChecked = true;
if (MaxDateTime == null && MinDateTime == null)
{
radio.IsEnabled = true;
radio.Opacity = 1;
}
else if (MaxDateTime != null && MinDateTime != null)
{
if ((year + i) <= ((DateTime)MaxDateTime).Year && (year + i) >= ((DateTime)MinDateTime).Year)
{
radio.IsEnabled = true;
radio.Opacity = 1;
}
else
{
radio.IsEnabled = false;
radio.Opacity = 0.2;
}
}
else if (MaxDateTime != null && (year + i) <= ((DateTime)MaxDateTime).Year)
{
radio.IsEnabled = true;
radio.Opacity = 1;
}
else if (MinDateTime != null && (year + i) >= ((DateTime)MinDateTime).Year)
{
radio.IsEnabled = true;
radio.Opacity = 1;
}
else
{
radio.IsEnabled = false;
radio.Opacity = 0.2;
}
}
}
private void ResetAndSelectMonth(int month)
{
if (GrdMonthPanel.Children.Count != 12)
return;
BtnMonthInterval.Content = SelectedDateTime.Year + "年";
for (int i = 1; i <= 12; i++)
{
var radio = GrdMonthPanel.Children[i - 1] as PURadioButton;
if (i == month)
radio.IsChecked = true;
if (MaxDateTime == null && MinDateTime == null)
{
radio.IsEnabled = true;
radio.Opacity = 1;
}
else if (MaxDateTime != null && MinDateTime != null)
{
if ((SelectedDateTime.Year != ((DateTime)MaxDateTime).Year || i <= ((DateTime)MaxDateTime).Month) && (SelectedDateTime.Year != ((DateTime)MinDateTime).Year || i >= ((DateTime)MinDateTime).Month))
{
radio.IsEnabled = true;
radio.Opacity = 1;
}
else
{
radio.IsEnabled = false;
radio.Opacity = 0.2;
}
}
else if (MaxDateTime != null && (SelectedDateTime.Year != ((DateTime)MaxDateTime).Year || i <= ((DateTime)MaxDateTime).Month))
{
radio.IsEnabled = true;
radio.Opacity = 1;
}
else if (MinDateTime != null && (SelectedDateTime.Year != ((DateTime)MinDateTime).Year || i >= ((DateTime)MinDateTime).Month))
{
radio.IsEnabled = true;
radio.Opacity = 1;
}
else
{
radio.IsEnabled = false;
radio.Opacity = 0.2;
}
}
}
private void CheckDateTimeLimit()
{
ResetAndSelectYear(SelectedDateTime.Year);
ResetAndSelectMonth(SelectedDateTime.Month);
ResetDate(SelectedDateTime.Year, SelectedDateTime.Month);
if (MaxDateTime != null)
{
var max = (DateTime)MaxDateTime;
if (SelectedDateTime.Date > max.Date)
{
SelectedDateTime = max;
}
if (SelectedDateTime.Year >= max.Year)
{
BtnAddYear.Visibility = Visibility.Hidden;
}
else
{
BtnAddYear.Visibility = Visibility.Visible;
}
if (SelectedDateTime.Year + 7 >= max.Year)
{
BtnYearRight.Visibility = Visibility.Hidden;
}
else
{
BtnYearRight.Visibility = Visibility.Visible;
}
if (SelectedDateTime.Year > max.Year || (SelectedDateTime.Year == max.Year && SelectedDateTime.Month >= max.Month))
{
BtnAddMonth.Visibility = Visibility.Hidden;
BtnMonthRight.Visibility = Visibility.Hidden;
}
else
{
BtnAddMonth.Visibility = Visibility.Visible;
BtnMonthRight.Visibility = Visibility.Visible;
}
}
else
{
BtnAddYear.Visibility = Visibility.Visible;
BtnAddMonth.Visibility = Visibility.Visible;
BtnYearRight.Visibility = Visibility.Visible;
BtnMonthRight.Visibility = Visibility.Visible;
}
if (MinDateTime != null)
{
var min = (DateTime)MinDateTime;
if (SelectedDateTime.Date < min.Date)
{
SelectedDateTime = min;
}
if (SelectedDateTime.Year <= min.Year)
{
BtnDecYear.Visibility = Visibility.Hidden;
}
else
{
BtnDecYear.Visibility = Visibility.Visible;
}
if (SelectedDateTime.Year - 7 <= min.Year)
{
BtnYearLeft.Visibility = Visibility.Hidden;
}
else
{
BtnYearLeft.Visibility = Visibility.Visible;
}
if (SelectedDateTime.Year < min.Year || (SelectedDateTime.Year == min.Year && SelectedDateTime.Month <= min.Month))
{
BtnDecMonth.Visibility = Visibility.Hidden;
BtnMonthLeft.Visibility = Visibility.Hidden;
}
else
{
BtnDecMonth.Visibility = Visibility.Visible;
BtnMonthLeft.Visibility = Visibility.Visible;
}
}
else
{
BtnDecYear.Visibility = Visibility.Visible;
BtnDecMonth.Visibility = Visibility.Visible;
BtnYearLeft.Visibility = Visibility.Visible;
BtnMonthLeft.Visibility = Visibility.Visible;
}
}
#endregion
#region Event
private void DateRadioButton_Click(object sender, RoutedEventArgs e)
{
var radio = sender as PURadioButton;
if (radio.Tag == null)
return;
var date = (DateTime)radio.Tag;
SelectedDateTime = new DateTime(date.Year, date.Month, date.Day, SelectedDateTime.Hour, SelectedDateTime.Minute, SelectedDateTime.Second);
if (radio.IsChecked == true)
{
if (DatePickerMode == DatePickerModes.DateTime)
{
GrdDate.Visibility = Visibility.Hidden;
GrdTime.Visibility = Visibility.Visible;
}
return;
}
}
private void HourRadioButton_Click(object sender, RoutedEventArgs e)
{
var radio = sender as PURadioButton;
if (radio.Tag == null)
return;
var hour = (int)radio.Tag;
SelectedDateTime = new DateTime(SelectedDateTime.Year, SelectedDateTime.Month, SelectedDateTime.Day, hour, SelectedDateTime.Minute, SelectedDateTime.Second);
}
private void MinuteRadioButton_Click(object sender, RoutedEventArgs e)
{
var radio = sender as PURadioButton;
if (radio.Tag == null)
return;
var minute = (int)radio.Tag;
SelectedDateTime = new DateTime(SelectedDateTime.Year, SelectedDateTime.Month, SelectedDateTime.Day, SelectedDateTime.Hour, minute, SelectedDateTime.Second);
}
private void SecondRadioButton_Click(object sender, RoutedEventArgs e)
{
var radio = sender as PURadioButton;
if (radio.Tag == null)
return;
var second = (int)radio.Tag;
SelectedDateTime = new DateTime(SelectedDateTime.Year, SelectedDateTime.Month, SelectedDateTime.Day, SelectedDateTime.Hour, SelectedDateTime.Minute, second);
}
private void YearRadioButton_Click(object sender, RoutedEventArgs e)
{
var radio = sender as PURadioButton;
if (radio.Tag == null)
return;
var year = (int)radio.Tag;
SelectedDateTime = new DateTime(year, SelectedDateTime.Month, SelectedDateTime.Day, SelectedDateTime.Hour, SelectedDateTime.Minute, SelectedDateTime.Second);
GrdDate.Visibility = Visibility.Visible;
GrdYear.Visibility = Visibility.Hidden;
}
private void MonthRadioButton_Click(object sender, RoutedEventArgs e)
{
var radio = sender as PURadioButton;
if (radio.Tag == null)
return;
var month = (int)radio.Tag;
SelectedDateTime = new DateTime(SelectedDateTime.Year, month, SelectedDateTime.Day, SelectedDateTime.Hour, SelectedDateTime.Minute, SelectedDateTime.Second);
GrdDate.Visibility = Visibility.Visible;
GrdMonth.Visibility = Visibility.Hidden;
}
private void BtnDecYear_Click(object sender, RoutedEventArgs e)
{
if (MinDateTime == null || SelectedDateTime.AddYears(-1) >= MinDateTime)
SelectedDateTime = SelectedDateTime.AddYears(-1);
else
SelectedDateTime = (DateTime)MinDateTime;
}
private void BtnDecMonth_Click(object sender, RoutedEventArgs e)
{
if (MinDateTime == null || SelectedDateTime.AddMonths(-1) >= MinDateTime)
SelectedDateTime = SelectedDateTime.AddMonths(-1);
else
SelectedDateTime = (DateTime)MinDateTime;
}
private void BtnAddMonth_Click(object sender, RoutedEventArgs e)
{
if (MaxDateTime == null || SelectedDateTime.AddMonths(1) <= MaxDateTime)
SelectedDateTime = SelectedDateTime.AddMonths(1);
else
SelectedDateTime = (DateTime)MaxDateTime;
}
private void BtnAddYear_Click(object sender, RoutedEventArgs e)
{
if (MaxDateTime == null || SelectedDateTime.AddYears(1) <= MaxDateTime)
SelectedDateTime = SelectedDateTime.AddYears(1);
else
SelectedDateTime = (DateTime)MaxDateTime;
}
private void BtnYearLeft_Click(object sender, RoutedEventArgs e)
{
if (MinDateTime == null || SelectedDateTime.AddYears(-15) >= MinDateTime)
SelectedDateTime = SelectedDateTime.AddYears(-15);
else
SelectedDateTime = (DateTime)MinDateTime;
}
private void BtnYearRight_Click(object sender, RoutedEventArgs e)
{
if (MaxDateTime == null || SelectedDateTime.AddYears(15) <= MaxDateTime)
SelectedDateTime = SelectedDateTime.AddYears(15);
else
SelectedDateTime = (DateTime)MaxDateTime;
}
private void BtnMonthLeft_Click(object sender, RoutedEventArgs e)
{
if (MinDateTime == null || SelectedDateTime.AddYears(-1) >= MinDateTime)
SelectedDateTime = SelectedDateTime.AddYears(-1);
else
SelectedDateTime = (DateTime)MinDateTime;
}
private void BtnMonthRight_Click(object sender, RoutedEventArgs e)
{
if (MaxDateTime == null || SelectedDateTime.AddYears(1) <= MaxDateTime)
SelectedDateTime = SelectedDateTime.AddYears(1);
else
SelectedDateTime = (DateTime)MaxDateTime;
}
private void BtnBackToDate_Click(object sender, RoutedEventArgs e)
{
GrdDate.Visibility = Visibility.Visible;
GrdTime.Visibility = Visibility.Hidden;
}
#endregion
private void BtnYear_Click(object sender, RoutedEventArgs e)
{
ResetAndSelectYear(SelectedDateTime.Year);
GrdDate.Visibility = Visibility.Hidden;
GrdYear.Visibility = Visibility.Visible;
}
private void BtnMonth_Click(object sender, RoutedEventArgs e)
{
ResetAndSelectMonth(SelectedDateTime.Month);
GrdDate.Visibility = Visibility.Hidden;
GrdMonth.Visibility = Visibility.Visible;
}
private void BtnMonthInterval_Click(object sender, RoutedEventArgs e)
{
ResetAndSelectYear(SelectedDateTime.Year);
GrdMonth.Visibility = Visibility.Hidden;
GrdYear.Visibility = Visibility.Visible;
}
}
}
================================================
FILE: Panuon.UI/A5_PagingNav/PUPagingNav.xaml
================================================
================================================
FILE: Panuon.UI/A5_PagingNav/PUPagingNav.xaml.cs
================================================
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
namespace Panuon.UI
{
///
/// PUPagingNav.xaml 的交互逻辑
///
public partial class PUPagingNav : UserControl
{
public PUPagingNav()
{
InitializeComponent();
Foreground = new SolidColorBrush(Colors.White);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Loaded += delegate
{
Load();
Select();
};
}
#region RoutedEvent
///
/// 页码发生改变事件。
///
public static readonly RoutedEvent CurrentPageChangedEvent = EventManager.RegisterRoutedEvent("CurrentPageChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(PUPagingNav));
public event RoutedPropertyChangedEventHandler CurrentPageChanged
{
add { AddHandler(CurrentPageChangedEvent, value); }
remove { RemoveHandler(CurrentPageChangedEvent, value); }
}
internal void OnCurrentPageChanged(int oldItem, int newItem)
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(oldItem, newItem, CurrentPageChangedEvent);
RaiseEvent(arg);
}
#endregion
#region Property
///
/// 获取或设置当前的总页数。默认值为1。
///
public int TotalPage
{
get { return (int)GetValue(TotalPageProperty); }
set { SetValue(TotalPageProperty, value); }
}
public static readonly DependencyProperty TotalPageProperty =
DependencyProperty.Register("TotalPage", typeof(int), typeof(PUPagingNav), new PropertyMetadata(1, OnTotalPageChanged));
private static void OnTotalPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == e.OldValue)
return;
var nav = d as PUPagingNav;
if (!nav.IsLoaded)
return;
nav.Load();
nav.Select();
}
///
/// 获取或设置当前的页码。默认值为1。
///
public int CurrentPage
{
get { return (int)GetValue(CurrentPageProperty); }
set { SetValue(CurrentPageProperty, value); }
}
public static readonly DependencyProperty CurrentPageProperty =
DependencyProperty.Register("CurrentPage", typeof(int), typeof(PUPagingNav), new PropertyMetadata(1, OnCurrentPageChanged));
private static void OnCurrentPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == e.OldValue)
return;
var nav = d as PUPagingNav;
if (!nav.IsLoaded)
return;
nav.OnCurrentPageChanged((int)e.OldValue, (int)e.NewValue);
nav.Load();
nav.Select();
}
///
/// 获取或设置按钮的圆角大小,默认值为3。
///
public CornerRadius ButtonCornerRadius
{
get { return (CornerRadius)GetValue(ButtonCornerRadiusProperty); }
set { SetValue(ButtonCornerRadiusProperty, value); }
}
public static readonly DependencyProperty ButtonCornerRadiusProperty =
DependencyProperty.Register("ButtonCornerRadius", typeof(CornerRadius), typeof(PUPagingNav), new PropertyMetadata(new CornerRadius(3)));
///
/// 获取或设置两侧的按钮是否显示。默认值为True。
///
public bool IsSideButtonShow
{
get { return (bool)GetValue(IsSideButtonShowProperty); }
set { SetValue(IsSideButtonShowProperty, value); }
}
public static readonly DependencyProperty IsSideButtonShowProperty =
DependencyProperty.Register("IsSideButtonShow", typeof(bool), typeof(PUPagingNav), new PropertyMetadata(true, OnIsSideButtonShowChanged));
private static void OnIsSideButtonShowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var nav = d as PUPagingNav;
if (nav.IsSideButtonShow)
{
nav.BtnLeft.Visibility = Visibility.Visible;
nav.BtnRight.Visibility = Visibility.Visible;
}
else
{
nav.BtnLeft.Visibility = Visibility.Collapsed;
nav.BtnRight.Visibility = Visibility.Collapsed;
}
}
///
/// 获取或设置按钮的背景颜色。默认值为#AA3E3E3E。
///
public Brush ButtonBrush
{
get { return (Brush)GetValue(ButtonBrushProperty); }
set { SetValue(ButtonBrushProperty, value); }
}
public static readonly DependencyProperty ButtonBrushProperty =
DependencyProperty.Register("ButtonBrush", typeof(Brush), typeof(PUPagingNav), new PropertyMetadata(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#AA3E3E3E"))));
///
/// 获取或设置按钮被选中或点击时的颜色。默认值为#3E3E3E。
///
public Brush SelectedBrush
{
get { return (Brush)GetValue(SelectedBrushProperty); }
set { SetValue(SelectedBrushProperty, value); }
}
public static readonly DependencyProperty SelectedBrushProperty =
DependencyProperty.Register("SelectedBrush", typeof(Brush), typeof(PUPagingNav), new PropertyMetadata(new SolidColorBrush((Color)ColorConverter.ConvertFromString("#3E3E3E"))));
#endregion
#region Function
private void Load()
{
if(TotalPage <= 0)
{
TotalPage = 0;
return;
}
if(CurrentPage <= 0)
{
CurrentPage = 1;
return;
}
if (CurrentPage > TotalPage)
{
CurrentPage = TotalPage;
return;
}
StkMain.Children.Clear();
if (TotalPage <= 7)
{
for (var i = 1; i <= TotalPage; i++)
{
StkMain.Children.Add(GetRadioButton(i));
}
}
else
{
StkMain.Children.Add(GetRadioButton(1));
StkMain.Children.Add(GetRadioButton(2));
//第1或2页或3,直接追加到5
if (CurrentPage == 1 || CurrentPage == 2 || CurrentPage == 3 || CurrentPage == 4)
{
StkMain.Children.Add(GetRadioButton(3));
StkMain.Children.Add(GetRadioButton(4));
StkMain.Children.Add(GetRadioButton(5));
}
//...
StkMain.Children.Add(GetTextBlock());
//距离终点小于4,直接追加直到末尾
if (CurrentPage >= TotalPage - 3)
{
StkMain.Children.Add(GetTextBlock());
for (var i = TotalPage - 4; i <= TotalPage; i++)
{
StkMain.Children.Add(GetRadioButton(i));
}
return;
}
if (CurrentPage != 1 && CurrentPage != 2 && CurrentPage != 3 && CurrentPage != 4)
{
//追加三条
for (var i = CurrentPage - 1; i <= (CurrentPage + 1); i++)
{
StkMain.Children.Add(GetRadioButton(i));
}
}
StkMain.Children.Add(GetTextBlock());
for (var i = TotalPage - 1; i <= TotalPage; i++)
{
StkMain.Children.Add(GetRadioButton(i));
}
}
}
private void Select()
{
foreach (var item in StkMain.Children)
{
var radio = item as PURadioButton;
if (radio == null)
continue;
if (radio.Content.ToString() == CurrentPage.ToString())
{
radio.IsChecked = true;
break;
}
}
}
private PURadioButton GetRadioButton(int content)
{
var radio = new PURadioButton()
{
RadioButtonStyle = RadioButtonStyles.Button,
Content = content,
HorizontalAlignment = HorizontalAlignment.Left,
HorizontalContentAlignment = HorizontalAlignment.Center,
Padding = new Thickness(5,0,5,0),
Margin = new Thickness(6, 0, 0, 0),
};
var back = new Binding() { Source = this, Path = new PropertyPath("ButtonBrush"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.BackgroundProperty, back);
var cover = new Binding() { Source = this, Path = new PropertyPath("SelectedBrush"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.CoverBrushProperty, cover);
var fore = new Binding() { Source = this, Path = new PropertyPath("Foreground"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.ForegroundProperty, fore);
var height = new Binding() { Source = this, Path = new PropertyPath("ActualHeight"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.HeightProperty, height);
var radius = new Binding() { Source = this, Path = new PropertyPath("ButtonCornerRadius"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(radio, PURadioButton.BorderCornerRadiusProperty, radius);
radio.Click += delegate
{
CurrentPage = content;
};
return radio;
}
private TextBlock GetTextBlock()
{
var txt = new TextBlock()
{
Text = "...",
Margin = new Thickness(5, 0, 5, 0),
VerticalAlignment = VerticalAlignment.Center,
};
var fore = new Binding() { Source = this, Path = new PropertyPath("ButtonBrush"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(txt, TextBlock.ForegroundProperty, fore);
return txt;
}
#endregion
#region Sys
private void BtnLeft_Click(object sender, RoutedEventArgs e)
{
if (CurrentPage > 1)
CurrentPage--;
}
private void BtnRight_Click(object sender, RoutedEventArgs e)
{
if (CurrentPage < TotalPage)
CurrentPage++;
}
#endregion
}
}
================================================
FILE: Panuon.UI/A6_ContextMenu/PUContextMenu.cs
================================================
using System;
using System.Collections;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
public class PUContextMenu : ContextMenu
{
static PUContextMenu()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUContextMenu), new FrameworkPropertyMetadata(typeof(PUContextMenu)));
}
#region Property
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("该属性对此控件无效。请使用BindingItems属性替代。",true)]
public new IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
private set { SetValue(ItemsSourceProperty, value); }
}
public new static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(PUContextMenu));
///
/// 获取或设置当鼠标悬浮在子项上时,子项的背景颜色。默认值为#33AAAAAA。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUContextMenu));
///
/// 获取或设置边框的圆角大小,默认值为0。
///
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static readonly DependencyProperty BorderCornerRadiusProperty =
DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(PUContextMenu));
///
/// 获取或设置边框的阴影颜色。默认值为#44444444。
///
public Color ShadowColor
{
get { return (Color)GetValue(ShadowColorProperty); }
set { SetValue(ShadowColorProperty, value); }
}
public static readonly DependencyProperty ShadowColorProperty =
DependencyProperty.Register("ShadowColor", typeof(Color), typeof(PUContextMenu));
#endregion
}
}
================================================
FILE: Panuon.UI/A6_ContextMenu/PUContextMenuItem.cs
================================================
using System.Windows;
using System.Windows.Controls;
namespace Panuon.UI
{
public class PUContextMenuItem : MenuItem
{
static PUContextMenuItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUContextMenuItem), new FrameworkPropertyMetadata(typeof(PUContextMenuItem)));
}
#region Property
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(PUContextMenuItem));
#endregion
}
}
================================================
FILE: Panuon.UI/A7_Bubble/PUBubble.cs
================================================
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Panuon.UI
{
public class PUBubble : UserControl
{
static PUBubble()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PUBubble), new FrameworkPropertyMetadata(typeof(PUBubble)));
}
#region Property
///
/// 获取或设置当鼠标悬浮在气泡上时,气泡的背景颜色。默认值为#555555。
///
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUBubble), new PropertyMetadata(new SolidColorBrush(Colors.LightGray)));
///
/// 获取或设置尖角的位置,默认值为Left(左侧)。
///
public AnglePositions AnglePosition
{
get { return (AnglePositions)GetValue(AnglePositionProperty); }
set { SetValue(AnglePositionProperty, value); }
}
public static readonly DependencyProperty AnglePositionProperty =
DependencyProperty.Register("AnglePosition", typeof(AnglePositions), typeof(PUBubble), new PropertyMetadata(AnglePositions.Left));
///
/// 获取或设置圆角大小。默认值为0。
///
public CornerRadius BorderCornerRadius
{
get { return (CornerRadius)GetValue(BorderCornerRadiusProperty); }
set { SetValue(BorderCornerRadiusProperty, value); }
}
public static readonly DependencyProperty BorderCornerRadiusProperty =
DependencyProperty.Register("BorderCornerRadius", typeof(CornerRadius), typeof(PUBubble));
#endregion
}
}
================================================
FILE: Panuon.UI/Helper/Helper.cs
================================================
using System.Windows;
using System.Windows.Controls;
namespace Panuon.UI
{
public class Helper : DependencyObject
{
#region Column & Row
public static double GetColumnDefinition(DependencyObject obj)
{
return (double)obj.GetValue(ColumnDefinitionProperty);
}
public static void SetColumnDefinition(DependencyObject obj, double value)
{
obj.SetValue(ColumnDefinitionProperty, value);
}
public static readonly DependencyProperty ColumnDefinitionProperty =
DependencyProperty.RegisterAttached("ColumnDefinition", typeof(double), typeof(Helper), new PropertyMetadata(OnColumnDefinitionChanged));
private static void OnColumnDefinitionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var value = (double)e.NewValue;
var ele = d as FrameworkElement;
var parent = ele.Parent as Grid;
if (parent == null)
return;
Grid.SetColumn(ele, parent.ColumnDefinitions.Count);
parent.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(value, GridUnitType.Star) });
}
public static double GetRowDefinition(DependencyObject obj)
{
return (double)obj.GetValue(RowDefinitionProperty);
}
public static void SetRowDefinition(DependencyObject obj, double value)
{
obj.SetValue(RowDefinitionProperty, value);
}
public static readonly DependencyProperty RowDefinitionProperty =
DependencyProperty.RegisterAttached("RowDefinition", typeof(double), typeof(Helper), new PropertyMetadata(OnRowDefinitionChanged));
private static void OnRowDefinitionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var value = (double)e.NewValue;
var ele = d as FrameworkElement;
var parent = ele.Parent as Grid;
if (parent == null)
return;
Grid.SetRow(ele, parent.RowDefinitions.Count);
parent.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(value, GridUnitType.Star) });
}
#endregion
#region Height & Width
public static double GetHeight(DependencyObject obj)
{
return (double)obj.GetValue(HeightProperty);
}
public static void SetHeight(DependencyObject obj, double value)
{
obj.SetValue(HeightProperty, value);
}
public static readonly DependencyProperty HeightProperty =
DependencyProperty.RegisterAttached("Height", typeof(double), typeof(Helper), new PropertyMetadata(OnHeightChanged));
private static void OnHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var value = (double)e.NewValue;
var ele = d as FrameworkElement;
var parent = ele.Parent as FrameworkElement;
if (parent == null)
return;
parent.Loaded += delegate
{
ele.Height = parent.ActualWidth * value;
};
}
public static double GetWidth(DependencyObject obj)
{
return (double)obj.GetValue(WidthProperty);
}
public static void SetWidth(DependencyObject obj, double value)
{
obj.SetValue(WidthProperty, value);
}
public static readonly DependencyProperty WidthProperty =
DependencyProperty.RegisterAttached("Width", typeof(double), typeof(Helper), new PropertyMetadata(OnWidthChanged));
private static void OnWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var value = (double)e.NewValue;
var ele = d as FrameworkElement;
var parent = ele.Parent as FrameworkElement;
if (parent == null)
return;
parent.Loaded += delegate
{
ele.Width = parent.ActualWidth * value;
};
}
#endregion
}
}
================================================
FILE: Panuon.UI/Others/Enums.cs
================================================
/*==============================================================
*作者:ZEOUN
*时间:2018/11/19 11:09:29
*说明:
*日志:2018/11/19 11:09:29 创建。
*==============================================================*/
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Panuon.UI
{
public enum ButtonStyles
{
///
/// 一个常规按钮。
///
General = 1,
///
/// 一个带边框的空心按钮,当鼠标悬浮时才会显示背景色。
/// 当鼠标移入时,该按钮的背景色将由Background变为指定的CoverBrush。
///
Hollow = 2,
///
/// 一个带边框的空心按钮,当鼠标悬浮时才会显示前景色。
/// 当鼠标移入时,该按钮的边框和前景色将由BorderBrush和Foreground变为指定的CoverBrush。
///
Outline = 3,
///
/// 一个不带任何边框和背景色的文字按钮。
/// 当鼠标移入时,该按钮的前景色将由Foreground变为指定的CoverBrush。
///
Link = 4,
}
public enum RepeatButtonStyles
{
///
/// 一个常规按钮。
///
General = 1,
///
/// 一个带边框的空心按钮,当鼠标悬浮时才会显示背景色。
/// 当鼠标移入时,该按钮的背景色将由Background变为指定的CoverBrush。
///
Hollow = 2,
///
/// 一个带边框的空心按钮,当鼠标悬浮时才会显示前景色。
/// 当鼠标移入时,该按钮的边框和前景色将由BorderBrush和Foreground变为指定的CoverBrush。
///
Outline = 3,
///
/// 一个不带任何边框和背景色的文字按钮。
/// 当鼠标移入时,该按钮的前景色将由Foreground变为指定的CoverBrush。
///
Link = 4,
}
public enum ClickStyles
{
///
/// 点击按钮时不触发下沉操作。
///
Classic,
///
/// 点击时按钮下沉2个px。
///
Sink,
}
public enum TextBoxStyles
{
///
/// 一个标准的输入框。
///
General = 1,
///
/// 一个输入框前带图标的输入框。
///
IconGroup = 2,
}
public enum PasswordBoxStyles
{
///
/// 一个标准的密码框。
///
General = 1,
///
/// 一个密码框前带图标的密码框。
///
IconGroup = 2,
}
public enum SelectedValuePaths
{
Header,
Value
}
public enum DeleteModes
{
///
/// 当用户点击删除按钮时,删除项目并触发DeleteItem路由事件。
///
Delete,
///
/// 当用户点击删除按钮时,不直接删除项目(只触发DeleteItem路由事件)。
///
EventOnly,
}
public enum SearchModes
{
///
/// 不显示搜索框。
///
None,
///
/// 在搜索框按下键盘时搜索。
///
TextChanged,
///
/// 当按下Enter键时发起搜索。
///
Enter,
}
public enum CheckBoxStyles
{
///
/// 一个标准的选择框。
///
General = 1,
///
/// 一个经典样式的选择框。
///
Classic = 2,
///
/// 一个开关样式的选择框。
///
Switch = 3,
///
/// 一个带有左边线的选择框。
///
Branch = 4,
///
/// 一个类似于按钮样式的选择框。
///
Button = 5,
}
public enum RadioButtonStyles
{
///
/// 一个标准的RadioButton。
///
General = 1,
///
/// 一个经典样式的RadioButton。
///
Classic = 2,
///
/// 一个开关样式的RadioButton。
///
Switch = 3,
///
/// 一个带有左边线的RadioButton。
///
Branch = 4,
///
/// 一个类似于按钮样式的选择框。
///
Button = 5,
}
public enum ProgressDirections
{
LeftToRight,
RightToLeft,
TopToBottom,
BottomToTop,
}
public enum ProgressBarStyles
{
///
/// 一个标准的进度条。
///
General,
///
/// 一个环形的进度条。
///
Ring
}
public enum TreeViewStyles
{
General,
Classic,
}
public enum TabControlStyles
{
General,
Classic,
}
public enum DatePickerModes
{
///
/// 年 月 日。
///
DateOnly,
///
/// 时 分 秒。
///
TimeOnly,
///
/// 年 月 日 时 分 秒。
///
DateTime,
}
public enum AnglePositions
{
Left,
BottomLeft,
BottomCenter,
BottomRight,
Right,
}
}
================================================
FILE: Panuon.UI/Panuon.UI.csproj
================================================
Debug
AnyCPU
{72B3698E-1784-4101-99AE-FC7B8F48E96D}
library
Panuon.UI
Panuon.UI
v4.0
512
{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
4
true
full
false
bin\Debug\
DEBUG;TRACE
prompt
4
false
pdbonly
true
bin\Release\
TRACE
prompt
4
false
4.0
Designer
MSBuild:Compile
Designer
MSBuild:Compile
Designer
MSBuild:Compile
MSBuild:Compile
Designer
Designer
MSBuild:Compile
Designer
MSBuild:Compile
MSBuild:Compile
Designer
Designer
MSBuild:Compile
Designer
MSBuild:Compile
MSBuild:Compile
Designer
Designer
MSBuild:Compile
PUImageCuter.xaml
PUIndicator.xaml
PULoading.xaml
PUMessageBox.xaml
PUSlideShow.xaml
PUSlider.xaml
PUDatePicker.xaml
PUPagingNav.xaml
Code
True
True
Resources.resx
True
Settings.settings
True
ResXFileCodeGenerator
Resources.Designer.cs
SettingsSingleFileGenerator
Settings.Designer.cs
================================================
FILE: Panuon.UI/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Panuon.UI")]
[assembly: AssemblyDescription("A wpf custom control library")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Panuon.UI")]
[assembly: AssemblyCopyright("Copyright ©Panuon 2016-2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
//若要开始生成可本地化的应用程序,请设置
//.csproj 文件中的 CultureYouAreCodingWith
//例如,如果您在源文件中使用的是美国英语,
//使用的是美国英语,请将 设置为 en-US。 然后取消
//对以下 NeutralResourceLanguage 特性的注释。 更新
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
//(未在页面中找到资源时使用,
//或应用程序资源字典中找到时使用)
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
//(未在页面中找到资源时使用,
//、应用程序或任何主题专用资源字典中找到时使用)
)]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.2")]
[assembly: Guid("61afca85-a805-4bca-1b07-60d11797ecdd")]
================================================
FILE: Panuon.UI/Properties/Resources.Designer.cs
================================================
//------------------------------------------------------------------------------
//
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
//
//------------------------------------------------------------------------------
namespace Panuon.UI.Properties {
using System;
///
/// 一个强类型的资源类,用于查找本地化的字符串等。
///
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
///
/// 返回此类使用的缓存的 ResourceManager 实例。
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Panuon.UI.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
///
/// 使用此强类型资源类,为所有资源查找
/// 重写当前线程的 CurrentUICulture 属性。
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
================================================
FILE: Panuon.UI/Properties/Resources.resx
================================================
text/microsoft-resx
2.0
System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
================================================
FILE: Panuon.UI/Properties/Settings.Designer.cs
================================================
//------------------------------------------------------------------------------
//
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
//
//------------------------------------------------------------------------------
namespace Panuon.UI.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}
================================================
FILE: Panuon.UI/Properties/Settings.settings
================================================
================================================
FILE: Panuon.UI/Themes/Control.xaml
================================================
/#fontawesome
================================================
FILE: Panuon.UI/Themes/Generic.xaml
================================================
================================================
FILE: Panuon.UI/Themes/Resources.xaml
================================================
================================================
FILE: Panuon.UI/Utils/Converters.cs
================================================
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
namespace Panuon.UI
{
//ProgressBar专用内部圆角转换器
internal class GeneralProgressBarConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是CornerRadius,1是Direction
var cr = (CornerRadius)values[0];
var dir = (ProgressDirections)values[1];
if (dir == ProgressDirections.LeftToRight)
return new CornerRadius(cr.TopLeft, 0, 0, cr.BottomLeft);
else if (dir == ProgressDirections.RightToLeft)
return new CornerRadius(0, cr.TopRight, cr.BottomRight, 0);
else if (dir == ProgressDirections.TopToBottom)
return new CornerRadius(cr.TopLeft, cr.TopRight, 0, 0);
else
return new CornerRadius(0, 0, cr.BottomRight, cr.BottomLeft);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
internal class RingProgressBarConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是CornerRadius,1是Direction
var width = (double)values[0];
var height = (double)values[1];
var radius = (double)values[2];
var percent = values.Length == 3 ? 1 : (double)values[3];
var point1X = height / 2 * Math.Cos((2 * percent - 0.5) * Math.PI) + height / 2;
var point1Y = height / 2 - height / 2 * Math.Sin((2 * percent + 0.5) * Math.PI);
var point2X = (height - radius)/ 2 * Math.Cos((2 * percent - 0.5) * Math.PI) + height / 2;
var point2Y = height / 2 - (height - radius) / 2 * Math.Sin((2 * percent + 0.5) * Math.PI);
var path = "";
if(percent == 0)
{
path = "";
}
else if (percent < 0.5)
{
path = "M " + width / 2 + "," + radius / 2 + " A " + (width - radius) / 2 + "," + (width - radius) / 2 + " 0 0 1 " + point2X + "," + point2Y + "";
}
else if(percent == 0.5)
{
path = "M " + width / 2 + "," + radius / 2 + " A " + (width - radius) / 2 + "," + (width - radius) / 2 + " 0 0 1 " + width / 2 + "," + (height - radius / 2);
}
else
{
path = "M " + width / 2 + "," + radius / 2 + " A " + (width - radius) / 2 + "," + (width - radius) / 2 + " 0 0 1 " + width / 2 + "," + (height - radius / 2) +
" A " + (width - radius) / 2 + "," + (width - radius) / 2 + " 0 0 1 " + point2X + "," + point2Y + "";
}
return PathGeometry.Parse(path);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
internal class BubbleConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var location = (AnglePositions)values[0];
var radius = (CornerRadius)values[1];
var width = (double)values[2];
var height = (double)values[3];
var path = "";
switch (location)
{
case AnglePositions.Left:
if (radius == new CornerRadius(0))
path = "M0," + height / 2 + "L5," + (height / 2 + 4) +
"V" + height + "H" + width + "V 0 H 5 V" + (height / 2 - 4) + "Z";
else
path = "M0," + height / 2 + "L5," + (height / 2 + 4) +
"V" + (height - radius.BottomLeft) + "A" + radius.BottomLeft + "," + radius.BottomLeft + " 0 0 0 " + (5 + radius.BottomLeft) + "," + height +
"H" + (width - radius.BottomRight) + "A" + radius.BottomRight + "," + radius.BottomRight + " 0 0 0 " + width + "," + (height - radius.BottomRight) +
"V" + radius.TopRight + "A" + radius.TopRight + "," + radius.TopRight + " 0 0 0 " + (width - radius.TopRight) + "," + 0 +
"H" + (5 + radius.TopLeft) + "A" + radius.TopLeft + "," + radius.TopLeft + " 0 0 0 " + 5 + "," + radius.TopLeft +
"V" + (height / 2 - 4) + "Z";
break;
case AnglePositions.BottomLeft:
if (radius == new CornerRadius(0))
path = "M0," + height + "L4," + (height - 5) +
"H " + width + "V 0 H 0 Z";
else
path = "M0," + height + "L4," + (height - 5) +
"H" + (width - radius.BottomRight) + "A" + radius.BottomRight +"," + radius.BottomRight + " 0 0 0 " + width + "," + (height - radius.BottomRight - 5) +
"V" + radius.TopRight + "A" + radius.TopRight + "," + radius.TopRight + " 0 0 0 " + (width - radius.TopRight) + "," + 0 +
"H" + radius.TopLeft + "A" + radius.TopLeft + "," + radius.TopLeft + " 0 0 0 " + 0 + "," + radius.TopLeft +
"Z";
break;
case AnglePositions.BottomCenter:
if (radius == new CornerRadius(0))
path = "M" + width / 2 + "," + height + "L" + (width / 2 + 5) + "," + (height - 4) +
"H" + width + "V 0 H 0 V" + (height - 4) + "H" + (width / 2 - 5) + "Z";
else
path = "M" + width / 2 + "," + height + "L" + (width / 2 + 5) + "," + (height - 4) +
"H" + (width - radius.BottomRight) + "A" + radius.BottomRight + "," + radius.BottomRight + " 0 0 0 " + width + "," + (height - radius.BottomRight - 5) +
"V" + radius.TopRight + "A" + radius.TopRight + "," + radius.TopRight + " 0 0 0 " + (width - radius.TopRight) + "," + 0 +
"H" + radius.TopLeft + "A" + radius.TopLeft + "," + radius.TopLeft + " 0 0 0 " + 0 + "," + radius.TopLeft +
"V" + (height - radius.BottomRight - 5) + "A" + radius.BottomRight + "," + radius.BottomRight + " 0 0 0 " + radius.BottomRight + "," + (height - 5) +
"H" + (width / 2 - 5) + "Z";
break;
case AnglePositions.BottomRight:
if (radius == new CornerRadius(0))
path = "M" + width + "," + height + "V 0 H 0 V " + (height - 4) + "H" + (width - 5) + "Z";
else
path = "M" + width + "," + height + "V" + radius.TopRight + "A" + radius.TopRight + ","+ radius.TopRight + " 0 0 0 " + (width - radius.TopRight) + "," + 0 +
"H" + radius.TopLeft + "A" + radius.TopLeft + "," + radius.TopLeft + " 0 0 0 " + 0 + "," + radius.TopLeft +
"V" + (height - radius.BottomRight - 5) + "A" + radius.BottomRight + "," + radius.BottomRight + " 0 0 0 " + radius.BottomRight + "," + (height - 5) +
"H" + (width - 5) + "Z";
break;
case AnglePositions.Right:
if (radius == new CornerRadius(0))
path = "M" + width + "," + height / 2 + "L" + (width - 5) + "," + (height / 2 - 4) + "V 0 H 0 V" +
height + "H " + (width - 5) + "V" + (height / 2 + 4) + "Z";
else
path = "M" + width + "," + height / 2 + "L" + (width - 5) + "," + (height / 2 - 4) + "V" + radius.TopRight + "A" + radius.TopRight + "," + radius.TopRight + " 0 0 0 " + (width - radius.TopRight - 5) + "," + 0 +
"H" + radius.TopLeft + "A" + radius.TopLeft + "," + radius.TopLeft + " 0 0 0 " + 0 + "," + radius.TopLeft +
"V" + (height - radius.BottomLeft) + "A" + radius.BottomLeft + "," + radius.BottomLeft + " 0 0 0 " + radius.BottomLeft + "," + height +
"H" + (width - radius.BottomRight - 5) + "A" + radius.BottomRight + "," + radius.BottomRight + " 0 0 0 " + (width - 5) + "," + (height - radius.BottomRight) +
"V" + (height / 2 + 4) + "Z";
break;
}
return Geometry.Parse(path);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
internal class WidthToMarginConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var actualWidth = (double)value;
return new Thickness(actualWidth, 0, 0, 1);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
internal class MarginToWidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var thickness = (Thickness)value;
return thickness.Left;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
//Window Header和Title转换器
internal class HeaderConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是Header,1是Title
return (string)values[0] == null ? (string)values[1]: (string)values[0];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
//Icon字体大小转换器( + 5)
internal class IconFontSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value + 5;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
//CheckBox General样式内部对号的缩放比例
internal class ScaleConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是InnerWidth,1是InnerHeight
var minvalue = (double)values[0] < (double)values[1] ? (double)values[0] : (double)values[1];
return minvalue / 22;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
internal class ToggleHeightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value - 2;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
//内部Toggle的圆角转换器
internal class ToHalfConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value / 2;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
//内部Toggle的水平偏移量转换器
internal class ToggleTranslateXConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是InnerWidth,1是InnerHeight
return ((double)values[0] - (double)values[1] + 1) * -1;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
//输入框内部宽度转换器
internal class TextBoxInnerWidthConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是Width,1是Padding,,2是HorizontalContentAlignment
if ((HorizontalAlignment)values[2] != HorizontalAlignment.Center)
return (double)values[0] - ((Thickness)values[1]).Left - ((Thickness)values[1]).Right;
else
return DependencyProperty.UnsetValue;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
//输入框内部高度转换器
internal class TextBoxInnerHeightConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是Heihgt,1是Padding,2是VerticalContentAlignment
if ((VerticalAlignment)values[2] != VerticalAlignment.Center)
return (double)values[0] - ((Thickness)values[1]).Top - ((Thickness)values[1]).Bottom;
else
return DependencyProperty.UnsetValue;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
}
================================================
FILE: Panuon.UI/Utils/Extends.cs
================================================
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Panuon.UI.Utils
{
public static class Extends
{
#region String
///
/// 尝试将字符串转换为整数,若转换失败,则返回0。
///
public static int ToInt(this string context)
{
var result = 0;
if (Int32.TryParse(context, out result))
return result;
else
return 0;
}
///
/// 尝试将字符串转换为小数,若转换失败,则返回0。
///
public static double ToDouble(this string context)
{
var result = 0.0;
if (Double.TryParse(context, out result))
return result;
else
return 0;
}
#endregion
#region DateTime
///
/// 将时间转换成时间戳(精确到毫秒)。
///
public static long ToTimeStamp(this DateTime date)
{
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1);
return Convert.ToInt64(ts.TotalMilliseconds);
}
///
/// 与另一个日期的年月日进行比较,若相同,则返回True。
///
public static bool CompareYearMonthDay(this DateTime date1, DateTime date2)
{
return date1.Year == date2.Year && date1.Month == date2.Month && date1.Day == date2.Day;
}
#endregion
#region Long
///
/// 将时间戳转换成时间(精确到毫秒)。
///
public static DateTime ToDate(this long timeStamp)
{
return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).AddMilliseconds((long)timeStamp);
}
#endregion
#region List
///
/// 将列表中的每个元素拼接成一段字符串。
///
/// 分隔符。
public static string ToString(this IList list,string spliter)
{
return String.Join(spliter, list);
}
public static ObservableCollection ToObservableCollection(this IList list)
{
return new ObservableCollection(list);
}
#endregion
}
}
================================================
FILE: Panuon.UI/Utils/Utils.cs
================================================
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Panuon.UI.Utils
{
///
/// 提供Task的简易池化管理,并发任务数量可控。
///
public class TaskPoll
{
#region Identity
private static ConcurrentQueue _taskQueue;
private static int _runningTaskQuantity;
#endregion
#region Property
///
/// 获取或设置可以允许同时运行的最大任务数量。
/// 若值为Null,则不限制最大执行数量。
///
public static int? MaxTaskQuantity
{
get { return _maxTaskQuantity; }
set { _maxTaskQuantity = value; RecheckQueue(); }
}
private static int? _maxTaskQuantity;
///
/// 获取当前任务池中的任务总数(包括排队中和正在执行的)。
///
public static int CurrentTaskQuantity
{
get { return _taskQueue == null ? 0 : _taskQueue.Count; }
}
///
/// 获取当前正在执行的任务数量。
///
public static int RunningTaskQuantity
{
get { return _runningTaskQuantity; }
}
#endregion
#region APIs
///
/// 使用默认值初始化TaskManager。首次调用StartNew方法时,TaskManager将自动执行初始化。
///
public static void Init()
{
_taskQueue = new ConcurrentQueue();
_runningTaskQuantity = 0;
}
///
/// 使用指定值初始化TaskManager。
/// 允许同时运行的最大任务数量。
///
public static void Init(int maxTaskQuantity)
{
MaxTaskQuantity = maxTaskQuantity;
_taskQueue = new ConcurrentQueue();
_runningTaskQuantity = 0;
}
///
/// 向任务队列中插入一个待执行的新任务,该任务将在合适的时机执行。
///
public static void StartNew(Task task)
{
if (_taskQueue == null)
Init();
_taskQueue.Enqueue(task);
RecheckQueue();
}
///
/// 向任务队列中插入一个待执行的新任务,该任务将在合适的时机执行。
///
public static void StartNew(Task task)
{
if (_taskQueue == null)
Init();
_taskQueue.Enqueue(task);
RecheckQueue();
}
#endregion
#region Funtion
private static void RecheckQueue()
{
if (_taskQueue == null)
return;
if (_taskQueue.Count == 0 || (MaxTaskQuantity != null && _runningTaskQuantity >= MaxTaskQuantity))
return;
Task task;
if (!_taskQueue.TryDequeue(out task))
{
RecheckQueue();
return;
}
if (task.Status != TaskStatus.Created && task.Status != TaskStatus.WaitingToRun)
{
RecheckQueue();
return;
}
Interlocked.Increment(ref _runningTaskQuantity);
task.ContinueWith((t) =>
{
Interlocked.Decrement(ref _runningTaskQuantity);
RecheckQueue();
});
task.Start();
if(_runningTaskQuantity < MaxTaskQuantity)
RecheckQueue();
}
#endregion
}
///
/// 提供缓存管理(线程安全的),便于缓存数量逐步扩展。
///
public class PUCache
{
#region Identity
///
/// 缓存集合。
///
private static ConcurrentDictionary Caches { get; set; }
#endregion
#region EventHandle
///
/// 当FindAny方法提供的ID数组中有部分值不存在时,触发此事件。
/// 事件参数(UID列表)类型:IList
///
public static EventHandler LackItems;
#endregion
#region Constructor
static PUCache()
{
Caches = new ConcurrentDictionary();
}
#endregion
#region Property
///
/// 获取当前缓存的数量。
///
public static int Count
{
get { return Caches.Count; }
}
#endregion
#region APIs
///
/// 向缓存中添加数据。若ID已存在,则覆盖原有的值。
///
/// 标识该对象的唯一ID。
/// 要添加的对象。
public static void Add(string uid, T obj)
{
Caches.AddOrUpdate(uid, obj, (key, oldValue) => obj);
}
///
/// 查找指定ID的值。若找不到,则返回默认值。
///
/// 标识该对象的唯一ID。
///
public static T Find(string uid)
{
var obj = Caches.FirstOrDefault(x => x.Key == uid);
if (obj.Equals(default(KeyValuePair)))
return default(T);
else
return obj.Value;
}
///
/// 查找多个指定ID的值。不存在的ID不会存在于返回值列表中,并且会触发LackItems事件。
///
/// 要查找的唯一ID数组。
///
public static IList> FindAny(params string[] uids)
{
var resultList = Caches.Where(x => uids.Contains(x.Key));
var lackuids = uids.Except(resultList.Select(x => x.Key).ToList()).ToList();
if (LackItems != null && lackuids.Count != 0)
LackItems(lackuids, null);
return resultList.ToList();
}
///
/// 清除所有缓存。
///
public static void Clear()
{
Caches.Clear();
}
///
/// 移除指定ID的值。若移除成功,则返回True。
///
///
public static bool Remove(string uid)
{
T obj;
return Caches.TryRemove(uid, out obj);
}
///
/// 获取指定的ID是否存在于缓存中。
///
///
public static bool Exists(string uid)
{
return !String.IsNullOrEmpty(Caches.FirstOrDefault(x => x.Key == uid).Key);
}
///
/// 获取指定的ID是否存在于缓存中,并返回不存在的ID集合。
///
public static IList Exists(params string[] uids)
{
return Caches.Where(x => !uids.Contains(x.Key)).Select(x => x.Key).ToList();
}
#endregion
}
}
================================================
FILE: Panuon.UI/Z_Helper/Helper.cs
================================================
using System.Windows;
using System.Windows.Controls;
namespace Panuon.UI
{
public class Helper : DependencyObject
{
#region Column & Row
public static string GetColumnDefinition(DependencyObject obj)
{
return (string)obj.GetValue(ColumnDefinitionProperty);
}
public static void SetColumnDefinition(DependencyObject obj, string value)
{
obj.SetValue(ColumnDefinitionProperty, value);
}
public static readonly DependencyProperty ColumnDefinitionProperty =
DependencyProperty.RegisterAttached("ColumnDefinition", typeof(string), typeof(Helper), new PropertyMetadata(OnColumnDefinitionChanged));
private static void OnColumnDefinitionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var value = (string)e.NewValue;
var ele = d as FrameworkElement;
var parent = ele.Parent as Grid;
if (parent == null)
return;
Grid.SetColumn(ele, parent.ColumnDefinitions.Count);
var length = 0.0;
if (value.Contains("*"))
{
value = value.Replace("*", "");
double.TryParse(value ,out length);
if (length == 0)
length = 1;
parent.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(length, GridUnitType.Star) });
}
else
{
double.TryParse(value, out length);
parent.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(length, GridUnitType.Pixel) });
}
}
public static string GetRowDefinition(DependencyObject obj)
{
return (string)obj.GetValue(RowDefinitionProperty);
}
public static void SetRowDefinition(DependencyObject obj, string value)
{
obj.SetValue(RowDefinitionProperty, value);
}
public static readonly DependencyProperty RowDefinitionProperty =
DependencyProperty.RegisterAttached("RowDefinition", typeof(string), typeof(Helper), new PropertyMetadata(OnRowDefinitionChanged));
private static void OnRowDefinitionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var value = (string)e.NewValue;
var ele = d as FrameworkElement;
var parent = ele.Parent as Grid;
if (parent == null)
return;
Grid.SetRow(ele, parent.RowDefinitions.Count);
var length = 0.0;
if (value.Contains("*"))
{
value = value.Replace("*", "");
double.TryParse(value, out length);
if (length == 0)
length = 1;
parent.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(length, GridUnitType.Star) });
}
else
{
double.TryParse(value, out length);
parent.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(length, GridUnitType.Pixel) });
}
}
#endregion
#region Height & Width
public static double GetHeight(DependencyObject obj)
{
return (double)obj.GetValue(HeightProperty);
}
public static void SetHeight(DependencyObject obj, double value)
{
obj.SetValue(HeightProperty, value);
}
public static readonly DependencyProperty HeightProperty =
DependencyProperty.RegisterAttached("Height", typeof(double), typeof(Helper), new PropertyMetadata(OnHeightChanged));
private static void OnHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var value = (double)e.NewValue;
var ele = d as FrameworkElement;
var parent = ele.Parent as FrameworkElement;
if (parent == null)
return;
parent.Loaded += delegate
{
ele.Height = parent.ActualWidth * value;
};
}
public static double GetWidth(DependencyObject obj)
{
return (double)obj.GetValue(WidthProperty);
}
public static void SetWidth(DependencyObject obj, double value)
{
obj.SetValue(WidthProperty, value);
}
public static readonly DependencyProperty WidthProperty =
DependencyProperty.RegisterAttached("Width", typeof(double), typeof(Helper), new PropertyMetadata(OnWidthChanged));
private static void OnWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var value = (double)e.NewValue;
var ele = d as FrameworkElement;
var parent = ele.Parent as FrameworkElement;
if (parent == null)
return;
parent.Loaded += delegate
{
ele.Width = parent.ActualWidth * value;
};
}
#endregion
}
}
================================================
FILE: Panuon.UI/Z_Models/PUComboBoxItemModel.cs
================================================
using System;
using System.ComponentModel;
namespace Panuon.UI
{
public class PUComboBoxItemModel : INotifyPropertyChanged
{
protected internal virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
#region Constructor
public PUComboBoxItemModel()
{
Uid = Guid.NewGuid().ToString("N");
}
#endregion
#region Property
///
/// 要显示的名称。可以作为SelectValuePath的值。
///
public string Header
{
get { return _header; }
set { _header = value; OnPropertyChanged("Header"); }
}
private string _header = "";
///
/// 该对象的值。可以作为SelectValuePath的值。
/// 若Value不是值类型,使用Value作为匹配时会逐一比较每一个可写属性的值(参见PanuonUI.Utils扩展方法IsEqual)。
///
public object Value
{
get { return _value; }
set { _value = value; OnPropertyChanged("Value"); }
}
private object _value;
///
/// 是否显示删除按钮。
///
public bool CanDelete
{
get { return _canDelete; }
set { _canDelete = value; OnPropertyChanged("CanDelete"); }
}
private bool _canDelete = false;
///
/// 生成该对象时,自动生成的唯一ID。该属性 与该对象生成的PUComboBoxItem的Uid属性值相等。
///
public string Uid
{
get { return _uid; }
private set { _uid = value; }
}
private string _uid;
#endregion
}
}
================================================
FILE: Panuon.UI/Z_Models/PUListBoxItemModel.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
namespace Panuon.UI
{
///
/// 用于ListBox绑定的模型。
///
public class PUListBoxItemModel : INotifyPropertyChanged
{
protected internal virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
#region Constructor
public PUListBoxItemModel()
{
Uid = Guid.NewGuid().ToString("N");
}
#endregion
#region Property
///
/// 要显示的内容。可以作为SelectValuePath的值。用于设置ListBoxItem的Content属性。
///
public object Header
{
get { return _header; }
set
{
_header = value; OnPropertyChanged("Header");
}
}
private object _header = "";
///
/// 该对象的值。可以作为SelectValuePath的值。
/// 若Value不是值类型,使用Value作为匹配时会逐一比较每一个可写属性的值(参见PanuonUI.Utils扩展方法IsEqual)。
///
public object Value
{
get { return _value; }
set
{
_value = value; OnPropertyChanged("Value");
}
}
private object _value;
#endregion
#region Internal Property
internal string Uid
{
get { return _uid; }
set { _uid = value; }
}
private string _uid;
#endregion
}
}
================================================
FILE: Panuon.UI/Z_Models/PUTabItemModel.cs
================================================
using System;
using System.ComponentModel;
namespace Panuon.UI
{
public class PUTabItemModel : INotifyPropertyChanged
{
protected internal virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
#region Constructor
public PUTabItemModel()
{
Uid = Guid.NewGuid().ToString("N");
}
#endregion
#region Property
///
/// 要显示的名称。可以作为SelectValuePath的值。
///
public object Header
{
get { return _header; }
set { _header = value; OnPropertyChanged("Header"); }
}
private object _header = "";
///
/// 该对象的值。可以作为SelectValuePath的值。
/// 若Value不是值类型,使用Value作为匹配时会逐一比较每一个可写属性的值(参见PanuonUI.Utils扩展方法IsEqual)。
///
public object Value
{
get { return _value; }
set { _value = value; OnPropertyChanged("Value"); }
}
private object _value;
///
/// 显示在标题前的图标,为空时不显示。
///
public object Icon
{
get { return _icon; }
set { _icon = value; OnPropertyChanged("Icon"); }
}
private object _icon;
///
/// 是否显示删除按钮。
///
public bool CanDelete
{
get { return _canDelete; }
set { _canDelete = value; OnPropertyChanged("CanDelete"); }
}
private bool _canDelete = false;
///
/// TabItem的内容。
///
public object Content
{
get { return _content; }
set { _content = value; OnPropertyChanged("Content"); }
}
private object _content = 0;
///
/// 高度,默认值为30。
///
public double Height
{
get { return _height; }
set { _height = value; OnPropertyChanged("Height"); }
}
private double _height = 30;
#endregion
#region Internal Property
internal string Uid
{
get { return _uid; }
set { _uid = value; }
}
private string _uid;
#endregion
}
}
================================================
FILE: Panuon.UI/Z_Models/PUTreeViewItemModel.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
namespace Panuon.UI
{
///
/// 用于TreeView绑定的模型。
///
public class PUTreeViewItemModel : INotifyPropertyChanged
{
protected internal virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
#region Constructor
public PUTreeViewItemModel()
{
Uid = Guid.NewGuid().ToString("N");
Padding = new Thickness(10, 0, 0, 0);
}
#endregion
#region Property
///
/// 要显示的名称。可以作为SelectValuePath的值。
///
public string Header
{
get { return _header; }
set
{
_header = value; OnPropertyChanged("Header");
}
}
private string _header = "";
///
/// 该对象的值。可以作为SelectValuePath的值。
/// 若Value不是值类型,使用Value作为匹配时会逐一比较每一个可写属性的值(参见PanuonUI.Utils扩展方法IsEqual)。
///
public object Value
{
get { return _value; }
set
{
_value = value; OnPropertyChanged("Value");
}
}
private object _value;
///
/// 该项的子项目。
///
public List Items
{
get { return _items; }
set
{
_items = value; OnPropertyChanged("Items");
}
}
private List _items;
///
/// 缩进。默认值为10,0,0,0。
///
public Thickness Padding
{
get { return _padding; }
set
{
_padding = value; OnPropertyChanged("Padding");
}
}
private Thickness _padding;
///
/// 悬浮时显示的内容。
///
public object ToolTip
{
get { return _toolTip; }
set
{
_toolTip = value; OnPropertyChanged("ToolTip");
}
}
private object _toolTip;
#endregion
#region Internal Property
internal string Uid
{
get { return _uid; }
set { _uid = value; }
}
private string _uid;
#endregion
}
}
================================================
FILE: Panuon.UI/Z_Others/Converters.cs
================================================
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
namespace Panuon.UI
{
internal class DropDownBorderPathConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var width = values[0] as double? ?? 0;
var height = values[1] as double? ?? 0;
var contentWidth = values[2] as double? ?? 0;
var contentHeight = values[3] as double? ?? 0;
var placement = values[4] as DropDownPlacement? ?? DropDownPlacement.LeftBottom;
var radius = values[5] as double? ?? 0;
var path = "";
switch (placement)
{
case DropDownPlacement.LeftBottom:
path = $"M 1,{radius + 7} A{radius},{radius} 0 0 1 {radius + 1}, 7 H {width - contentWidth / 2 - 5} L {width - contentWidth / 2},1 L {width - contentWidth / 2 + 5},7 H {width - radius - 1} A{radius},{radius} 0 0 1 {width - 1}, {radius + 7}" +
$"V {height - radius - 1} A{radius},{radius} 0 0 1 {width - radius - 1}, {height - 1} H {radius + 1} A{radius},{radius} 0 0 1 1, {height - radius - 1} Z";
break;
}
return Geometry.Parse(path);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
//ProgressBar专用内部圆角转换器
internal class GeneralProgressBarConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是CornerRadius,1是Direction
var cr = (CornerRadius)values[0];
var dir = (ProgressDirections)values[1];
if (dir == ProgressDirections.LeftToRight)
return new CornerRadius(cr.TopLeft, 0, 0, cr.BottomLeft);
else if (dir == ProgressDirections.RightToLeft)
return new CornerRadius(0, cr.TopRight, cr.BottomRight, 0);
else if (dir == ProgressDirections.TopToBottom)
return new CornerRadius(cr.TopLeft, cr.TopRight, 0, 0);
else
return new CornerRadius(0, 0, cr.BottomRight, cr.BottomLeft);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
internal class RingProgressBarConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是CornerRadius,1是Direction
var width = (double)values[0];
var height = (double)values[1];
var radius = (double)values[2];
var percent = values.Length == 3 ? 1 : (double)values[3];
var point1X = height / 2 * Math.Cos((2 * percent - 0.5) * Math.PI) + height / 2;
var point1Y = height / 2 - height / 2 * Math.Sin((2 * percent + 0.5) * Math.PI);
var point2X = (height - radius)/ 2 * Math.Cos((2 * percent - 0.5) * Math.PI) + height / 2;
var point2Y = height / 2 - (height - radius) / 2 * Math.Sin((2 * percent + 0.5) * Math.PI);
var path = "";
if(percent == 0)
{
path = "";
}
else if (percent < 0.5)
{
path = "M " + width / 2 + "," + radius / 2 + " A " + (width - radius) / 2 + "," + (width - radius) / 2 + " 0 0 1 " + point2X + "," + point2Y + "";
}
else if(percent == 0.5)
{
path = "M " + width / 2 + "," + radius / 2 + " A " + (width - radius) / 2 + "," + (width - radius) / 2 + " 0 0 1 " + width / 2 + "," + (height - radius / 2);
}
else
{
path = "M " + width / 2 + "," + radius / 2 + " A " + (width - radius) / 2 + "," + (width - radius) / 2 + " 0 0 1 " + width / 2 + "," + (height - radius / 2) +
" A " + (width - radius) / 2 + "," + (width - radius) / 2 + " 0 0 1 " + point2X + "," + point2Y + "";
}
return PathGeometry.Parse(path);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
internal class BubbleConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var location = (AnglePositions)values[0];
var radius = (CornerRadius)values[1];
var width = (double)values[2];
var height = (double)values[3];
var path = "";
switch (location)
{
case AnglePositions.Left:
if (radius == new CornerRadius(0))
path = "M0," + height / 2 + "L5," + (height / 2 + 4) +
"V" + height + "H" + width + "V 0 H 5 V" + (height / 2 - 4) + "Z";
else
path = "M0," + height / 2 + "L5," + (height / 2 + 4) +
"V" + (height - radius.BottomLeft) + "A" + radius.BottomLeft + "," + radius.BottomLeft + " 0 0 0 " + (5 + radius.BottomLeft) + "," + height +
"H" + (width - radius.BottomRight) + "A" + radius.BottomRight + "," + radius.BottomRight + " 0 0 0 " + width + "," + (height - radius.BottomRight) +
"V" + radius.TopRight + "A" + radius.TopRight + "," + radius.TopRight + " 0 0 0 " + (width - radius.TopRight) + "," + 0 +
"H" + (5 + radius.TopLeft) + "A" + radius.TopLeft + "," + radius.TopLeft + " 0 0 0 " + 5 + "," + radius.TopLeft +
"V" + (height / 2 - 4) + "Z";
break;
case AnglePositions.BottomLeft:
if (radius == new CornerRadius(0))
path = "M0," + height + "L4," + (height - 5) +
"H " + width + "V 0 H 0 Z";
else
path = "M0," + height + "L4," + (height - 5) +
"H" + (width - radius.BottomRight) + "A" + radius.BottomRight +"," + radius.BottomRight + " 0 0 0 " + width + "," + (height - radius.BottomRight - 5) +
"V" + radius.TopRight + "A" + radius.TopRight + "," + radius.TopRight + " 0 0 0 " + (width - radius.TopRight) + "," + 0 +
"H" + radius.TopLeft + "A" + radius.TopLeft + "," + radius.TopLeft + " 0 0 0 " + 0 + "," + radius.TopLeft +
"Z";
break;
case AnglePositions.BottomCenter:
if (radius == new CornerRadius(0))
path = "M" + width / 2 + "," + height + "L" + (width / 2 + 5) + "," + (height - 4) +
"H" + width + "V 0 H 0 V" + (height - 4) + "H" + (width / 2 - 5) + "Z";
else
path = "M" + width / 2 + "," + height + "L" + (width / 2 + 5) + "," + (height - 4) +
"H" + (width - radius.BottomRight) + "A" + radius.BottomRight + "," + radius.BottomRight + " 0 0 0 " + width + "," + (height - radius.BottomRight - 5) +
"V" + radius.TopRight + "A" + radius.TopRight + "," + radius.TopRight + " 0 0 0 " + (width - radius.TopRight) + "," + 0 +
"H" + radius.TopLeft + "A" + radius.TopLeft + "," + radius.TopLeft + " 0 0 0 " + 0 + "," + radius.TopLeft +
"V" + (height - radius.BottomRight - 5) + "A" + radius.BottomRight + "," + radius.BottomRight + " 0 0 0 " + radius.BottomRight + "," + (height - 5) +
"H" + (width / 2 - 5) + "Z";
break;
case AnglePositions.BottomRight:
if (radius == new CornerRadius(0))
path = "M" + width + "," + height + "V 0 H 0 V " + (height - 4) + "H" + (width - 5) + "Z";
else
path = "M" + width + "," + height + "V" + radius.TopRight + "A" + radius.TopRight + ","+ radius.TopRight + " 0 0 0 " + (width - radius.TopRight) + "," + 0 +
"H" + radius.TopLeft + "A" + radius.TopLeft + "," + radius.TopLeft + " 0 0 0 " + 0 + "," + radius.TopLeft +
"V" + (height - radius.BottomRight - 5) + "A" + radius.BottomRight + "," + radius.BottomRight + " 0 0 0 " + radius.BottomRight + "," + (height - 5) +
"H" + (width - 5) + "Z";
break;
case AnglePositions.Right:
if (radius == new CornerRadius(0))
path = "M" + width + "," + height / 2 + "L" + (width - 5) + "," + (height / 2 - 4) + "V 0 H 0 V" +
height + "H " + (width - 5) + "V" + (height / 2 + 4) + "Z";
else
path = "M" + width + "," + height / 2 + "L" + (width - 5) + "," + (height / 2 - 4) + "V" + radius.TopRight + "A" + radius.TopRight + "," + radius.TopRight + " 0 0 0 " + (width - radius.TopRight - 5) + "," + 0 +
"H" + radius.TopLeft + "A" + radius.TopLeft + "," + radius.TopLeft + " 0 0 0 " + 0 + "," + radius.TopLeft +
"V" + (height - radius.BottomLeft) + "A" + radius.BottomLeft + "," + radius.BottomLeft + " 0 0 0 " + radius.BottomLeft + "," + height +
"H" + (width - radius.BottomRight - 5) + "A" + radius.BottomRight + "," + radius.BottomRight + " 0 0 0 " + (width - 5) + "," + (height - radius.BottomRight) +
"V" + (height / 2 + 4) + "Z";
break;
}
return Geometry.Parse(path);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
internal class IsNullConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
internal class WidthToMarginConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var actualWidth = (double)value;
return new Thickness(actualWidth, 0, 0, 1);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
internal class HeightToMarginConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var actualHeight = (double)value;
return new Thickness(0, actualHeight, 0, 1);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
internal class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var visible = (bool)value;
return visible ? Visibility.Visible : Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return false;
}
}
internal class MarginToWidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var thickness = (Thickness)value;
return thickness.Left;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
//Window Header和Title转换器
internal class HeaderConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是Header,1是Title
return (string)values[0] == null ? (string)values[1]: (string)values[0];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
//Icon字体大小转换器( + 5)
internal class IconFontSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value + 5;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
//CheckBox General样式内部对号的缩放比例
internal class ScaleConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是InnerWidth,1是InnerHeight
var minvalue = (double)values[0] < (double)values[1] ? (double)values[0] : (double)values[1];
return minvalue / 22;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
internal class ToggleHeightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value - 2;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
//内部Toggle的圆角转换器
internal class ToHalfConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value / 2;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
//内部Toggle的水平偏移量转换器
internal class ToggleTranslateXConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是InnerWidth,1是InnerHeight
return ((double)values[0] - (double)values[1] + 1) * -1;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
//文本框内部宽度转换器
internal class TextBoxInnerWidthConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是Width,1是Padding,,2是HorizontalContentAlignment
if ((HorizontalAlignment)values[2] != HorizontalAlignment.Center)
return (double)values[0] - ((Thickness)values[1]).Left - ((Thickness)values[1]).Right;
else
return DependencyProperty.UnsetValue;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
//文本框内部高度转换器
internal class TextBoxInnerHeightConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//0是Heihgt,1是Padding,2是VerticalContentAlignment
if ((VerticalAlignment)values[2] != VerticalAlignment.Center)
return (double)values[0] - ((Thickness)values[1]).Top - ((Thickness)values[1]).Bottom;
else
return DependencyProperty.UnsetValue;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
}
}
}
================================================
FILE: Panuon.UI/Z_Others/Enums.cs
================================================
/*==============================================================
*作者:ZEOUN
*时间:2018/11/19 11:09:29
*说明:
*日志:2018/11/19 11:09:29 创建。
*==============================================================*/
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Panuon.UI
{
#region DropDown
public enum DropDownPlacement
{
Bottom,
RightBottom,
LeftBottom
}
#endregion
public enum ImageType
{
Rectangle,
Square,
}
///
/// (PanuonUI) Animation styles for PUWindow.
///
public enum AnimationStyles
{
///
/// 缩放。
///
Scale = 0,
///
/// 一个从上到下的渐变显示。
///
Gradual = 1,
///
/// 渐入渐出。
///
Fade = 2
}
///
/// (PanuonUI) Button styles for PUButton.
///
public enum ButtonStyles
{
///
/// 一个常规按钮。
///
General = 1,
///
/// 一个带边框的空心按钮,当鼠标悬浮时才会显示背景色。
/// 当鼠标移入时,该按钮的背景色将由Background变为指定的CoverBrush。
///
Hollow = 2,
///
/// 一个带边框的空心按钮,当鼠标悬浮时才会显示前景色。
/// 当鼠标移入时,该按钮的边框和前景色将由BorderBrush和Foreground变为指定的CoverBrush。
///
Outline = 3,
///
/// 一个不带任何边框和背景色的文字按钮。
/// 当鼠标移入时,该按钮的前景色将由Foreground变为指定的CoverBrush。
///
Link = 4,
}
///
/// (PanuonUI) Button styles for PURepeatButton.
///
public enum RepeatButtonStyles
{
///
/// 一个常规按钮。
///
General = 1,
///
/// 一个带边框的空心按钮,当鼠标悬浮时才会显示背景色。
/// 当鼠标移入时,该按钮的背景色将由Background变为指定的CoverBrush。
///
Hollow = 2,
///
/// 一个带边框的空心按钮,当鼠标悬浮时才会显示前景色。
/// 当鼠标移入时,该按钮的边框和前景色将由BorderBrush和Foreground变为指定的CoverBrush。
///
Outline = 3,
///
/// 一个不带任何边框和背景色的文字按钮。
/// 当鼠标移入时,该按钮的前景色将由Foreground变为指定的CoverBrush。
///
Link = 4,
}
///
/// (PanuonUI) Button click styles for PUButton.
///
public enum ClickStyles
{
///
/// 点击按钮时不触发下沉操作。
///
Classic,
///
/// 点击时按钮下沉2个px。
///
Sink,
}
///
/// (PanuonUI) TextBox styles for PUTextBox.
///
public enum TextBoxStyles
{
///
/// 一个标准的文本框。
///
General = 1,
///
/// 一个文本框前带图标的文本框。
///
IconGroup = 2,
}
///
/// (PanuonUI) PasswordBox styles for PUPasswordBox.
///
public enum PasswordBoxStyles
{
///
/// 一个标准的密码框。
///
General = 1,
///
/// 一个密码框前带图标的密码框。
///
IconGroup = 2,
}
///
/// (PanuonUI) SelectedValuePath for PUTabControl , PUComboBox and PUTreeView
///
public enum SelectedValuePaths
{
///
/// SelectedValue应呈现被选中子项的Header属性(在ComboBox中为Content属性)。
///
Header,
///
/// SelectedValue应呈现被选中子项的Value属性。
///
Value
}
///
/// (PanuonUI) SelectedValuePath for PUTabControl , PUComboBox and PUTreeView
///
public enum ChoosedValuePaths
{
///
/// ChoosedValue应呈现被选中子项的Header属性。
///
Header,
///
/// ChoosedValue应呈现被选中子项的Value属性。
///
Value
}
///
/// (PanuonUI) DeleteModes for PUTabControl and PUComboBox
///
public enum DeleteModes
{
///
/// 当用户点击删除按钮时,应立即删除项目并触发DeleteItem路由事件。
///
Delete,
///
/// 当用户点击删除按钮时,不删除项目,只触发DeleteItem路由事件。
///
EventOnly,
}
///
/// (PanuonUI) SearchMode for PUComboBox
///
public enum SearchModes
{
///
/// 不显示搜索框。
///
None,
///
/// 在搜索框按下键盘时搜索。
///
TextChanged,
///
/// 当按下Enter键时发起搜索。
///
Enter,
}
///
/// (PanuonUI) CheckBoxStyles for PUCheckBox
///
public enum CheckBoxStyles
{
///
/// 一个标准的选择框。
///
General = 1,
///
/// 一个经典样式的选择框。
///
Classic = 2,
///
/// 一个开关样式的选择框。
///
Switch = 3,
///
/// 一个带有左边线的选择框。
///
Branch = 4,
///
/// 一个类似于按钮样式的选择框。
///
Button = 5,
}
///
/// (PanuonUI) RadioButtonStyles for PURadioButton
///
public enum RadioButtonStyles
{
///
/// 一个标准的RadioButton。
///
General = 1,
///
/// 一个经典样式的RadioButton。
///
Classic = 2,
///
/// 一个开关样式的RadioButton。
///
Switch = 3,
///
/// 一个带有左边线的RadioButton。
///
Branch = 4,
///
/// 一个类似于按钮样式的选择框。
///
Button = 5,
}
///
/// (PanuonUI) ProgressDirections for PUProgressBar
///
public enum ProgressDirections
{
///
/// 从左到右填充进度。
///
LeftToRight,
///
/// 从右到左填充进度。
///
RightToLeft,
///
/// 从上到下填充进度。
///
TopToBottom,
///
/// 从下到上填充进度。
///
BottomToTop,
}
///
/// (PanuonUI) ProgressBarStyles for PUProgressBar
///
public enum ProgressBarStyles
{
///
/// 一个标准的进度条。
///
General,
///
/// 一个环形的进度条。
///
Ring
}
///
/// (PanuonUI) TreeViewStyles for PUTreeView
///
public enum TreeViewStyles
{
General,
Classic,
}
public enum ExpandModes
{
///
/// 单击TreeViewItem时展开(如果有子项)。
///
Click,
///
/// 双击TreeViewItem时展开(如果有子项)。
///
DoubleClick,
}
///
/// (PanuonUI) TabControlStyles for PUTabControl
///
public enum TabControlStyles
{
General,
Classic,
}
///
/// (PanuonUI) DatePickerModes for PUDatePicker
///
public enum DatePickerModes
{
///
/// 年 月 日。
///
DateOnly,
///
/// 时 分 秒。
///
TimeOnly,
///
/// 年 月 日 时 分 秒。
///
DateTime,
}
///
/// (PanuonUI) AnglePositions for PUBubble
///
public enum AnglePositions
{
///
/// 尖角位于左侧。
///
Left,
///
/// 尖角位于左下角。
///
BottomLeft,
///
/// 尖角位于中间的底部。
///
BottomCenter,
///
/// 尖角位于右下角。
///
BottomRight,
///
/// 尖角位于右侧。
///
Right,
}
///
/// (PanuonUI) Buttons for PUMessageBox
///
public enum Buttons
{
///
/// 好
///
Sure,
///
/// 是
///
Yes,
///
/// 确定
///
OK,
///
/// 取消
///
Cancel,
///
/// 是/否
///
YesOrNo,
///
/// 是/取消
///
YesOrCancel,
///
/// 确定/取消
///
OKOrCancel,
///
/// 接受/取消
///
AcceptOrCancel,
///
/// 接受/拒绝
///
AcceptOrRefused,
}
///
/// (PanuonUI) TextTypes for PUTextBox
///
public enum TextTypes
{
///
/// 允许所有文本输入。
///
Text,
///
/// 只允许输入数字、以及其他操控键。
///
Number,
///
/// 只允许输入数字、小数点、以及其他操控键。
///
Decimal,
}
}
================================================
FILE: Panuon.UI/Z_Others/SkipCompareAttribute.cs
================================================
using System;
namespace Panuon.UI
{
[AttributeUsage(AttributeTargets.Property)]
public class SkipCompareAttribute : Attribute
{
}
}
================================================
FILE: Panuon.UI/Z_Utils/Extends.cs
================================================
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
namespace Panuon.UI.Utils
{
public static class Extends
{
#region Interger
///
/// 将0~10的数字转换为文字。
///
public static char ToSingleChineseNumber(this int number)
{
var array = "零一二三四五六七八九十";
return array[number];
}
public static string ToSizeString(this int byteSize)
{
if (byteSize > 1024 * 1024 * 1024)
{
return (byteSize * 1.0 / 1024 / 1024 / 1024).ToString("f2") + "GB";
}
else if (byteSize > 1024 * 1024)
{
return (byteSize * 1.0 / 1024 / 1024).ToString("f2") + "MB";
}
else if (byteSize > 1024)
{
return (byteSize * 1.0 / 1024).ToString("f2") + "KB";
}
else
{
return byteSize + "B";
}
}
#endregion
#region String
///
/// 尝试将字符串转换为整数,若转换失败,则返回0。
///
public static int ToInt(this string context)
{
if (string.IsNullOrEmpty(context))
return 0;
var result = 0;
if (int.TryParse(context, out result))
return result;
else
return 0;
}
///
/// 尝试将字符串转换为小数,若转换失败,则返回0。
///
public static double ToDouble(this string context)
{
if (string.IsNullOrEmpty(context))
return 0;
var result = 0.0;
if (double.TryParse(context, out result))
return result;
else
return 0;
}
///
/// 尝试将字符串转换为布尔值,若转换失败,则返回False。
///
public static bool ToBoolean(this string context)
{
if (string.IsNullOrEmpty(context))
return false;
var result = false;
if (bool.TryParse(context, out result))
return result;
else
return false;
}
#endregion
#region DateTime
///
/// 将时间转换成时间戳(精确到毫秒)。
///
public static long ToTimeStamp(this DateTime date)
{
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1);
return Convert.ToInt64(ts.TotalMilliseconds);
}
///
/// 与另一个日期的年月日进行比较,若相同,则返回True。
///
public static bool CompareYearMonthDay(this DateTime date1, DateTime date2)
{
return date1.Date == date2.Date;
}
#endregion
#region Long
///
/// 将时间戳转换成时间(精确到毫秒)。
///
public static DateTime ToDate(this long timeStamp)
{
return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).AddMilliseconds((long)timeStamp);
}
public static string ToSizeString(this long byteSize)
{
if (byteSize > 1024 * 1024 * 1024)
{
return (byteSize * 1.0 / 1024 / 1024 / 1024).ToString("f2") + "GB";
}
else if (byteSize > 1024 * 1024)
{
return (byteSize * 1.0 / 1024 / 1024).ToString("f2") + "MB";
}
else if (byteSize > 1024)
{
return (byteSize * 1.0 / 1024).ToString("f2") + "KB";
}
else
{
return byteSize + "B";
}
}
#endregion
#region List
///
/// 将列表中的每个元素拼接成一段字符串。
///
/// 分隔符。
public static string ToString(this IList list, string spliter)
{
return String.Join(spliter, list);
}
public static ObservableCollection ToObservableCollection(this IList list)
{
return new ObservableCollection(list);
}
#endregion
#region Dictionary
///
/// 将字典中指定键的键值对返回到一个枚举集合中。
///
/// 唯一键。
/// 数据值。
/// 要查找的键集合。
///
public static IEnumerable> GetValues(this IDictionary dic, IEnumerable keys)
{
foreach (var key in keys)
{
yield return new KeyValuePair(key, dic[key]);
}
}
#endregion
#region Others
///
/// 比较两个对象的可写属性(具有非Private的Set访问器)是否完全相等。
/// 对于无需比较的属性或集合型属性,您必须为其加上SkipCompare特性标签。集合型属性在比较时会因异常而返回False。
/// 若两个对象均为Null,则返回True;若只有一个为Null,则返回False。
///
/// 要比较的另一个值。
public static bool IsEqual(this T obj, T value)
{
try
{
if (obj == null && value == null)
return true;
else if (obj == null || value == null)
return false;
Type type = obj.GetType();
if (type.IsValueType || type.FullName == typeof(string).FullName)
return obj.Equals(value);
foreach (var propertyInfo in type.GetProperties())
{
if (propertyInfo.CanWrite)
{
if (Attribute.IsDefined(propertyInfo, typeof(SkipCompareAttribute)))
{
continue;
}
var propType = propertyInfo.PropertyType;
var prop1 = propertyInfo.GetValue(obj, null);
var prop2 = propertyInfo.GetValue(value, null);
if (prop1 == null && prop2 == null)
continue;
else if (prop1 == null || prop2 == null)
return false;
else if (!propType.IsValueType && propType.FullName != typeof(string).FullName)
{
if (!prop1.IsEqual(prop2))
{
return false;
}
continue;
}
else if (!prop1.Equals(prop2))
return false;
}
}
return true;
}
catch (Exception ex)
{
return false;
}
}
#endregion
#region Function
#endregion
}
}
================================================
FILE: Panuon.UI/Z_Utils/Utils.cs
================================================
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Panuon.UI.Utils
{
///
/// 提供Task的简易池化管理,并发任务数量可控。
///
public class TaskPoll
{
#region Identity
private static ConcurrentQueue _taskQueue;
private static int _runningTaskQuantity;
#endregion
#region Property
///
/// 获取或设置可以允许同时运行的最大任务数量。
/// 若值为Null,则不限制最大执行数量。
///
public static int? MaxTaskQuantity
{
get { return _maxTaskQuantity; }
set { _maxTaskQuantity = value; RecheckQueue(); }
}
private static int? _maxTaskQuantity;
///
/// 获取当前任务池中的任务总数(包括排队中和正在执行的)。
///
public static int CurrentTaskQuantity
{
get { return _taskQueue == null ? 0 : _taskQueue.Count; }
}
///
/// 获取当前正在执行的任务数量。
///
public static int RunningTaskQuantity
{
get { return _runningTaskQuantity; }
}
#endregion
#region APIs
///
/// 使用默认值初始化TaskManager。首次调用StartNew方法时,TaskManager将自动执行初始化。
///
public static void Init()
{
_taskQueue = new ConcurrentQueue();
_runningTaskQuantity = 0;
}
///
/// 使用指定值初始化TaskManager。
/// 允许同时运行的最大任务数量。
///
public static void Init(int maxTaskQuantity)
{
MaxTaskQuantity = maxTaskQuantity;
_taskQueue = new ConcurrentQueue();
_runningTaskQuantity = 0;
}
///
/// 向任务队列中插入一个待执行的新任务,该任务将在合适的时机执行。
///
public static void StartNew(Task task)
{
if (_taskQueue == null)
Init();
_taskQueue.Enqueue(task);
RecheckQueue();
}
///
/// 向任务队列中插入一个待执行的新任务,该任务将在合适的时机执行。
///
public static void StartNew(Task task)
{
if (_taskQueue == null)
Init();
_taskQueue.Enqueue(task);
RecheckQueue();
}
#endregion
#region Funtion
private static void RecheckQueue()
{
if (_taskQueue == null)
return;
if (_taskQueue.Count == 0 || (MaxTaskQuantity != null && _runningTaskQuantity >= MaxTaskQuantity))
return;
Task task;
if (!_taskQueue.TryDequeue(out task))
{
RecheckQueue();
return;
}
if (task.Status != TaskStatus.Created && task.Status != TaskStatus.WaitingToRun)
{
RecheckQueue();
return;
}
Interlocked.Increment(ref _runningTaskQuantity);
task.ContinueWith((t) =>
{
Interlocked.Decrement(ref _runningTaskQuantity);
RecheckQueue();
});
task.Start();
if (_runningTaskQuantity < MaxTaskQuantity)
RecheckQueue();
}
#endregion
}
///
/// 伸缩缓存池。当你需要在缓存中保存大量的数据时(一次性读取可能占用较高内存),只需读取数据的唯一键并储存该键到缓存池中即可。
/// 当你使用Get或GetAll方法访问缓存值时,您可以指定当缓存中不存在某个(或某些)键的值,或某些键对应的值为Default值时,应该进行的后续处理操作。
///
/// 标识该缓存的唯一键。
/// 该缓存的实际值。
public class CachePoll
{
#region Constructor
///
/// 初始化伸缩缓存池实例。该缓存池将不会定时回收资源。
///
public CachePoll()
{
_caches = new ConcurrentDictionary>();
}
///
/// 初始化伸缩缓存池实例,并指定缓存的生命周期时间。该缓存池将不会定时回收资源,但您可以使用Collect()方法手动回收缓存。
///
/// 每个缓存的生命周期。当调用Collect()方法时,若该缓存的最后一次访问(更新或获取)时间超过此期限,则其缓存值将被释放(但不会移除键)。
public CachePoll(TimeSpan ttl)
{
_caches = new ConcurrentDictionary>();
}
///
/// 初始化伸缩缓存池实例,并指定缓存的生命周期时间,以及定时回收缓存的时间间隔。您也可以使用Collect()方法立即回收缓存。
///
/// 每个缓存的生命周期。当调用Collect()方法时,若该缓存的最后一次访问(更新或获取)时间超过此期限,则其缓存值将被释放(但不会移除键)。
/// 定时回收缓存的时间间隔,计时器将定时调用Collect()方法。建议值为1倍~2倍的缓存生命周期时间。
public CachePoll(TimeSpan ttl, TimeSpan collectInterval)
{
_caches = new ConcurrentDictionary>();
_ttl = ttl;
_collectInterval = collectInterval;
_timer = new Timer(OnTick, null, (int)_collectInterval.Value.TotalMilliseconds, Timeout.Infinite);
}
#endregion
#region Identity
private static ConcurrentDictionary> _caches { get; set; }
private static Timer _timer;
private static TimeSpan? _ttl;
private static TimeSpan? _collectInterval;
private int _isCollecting;
#endregion
#region EventHandler
///
/// 表示缓存值已更新(仅更新键时将不会触发此事件)。当指定此事件的后续处理时,该处理将以同步模式执行。事件参数: sender = List, e = null
///
public EventHandler Updated;
///
/// 缓存已回收。当指定此事件的后续处理时,该处理将以同步模式执行。事件参数:sender = List, e = null
///
public EventHandler Collected;
#endregion
#region Property
///
/// 获取当前的所有缓存。
///
public IEnumerable> Caches
{
get
{
return _caches.Select(x => new KeyValuePair(x.Key, x.Value.Value));
}
}
///
/// 获取真实缓存的数量(TValue为默认值的缓存不会计入)。
///
public int RealCount
{
get
{
return _caches.Count(x => x.Value.Value != null);
}
}
///
/// 获取所有缓存的数量。
///
public int Count
{
get
{
return _caches.Count;
}
}
///
/// 获取是否正在回收缓存。
///
public bool IsCollecting
{
get
{
return _isCollecting == 1;
}
}
///
/// 获取缓存的生命周期。
///
public TimeSpan? CacheTTL
{
get
{
return _ttl;
}
}
///
/// 获取缓存的回收间隔。
///
public TimeSpan? CollectInterval
{
get
{
return _collectInterval;
}
}
#endregion
#region APIs
public bool ContainsKey(TKey key)
{
return _caches.ContainsKey(key);
}
///
/// 向缓存池中添加一个占位缓存,该缓存的实际值为Default值。
/// 若该键已存在,则不会有任何操作。
///
/// 要添加的键。
public void AddKey(TKey key)
{
_caches.TryAdd(key, new CacheModel());
}
///
/// 向缓存池中添加一组占位缓存,该缓存只有键而不具有实际值。、
/// 若该键已存在,则不会有任何操作。
///
/// 要添加的一组键。
public void AddKeys(IEnumerable keys)
{
foreach (var key in keys)
{
_caches.TryAdd(key, new CacheModel());
}
}
///
/// 向缓存池中添加一个键值对,若添加成功,将触发Updated事件。若键已存在于缓存池中,将替换原有的值。
/// 请勿在循环中调用此方法,这将频繁触发Updated事件,并严重影响性能。若要一次性添加多个值,请使用AddOrUpdates方法。
///
/// 要添加的键。
/// 该键对应的值。
public void AddOrUpdate(TKey key, TValue value)
{
var newModel = new CacheModel(value);
if (_caches.AddOrUpdate(key, newModel, (k, v) => newModel) != null)
{
Updated?.Invoke(new List { key }, null);
};
}
///
/// 向缓存池中添加一组键值对,若有至少一个值添加成功,将在添加结束后触发Updated事件。若键已存在于缓存池中,将替换原有的值。
///
/// 要添加的一组键值对。
public void AddOrUpdates(IEnumerable> keyValuePairs)
{
var updatedKeys = new List();
foreach (var pair in keyValuePairs)
{
var newModel = new CacheModel(pair.Value);
if(_caches.AddOrUpdate(pair.Key, newModel, (k, v) => newModel) != null)
{
updatedKeys.Add(pair.Key);
}
}
if(updatedKeys.Count != 0)
Updated?.Invoke(updatedKeys, null);
}
///
/// 获取指定键的缓存值。若该键不存在,则返回默认值。
///
/// 要查找的键。
///
public TValue Get(TKey key)
{
if (_caches.ContainsKey(key))
{
var cache = _caches[key];
cache.LastTime = DateTime.Now.ToTimeStamp();
return cache.Value;
}
else
{
return default(TValue);
}
}
///
/// 获取指定键的缓存值。若该键不存在或该键对应的值为Default值,则将在调用事件处理方法后继续尝试返回该键的值。
/// 若连续5次调用事件处理后仍无法找到该键或该键对应的值始终为Default值,将抛出CacheNotExistsException异常。
///
/// 要查找的键。
/// 若该键不存在或该键对应的值为Default值,则调用此回调方法来处理后续内容。您应当在此事件处理中向缓存池添加该键(若不存在)及其实际值,否则该处理事件将将被继续调用。
///
public TValue Get(TKey key, EventHandler lackItemCallback)
{
int count = 0;
while (!_caches.ContainsKey(key) || IsDefault(_caches[key].Value))
{
if (count == 5)
{
return default(TValue);
}
lackItemCallback.Invoke(key, null);
count++;
}
var cache = _caches[key];
cache.LastTime = DateTime.Now.ToTimeStamp();
return cache.Value;
}
public IEnumerable> GetAll(IEnumerable keys)
{
var dictionary = keys.ToDictionary(k => k, v => default(TValue));
var timeStamp = DateTime.Now.ToTimeStamp();
foreach (var key in keys)
{
var cache = _caches[key];
dictionary[key] = cache.Value;
cache.LastTime = timeStamp;
}
return dictionary;
}
///
/// 获取所有指定键的缓存值。若至少一个键不存在,或该键的缓存值为默认值,则触发事件回调处理。
///
///
/// 若至少一个键不存在,或其缓存值为默认值,则触发此回调方法处理后续操作。
///
public IDictionary GetAll(IEnumerable keys, EventHandler lackItemsCallback)
{
var resultDic = keys.ToDictionary(k => k, v => default(TValue));
var lackKeys = new List();
var timeStamp = DateTime.Now.ToTimeStamp();
foreach (var key in keys)
{
if (_caches.ContainsKey(key))
{
var cache = _caches[key];
if (!IsDefault(cache.Value))
{
resultDic[key] = cache.Value;
cache.LastTime = timeStamp;
continue;
}
}
lackKeys.Add(key);
}
while (lackKeys.Count != 0)
{
lackItemsCallback.Invoke(lackKeys, null);
var lackKeysCopy = lackKeys.ToList();
lackKeys.Clear();
foreach(var key in lackKeysCopy)
{
var cache = _caches[key];
if (IsDefault(cache.Value))
{
lackKeys.Add(key);
}
else
{
resultDic[key] = cache.Value;
cache.LastTime = timeStamp;
}
}
}
return resultDic;
}
public void ReleaseCache(TKey key)
{
if (_caches.ContainsKey(key))
{
_caches[key].Value = default(TValue);
}
}
public void ReleaseCaches(IEnumerable keys)
{
foreach(var key in keys)
{
if (_caches.ContainsKey(key))
{
_caches[key].Value = default(TValue);
}
}
}
public void Remove(TKey key)
{
CacheModel outValue;
_caches.TryRemove(key, out outValue);
}
public void RemoveAll(IEnumerable keys)
{
foreach(var key in keys)
{
CacheModel outValue;
_caches.TryRemove(key, out outValue);
}
}
public bool ChangeKey(TKey oldKey, TKey newKey)
{
if (_caches.ContainsKey(newKey) || !_caches.ContainsKey(oldKey))
return false;
else
{
CacheModel outValue;
if (!_caches.TryRemove(oldKey, out outValue))
return false;
if (!_caches.TryAdd(newKey, new CacheModel(outValue.Value)))
return false;
return true;
}
}
///
/// 立即回收缓存池。最后一次访问(更新或获取)时间超过缓存生命周期的缓存值将被释放(但不会移除其键)。
/// 若至少有一个缓存被成功回收,将调用一次GC的垃圾回收方法来强制清理内存。
/// 频繁回收缓存将严重影响性能。建议调用时间间隔为1倍~2倍的缓存生命周期时间。
///
public void Collect()
{
if (IsCollecting || _ttl == null)
return;
var collectIDs = new List();
Interlocked.Exchange(ref _isCollecting, 1);
var timeStamp = DateTime.Now.ToTimeStamp();
foreach(var cache in _caches)
{
if(!IsDefault(cache.Value.Value) && timeStamp - cache.Value.LastTime > _ttl.Value.TotalMilliseconds)
{
collectIDs.Add(cache.Key);
cache.Value.Value = default(TValue);
}
}
Interlocked.Exchange(ref _isCollecting, 0);
if(collectIDs.Count != 0)
{
Collected?.Invoke(collectIDs, null);
Updated?.Invoke(collectIDs, null);
GC.Collect();
}
}
#endregion
#region Function
private void OnTick(object state)
{
Collect();
_timer.Change((int)_collectInterval.Value.TotalMilliseconds, Timeout.Infinite);
}
private bool IsDefault( TValue value)
{
return EqualityComparer.Default.Equals(value, default(TValue));
}
#endregion
}
class CacheModel
{
#region Constructor
public CacheModel()
{
LastTime = DateTime.Now.ToTimeStamp();
}
public CacheModel(T value)
{
LastTime = DateTime.Now.ToTimeStamp();
Value = value;
}
#endregion
#region Property
public T Value { get; set; }
public long LastTime { get; set; }
#endregion
}
public class CacheNotExistsException : Exception
{
#region Constructor
public CacheNotExistsException()
{
}
public CacheNotExistsException(Modes mode)
{
Mode = mode;
}
#endregion
#region Property
public Modes Mode { get; set; }
#endregion
public enum Modes
{
///
/// 多次无法从缓存中找到指定键。
///
KeyNotFound,
///
/// 该键的缓存值始终为Default值。
///
DefaultValue,
}
}
}
================================================
FILE: Panuon.UI.Charts/0_Base/PUChartPoint.cs
================================================
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Panuon.UI.Charts
{
///
/// 适用于LineChart折线图的Points属性。
///
public class PUChartPoint
{
///
/// 从0 ~ 1的值,表示该点在纵轴上的高度比例。
///
public double Value { get; set; }
///
/// 当鼠标悬浮在该点上时应该显示的实际值。
///
public string ValueTip { get; set; }
}
}
================================================
FILE: Panuon.UI.Charts/0_Base/PUChartToolTip.xaml
================================================
================================================
FILE: Panuon.UI.Charts/0_Base/PUChartToolTip.xaml.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Panuon.UI.Charts
{
///
/// PUChartToolTip.xaml 的交互逻辑
///
public partial class PUChartToolTip : UserControl
{
public PUChartToolTip()
{
InitializeComponent();
}
public PUChartToolTip(object header, object value)
{
Header = header;
Value = value;
}
#region Property
public object Header
{
get { return (object)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(object), typeof(PUChartToolTip));
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(PUChartToolTip));
public Brush CoverBrush
{
get { return (Brush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty =
DependencyProperty.Register("CoverBrush", typeof(Brush), typeof(PUChartToolTip), new PropertyMetadata(new SolidColorBrush(Colors.DimGray)));
#endregion
}
}
================================================
FILE: Panuon.UI.Charts/1_LineChart/PULineChart.cs
================================================
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace Panuon.UI.Charts
{
public class PULineChart : UserControl
{
static PULineChart()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PULineChart), new FrameworkPropertyMetadata(typeof(PULineChart)));
}
#region Property
///
/// X轴(横)内容集合。
///
public string[] XAxis
{
get { return (string[])GetValue(XAxisProperty); }
set { SetValue(XAxisProperty, value); }
}
public static readonly DependencyProperty XAxisProperty = DependencyProperty.Register("XAxis", typeof(string[]), typeof(PULineChart), new PropertyMetadata(true));
///
/// Y轴(纵)内容集合。
///
public string[] YAxis
{
get { return (string[])GetValue(YAxisProperty); }
set { SetValue(YAxisProperty, value); }
}
public static readonly DependencyProperty YAxisProperty = DependencyProperty.Register("YAxis", typeof(string[]), typeof(PULineChart), new PropertyMetadata(true));
///
/// 点集合,从左侧开始排列。若点的数量不等于X轴座的数量,可能会造成显示不全。
///
public Point[] Points
{
get { return (Point[])GetValue(PointsProperty); }
set { SetValue(PointsProperty, value); }
}
public static readonly DependencyProperty PointsProperty = DependencyProperty.Register("Points", typeof(Point[]), typeof(PULineChart), new PropertyMetadata(true));
///
/// 将线下方的颜色上色,默认值为透明。
///
public SolidColorBrush CoverBrush
{
get { return (SolidColorBrush)GetValue(CoverBrushProperty); }
set { SetValue(CoverBrushProperty, value); }
}
public static readonly DependencyProperty CoverBrushProperty = DependencyProperty.Register("CoverBrush", typeof(SolidColorBrush), typeof(PULineChart), new PropertyMetadata(new SolidColorBrush(Colors.Transparent)));
///
/// 坐标改变时是否使用动画,默认值为True(使用)。
///
public bool UsingAnimate
{
get { return (bool)GetValue(UsingAnimateProperty); }
set { SetValue(UsingAnimateProperty, value); }
}
public static readonly DependencyProperty UsingAnimateProperty = DependencyProperty.Register("UsingAnimate", typeof(bool), typeof(PULineChart), new PropertyMetadata(true));
#endregion
}
}
================================================
FILE: Panuon.UI.Charts/1_LineChart/PULineChart.xaml
================================================
================================================
FILE: Panuon.UI.Charts/1_LineChart/PULineChart.xaml.cs
================================================
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace Panuon.UI.Charts
{
///
/// PULineChart.xaml 的交互逻辑
///
public partial class PULineChart : UserControl
{
#region Identity
private double _yWidth = 100;
private double _xHeight = 30;
#endregion
public PULineChart()
{
InitializeComponent();
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Loaded += delegate
{
Draw();
};
}
#region Property
///
/// X轴显示间距。
///
public int XAxisGap
{
get { return (int)GetValue(XAxisGapProperty); }
set { SetValue(XAxisGapProperty, value); }
}
public static readonly DependencyProperty XAxisGapProperty =
DependencyProperty.Register("XAxisGap", typeof(int), typeof(PULineChart), new PropertyMetadata(0, OnXAxisGapChanged));
private static void OnXAxisGapChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = d as PULineChart;
if (chart.IsLoaded)
{
chart.LoadXAxis(chart.ActualWidth);
}
}
///
/// 获取或设置使用动画的方式。默认值为始终使用(Always)。
///
public AnimationModes AnimationMode
{
get { return (AnimationModes)GetValue(AnimationModeProperty); }
set { SetValue(AnimationModeProperty, value); }
}
public static readonly DependencyProperty AnimationModeProperty =
DependencyProperty.Register("AnimationMode", typeof(AnimationModes), typeof(PULineChart), new PropertyMetadata(AnimationModes.Always));
///
/// 获取或设置网格画刷。
///
public Brush GridBrush
{
get { return (Brush)GetValue(GridBrushProperty); }
set { SetValue(GridBrushProperty, value); }
}
public static readonly DependencyProperty GridBrushProperty =
DependencyProperty.Register("GridBrush", typeof(Brush), typeof(PULineChart), new PropertyMetadata(new SolidColorBrush(Colors.LightGray)));
///
/// 获取或设置线条画刷。
///
public Brush LineBrush
{
get { return (Brush)GetValue(LineBrushProperty); }
set { SetValue(LineBrushProperty, value); }
}
public static readonly DependencyProperty LineBrushProperty =
DependencyProperty.Register("LineBrush", typeof(Brush), typeof(PULineChart), new PropertyMetadata(new SolidColorBrush(Colors.DimGray)));
///
/// 获取或设置线条粗细。
///
public double LineThickness
{
get { return (double)GetValue(LineThicknessProperty); }
set { SetValue(LineThicknessProperty, value); }
}
public static readonly DependencyProperty LineThicknessProperty =
DependencyProperty.Register("LineThickness", typeof(double), typeof(PULineChart), new PropertyMetadata(1.0));
///
/// 获取或设置线条下方的区域画刷。
///
public Brush AreaBrush
{
get { return (Brush)GetValue(AreaBrushProperty); }
set { SetValue(AreaBrushProperty, value); }
}
public static readonly DependencyProperty AreaBrushProperty =
DependencyProperty.Register("AreaBrush", typeof(Brush), typeof(PULineChart));
///
/// 获取或设置点大小。
///
public double PointSize
{
get { return (double)GetValue(PointSizeProperty); }
set { SetValue(PointSizeProperty, value); }
}
public static readonly DependencyProperty PointSizeProperty =
DependencyProperty.Register("PointSize", typeof(double), typeof(PULineChart), new PropertyMetadata(8.0));
///
/// 获取或设置X轴的值数组。
///
public ObservableCollection XAxis
{
get { return (ObservableCollection)GetValue(XAxisProperty); }
set { SetValue(XAxisProperty, value); }
}
public static readonly DependencyProperty XAxisProperty =
DependencyProperty.Register("XAxis", typeof(ObservableCollection), typeof(PULineChart), new PropertyMetadata(OnXAxisChanged));
private static void OnXAxisChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = d as PULineChart;
if (chart.XAxis != null)
{
chart.XAxis.CollectionChanged -= chart.XAxisChanged;
chart.XAxis.CollectionChanged += chart.XAxisChanged;
chart.XAxisChanged(null, null);
}
}
private void XAxisChanged(object sender, NotifyCollectionChangedEventArgs e)
{
LoadXAxis(ActualWidth);
DrawGrid(ActualWidth, ActualHeight);
}
///
/// 获取或设置Y轴的值数组。
///
public ObservableCollection YAxis
{
get { return (ObservableCollection)GetValue(YAxisProperty); }
set { SetValue(YAxisProperty, value); }
}
public static readonly DependencyProperty YAxisProperty =
DependencyProperty.Register("YAxis", typeof(ObservableCollection), typeof(PULineChart), new PropertyMetadata(OnYAxisChanged));
private static void OnYAxisChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = d as PULineChart;
if (chart.YAxis != null)
{
chart.YAxis.CollectionChanged -= chart.YAxisChanged;
chart.YAxis.CollectionChanged += chart.YAxisChanged;
chart.YAxisChanged(null, null);
}
}
private void YAxisChanged(object sender, NotifyCollectionChangedEventArgs e)
{
LoadYAxis(ActualHeight);
DrawGrid(ActualWidth, ActualHeight);
}
///
/// 获取或设置点集合。
///
public ObservableCollection Points
{
get { return (ObservableCollection)GetValue(PointsProperty); }
set { SetValue(PointsProperty, value); }
}
public static readonly DependencyProperty PointsProperty =
DependencyProperty.Register("Points", typeof(ObservableCollection), typeof(PULineChart), new PropertyMetadata(OnPointsChanged));
private static void OnPointsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = d as PULineChart;
if (chart.Points != null)
{
chart.Points.CollectionChanged -= chart.PointsChanged;
chart.Points.CollectionChanged += chart.PointsChanged;
chart.PointsChanged(null, null);
}
}
private void PointsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (IsLoaded)
{
InitLine(ActualWidth, ActualHeight, AnimationMode == AnimationModes.Always);
}
}
#endregion
#region Funtion
///
/// 重新绘制X、Y轴。
///
private void Draw()
{
var actualWidth = this.ActualWidth;
var actualHeight = this.ActualHeight;
if (Points == null)
return;
LoadXAxis(actualWidth);
LoadYAxis(actualHeight);
DrawGrid(actualWidth, actualHeight);
InitLine(actualWidth, actualHeight, AnimationMode != AnimationModes.None);
}
private void LoadYAxis(double actualHeight)
{
if (YAxis == null)
return;
var yAxis = YAxis.Reverse().ToArray();
var xHeight = (actualHeight - _xHeight) / (yAxis.Length - 0.5);
if (canvasYAxis.Children.Count > yAxis.Length)
{
var count = canvasYAxis.Children.Count;
for (int i = 0; i < count - yAxis.Length; i++)
{
canvasYAxis.Children.RemoveAt(canvasYAxis.Children.Count - 1);
}
}
for (int i = 0; i < canvasYAxis.Children.Count; i++)
{
var txt = canvasYAxis.Children[i] as TextBlock;
txt.Text = yAxis[i];
Canvas.SetTop(txt, xHeight * (i + 0.5) - GetTexHeight(txt) / 2);
}
for (int i = canvasYAxis.Children.Count; i < yAxis.Length; i++)
{
var txt = new TextBlock()
{
Text = yAxis[i],
};
var fore = new Binding() { Source = this, Path = new PropertyPath("Foreground"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(txt, TextBlock.ForegroundProperty, fore);
Canvas.SetRight(txt, 10);
Canvas.SetTop(txt, xHeight * (i + 0.5) - GetTexHeight(txt) / 2);
canvasYAxis.Children.Add(txt);
}
}
private void LoadXAxis(double actualWidth)
{
if (XAxis == null)
return;
var yWidth = (actualWidth - _yWidth) / (XAxis.Count - 0.5);
if (canvasXAxis.Children.Count > XAxis.Count)
{
var count = canvasXAxis.Children.Count;
for (int i = 0; i < count - XAxis.Count; i++)
{
canvasXAxis.Children.RemoveAt(canvasXAxis.Children.Count - 1);
}
}
for (int i = 0; i < canvasXAxis.Children.Count; i++)
{
var txt = canvasXAxis.Children[i] as TextBlock;
txt.Text = XAxisGap == 0 ? XAxis[i] : (i % (XAxisGap + 1) != 0 ? "" : XAxis[i]);
Canvas.SetLeft(txt, yWidth * i + _yWidth - (GetTextWidth(txt) / 2));
}
for (int i = canvasXAxis.Children.Count; i < XAxis.Count; i++)
{
var txt = new TextBlock()
{
Text = XAxis[i],
};
var fore = new Binding() { Source = this, Path = new PropertyPath("Foreground"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(txt, TextBlock.ForegroundProperty, fore);
Canvas.SetTop(txt, 5);
Canvas.SetLeft(txt, yWidth * i + _yWidth - (GetTextWidth(txt) / 2));
canvasXAxis.Children.Add(txt);
}
}
private double GetTextWidth(TextBlock textBlock)
{
var formattedText = new FormattedText(
textBlock.Text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch),
textBlock.FontSize,
Brushes.Black,
new NumberSubstitution(),
TextFormattingMode.Display);
return formattedText.Width;
}
private double GetTexHeight(TextBlock textBlock)
{
var formattedText = new FormattedText(
textBlock.Text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch),
textBlock.FontSize,
Brushes.Black,
new NumberSubstitution(),
TextFormattingMode.Display);
return formattedText.Height;
}
private void DrawGrid(double actualWidth, double actualHeight)
{
if (YAxis == null || XAxis == null)
return;
var cvaHeight = actualHeight - _xHeight;
var cvaWidth = actualWidth - _yWidth;
var xHeight = cvaHeight / (YAxis.Count - 0.5);
var yWidth = cvaWidth / (XAxis.Count - 0.5);
var path = "";
for (int i = 0; i < XAxis.Count; i++)
{
path += "M " + i * yWidth + ",0 V" + cvaHeight;
}
for (int i = 1; i <= YAxis.Count; i++)
{
path += "M 0," + (i - 0.5) * xHeight + " H" + cvaWidth;
}
pathGrid.Data = Geometry.Parse(path);
}
private void InitLine(double actualWidth, double actualHeight, bool usingAnima)
{
if (XAxis == null || YAxis == null || Points == null)
return;
ScaleTransform scale;
if (usingAnima)
scale = new ScaleTransform() { ScaleY = 0 };
else
scale = new ScaleTransform() { ScaleY = 1 };
polygon.RenderTransform = scale;
polyline.RenderTransform = scale;
var cvaHeight = actualHeight - _xHeight;
var cvaWidth = actualWidth - _yWidth;
var xHeight = cvaHeight / (YAxis.Count - 0.5);
var yWidth = cvaWidth / (XAxis.Count - 0.5);
var realHeight = cvaHeight - xHeight * 0.5;
polyline.Points.Clear();
polygon.Points.Clear();
canvasPoints.Children.Clear();
var count = XAxis.Count > Points.Count ? Points.Count : XAxis.Count;
for (int i = 0; i < count; i++)
{
var point = new Point(yWidth * i, (1 - Points[i].Value) * realHeight + 0.5 * xHeight);
polyline.Points.Add(point);
polygon.Points.Add(point);
var ell = new Ellipse();
var toolTip = new PUChartToolTip() { Header = XAxis[i], Value = Points[i].ValueTip };
var cover = new Binding() { Source = this, Path = new PropertyPath("LineBrush"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(toolTip, PUChartToolTip.CoverBrushProperty, cover);
ell.ToolTip = toolTip;
var back = new Binding() { Source = this, Path = new PropertyPath("LineBrush"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(ell, Ellipse.FillProperty, back);
var size = new Binding() { Source = this, Path = new PropertyPath("PointSize"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
BindingOperations.SetBinding(ell, Ellipse.WidthProperty, size);
BindingOperations.SetBinding(ell, Ellipse.HeightProperty, size);
Canvas.SetLeft(ell, yWidth * i - PointSize / 2);
if (usingAnima)
{
Canvas.SetTop(ell, cvaHeight - PointSize / 2);
ell.BeginAnimation(Canvas.TopProperty, GetDoubleAnimation((1 - Points[i].Value) * realHeight + 0.5 * xHeight - PointSize / 2, 1));
}
else
{
Canvas.SetTop(ell, (1 - Points[i].Value) * realHeight + 0.5 * xHeight - PointSize / 2);
}
canvasPoints.Children.Add(ell);
}
polygon.Points.Add(new Point(yWidth * (Points.Count - 1), cvaHeight));
polygon.Points.Add(new Point(0, cvaHeight));
if (usingAnima)
{
scale.BeginAnimation(ScaleTransform.ScaleYProperty, GetDoubleAnimation(1, 1));
}
}
private DoubleAnimation GetDoubleAnimation(double to, double duration = 0.2)
{
return new DoubleAnimation()
{
To = to,
Duration = TimeSpan.FromSeconds(duration),
EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseInOut },
};
}
#endregion
#region Sys
private void chart_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (ActualWidth <= 0)
throw new Exception("折线图控件的实际宽度必须大于0。");
canvasYAxis.Height = this.ActualHeight;
canvasYAxis.Width = _yWidth;
canvasXAxis.Width = this.ActualWidth;
canvasXAxis.Height = _xHeight;
canvasContainer.Width = this.ActualWidth - _yWidth;
canvasContainer.Height = this.ActualHeight - _xHeight;
Canvas.SetLeft(canvasContainer, _yWidth);
canvasPoints.Width = this.ActualWidth - _yWidth;
canvasPoints.Height = this.ActualHeight - _xHeight;
polygon.Width = this.ActualWidth - _yWidth;
polygon.Height = this.ActualHeight - _xHeight;
polyline.Width = this.ActualWidth - _yWidth;
polyline.Height = this.ActualHeight - _xHeight;
if (IsLoaded)
Draw();
}
#endregion
}
}
================================================
FILE: Panuon.UI.Charts/Others/Enums.cs
================================================
/*==============================================================
*作者:ZEOUN
*时间:2018/11/30 10:02:45
*说明:
*日志:2018/11/30 10:02:45 创建。
*==============================================================*/
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Panuon.UI.Charts
{
public enum AnimationModes
{
///
/// 从不使用动画。
///
None,
///
/// 仅在首次加载时使用动画。
///
OneTime,
///
/// 始终使用动画。
///
Always,
}
}
================================================
FILE: Panuon.UI.Charts/Panuon.UI.Charts.csproj
================================================
Debug
AnyCPU
{39898E4A-724F-4711-BA20-CEFB3DC379F0}
Library
Properties
Panuon.UI.Charts
Panuon.UI.Charts
v4.0
512
true
full
false
bin\Debug\
DEBUG;TRACE
prompt
4
pdbonly
true
bin\Release\
TRACE
prompt
4
PUChartToolTip.xaml
PULineChart.xaml
Designer
MSBuild:Compile
Designer
MSBuild:Compile
================================================
FILE: Panuon.UI.Charts/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Panuon.UI.Charts")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Panuon.UI.Charts")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("39898e4a-724f-4711-ba20-cefb3dc379f0")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
================================================
FILE: Panuon.UI.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Panuon.UI", "Panuon.UI\Panuon.UI.csproj", "{72B3698E-1784-4101-99AE-FC7B8F48E96D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Panuon.UI.Charts", "Panuon.UI.Charts\Panuon.UI.Charts.csproj", "{39898E4A-724F-4711-BA20-CEFB3DC379F0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Panuon.UIBrowser", "Panuon.UIBrowser\Panuon.UIBrowser.csproj", "{3D0CEF7D-5E24-45FA-BFBD-95EEECFE88C2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{72B3698E-1784-4101-99AE-FC7B8F48E96D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{72B3698E-1784-4101-99AE-FC7B8F48E96D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72B3698E-1784-4101-99AE-FC7B8F48E96D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72B3698E-1784-4101-99AE-FC7B8F48E96D}.Release|Any CPU.Build.0 = Release|Any CPU
{39898E4A-724F-4711-BA20-CEFB3DC379F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{39898E4A-724F-4711-BA20-CEFB3DC379F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39898E4A-724F-4711-BA20-CEFB3DC379F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39898E4A-724F-4711-BA20-CEFB3DC379F0}.Release|Any CPU.Build.0 = Release|Any CPU
{3D0CEF7D-5E24-45FA-BFBD-95EEECFE88C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3D0CEF7D-5E24-45FA-BFBD-95EEECFE88C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D0CEF7D-5E24-45FA-BFBD-95EEECFE88C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D0CEF7D-5E24-45FA-BFBD-95EEECFE88C2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {854992E3-C079-4F01-A327-5CC0229995E1}
EndGlobalSection
EndGlobal
================================================
FILE: Panuon.UIBrowser/App.xaml
================================================
================================================
FILE: Panuon.UIBrowser/App.xaml.cs
================================================
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
namespace Panuon.UIBrowser
{
///
/// App.xaml 的交互逻辑
///
public partial class App : Application
{
}
}
================================================
FILE: Panuon.UIBrowser/AppBootstrapper.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using System.Windows;
using System.Windows.Threading;
using Caliburn.Micro;
using Panuon.UI;
namespace Panuon.UIBrowser
{
public class AppBootstrapper : BootstrapperBase
{
private CompositionContainer container;
public AppBootstrapper()
{
Initialize();
}
protected override void Configure()
{
container = new CompositionContainer(new AggregateCatalog(
AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType()));
var batch = new CompositionBatch();
batch.AddExportedValue(new WindowManager());
batch.AddExportedValue(new EventAggregator());
batch.AddExportedValue(container);
container.Compose(batch);
}
protected override void OnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
base.OnUnhandledException(sender, e);
PUMessageBox.ShowDialog("异常:" + e.Exception.Message);
e.Handled = true;
}
protected override object GetInstance(Type serviceType, string key)
{
string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
var exports = container.GetExportedValues