mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-05-01 21:41:28 +08:00
结构调整,便于后续扩展
This commit is contained in:
@@ -13,16 +13,6 @@
|
||||
<Page Remove="DesignItems\Custom\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Controls\AnimationHelper.cs" />
|
||||
<Compile Remove="Controls\CancelRoutedEventArgs.cs" />
|
||||
<Compile Remove="Controls\ContextMenuToggleButton.cs" />
|
||||
<Compile Remove="Controls\ScrollViewer.xaml.cs" />
|
||||
<Compile Remove="Controls\TabControl.xaml.cs" />
|
||||
<Compile Remove="Controls\TabItem.cs" />
|
||||
<Compile Remove="Controls\TabPanel.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Icons\App.ico" />
|
||||
<None Remove="Images\AlignObjectsBottom.png" />
|
||||
@@ -115,8 +105,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Remove="Controls\ScrollViewer.xaml" />
|
||||
<Page Remove="Controls\TabControl.xaml" />
|
||||
<Page Remove="Images\VectorIcons.xaml" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -128,13 +116,13 @@
|
||||
<PackageReference Include="MahApps.Metro.IconPacks" Version="4.8.0" />
|
||||
<PackageReference Include="MahApps.Metro.IconPacks.FontAwesome" Version="4.8.0" />
|
||||
<PackageReference Include="MahApps.Metro.IconPacks.VaadinIcons" Version="4.8.0" />
|
||||
<PackageReference Include="MathParser.org-mXparser" Version="4.4.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Util.Svg2XamlTestExtension" Version="1.2.5" />
|
||||
<PackageReference Include="WpfAnimatedGif" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AIStudio.Wpf.BaseDiagram\AIStudio.Wpf.BaseDiagram.csproj" />
|
||||
<ProjectReference Include="..\AIStudio.Wpf.Flowchart\AIStudio.Wpf.Flowchart.csproj" />
|
||||
<ProjectReference Include="..\AIStudio.Wpf.Logical\AIStudio.Wpf.Logical.csproj" />
|
||||
<ProjectReference Include="..\Util.DiagramDesigner\Util.DiagramDesigner.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -239,32 +227,6 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\PopupWindow.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="Demos\Logical\ViewModels\LogicalGateItemViewModel.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Demos\Others\ViewModels\BarcodeDesignerItemViewModel.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Demos\Others\ViewModels\PersistDesignerItemViewModel.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Demos\Others\ViewModels\SettingsDesignerItemViewModel.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Demos\Others\ViewModels\OutLineTextDesignerItemViewModel.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Demos\Others\ViewModels\PathItemViewModel.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="Themes\Generic.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
<ResourceDictionary Source="pack://application:,,,/Fluent;component/Themes/Generic.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/Dragablz;component/Themes/Generic.xaml" />
|
||||
<ResourceDictionary Source="/AIStudio.Wpf.ADiagram;component/Themes/Generic.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/AIStudio.Wpf.Flowchart;component/ViewModels/FlowNode.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/AIStudio.Wpf.Logical;component/ViewModels/LogicalGateItemViewModel.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
using AIStudio.Wpf.ADiagram.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple service interface
|
||||
/// </summary>
|
||||
public interface IServiceProvider
|
||||
{
|
||||
IUIVisualizerService VisualizerService { get; }
|
||||
IMessageBoxService MessageBoxService { get; }
|
||||
//IDatabaseAccessService DatabaseAccessService { get; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Simple service locator
|
||||
/// </summary>
|
||||
public class ServiceProvider : IServiceProvider
|
||||
{
|
||||
private IUIVisualizerService visualizerService = new WPFUIVisualizerService();
|
||||
private IMessageBoxService messageBoxService = new WPFMessageBoxService();
|
||||
//private IDatabaseAccessService databaseAccessService = new DatabaseAccessService();
|
||||
|
||||
public IUIVisualizerService VisualizerService
|
||||
{
|
||||
get { return visualizerService; }
|
||||
}
|
||||
|
||||
public IMessageBoxService MessageBoxService
|
||||
{
|
||||
get { return messageBoxService; }
|
||||
}
|
||||
|
||||
//public IDatabaseAccessService DatabaseAccessService
|
||||
//{
|
||||
// get { return databaseAccessService; }
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Simple service locator helper
|
||||
/// </summary>
|
||||
public class ApplicationServicesProvider
|
||||
{
|
||||
private static Lazy<ApplicationServicesProvider> instance = new Lazy<ApplicationServicesProvider>(() => new ApplicationServicesProvider());
|
||||
private IServiceProvider serviceProvider = new ServiceProvider();
|
||||
|
||||
private ApplicationServicesProvider()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static ApplicationServicesProvider()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SetNewServiceProvider(IServiceProvider provider)
|
||||
{
|
||||
serviceProvider = provider;
|
||||
}
|
||||
|
||||
public IServiceProvider Provider
|
||||
{
|
||||
get { return serviceProvider; }
|
||||
}
|
||||
|
||||
public static ApplicationServicesProvider Instance
|
||||
{
|
||||
get { return instance.Value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
@@ -1,908 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// This class allows delegating the commanding logic to methods passed as parameters,
|
||||
/// and enables a View to bind commands to objects that are not part of the element tree.
|
||||
/// </summary>
|
||||
public class CanExecuteDelegateCommand : IDelegateCommand
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CanExecuteDelegateCommand(Action executeMethod)
|
||||
: this(executeMethod, null, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CanExecuteDelegateCommand(Action executeMethod, Func<bool> canExecuteMethod)
|
||||
: this(executeMethod, canExecuteMethod, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CanExecuteDelegateCommand(Action executeMethod, Func<bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
|
||||
{
|
||||
if (executeMethod == null)
|
||||
{
|
||||
throw new ArgumentNullException("executeMethod");
|
||||
}
|
||||
|
||||
_executeMethod = executeMethod;
|
||||
_canExecuteMethod = canExecuteMethod;
|
||||
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Method to determine if the command can be executed
|
||||
/// </summary>
|
||||
public bool CanExecute()
|
||||
{
|
||||
if (_canExecuteMethod != null)
|
||||
{
|
||||
return _canExecuteMethod();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execution of the command
|
||||
/// </summary>
|
||||
public void Execute()
|
||||
{
|
||||
if (_executeMethod != null)
|
||||
{
|
||||
_executeMethod();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public object Target
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_executeMethod == null)
|
||||
return null;
|
||||
|
||||
return _executeMethod.Target;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property to enable or disable CommandManager's automatic requery on this command
|
||||
/// </summary>
|
||||
public bool IsAutomaticRequeryDisabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isAutomaticRequeryDisabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_isAutomaticRequeryDisabled != value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
|
||||
}
|
||||
_isAutomaticRequeryDisabled = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the CanExecuteChaged event
|
||||
/// </summary>
|
||||
public void RaiseCanExecuteChanged()
|
||||
{
|
||||
OnCanExecuteChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Protected virtual method to raise CanExecuteChanged event
|
||||
/// </summary>
|
||||
protected virtual void OnCanExecuteChanged()
|
||||
{
|
||||
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICommand Members
|
||||
|
||||
/// <summary>
|
||||
/// ICommand.CanExecuteChanged implementation
|
||||
/// </summary>
|
||||
public event EventHandler CanExecuteChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
if (!_isAutomaticRequeryDisabled)
|
||||
{
|
||||
CommandManager.RequerySuggested += value;
|
||||
}
|
||||
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
|
||||
}
|
||||
remove
|
||||
{
|
||||
if (!_isAutomaticRequeryDisabled)
|
||||
{
|
||||
CommandManager.RequerySuggested -= value;
|
||||
}
|
||||
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
|
||||
}
|
||||
}
|
||||
|
||||
bool ICommand.CanExecute(object parameter)
|
||||
{
|
||||
return CanExecute();
|
||||
}
|
||||
|
||||
void ICommand.Execute(object parameter)
|
||||
{
|
||||
Execute();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data
|
||||
|
||||
private readonly Action _executeMethod = null;
|
||||
private readonly Func<bool> _canExecuteMethod = null;
|
||||
private bool _isAutomaticRequeryDisabled = false;
|
||||
private List<WeakReference> _canExecuteChangedHandlers;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class CanExecuteDelegateCommand<T1> : IDelegateCommand
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CanExecuteDelegateCommand(Action<T1> executeMethod)
|
||||
: this(executeMethod, null, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CanExecuteDelegateCommand(Action<T1> executeMethod, Func<T1, bool> canExecuteMethod)
|
||||
: this(executeMethod, canExecuteMethod, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CanExecuteDelegateCommand(Action<T1> executeMethod, Func<T1, bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
|
||||
{
|
||||
if (executeMethod == null)
|
||||
{
|
||||
throw new ArgumentNullException("executeMethod");
|
||||
}
|
||||
|
||||
_executeMethod = executeMethod;
|
||||
_canExecuteMethod = canExecuteMethod;
|
||||
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Method to determine if the command can be executed
|
||||
/// </summary>
|
||||
public bool CanExecute(T1 parameter1)
|
||||
{
|
||||
if (_canExecuteMethod != null)
|
||||
{
|
||||
return _canExecuteMethod(parameter1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execution of the command
|
||||
/// </summary>
|
||||
public void Execute(T1 parameter1)
|
||||
{
|
||||
if (_executeMethod != null)
|
||||
{
|
||||
_executeMethod(parameter1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the CanExecuteChaged event
|
||||
/// </summary>
|
||||
public void RaiseCanExecuteChanged()
|
||||
{
|
||||
OnCanExecuteChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Protected virtual method to raise CanExecuteChanged event
|
||||
/// </summary>
|
||||
protected virtual void OnCanExecuteChanged()
|
||||
{
|
||||
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property to enable or disable CommandManager's automatic requery on this command
|
||||
/// </summary>
|
||||
public bool IsAutomaticRequeryDisabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isAutomaticRequeryDisabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_isAutomaticRequeryDisabled != value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
|
||||
}
|
||||
_isAutomaticRequeryDisabled = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public object Target
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_executeMethod == null)
|
||||
return null;
|
||||
|
||||
return _executeMethod.Target;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICommand Members
|
||||
|
||||
/// <summary>
|
||||
/// ICommand.CanExecuteChanged implementation
|
||||
/// </summary>
|
||||
public event EventHandler CanExecuteChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
if (!_isAutomaticRequeryDisabled)
|
||||
{
|
||||
CommandManager.RequerySuggested += value;
|
||||
}
|
||||
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
|
||||
}
|
||||
remove
|
||||
{
|
||||
if (!_isAutomaticRequeryDisabled)
|
||||
{
|
||||
CommandManager.RequerySuggested -= value;
|
||||
}
|
||||
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool CanExecute(object parameter)
|
||||
{
|
||||
if (parameter == null || (parameter is object[] && (parameter as object[]).Length < 1))
|
||||
return false;
|
||||
|
||||
if (parameter is object[])
|
||||
{
|
||||
object[] parameters = parameter as object[];
|
||||
|
||||
// if T is of value type and the parameter is not
|
||||
// set yet, then return false if CanExecute delegate
|
||||
// exists, else return true
|
||||
if ((parameters[0] != null && !typeof(T1).IsAssignableFrom(parameters[0].GetType()))
|
||||
|| (parameters[0] == null && typeof(T1).IsValueType)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return CanExecute((T1)parameters[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parameter != null && !typeof(T1).IsAssignableFrom(parameter.GetType()))
|
||||
parameter = null;
|
||||
|
||||
return CanExecute((T1)parameter);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Execute(object parameter)
|
||||
{
|
||||
//如果T1不允许为空,而parameter参数又为空,则直接返回
|
||||
if (typeof(T1).IsValueType && (parameter == null || (parameter is object[] && (parameter as object[]).Length < 1)))
|
||||
return;
|
||||
|
||||
if (parameter is object[])
|
||||
{
|
||||
object[] parameters = parameter as object[];
|
||||
|
||||
// if T1 is of value type and the parameter is not
|
||||
// set yet, then return false if CanExecute delegate
|
||||
// exists, else return true
|
||||
if ((parameters[0] != null && !typeof(T1).IsAssignableFrom(parameters[0].GetType()))
|
||||
|| (parameters[0] == null && typeof(T1).IsValueType)
|
||||
)
|
||||
return;
|
||||
|
||||
Execute((T1)parameters[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parameter != null && !typeof(T1).IsAssignableFrom(parameter.GetType()))
|
||||
parameter = null;
|
||||
|
||||
Execute((T1)parameter);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data
|
||||
|
||||
private readonly Action<T1> _executeMethod = null;
|
||||
private readonly Func<T1, bool> _canExecuteMethod = null;
|
||||
private bool _isAutomaticRequeryDisabled = false;
|
||||
private List<WeakReference> _canExecuteChangedHandlers;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class CanExecuteDelegateCommand<T1, T2> : IDelegateCommand
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CanExecuteDelegateCommand(Action<T1, T2> executeMethod)
|
||||
: this(executeMethod, null, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CanExecuteDelegateCommand(Action<T1, T2> executeMethod, Func<T1, T2, bool> canExecuteMethod)
|
||||
: this(executeMethod, canExecuteMethod, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CanExecuteDelegateCommand(Action<T1, T2> executeMethod, Func<T1, T2, bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
|
||||
{
|
||||
if (executeMethod == null)
|
||||
{
|
||||
throw new ArgumentNullException("executeMethod");
|
||||
}
|
||||
|
||||
_executeMethod = executeMethod;
|
||||
_canExecuteMethod = canExecuteMethod;
|
||||
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Method to determine if the command can be executed
|
||||
/// </summary>
|
||||
public bool CanExecute(T1 parameter1, T2 parameter2)
|
||||
{
|
||||
if (_canExecuteMethod != null)
|
||||
{
|
||||
return _canExecuteMethod(parameter1, parameter2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execution of the command
|
||||
/// </summary>
|
||||
public void Execute(T1 parameter1, T2 parameter2)
|
||||
{
|
||||
if (_executeMethod != null)
|
||||
{
|
||||
_executeMethod(parameter1, parameter2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the CanExecuteChaged event
|
||||
/// </summary>
|
||||
public void RaiseCanExecuteChanged()
|
||||
{
|
||||
OnCanExecuteChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Protected virtual method to raise CanExecuteChanged event
|
||||
/// </summary>
|
||||
protected virtual void OnCanExecuteChanged()
|
||||
{
|
||||
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property to enable or disable CommandManager's automatic requery on this command
|
||||
/// </summary>
|
||||
public bool IsAutomaticRequeryDisabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isAutomaticRequeryDisabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_isAutomaticRequeryDisabled != value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
|
||||
}
|
||||
_isAutomaticRequeryDisabled = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public object Target
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_executeMethod == null)
|
||||
return null;
|
||||
|
||||
return _executeMethod.Target;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICommand Members
|
||||
|
||||
/// <summary>
|
||||
/// ICommand.CanExecuteChanged implementation
|
||||
/// </summary>
|
||||
public event EventHandler CanExecuteChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
if (!_isAutomaticRequeryDisabled)
|
||||
{
|
||||
CommandManager.RequerySuggested += value;
|
||||
}
|
||||
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
|
||||
}
|
||||
remove
|
||||
{
|
||||
if (!_isAutomaticRequeryDisabled)
|
||||
{
|
||||
CommandManager.RequerySuggested -= value;
|
||||
}
|
||||
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool CanExecute(object parameter)
|
||||
{
|
||||
if (parameter == null || !(parameter is object[]) || (parameter as object[]).Length < 2)
|
||||
return false;
|
||||
|
||||
object[] parameters = parameter as object[];
|
||||
|
||||
// if T is of value type and the parameter is not
|
||||
// set yet, then return false if CanExecute delegate
|
||||
// exists, else return true
|
||||
if ((parameters[0] != null && !typeof(T1).IsAssignableFrom(parameters[0].GetType()))
|
||||
|| (parameters[0] == null && typeof(T1).IsValueType)
|
||||
|| (parameters[1] != null && !typeof(T2).IsAssignableFrom(parameters[1].GetType()))
|
||||
|| (parameters[1] == null && typeof(T2).IsValueType)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return CanExecute((T1)parameters[0], (T2)parameters[1]);
|
||||
}
|
||||
|
||||
public virtual void Execute(object parameter)
|
||||
{
|
||||
if (parameter == null || !(parameter is object[]) || (parameter as object[]).Length < 2)
|
||||
return;
|
||||
|
||||
object[] parameters = parameter as object[];
|
||||
|
||||
// if T is of value type and the parameter is not
|
||||
// set yet, then return false if CanExecute delegate
|
||||
// exists, else return true
|
||||
if ((parameters[0] != null && !typeof(T1).IsAssignableFrom(parameters[0].GetType()))
|
||||
|| (parameters[0] == null && typeof(T1).IsValueType)
|
||||
|| (parameters[1] != null && !typeof(T2).IsAssignableFrom(parameters[1].GetType()))
|
||||
|| (parameters[1] == null && typeof(T2).IsValueType)
|
||||
)
|
||||
return;
|
||||
|
||||
Execute((T1)parameters[0], (T2)parameters[1]);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data
|
||||
|
||||
private readonly Action<T1, T2> _executeMethod = null;
|
||||
private readonly Func<T1, T2, bool> _canExecuteMethod = null;
|
||||
private bool _isAutomaticRequeryDisabled = false;
|
||||
private List<WeakReference> _canExecuteChangedHandlers;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class CanExecuteDelegateCommand<T1, T2, T3> : IDelegateCommand
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CanExecuteDelegateCommand(Action<T1, T2, T3> executeMethod)
|
||||
: this(executeMethod, null, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CanExecuteDelegateCommand(Action<T1, T2, T3> executeMethod, Func<T1, T2, T3, bool> canExecuteMethod)
|
||||
: this(executeMethod, canExecuteMethod, false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public CanExecuteDelegateCommand(Action<T1, T2, T3> executeMethod, Func<T1, T2, T3, bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
|
||||
{
|
||||
if (executeMethod == null)
|
||||
{
|
||||
throw new ArgumentNullException("executeMethod");
|
||||
}
|
||||
|
||||
_executeMethod = executeMethod;
|
||||
_canExecuteMethod = canExecuteMethod;
|
||||
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Method to determine if the command can be executed
|
||||
/// </summary>
|
||||
public bool CanExecute(T1 parameter1, T2 parameter2, T3 parameter3)
|
||||
{
|
||||
if (_canExecuteMethod != null)
|
||||
{
|
||||
return _canExecuteMethod(parameter1, parameter2, parameter3);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execution of the command
|
||||
/// </summary>
|
||||
public void Execute(T1 parameter1, T2 parameter2, T3 parameter3)
|
||||
{
|
||||
if (_executeMethod != null)
|
||||
{
|
||||
_executeMethod(parameter1, parameter2, parameter3);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the CanExecuteChaged event
|
||||
/// </summary>
|
||||
public void RaiseCanExecuteChanged()
|
||||
{
|
||||
OnCanExecuteChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Protected virtual method to raise CanExecuteChanged event
|
||||
/// </summary>
|
||||
protected virtual void OnCanExecuteChanged()
|
||||
{
|
||||
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property to enable or disable CommandManager's automatic requery on this command
|
||||
/// </summary>
|
||||
public bool IsAutomaticRequeryDisabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isAutomaticRequeryDisabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_isAutomaticRequeryDisabled != value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
|
||||
}
|
||||
_isAutomaticRequeryDisabled = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public object Target
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_executeMethod == null)
|
||||
return null;
|
||||
|
||||
return _executeMethod.Target;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICommand Members
|
||||
|
||||
/// <summary>
|
||||
/// ICommand.CanExecuteChanged implementation
|
||||
/// </summary>
|
||||
public event EventHandler CanExecuteChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
if (!_isAutomaticRequeryDisabled)
|
||||
{
|
||||
CommandManager.RequerySuggested += value;
|
||||
}
|
||||
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
|
||||
}
|
||||
remove
|
||||
{
|
||||
if (!_isAutomaticRequeryDisabled)
|
||||
{
|
||||
CommandManager.RequerySuggested -= value;
|
||||
}
|
||||
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool CanExecute(object parameter)
|
||||
{
|
||||
if (parameter == null || !(parameter is object[]) || (parameter as object[]).Length < 3)
|
||||
return false;
|
||||
|
||||
object[] parameters = parameter as object[];
|
||||
|
||||
// if T is of value type and the parameter is not
|
||||
// set yet, then return false if CanExecute delegate
|
||||
// exists, else return true
|
||||
if ((parameters[0] != null && !typeof(T1).IsAssignableFrom(parameters[0].GetType()))
|
||||
|| (parameters[0] == null && typeof(T1).IsValueType)
|
||||
|| (parameters[1] != null && !typeof(T2).IsAssignableFrom(parameters[1].GetType()))
|
||||
|| (parameters[1] == null && typeof(T2).IsValueType)
|
||||
|| (parameters[2] != null && !typeof(T3).IsAssignableFrom(parameters[2].GetType()))
|
||||
|| (parameters[2] == null && typeof(T3).IsValueType)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return CanExecute((T1)parameters[0], (T2)parameters[1], (T3)parameters[2]);
|
||||
}
|
||||
|
||||
public virtual void Execute(object parameter)
|
||||
{
|
||||
if (parameter == null || !(parameter is object[]) || (parameter as object[]).Length < 3)
|
||||
return;
|
||||
|
||||
object[] parameters = parameter as object[];
|
||||
|
||||
// if T is of value type and the parameter is not
|
||||
// set yet, then return false if CanExecute delegate
|
||||
// exists, else return true
|
||||
if ((parameters[0] != null && !typeof(T1).IsAssignableFrom(parameters[0].GetType()))
|
||||
|| (parameters[0] == null && typeof(T1).IsValueType)
|
||||
|| (parameters[1] != null && !typeof(T2).IsAssignableFrom(parameters[1].GetType()))
|
||||
|| (parameters[1] == null && typeof(T2).IsValueType)
|
||||
|| (parameters[2] != null && !typeof(T3).IsAssignableFrom(parameters[2].GetType()))
|
||||
|| (parameters[2] == null && typeof(T3).IsValueType)
|
||||
)
|
||||
return;
|
||||
|
||||
Execute((T1)parameters[0], (T2)parameters[1], (T3)parameters[2]);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Data
|
||||
|
||||
private readonly Action<T1, T2, T3> _executeMethod = null;
|
||||
private readonly Func<T1, T2, T3, bool> _canExecuteMethod = null;
|
||||
private bool _isAutomaticRequeryDisabled = false;
|
||||
private List<WeakReference> _canExecuteChangedHandlers;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public interface IDelegateCommand : ICommand
|
||||
{
|
||||
object Target { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class contains methods for the CommandManager that help avoid memory leaks by
|
||||
/// using weak references.
|
||||
/// </summary>
|
||||
internal class CommandManagerHelper
|
||||
{
|
||||
internal static void CallWeakReferenceHandlers(List<WeakReference> handlers)
|
||||
{
|
||||
if (handlers != null)
|
||||
{
|
||||
// Take a snapshot of the handlers before we call out to them since the handlers
|
||||
// could cause the array to me modified while we are reading it.
|
||||
|
||||
EventHandler[] callees = new EventHandler[handlers.Count];
|
||||
int count = 0;
|
||||
|
||||
for (int i = handlers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
WeakReference reference = handlers[i];
|
||||
EventHandler handler = reference.Target as EventHandler;
|
||||
if (handler == null)
|
||||
{
|
||||
// Clean up old handlers that have been collected
|
||||
handlers.RemoveAt(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
callees[count] = handler;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Call the handlers that we snapshotted
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
EventHandler handler = callees[i];
|
||||
handler(null, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void AddHandlersToRequerySuggested(List<WeakReference> handlers)
|
||||
{
|
||||
if (handlers != null)
|
||||
{
|
||||
foreach (WeakReference handlerRef in handlers)
|
||||
{
|
||||
EventHandler handler = handlerRef.Target as EventHandler;
|
||||
if (handler != null)
|
||||
{
|
||||
CommandManager.RequerySuggested += handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void RemoveHandlersFromRequerySuggested(List<WeakReference> handlers)
|
||||
{
|
||||
if (handlers != null)
|
||||
{
|
||||
foreach (WeakReference handlerRef in handlers)
|
||||
{
|
||||
EventHandler handler = handlerRef.Target as EventHandler;
|
||||
if (handler != null)
|
||||
{
|
||||
CommandManager.RequerySuggested -= handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler)
|
||||
{
|
||||
AddWeakReferenceHandler(ref handlers, handler, -1);
|
||||
}
|
||||
|
||||
internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler, int defaultListSize)
|
||||
{
|
||||
if (handlers == null)
|
||||
{
|
||||
handlers = (defaultListSize > 0 ? new List<WeakReference>(defaultListSize) : new List<WeakReference>());
|
||||
}
|
||||
|
||||
handlers.Add(new WeakReference(handler));
|
||||
}
|
||||
|
||||
internal static void RemoveWeakReferenceHandler(List<WeakReference> handlers, EventHandler handler)
|
||||
{
|
||||
if (handlers != null)
|
||||
{
|
||||
for (int i = handlers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
WeakReference reference = handlers[i];
|
||||
EventHandler existingHandler = reference.Target as EventHandler;
|
||||
if ((existingHandler == null) || (existingHandler == handler))
|
||||
{
|
||||
// Clean up old handlers that have been collected
|
||||
// in addition to the handler that is to be removed.
|
||||
handlers.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Commands
|
||||
{
|
||||
public class CommandReference : Freezable, ICommand
|
||||
{
|
||||
public CommandReference()
|
||||
{
|
||||
// Blank
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandReference), new PropertyMetadata(new PropertyChangedCallback(OnCommandChanged)));
|
||||
|
||||
public ICommand Command
|
||||
{
|
||||
get { return (ICommand)GetValue(CommandProperty); }
|
||||
set { SetValue(CommandProperty, value); }
|
||||
}
|
||||
|
||||
#region ICommand Members
|
||||
|
||||
public bool CanExecute(object parameter)
|
||||
{
|
||||
if (Command != null)
|
||||
return Command.CanExecute(parameter);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Execute(object parameter)
|
||||
{
|
||||
Command.Execute(parameter);
|
||||
}
|
||||
|
||||
public event EventHandler CanExecuteChanged;
|
||||
|
||||
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
CommandReference commandReference = d as CommandReference;
|
||||
ICommand oldCommand = e.OldValue as ICommand;
|
||||
ICommand newCommand = e.NewValue as ICommand;
|
||||
|
||||
if (oldCommand != null)
|
||||
{
|
||||
oldCommand.CanExecuteChanged -= commandReference.CanExecuteChanged;
|
||||
}
|
||||
if (newCommand != null)
|
||||
{
|
||||
newCommand.CanExecuteChanged += commandReference.CanExecuteChanged;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Freezable
|
||||
|
||||
protected override Freezable CreateInstanceCore()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// The CompositeCommand composes one or more ICommands.
|
||||
/// </summary>
|
||||
public class CompositeCommand : ICommand
|
||||
{
|
||||
private readonly List<ICommand> _registeredCommands = new List<ICommand>();
|
||||
private readonly bool _monitorCommandActivity;
|
||||
private readonly EventHandler _onRegisteredCommandCanExecuteChangedHandler;
|
||||
private SynchronizationContext _synchronizationContext;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="CompositeCommand"/>.
|
||||
/// </summary>
|
||||
public CompositeCommand()
|
||||
{
|
||||
this._onRegisteredCommandCanExecuteChangedHandler = new EventHandler(this.OnRegisteredCommandCanExecuteChanged);
|
||||
_synchronizationContext = SynchronizationContext.Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="CompositeCommand"/>.
|
||||
/// </summary>
|
||||
/// <param name="monitorCommandActivity">Indicates when the command activity is going to be monitored.</param>
|
||||
public CompositeCommand(bool monitorCommandActivity)
|
||||
: this()
|
||||
{
|
||||
this._monitorCommandActivity = monitorCommandActivity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command to the collection and signs up for the <see cref="ICommand.CanExecuteChanged"/> event of it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If this command is set to monitor command activity, and <paramref name="command"/>
|
||||
/// implements the <see cref="IActiveAware"/> interface, this method will subscribe to its
|
||||
/// <see cref="IActiveAware.IsActiveChanged"/> event.
|
||||
/// </remarks>
|
||||
/// <param name="command">The command to register.</param>
|
||||
public virtual void RegisterCommand(ICommand command)
|
||||
{
|
||||
if (command == null) throw new ArgumentNullException(nameof(command));
|
||||
if (command == this)
|
||||
{
|
||||
throw new ArgumentException("CannotRegisterCompositeCommandInItself");
|
||||
}
|
||||
|
||||
lock (this._registeredCommands)
|
||||
{
|
||||
if (this._registeredCommands.Contains(command))
|
||||
{
|
||||
throw new InvalidOperationException("CannotRegisterSameCommandTwice");
|
||||
}
|
||||
this._registeredCommands.Add(command);
|
||||
}
|
||||
|
||||
command.CanExecuteChanged += this._onRegisteredCommandCanExecuteChangedHandler;
|
||||
this.OnCanExecuteChanged();
|
||||
|
||||
if (this._monitorCommandActivity)
|
||||
{
|
||||
var activeAwareCommand = command as IActiveAware;
|
||||
if (activeAwareCommand != null)
|
||||
{
|
||||
activeAwareCommand.IsActiveChanged += this.Command_IsActiveChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a command from the collection and removes itself from the <see cref="ICommand.CanExecuteChanged"/> event of it.
|
||||
/// </summary>
|
||||
/// <param name="command">The command to unregister.</param>
|
||||
public virtual void UnregisterCommand(ICommand command)
|
||||
{
|
||||
if (command == null) throw new ArgumentNullException(nameof(command));
|
||||
bool removed;
|
||||
lock (this._registeredCommands)
|
||||
{
|
||||
removed = this._registeredCommands.Remove(command);
|
||||
}
|
||||
|
||||
if (removed)
|
||||
{
|
||||
command.CanExecuteChanged -= this._onRegisteredCommandCanExecuteChangedHandler;
|
||||
this.OnCanExecuteChanged();
|
||||
|
||||
if (this._monitorCommandActivity)
|
||||
{
|
||||
var activeAwareCommand = command as IActiveAware;
|
||||
if (activeAwareCommand != null)
|
||||
{
|
||||
activeAwareCommand.IsActiveChanged -= this.Command_IsActiveChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRegisteredCommandCanExecuteChanged(object sender, EventArgs e)
|
||||
{
|
||||
this.OnCanExecuteChanged();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Forwards <see cref="ICommand.CanExecute"/> to the registered commands and returns
|
||||
/// <see langword="true" /> if all of the commands return <see langword="true" />.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Data used by the command.
|
||||
/// If the command does not require data to be passed, this object can be set to <see langword="null" />.
|
||||
/// </param>
|
||||
/// <returns><see langword="true" /> if all of the commands return <see langword="true" />; otherwise, <see langword="false" />.</returns>
|
||||
public virtual bool CanExecute(object parameter)
|
||||
{
|
||||
bool hasEnabledCommandsThatShouldBeExecuted = false;
|
||||
|
||||
ICommand[] commandList;
|
||||
lock (this._registeredCommands)
|
||||
{
|
||||
commandList = this._registeredCommands.ToArray();
|
||||
}
|
||||
foreach (ICommand command in commandList)
|
||||
{
|
||||
if (this.ShouldExecute(command))
|
||||
{
|
||||
if (!command.CanExecute(parameter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
hasEnabledCommandsThatShouldBeExecuted = true;
|
||||
}
|
||||
}
|
||||
|
||||
return hasEnabledCommandsThatShouldBeExecuted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when any of the registered commands raise <see cref="ICommand.CanExecuteChanged"/>.
|
||||
/// </summary>
|
||||
public virtual event EventHandler CanExecuteChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Forwards <see cref="ICommand.Execute"/> to the registered commands.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Data used by the command.
|
||||
/// If the command does not require data to be passed, this object can be set to <see langword="null" />.
|
||||
/// </param>
|
||||
public virtual void Execute(object parameter)
|
||||
{
|
||||
Queue<ICommand> commands;
|
||||
lock (this._registeredCommands)
|
||||
{
|
||||
commands = new Queue<ICommand>(this._registeredCommands.Where(this.ShouldExecute).ToList());
|
||||
}
|
||||
|
||||
while (commands.Count > 0)
|
||||
{
|
||||
ICommand command = commands.Dequeue();
|
||||
command.Execute(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates if a command should execute.
|
||||
/// </summary>
|
||||
/// <param name="command">The command to evaluate.</param>
|
||||
/// <returns>A <see cref="bool"/> value indicating whether the command should be used
|
||||
/// when evaluating <see cref="CompositeCommand.CanExecute"/> and <see cref="CompositeCommand.Execute"/>.</returns>
|
||||
/// <remarks>
|
||||
/// If this command is set to monitor command activity, and <paramref name="command"/>
|
||||
/// implements the <see cref="IActiveAware"/> interface,
|
||||
/// this method will return <see langword="false" /> if the command's <see cref="IActiveAware.IsActive"/>
|
||||
/// property is <see langword="false" />; otherwise it always returns <see langword="true" />.</remarks>
|
||||
protected virtual bool ShouldExecute(ICommand command)
|
||||
{
|
||||
var activeAwareCommand = command as IActiveAware;
|
||||
|
||||
if (this._monitorCommandActivity && activeAwareCommand != null)
|
||||
{
|
||||
return activeAwareCommand.IsActive;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of all the registered commands.
|
||||
/// </summary>
|
||||
/// <value>A list of registered commands.</value>
|
||||
/// <remarks>This returns a copy of the commands subscribed to the CompositeCommand.</remarks>
|
||||
public IList<ICommand> RegisteredCommands
|
||||
{
|
||||
get
|
||||
{
|
||||
IList<ICommand> commandList;
|
||||
lock (this._registeredCommands)
|
||||
{
|
||||
commandList = this._registeredCommands.ToList();
|
||||
}
|
||||
|
||||
return commandList;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises <see cref="ICommand.CanExecuteChanged"/> on the UI thread so every
|
||||
/// command invoker can requery <see cref="ICommand.CanExecute"/> to check if the
|
||||
/// <see cref="CompositeCommand"/> can execute.
|
||||
/// </summary>a
|
||||
protected virtual void OnCanExecuteChanged()
|
||||
{
|
||||
var handler = CanExecuteChanged;
|
||||
if (handler != null)
|
||||
{
|
||||
if (_synchronizationContext != null && _synchronizationContext != SynchronizationContext.Current)
|
||||
_synchronizationContext.Post((o) => handler.Invoke(this, EventArgs.Empty), null);
|
||||
else
|
||||
handler.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handler for IsActiveChanged events of registered commands.
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender.</param>
|
||||
/// <param name="e">EventArgs to pass to the event.</param>
|
||||
private void Command_IsActiveChanged(object sender, EventArgs e)
|
||||
{
|
||||
this.OnCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,334 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Commands
|
||||
{
|
||||
[MarkupExtensionReturnType(typeof(object))]
|
||||
public class ControlBinding : MarkupExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否禁止处理绑定
|
||||
/// </summary>
|
||||
public static bool Disabled = false;
|
||||
|
||||
#region Properties
|
||||
|
||||
public IValueConverter Converter { get; set; }
|
||||
public object ConverterParameter { get; set; }
|
||||
public string ElementName { get; set; }
|
||||
public RelativeSource RelativeSource { get; set; }
|
||||
public object Source { get; set; }
|
||||
public bool ValidatesOnDataErrors { get; set; }
|
||||
public bool ValidatesOnExceptions { get; set; }
|
||||
public bool NotifyOnValidationError { get; set; }
|
||||
public object TargetNullValue { get; set; }
|
||||
public object FallBackValue { get; set; }
|
||||
public string StringFormat { get; set; }
|
||||
public UpdateSourceTrigger UpdateSourceTrigger { get; set; }
|
||||
public Collection<ValidationRule> ValidationRules { get; set; }
|
||||
|
||||
public BindingMode Mode { get; set; }
|
||||
private int AncestorLevel = 1;
|
||||
[ConstructorArgument("path")]
|
||||
public PropertyPath Path { get; set; }
|
||||
[TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))]
|
||||
public CultureInfo ConverterCulture { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
public ControlBinding()
|
||||
{
|
||||
Mode = BindingMode.Default;
|
||||
ValidationRules = new Collection<ValidationRule>();
|
||||
}
|
||||
|
||||
public ControlBinding(PropertyPath path)
|
||||
{
|
||||
Path = path;
|
||||
Mode = BindingMode.Default;
|
||||
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
|
||||
NotifyOnValidationError = true;
|
||||
ValidatesOnDataErrors = true;
|
||||
ValidatesOnExceptions = true;
|
||||
TargetNullValue = null;
|
||||
ValidationRules = new Collection<ValidationRule>();
|
||||
}
|
||||
|
||||
public ControlBinding(PropertyPath path, string elementName)
|
||||
: this(path)
|
||||
{
|
||||
Path = path;
|
||||
|
||||
if (elementName == "$")
|
||||
AncestorLevel = 2;
|
||||
else
|
||||
ElementName = elementName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取代理Binding对象
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal Binding GetBinding(object rootObject)
|
||||
{
|
||||
Binding binding = new Binding();
|
||||
binding.StringFormat = StringFormat;
|
||||
binding.Path = Path;
|
||||
binding.Mode = Mode;
|
||||
binding.Converter = Converter;
|
||||
binding.ConverterCulture = ConverterCulture;
|
||||
binding.ConverterParameter = ConverterParameter;
|
||||
binding.UpdateSourceTrigger = UpdateSourceTrigger;
|
||||
if (TargetNullValue != null) binding.TargetNullValue = TargetNullValue;
|
||||
if (FallBackValue != null)
|
||||
binding.FallbackValue = FallBackValue;
|
||||
//单向绑定不需要进行数据校验
|
||||
NotifyOnValidationError &= (Mode != BindingMode.OneWay && Mode != BindingMode.OneTime);
|
||||
|
||||
binding.ValidatesOnDataErrors = NotifyOnValidationError;
|
||||
binding.ValidatesOnExceptions = NotifyOnValidationError;
|
||||
binding.NotifyOnValidationError = NotifyOnValidationError;
|
||||
|
||||
|
||||
//添加ValidationRule
|
||||
foreach (ValidationRule vr in ValidationRules)
|
||||
binding.ValidationRules.Add(vr);
|
||||
|
||||
if (ElementName != null)
|
||||
binding.ElementName = ElementName;
|
||||
if (Source != null)
|
||||
{
|
||||
if (!(Source is string) || (Source as string) != "$")
|
||||
binding.Source = Source;
|
||||
}
|
||||
if (RelativeSource != null)
|
||||
binding.RelativeSource = RelativeSource;
|
||||
|
||||
if (string.IsNullOrEmpty(ElementName) && Source == null && RelativeSource == null)
|
||||
{
|
||||
if (rootObject == null)
|
||||
{
|
||||
RelativeSource = new RelativeSource { AncestorLevel = AncestorLevel, AncestorType = typeof(UserControl), Mode = RelativeSourceMode.FindAncestor };
|
||||
|
||||
binding.RelativeSource = RelativeSource;
|
||||
}
|
||||
else
|
||||
{
|
||||
binding.Source = rootObject;
|
||||
if (rootObject is UserControl || rootObject is Window)
|
||||
{
|
||||
if (binding.Path == null || binding.Path.Path == ".")
|
||||
binding.Path = new PropertyPath("DataContext");
|
||||
else
|
||||
binding.Path = new PropertyPath("DataContext." + binding.Path.Path, binding.Path.PathParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
public override object ProvideValue(System.IServiceProvider serviceProvider)
|
||||
{
|
||||
var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
|
||||
if (valueProvider == null)
|
||||
return null;
|
||||
|
||||
|
||||
//当使用ControlMultiBinding或者MultiBinding时
|
||||
if (valueProvider.TargetProperty == null && valueProvider.TargetObject is ICollection)
|
||||
{
|
||||
if (valueProvider.TargetObject is Collection<ControlBinding>
|
||||
|| valueProvider.TargetObject.GetType().FullName == "MS.Internal.Data.BindingCollection")
|
||||
return this;
|
||||
}
|
||||
|
||||
//如果禁用
|
||||
if (ControlBinding.Disabled)
|
||||
return (valueProvider.TargetProperty as DependencyProperty).DefaultMetadata.DefaultValue;
|
||||
|
||||
var rootObjProvider = serviceProvider.GetService(typeof(System.Xaml.IRootObjectProvider)) as System.Xaml.IRootObjectProvider;
|
||||
|
||||
#region 如果是针对WinForm的ControlBinding
|
||||
|
||||
if (valueProvider.TargetObject is System.Windows.Forms.Control && rootObjProvider != null)
|
||||
{
|
||||
System.Windows.Forms.Control ctl = valueProvider.TargetObject as System.Windows.Forms.Control;
|
||||
System.Windows.Forms.Binding b = new System.Windows.Forms.Binding((valueProvider.TargetProperty as PropertyInfo).Name, rootObjProvider.RootObject, Path.Path);
|
||||
if (Mode == BindingMode.OneWay)
|
||||
{
|
||||
b.ControlUpdateMode = System.Windows.Forms.ControlUpdateMode.OnPropertyChanged;
|
||||
b.DataSourceUpdateMode = System.Windows.Forms.DataSourceUpdateMode.Never;
|
||||
}
|
||||
else if (Mode == BindingMode.OneWayToSource)
|
||||
{
|
||||
b.ControlUpdateMode = System.Windows.Forms.ControlUpdateMode.Never;
|
||||
if (UpdateSourceTrigger == System.Windows.Data.UpdateSourceTrigger.PropertyChanged
|
||||
|| UpdateSourceTrigger == System.Windows.Data.UpdateSourceTrigger.Default)
|
||||
b.DataSourceUpdateMode = System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged;
|
||||
else if (UpdateSourceTrigger == System.Windows.Data.UpdateSourceTrigger.LostFocus)
|
||||
b.DataSourceUpdateMode = System.Windows.Forms.DataSourceUpdateMode.OnValidation;
|
||||
}
|
||||
else if (Mode == BindingMode.TwoWay || Mode == BindingMode.Default)
|
||||
{
|
||||
b.ControlUpdateMode = System.Windows.Forms.ControlUpdateMode.OnPropertyChanged;
|
||||
b.DataSourceUpdateMode = System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged;
|
||||
}
|
||||
else if (Mode == BindingMode.OneTime)
|
||||
{
|
||||
//这里应该赋值一次:OneTime
|
||||
//......
|
||||
|
||||
b.ControlUpdateMode = System.Windows.Forms.ControlUpdateMode.Never;
|
||||
b.DataSourceUpdateMode = System.Windows.Forms.DataSourceUpdateMode.Never;
|
||||
}
|
||||
|
||||
ctl.DataBindings.Add(b);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
var bindingTarget = valueProvider.TargetObject as DependencyObject;
|
||||
var bindingProperty = valueProvider.TargetProperty as DependencyProperty;
|
||||
if (bindingProperty == null)
|
||||
return null;
|
||||
|
||||
#region 使用代理Binding返回最终的值
|
||||
|
||||
//得到Binding对象
|
||||
Binding binding = GetBinding(rootObjProvider == null ? null : rootObjProvider.RootObject);
|
||||
if (binding == null) return null;
|
||||
|
||||
object retValue = binding.ProvideValue(serviceProvider);
|
||||
|
||||
#endregion
|
||||
|
||||
return retValue;
|
||||
}
|
||||
}
|
||||
|
||||
[ContentProperty("Bindings")]
|
||||
public class ControlMultiBinding : MarkupExtension
|
||||
{
|
||||
#region Properties
|
||||
|
||||
public Collection<ControlBinding> Bindings { get; private set; }
|
||||
|
||||
public IMultiValueConverter Converter { get; set; }
|
||||
|
||||
[DefaultValue("")]
|
||||
[TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))]
|
||||
public CultureInfo ConverterCulture { get; set; }
|
||||
|
||||
[DefaultValue("")]
|
||||
public object ConverterParameter { get; set; }
|
||||
|
||||
public BindingMode Mode { get; set; }
|
||||
|
||||
[DefaultValue(false)]
|
||||
public bool NotifyOnSourceUpdated { get; set; }
|
||||
|
||||
[DefaultValue(false)]
|
||||
public bool NotifyOnTargetUpdated { get; set; }
|
||||
|
||||
[DefaultValue(false)]
|
||||
public bool NotifyOnValidationError { get; set; }
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public UpdateSourceExceptionFilterCallback UpdateSourceExceptionFilter { get; set; }
|
||||
|
||||
public UpdateSourceTrigger UpdateSourceTrigger { get; set; }
|
||||
|
||||
[DefaultValue(false)]
|
||||
public bool ValidatesOnDataErrors { get; set; }
|
||||
|
||||
[DefaultValue(false)]
|
||||
public bool ValidatesOnExceptions { get; set; }
|
||||
|
||||
public Collection<ValidationRule> ValidationRules { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
public ControlMultiBinding()
|
||||
{
|
||||
Bindings = new Collection<ControlBinding>();
|
||||
ValidationRules = new Collection<ValidationRule>();
|
||||
Mode = BindingMode.Default;
|
||||
UpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取代理MultiBindings对象
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal MultiBinding GetMultiBindings(object rootObject)
|
||||
{
|
||||
MultiBinding multiBindings = new MultiBinding();
|
||||
|
||||
if (this.Converter != null)
|
||||
multiBindings.Converter = this.Converter;
|
||||
if (this.ConverterCulture != null)
|
||||
multiBindings.ConverterCulture = this.ConverterCulture;
|
||||
if (this.ConverterParameter != null)
|
||||
multiBindings.ConverterParameter = this.ConverterParameter;
|
||||
if (this.UpdateSourceExceptionFilter != null)
|
||||
multiBindings.UpdateSourceExceptionFilter = this.UpdateSourceExceptionFilter;
|
||||
multiBindings.Mode = this.Mode;
|
||||
multiBindings.NotifyOnSourceUpdated = this.NotifyOnSourceUpdated;
|
||||
multiBindings.NotifyOnTargetUpdated = this.NotifyOnTargetUpdated;
|
||||
multiBindings.NotifyOnValidationError = this.NotifyOnValidationError;
|
||||
multiBindings.UpdateSourceTrigger = this.UpdateSourceTrigger;
|
||||
multiBindings.ValidatesOnDataErrors = this.ValidatesOnDataErrors;
|
||||
multiBindings.ValidatesOnExceptions = this.ValidatesOnExceptions;
|
||||
|
||||
foreach (object bd in Bindings)
|
||||
{
|
||||
if (bd is BindingBase)
|
||||
multiBindings.Bindings.Add(bd as BindingBase);
|
||||
else if (bd is ControlBinding)
|
||||
multiBindings.Bindings.Add((bd as ControlBinding).GetBinding(rootObject) as BindingBase);
|
||||
}
|
||||
|
||||
foreach (ValidationRule vr in ValidationRules)
|
||||
multiBindings.ValidationRules.Add(vr);
|
||||
|
||||
return multiBindings;
|
||||
}
|
||||
|
||||
public override object ProvideValue(System.IServiceProvider serviceProvider)
|
||||
{
|
||||
var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
|
||||
if (valueProvider == null)
|
||||
return null;
|
||||
|
||||
var bindingTarget = valueProvider.TargetObject as DependencyObject;
|
||||
var bindingProperty = valueProvider.TargetProperty as DependencyProperty;
|
||||
if (bindingProperty == null)
|
||||
return null;
|
||||
|
||||
//使用MultiBindings返回最终的值
|
||||
#region 使用代理Binding返回最终的值
|
||||
|
||||
var rootObjProvider = serviceProvider.GetService(typeof(System.Xaml.IRootObjectProvider)) as System.Xaml.IRootObjectProvider;
|
||||
|
||||
MultiBinding multiBindings = GetMultiBindings(rootObjProvider == null ? null : rootObjProvider.RootObject);
|
||||
if (multiBindings == null) return null;
|
||||
|
||||
object retValue = multiBindings.ProvideValue(serviceProvider);
|
||||
|
||||
#endregion
|
||||
|
||||
return retValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Commands
|
||||
{
|
||||
#region ConbrolCommand
|
||||
|
||||
public interface IControlCommand
|
||||
{
|
||||
void SetControl(Control cb);
|
||||
|
||||
void SetBase(IControlCommand cc);
|
||||
|
||||
void Execute(object parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ControlBase可以使用的命令类
|
||||
/// 使用此类,可以使Command具有继承的机制,在新的Command中可以调用旧的Command
|
||||
/// </summary>
|
||||
public class ControlCommand<T1> : CanExecuteDelegateCommand<ControlCommand<T1>, T1>, IControlCommand
|
||||
{
|
||||
public Control Control { get; protected set; }
|
||||
|
||||
public IControlCommand Base { get; protected set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public ControlCommand(Action<ControlCommand<T1>, T1> executeMethod, Func<ControlCommand<T1>, T1, bool> canExecuteMethod = null, bool isAutomaticRequeryDisabled = false, string name = "")
|
||||
: base(executeMethod, canExecuteMethod, isAutomaticRequeryDisabled)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public override bool CanExecute(object parameter)
|
||||
{
|
||||
return base.CanExecute(new object[] { this, parameter });
|
||||
}
|
||||
|
||||
public override void Execute(object parameter)
|
||||
{
|
||||
base.Execute(new object[] { this, parameter });
|
||||
}
|
||||
|
||||
public virtual void ExecuteBaseCommand(T1 parameter)
|
||||
{
|
||||
if (Base != null)
|
||||
Base.Execute((object)parameter);
|
||||
}
|
||||
|
||||
public void SetControl(Control cb)
|
||||
{
|
||||
Control = cb;
|
||||
}
|
||||
|
||||
public void SetBase(IControlCommand cc)
|
||||
{
|
||||
Base = cc;
|
||||
}
|
||||
}
|
||||
|
||||
public class ControlCommand : CanExecuteDelegateCommand<ControlCommand>, IControlCommand
|
||||
{
|
||||
public Control Control { get; protected set; }
|
||||
|
||||
public IControlCommand Base { get; protected set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public ControlCommand(Action<ControlCommand> executeMethod, Func<ControlCommand, bool> canExecuteMethod = null, bool isAutomaticRequeryDisabled = false, string name = "")
|
||||
: base(executeMethod, canExecuteMethod, isAutomaticRequeryDisabled)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public override bool CanExecute(object parameter)
|
||||
{
|
||||
return base.CanExecute(new object[] { this });
|
||||
}
|
||||
|
||||
public override void Execute(object parameter)
|
||||
{
|
||||
base.Execute(new object[] { this });
|
||||
}
|
||||
|
||||
public virtual void ExecuteBaseCommand()
|
||||
{
|
||||
if (Base != null)
|
||||
Base.Execute((object)null);
|
||||
}
|
||||
|
||||
public void SetControl(Control cb)
|
||||
{
|
||||
Control = cb;
|
||||
}
|
||||
|
||||
public void SetBase(IControlCommand cc)
|
||||
{
|
||||
Base = cc;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="ICommand"/> whose delegates can be attached for <see cref="Execute(T)"/> and <see cref="CanExecute(T)"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Parameter type.</typeparam>
|
||||
/// <remarks>
|
||||
/// The constructor deliberately prevents the use of value types.
|
||||
/// Because ICommand takes an object, having a value type for T would cause unexpected behavior when CanExecute(null) is called during XAML initialization for command bindings.
|
||||
/// Using default(T) was considered and rejected as a solution because the implementor would not be able to distinguish between a valid and defaulted values.
|
||||
/// <para/>
|
||||
/// Instead, callers should support a value type by using a nullable value type and checking the HasValue property before using the Value property.
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// public MyClass()
|
||||
/// {
|
||||
/// this.submitCommand = new DelegateCommand<int?>(this.Submit, this.CanSubmit);
|
||||
/// }
|
||||
///
|
||||
/// private bool CanSubmit(int? customerId)
|
||||
/// {
|
||||
/// return (customerId.HasValue && customers.Contains(customerId.Value));
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public class DelegateCommand<T> : DelegateCommandBase
|
||||
{
|
||||
readonly Action<T> _executeMethod;
|
||||
Func<T, bool> _canExecuteMethod;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="DelegateCommand{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="executeMethod">Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate.</param>
|
||||
/// <remarks><see cref="CanExecute(T)"/> will always return true.</remarks>
|
||||
public DelegateCommand(Action<T> executeMethod)
|
||||
: this(executeMethod, (o) => true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="DelegateCommand{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="executeMethod">Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate.</param>
|
||||
/// <param name="canExecuteMethod">Delegate to execute when CanExecute is called on the command. This can be null.</param>
|
||||
/// <exception cref="ArgumentNullException">When both <paramref name="executeMethod"/> and <paramref name="canExecuteMethod"/> are <see langword="null" />.</exception>
|
||||
public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
|
||||
: base()
|
||||
{
|
||||
if (executeMethod == null || canExecuteMethod == null)
|
||||
throw new ArgumentNullException(nameof(executeMethod), "DelegateCommandDelegatesCannotBeNull");
|
||||
|
||||
TypeInfo genericTypeInfo = typeof(T).GetTypeInfo();
|
||||
|
||||
// DelegateCommand allows object or Nullable<>.
|
||||
// note: Nullable<> is a struct so we cannot use a class constraint.
|
||||
if (genericTypeInfo.IsValueType)
|
||||
{
|
||||
if ((!genericTypeInfo.IsGenericType) || (!typeof(Nullable<>).GetTypeInfo().IsAssignableFrom(genericTypeInfo.GetGenericTypeDefinition().GetTypeInfo())))
|
||||
{
|
||||
throw new InvalidCastException("DelegateCommandInvalidGenericPayloadType");
|
||||
}
|
||||
}
|
||||
|
||||
_executeMethod = executeMethod;
|
||||
_canExecuteMethod = canExecuteMethod;
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Executes the command and invokes the <see cref="Action{T}"/> provided during construction.
|
||||
///</summary>
|
||||
///<param name="parameter">Data used by the command.</param>
|
||||
public void Execute(T parameter)
|
||||
{
|
||||
_executeMethod(parameter);
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Determines if the command can execute by invoked the <see cref="Func{T,Bool}"/> provided during construction.
|
||||
///</summary>
|
||||
///<param name="parameter">Data used by the command to determine if it can execute.</param>
|
||||
///<returns>
|
||||
///<see langword="true" /> if this command can be executed; otherwise, <see langword="false" />.
|
||||
///</returns>
|
||||
public bool CanExecute(T parameter)
|
||||
{
|
||||
return _canExecuteMethod(parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the internal invocation of <see cref="ICommand.Execute(object)"/>
|
||||
/// </summary>
|
||||
/// <param name="parameter">Command Parameter</param>
|
||||
protected override void Execute(object parameter)
|
||||
{
|
||||
Execute((T)parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the internal invocation of <see cref="ICommand.CanExecute(object)"/>
|
||||
/// </summary>
|
||||
/// <param name="parameter"></param>
|
||||
/// <returns><see langword="true"/> if the Command Can Execute, otherwise <see langword="false" /></returns>
|
||||
protected override bool CanExecute(object parameter)
|
||||
{
|
||||
return CanExecute((T)parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Observes a property that implements INotifyPropertyChanged, and automatically calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
|
||||
/// </summary>
|
||||
/// <typeparam name="TType">The type of the return value of the method that this delegate encapulates</typeparam>
|
||||
/// <param name="propertyExpression">The property expression. Example: ObservesProperty(() => PropertyName).</param>
|
||||
/// <returns>The current instance of DelegateCommand</returns>
|
||||
public DelegateCommand<T> ObservesProperty<TType>(Expression<Func<TType>> propertyExpression)
|
||||
{
|
||||
ObservesPropertyInternal(propertyExpression);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Observes a property that is used to determine if this command can execute, and if it implements INotifyPropertyChanged it will automatically call DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
|
||||
/// </summary>
|
||||
/// <param name="canExecuteExpression">The property expression. Example: ObservesCanExecute(() => PropertyName).</param>
|
||||
/// <returns>The current instance of DelegateCommand</returns>
|
||||
public DelegateCommand<T> ObservesCanExecute(Expression<Func<bool>> canExecuteExpression)
|
||||
{
|
||||
Expression<Func<T, bool>> expression = System.Linq.Expressions.Expression.Lambda<Func<T, bool>>(canExecuteExpression.Body, System.Linq.Expressions.Expression.Parameter(typeof(T), "o"));
|
||||
_canExecuteMethod = expression.Compile();
|
||||
ObservesPropertyInternal(canExecuteExpression);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="ICommand"/> whose delegates do not take any parameters for <see cref="Execute()"/> and <see cref="CanExecute()"/>.
|
||||
/// </summary>
|
||||
/// <see cref="DelegateCommandBase"/>
|
||||
/// <see cref="DelegateCommand{T}"/>
|
||||
public class DelegateCommand : DelegateCommandBase
|
||||
{
|
||||
Action _executeMethod;
|
||||
Func<bool> _canExecuteMethod;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="DelegateCommand"/> with the <see cref="Action"/> to invoke on execution.
|
||||
/// </summary>
|
||||
/// <param name="executeMethod">The <see cref="Action"/> to invoke when <see cref="ICommand.Execute(object)"/> is called.</param>
|
||||
public DelegateCommand(Action executeMethod)
|
||||
: this(executeMethod, () => true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="DelegateCommand"/> with the <see cref="Action"/> to invoke on execution
|
||||
/// and a <see langword="Func" /> to query for determining if the command can execute.
|
||||
/// </summary>
|
||||
/// <param name="executeMethod">The <see cref="Action"/> to invoke when <see cref="ICommand.Execute"/> is called.</param>
|
||||
/// <param name="canExecuteMethod">The <see cref="Func{TResult}"/> to invoke when <see cref="ICommand.CanExecute"/> is called</param>
|
||||
public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod)
|
||||
: base()
|
||||
{
|
||||
if (executeMethod == null || canExecuteMethod == null)
|
||||
throw new ArgumentNullException(nameof(executeMethod), "DelegateCommandDelegatesCannotBeNull");
|
||||
|
||||
_executeMethod = executeMethod;
|
||||
_canExecuteMethod = canExecuteMethod;
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// Executes the command.
|
||||
///</summary>
|
||||
public void Execute()
|
||||
{
|
||||
_executeMethod();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the command can be executed.
|
||||
/// </summary>
|
||||
/// <returns>Returns <see langword="true"/> if the command can execute,otherwise returns <see langword="false"/>.</returns>
|
||||
public bool CanExecute()
|
||||
{
|
||||
return _canExecuteMethod();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the internal invocation of <see cref="ICommand.Execute(object)"/>
|
||||
/// </summary>
|
||||
/// <param name="parameter">Command Parameter</param>
|
||||
protected override void Execute(object parameter)
|
||||
{
|
||||
Execute();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the internal invocation of <see cref="ICommand.CanExecute(object)"/>
|
||||
/// </summary>
|
||||
/// <param name="parameter"></param>
|
||||
/// <returns><see langword="true"/> if the Command Can Execute, otherwise <see langword="false" /></returns>
|
||||
protected override bool CanExecute(object parameter)
|
||||
{
|
||||
return CanExecute();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Observes a property that implements INotifyPropertyChanged, and automatically calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The object type containing the property specified in the expression.</typeparam>
|
||||
/// <param name="propertyExpression">The property expression. Example: ObservesProperty(() => PropertyName).</param>
|
||||
/// <returns>The current instance of DelegateCommand</returns>
|
||||
public DelegateCommand ObservesProperty<T>(Expression<Func<T>> propertyExpression)
|
||||
{
|
||||
ObservesPropertyInternal(propertyExpression);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Observes a property that is used to determine if this command can execute, and if it implements INotifyPropertyChanged it will automatically call DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
|
||||
/// </summary>
|
||||
/// <param name="canExecuteExpression">The property expression. Example: ObservesCanExecute(() => PropertyName).</param>
|
||||
/// <returns>The current instance of DelegateCommand</returns>
|
||||
public DelegateCommand ObservesCanExecute(Expression<Func<bool>> canExecuteExpression)
|
||||
{
|
||||
_canExecuteMethod = canExecuteExpression.Compile();
|
||||
ObservesPropertyInternal(canExecuteExpression);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="ICommand"/> whose delegates can be attached for <see cref="Execute"/> and <see cref="CanExecute"/>.
|
||||
/// </summary>
|
||||
public abstract class DelegateCommandBase : ICommand, IActiveAware
|
||||
{
|
||||
private bool _isActive;
|
||||
|
||||
private SynchronizationContext _synchronizationContext;
|
||||
private readonly HashSet<string> _observedPropertiesExpressions = new HashSet<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of a <see cref="DelegateCommandBase"/>, specifying both the execute action and the can execute function.
|
||||
/// </summary>
|
||||
protected DelegateCommandBase()
|
||||
{
|
||||
_synchronizationContext = SynchronizationContext.Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when changes occur that affect whether or not the command should execute.
|
||||
/// </summary>
|
||||
public virtual event EventHandler CanExecuteChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Raises <see cref="ICommand.CanExecuteChanged"/> so every
|
||||
/// command invoker can requery <see cref="ICommand.CanExecute"/>.
|
||||
/// </summary>
|
||||
protected virtual void OnCanExecuteChanged()
|
||||
{
|
||||
var handler = CanExecuteChanged;
|
||||
if (handler != null)
|
||||
{
|
||||
if (_synchronizationContext != null && _synchronizationContext != SynchronizationContext.Current)
|
||||
_synchronizationContext.Post((o) => handler.Invoke(this, EventArgs.Empty), null);
|
||||
else
|
||||
handler.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises <see cref="CanExecuteChanged"/> so every command invoker
|
||||
/// can requery to check if the command can execute.
|
||||
/// </summary>
|
||||
/// <remarks>Note that this will trigger the execution of <see cref="CanExecuteChanged"/> once for each invoker.</remarks>
|
||||
[SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")]
|
||||
public void RaiseCanExecuteChanged()
|
||||
{
|
||||
OnCanExecuteChanged();
|
||||
}
|
||||
|
||||
void ICommand.Execute(object parameter)
|
||||
{
|
||||
Execute(parameter);
|
||||
}
|
||||
|
||||
bool ICommand.CanExecute(object parameter)
|
||||
{
|
||||
return CanExecute(parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the internal invocation of <see cref="ICommand.Execute(object)"/>
|
||||
/// </summary>
|
||||
/// <param name="parameter">Command Parameter</param>
|
||||
protected abstract void Execute(object parameter);
|
||||
|
||||
/// <summary>
|
||||
/// Handle the internal invocation of <see cref="ICommand.CanExecute(object)"/>
|
||||
/// </summary>
|
||||
/// <param name="parameter"></param>
|
||||
/// <returns><see langword="true"/> if the Command Can Execute, otherwise <see langword="false" /></returns>
|
||||
protected abstract bool CanExecute(object parameter);
|
||||
|
||||
/// <summary>
|
||||
/// Observes a property that implements INotifyPropertyChanged, and automatically calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The object type containing the property specified in the expression.</typeparam>
|
||||
/// <param name="propertyExpression">The property expression. Example: ObservesProperty(() => PropertyName).</param>
|
||||
protected internal void ObservesPropertyInternal<T>(Expression<Func<T>> propertyExpression)
|
||||
{
|
||||
if (_observedPropertiesExpressions.Contains(propertyExpression.ToString()))
|
||||
{
|
||||
throw new ArgumentException($"{propertyExpression.ToString()} is already being observed.",
|
||||
nameof(propertyExpression));
|
||||
}
|
||||
else
|
||||
{
|
||||
_observedPropertiesExpressions.Add(propertyExpression.ToString());
|
||||
PropertyObserver.Observes(propertyExpression, RaiseCanExecuteChanged);
|
||||
}
|
||||
}
|
||||
|
||||
#region IsActive
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the object is active.
|
||||
/// </summary>
|
||||
/// <value><see langword="true" /> if the object is active; otherwise <see langword="false" />.</value>
|
||||
public bool IsActive
|
||||
{
|
||||
get { return _isActive; }
|
||||
set
|
||||
{
|
||||
if (_isActive != value)
|
||||
{
|
||||
_isActive = value;
|
||||
OnIsActiveChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fired if the <see cref="IsActive"/> property changes.
|
||||
/// </summary>
|
||||
public virtual event EventHandler IsActiveChanged;
|
||||
|
||||
/// <summary>
|
||||
/// This raises the <see cref="DelegateCommandBase.IsActiveChanged"/> event.
|
||||
/// </summary>
|
||||
protected virtual void OnIsActiveChanged()
|
||||
{
|
||||
IsActiveChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface that defines if the object instance is active
|
||||
/// and notifies when the activity changes.
|
||||
/// </summary>
|
||||
public interface IActiveAware
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the object is active.
|
||||
/// </summary>
|
||||
/// <value><see langword="true" /> if the object is active; otherwise <see langword="false" />.</value>
|
||||
bool IsActive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Notifies that the value for <see cref="IsActive"/> property has changed.
|
||||
/// </summary>
|
||||
event EventHandler IsActiveChanged;
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// Provide a way to observe property changes of INotifyPropertyChanged objects and invokes a
|
||||
/// custom action when the PropertyChanged event is fired.
|
||||
/// </summary>
|
||||
internal class PropertyObserver
|
||||
{
|
||||
private readonly Action _action;
|
||||
|
||||
private PropertyObserver(System.Linq.Expressions.Expression propertyExpression, Action action)
|
||||
{
|
||||
_action = action;
|
||||
SubscribeListeners(propertyExpression);
|
||||
}
|
||||
|
||||
private void SubscribeListeners(System.Linq.Expressions.Expression propertyExpression)
|
||||
{
|
||||
var propNameStack = new Stack<PropertyInfo>();
|
||||
while (propertyExpression is MemberExpression temp) // Gets the root of the property chain.
|
||||
{
|
||||
propertyExpression = temp.Expression;
|
||||
propNameStack.Push(temp.Member as PropertyInfo); // Records the member info as property info
|
||||
}
|
||||
|
||||
if (!(propertyExpression is ConstantExpression constantExpression))
|
||||
throw new NotSupportedException("Operation not supported for the given expression type. " +
|
||||
"Only MemberExpression and ConstantExpression are currently supported.");
|
||||
|
||||
var propObserverNodeRoot = new PropertyObserverNode(propNameStack.Pop(), _action);
|
||||
PropertyObserverNode previousNode = propObserverNodeRoot;
|
||||
foreach (var propName in propNameStack) // Create a node chain that corresponds to the property chain.
|
||||
{
|
||||
var currentNode = new PropertyObserverNode(propName, _action);
|
||||
previousNode.Next = currentNode;
|
||||
previousNode = currentNode;
|
||||
}
|
||||
|
||||
object propOwnerObject = constantExpression.Value;
|
||||
|
||||
if (!(propOwnerObject is INotifyPropertyChanged inpcObject))
|
||||
throw new InvalidOperationException("Trying to subscribe PropertyChanged listener in object that " +
|
||||
$"owns '{propObserverNodeRoot.PropertyInfo.Name}' property, but the object does not implements INotifyPropertyChanged.");
|
||||
|
||||
propObserverNodeRoot.SubscribeListenerFor(inpcObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Observes a property that implements INotifyPropertyChanged, and automatically calls a custom action on
|
||||
/// property changed notifications. The given expression must be in this form: "() => Prop.NestedProp.PropToObserve".
|
||||
/// </summary>
|
||||
/// <param name="propertyExpression">Expression representing property to be observed. Ex.: "() => Prop.NestedProp.PropToObserve".</param>
|
||||
/// <param name="action">Action to be invoked when PropertyChanged event occours.</param>
|
||||
internal static PropertyObserver Observes<T>(Expression<Func<T>> propertyExpression, Action action)
|
||||
{
|
||||
return new PropertyObserver(propertyExpression.Body, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents each node of nested properties expression and takes care of
|
||||
/// subscribing/unsubscribing INotifyPropertyChanged.PropertyChanged listeners on it.
|
||||
/// </summary>
|
||||
internal class PropertyObserverNode
|
||||
{
|
||||
private readonly Action _action;
|
||||
private INotifyPropertyChanged _inpcObject;
|
||||
|
||||
public PropertyInfo PropertyInfo { get; }
|
||||
public PropertyObserverNode Next { get; set; }
|
||||
|
||||
public PropertyObserverNode(PropertyInfo propertyInfo, Action action)
|
||||
{
|
||||
PropertyInfo = propertyInfo ?? throw new ArgumentNullException(nameof(propertyInfo));
|
||||
_action = () =>
|
||||
{
|
||||
action?.Invoke();
|
||||
if (Next == null) return;
|
||||
Next.UnsubscribeListener();
|
||||
GenerateNextNode();
|
||||
};
|
||||
}
|
||||
|
||||
public void SubscribeListenerFor(INotifyPropertyChanged inpcObject)
|
||||
{
|
||||
_inpcObject = inpcObject;
|
||||
_inpcObject.PropertyChanged += OnPropertyChanged;
|
||||
|
||||
if (Next != null) GenerateNextNode();
|
||||
}
|
||||
|
||||
private void GenerateNextNode()
|
||||
{
|
||||
var nextProperty = PropertyInfo.GetValue(_inpcObject);
|
||||
if (nextProperty == null) return;
|
||||
if (!(nextProperty is INotifyPropertyChanged nextInpcObject))
|
||||
throw new InvalidOperationException("Trying to subscribe PropertyChanged listener in object that " +
|
||||
$"owns '{Next.PropertyInfo.Name}' property, but the object does not implements INotifyPropertyChanged.");
|
||||
|
||||
Next.SubscribeListenerFor(nextInpcObject);
|
||||
}
|
||||
|
||||
private void UnsubscribeListener()
|
||||
{
|
||||
if (_inpcObject != null)
|
||||
_inpcObject.PropertyChanged -= OnPropertyChanged;
|
||||
|
||||
Next?.UnsubscribeListener();
|
||||
}
|
||||
|
||||
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e?.PropertyName == PropertyInfo.Name || string.IsNullOrEmpty(e?.PropertyName))
|
||||
{
|
||||
_action?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// 包含一些常用的动画辅助方法
|
||||
/// </summary>
|
||||
public class AnimationHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建一个Thickness动画
|
||||
/// </summary>
|
||||
/// <param name="thickness"></param>
|
||||
/// <param name="milliseconds"></param>
|
||||
/// <returns></returns>
|
||||
public static ThicknessAnimation CreateAnimation(Thickness thickness = default, double milliseconds = 200)
|
||||
{
|
||||
return new ThicknessAnimation(thickness, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
|
||||
{
|
||||
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个Double动画
|
||||
/// </summary>
|
||||
/// <param name="toValue"></param>
|
||||
/// <param name="milliseconds"></param>
|
||||
/// <returns></returns>
|
||||
public static DoubleAnimation CreateAnimation(double toValue, double milliseconds = 200)
|
||||
{
|
||||
return new DoubleAnimation(toValue, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
|
||||
{
|
||||
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
|
||||
};
|
||||
}
|
||||
|
||||
public const string DigitsPattern = @"[+-]?\d*\.?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?";
|
||||
|
||||
internal static void DecomposeGeometryStr(string geometryStr, out double[] arr)
|
||||
{
|
||||
var collection = Regex.Matches(geometryStr, DigitsPattern);
|
||||
arr = new double[collection.Count];
|
||||
for (var i = 0; i < collection.Count; i++)
|
||||
{
|
||||
arr[i] = Convert.ToDouble(collection[i].Value);
|
||||
}
|
||||
}
|
||||
|
||||
internal static Geometry ComposeGeometry(string[] strings, double[] arr)
|
||||
{
|
||||
var builder = new StringBuilder(strings[0]);
|
||||
for (var i = 0; i < arr.Length; i++)
|
||||
{
|
||||
var s = strings[i + 1];
|
||||
var n = arr[i];
|
||||
if (!double.IsNaN(n))
|
||||
{
|
||||
builder.Append(n).Append(s);
|
||||
}
|
||||
}
|
||||
|
||||
return Geometry.Parse(builder.ToString());
|
||||
}
|
||||
|
||||
internal static Geometry InterpolateGeometry(double[] from, double[] to, double progress, string[] strings)
|
||||
{
|
||||
var accumulated = new double[to.Length];
|
||||
for (var i = 0; i < to.Length; i++)
|
||||
{
|
||||
var fromValue = from[i];
|
||||
accumulated[i] = fromValue + (to[i] - fromValue) * progress;
|
||||
}
|
||||
|
||||
return ComposeGeometry(strings, accumulated);
|
||||
}
|
||||
|
||||
internal static double[] InterpolateGeometryValue(double[] from, double[] to, double progress)
|
||||
{
|
||||
var accumulated = new double[to.Length];
|
||||
for (var i = 0; i < to.Length; i++)
|
||||
{
|
||||
var fromValue = from[i];
|
||||
accumulated[i] = fromValue + (to[i] - fromValue) * progress;
|
||||
}
|
||||
|
||||
return accumulated;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<UserControl x:Class="AIStudio.Wpf.ADiagram.Controls.Barcode"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="2*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Path Name="imageBarcodeEncoderGeometry" Grid.RowSpan="3" Grid.ColumnSpan="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="Black" Stretch="Fill" Width="Auto" Height="Auto" />
|
||||
<ContentControl x:Name="PART_Icon" Grid.Row="1" Grid.Column="1"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,129 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
using WpfAnimatedGif;
|
||||
using ZXing;
|
||||
using ZXing.Presentation;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Barcode.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class Barcode : UserControl
|
||||
{
|
||||
public Barcode()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
|
||||
"Text", typeof(string), typeof(Barcode), new FrameworkPropertyMetadata(
|
||||
string.Empty,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure |
|
||||
FrameworkPropertyMetadataOptions.AffectsRender, OnFormattedTextInvalidated));
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => (string)GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FormatProperty = DependencyProperty.Register(
|
||||
"Format", typeof(BarcodeFormat), typeof(Barcode), new FrameworkPropertyMetadata(
|
||||
BarcodeFormat.QR_CODE,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure |
|
||||
FrameworkPropertyMetadataOptions.AffectsRender, OnFormattedTextInvalidated));
|
||||
|
||||
public BarcodeFormat Format
|
||||
{
|
||||
get => (BarcodeFormat)GetValue(FormatProperty);
|
||||
set => SetValue(FormatProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SizeProperty = DependencyProperty.Register(
|
||||
"Size", typeof(double), typeof(Barcode), new FrameworkPropertyMetadata(
|
||||
512d,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure |
|
||||
FrameworkPropertyMetadataOptions.AffectsRender, OnFormattedTextInvalidated));
|
||||
|
||||
public double Size
|
||||
{
|
||||
get => (double)GetValue(SizeProperty);
|
||||
set => SetValue(SizeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
|
||||
"Icon", typeof(string), typeof(Barcode), new FrameworkPropertyMetadata(null, OnIconChanged));
|
||||
|
||||
public string Icon
|
||||
{
|
||||
get => (string)GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
|
||||
private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var barcode = (Barcode)d;
|
||||
barcode.OnIconChanged();
|
||||
}
|
||||
|
||||
private void OnIconChanged()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(this.Icon))
|
||||
{
|
||||
var suffix = System.IO.Path.GetExtension(this.Icon).ToLower();
|
||||
Image image = new Image() { Stretch = Stretch.UniformToFill };
|
||||
var icon = new BitmapImage(new Uri(Icon));
|
||||
if (suffix != ".gif")
|
||||
{
|
||||
image.Source = icon;
|
||||
}
|
||||
else
|
||||
{
|
||||
image.SetCurrentValue(ImageBehavior.AnimatedSourceProperty, icon);
|
||||
image.SetCurrentValue(ImageBehavior.AutoStartProperty, true);
|
||||
}
|
||||
PART_Icon.Content = image;
|
||||
}
|
||||
else
|
||||
{
|
||||
PART_Icon.Content = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnFormattedTextInvalidated(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var barcode = (Barcode)d;
|
||||
barcode.OnFormattedTextInvalidated();
|
||||
}
|
||||
|
||||
private void OnFormattedTextInvalidated()
|
||||
{
|
||||
var writer = new BarcodeWriterGeometry
|
||||
{
|
||||
Format = Format,
|
||||
Options = new ZXing.Common.EncodingOptions
|
||||
{
|
||||
Height = (int)this.Size,
|
||||
Width = (int)this.Size,
|
||||
Margin = 0
|
||||
}
|
||||
};
|
||||
var image = writer.Write(Text ?? "AIStudio画板");
|
||||
imageBarcodeEncoderGeometry.Data = image;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
public class CancelRoutedEventArgs : RoutedEventArgs
|
||||
{
|
||||
public CancelRoutedEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source)
|
||||
{
|
||||
}
|
||||
|
||||
public bool Cancel { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// 带上下文菜单的切换按钮
|
||||
/// </summary>
|
||||
public class ContextMenuToggleButton : ToggleButton
|
||||
{
|
||||
public ContextMenu Menu { get; set; }
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
base.OnClick();
|
||||
if (Menu != null)
|
||||
{
|
||||
if (IsChecked == true)
|
||||
{
|
||||
Menu.PlacementTarget = this;
|
||||
Menu.IsOpen = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu.IsOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
<UserControl x:Class="AIStudio.Wpf.ADiagram.Controls.GradientStopControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
|
||||
xmlns:Fluent="urn:fluent-ribbon"
|
||||
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters"
|
||||
xmlns:helper="clr-namespace:AIStudio.Wpf.ADiagram.Helpers"
|
||||
xmlns:dd="https://astudio.github.io/diagram"
|
||||
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<UserControl.Resources>
|
||||
<ControlTemplate x:Key="RibbonDropDownButtonControlTemplate1" TargetType="{x:Type Fluent:DropDownButton}">
|
||||
<Grid>
|
||||
<Border x:Name="PART_ButtonBorder" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" Height="Auto">
|
||||
<StackPanel x:Name="stackPanel" Margin="{TemplateBinding Padding}" Width="Auto" Orientation="Vertical">
|
||||
<ContentPresenter x:Name="iconImage" Content="{Binding Icon, RelativeSource={RelativeSource TemplatedParent}}" Width="Auto" SnapsToDevicePixels="True" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Popup x:Name="PART_Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Margin="0,0,-4,0" VerticalAlignment="Top" Grid.ColumnSpan="2">
|
||||
<Grid Name="DropDown" SnapsToDevicePixels="True" Margin="0" VerticalAlignment="Top">
|
||||
<Border x:Name="PART_DropDownBorder" MinWidth="{TemplateBinding ActualWidth}" SnapsToDevicePixels="True" Background="{DynamicResource Fluent.Ribbon.Brushes.DropDown.BackgroundBrush}" BorderBrush="{DynamicResource Fluent.Ribbon.Brushes.DropDown.BorderBrush}" BorderThickness="1" HorizontalAlignment="Stretch" VerticalAlignment="Top">
|
||||
<Grid Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Top">
|
||||
<Border VerticalAlignment="Top" Width="Auto" Height="Auto" BorderBrush="{DynamicResource Fluent.Ribbon.Brushes.DropDown.BackgroundBrush}" BorderThickness="1" />
|
||||
<Grid Margin="1" HorizontalAlignment="Stretch" VerticalAlignment="Top">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ScrollViewer x:Name="PART_ScrollViewer" Style="{DynamicResource MenuScrollViewer}" IsTabStop="False" Margin="1" MaxHeight="{TemplateBinding MaxDropDownHeight}" SnapsToDevicePixels="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Hidden">
|
||||
<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Local" />
|
||||
</ScrollViewer>
|
||||
<Border x:Name="resizeBorder" HorizontalAlignment="Stretch" VerticalAlignment="Top" Height="11" BorderBrush="{DynamicResource Fluent.Ribbon.Brushes.DropDown.Resize.BorderBrush}" BorderThickness="0,1,0,0" Grid.Row="1" Background="{DynamicResource Fluent.Ribbon.Brushes.DropDown.Resize.BackgroundBrush}">
|
||||
<Grid>
|
||||
<Thumb x:Name="PART_ResizeVerticalThumb" HorizontalAlignment="Stretch" Margin="0,0,0,-90" Width="Auto" Height="10" VerticalAlignment="Top" Cursor="SizeNS" Template="{DynamicResource ResizeVerticalThumbControlTemplate}" />
|
||||
<Thumb x:Name="PART_ResizeBothThumb" HorizontalAlignment="Right" Margin="0,0,0,-90" Width="10" Height="10" VerticalAlignment="Top" Cursor="SizeNWSE" Template="{DynamicResource ResizeBothThumbControlTemplate}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Popup>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="ResizeMode" Value="None">
|
||||
<Setter Property="Visibility" TargetName="resizeBorder" Value="Collapsed" />
|
||||
</Trigger>
|
||||
<Trigger Property="ResizeMode" Value="Both">
|
||||
<Setter Property="Visibility" TargetName="PART_ResizeVerticalThumb" Value="Collapsed" />
|
||||
<Setter Property="Visibility" TargetName="PART_ResizeBothThumb" Value="Visible" />
|
||||
<Setter Property="Visibility" TargetName="resizeBorder" Value="Visible" />
|
||||
</Trigger>
|
||||
<Trigger Property="ResizeMode" Value="Vertical">
|
||||
<Setter Property="Visibility" TargetName="PART_ResizeBothThumb" Value="Collapsed" />
|
||||
<Setter Property="Visibility" TargetName="PART_ResizeVerticalThumb" Value="Visible" />
|
||||
<Setter Property="Visibility" TargetName="resizeBorder" Value="Visible" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsDropDownOpen" Value="True">
|
||||
<Setter Property="BorderBrush" TargetName="PART_ButtonBorder" Value="{DynamicResource Fluent.Ribbon.Brushes.Button.Pressed.BorderBrush}" />
|
||||
<Setter Property="Background" TargetName="PART_ButtonBorder" Value="{DynamicResource Fluent.Ribbon.Brushes.Button.Pressed.Background}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Opacity" TargetName="iconImage" Value="0.5" />
|
||||
<Setter Property="Effect" TargetName="iconImage">
|
||||
<Setter.Value>
|
||||
<Fluent:GrayscaleEffect />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Trigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsMouseOver" Value="True" />
|
||||
<Condition Property="IsDropDownOpen" Value="False" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter Property="Background" TargetName="PART_ButtonBorder" Value="{DynamicResource Fluent.Ribbon.Brushes.Button.MouseOver.Background}" />
|
||||
<Setter Property="BorderBrush" TargetName="PART_ButtonBorder" Value="{DynamicResource Fluent.Ribbon.Brushes.Button.MouseOver.BorderBrush}" />
|
||||
</MultiTrigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
</UserControl.Resources>
|
||||
<StackPanel>
|
||||
<DockPanel>
|
||||
<Fluent:Button DockPanel.Dock="Right" Size="Small"
|
||||
Icon="{iconPacks:Material Kind=Minus}" Command="{Binding DeleteGradientStopCommand}" Margin="5" />
|
||||
<Fluent:Button DockPanel.Dock="Right" Size="Small"
|
||||
Icon="{iconPacks:Material Kind=Plus}" Command="{Binding AddGradientStopCommand}" Margin="5" />
|
||||
<TextBlock Text="渐变光圈" VerticalAlignment="Center" Margin="5"/>
|
||||
</DockPanel>
|
||||
|
||||
<Grid Margin="5">
|
||||
<Rectangle Fill="{Binding GradientStop, Converter={StaticResource ColorBrushConverter}}" Height="4.0" VerticalAlignment="Center" />
|
||||
<ItemsControl ItemsSource="{Binding GradientStop}" >
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<Grid >
|
||||
|
||||
</Grid>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Slider Maximum="1" Minimum="0" LargeChange="0.1" SmallChange="0.01"
|
||||
Value="{Binding Offset}"
|
||||
Foreground="{Binding Color, Converter={StaticResource ColorBrushConverter}}"
|
||||
Style="{StaticResource TransparentSlider}"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
|
||||
<DockPanel>
|
||||
<!-- The following code shows theme colors mode for color gallery -->
|
||||
<Fluent:DropDownButton DockPanel.Dock="Right" Margin="5" Height="24" Width="60"
|
||||
Template="{StaticResource RibbonDropDownButtonControlTemplate1}"
|
||||
MaxDropDownHeight="500">
|
||||
<Fluent:DropDownButton.Icon>
|
||||
<Grid>
|
||||
<Rectangle Height="22" StrokeThickness="1" Stroke="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
|
||||
<Rectangle.Fill>
|
||||
<SolidColorBrush Color="{Binding SelectedGradientStop.Color}" />
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
</Grid>
|
||||
</Fluent:DropDownButton.Icon>
|
||||
<Fluent:ColorGallery SelectedColor="{Binding SelectedGradientStop.Color, Mode=TwoWay}"
|
||||
Mode="StandardColors"
|
||||
StandardColorGridRows="3"
|
||||
Columns="10"
|
||||
ThemeColorGridRows="5"
|
||||
IsNoColorButtonVisible="True" />
|
||||
</Fluent:DropDownButton>
|
||||
<TextBlock Margin="5" VerticalAlignment="Center" Text="颜色"/>
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -1,46 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
using Util.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// GradientStopControl.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class GradientStopControl : UserControl
|
||||
{
|
||||
public GradientStopControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public ColorObject ColorObject
|
||||
{
|
||||
get { return this.DataContext as ColorObject; }
|
||||
}
|
||||
|
||||
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnPreviewMouseDown(e);
|
||||
|
||||
var element = (e.OriginalSource as FrameworkElement);
|
||||
if (element.DataContext is Util.DiagramDesigner.GradientStop target)
|
||||
{
|
||||
ColorObject.SelectedGradientStop = target;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
<UserControl x:Class="AIStudio.Wpf.ADiagram.Controls.MultiSelectComboBox"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ComboBox Background="Transparent" BorderBrush="Transparent"
|
||||
x:Name="MultiSelectCombo"
|
||||
SnapsToDevicePixels="True"
|
||||
OverridesDefaultStyle="True"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
ScrollViewer.CanContentScroll="True"
|
||||
IsSynchronizedWithCurrentItem="True"
|
||||
>
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox Content="{Binding Title}"
|
||||
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"
|
||||
Tag="{RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}"
|
||||
Click="CheckBox_Click" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
<ComboBox.Template>
|
||||
<ControlTemplate TargetType="ComboBox">
|
||||
<Grid >
|
||||
<ToggleButton x:Name="ToggleButton" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
|
||||
Grid.Column="2" IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Focusable="false"
|
||||
ClickMode="Press" HorizontalContentAlignment="Left" >
|
||||
<ToggleButton.Template>
|
||||
<ControlTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="12"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border
|
||||
x:Name="Border"
|
||||
Grid.ColumnSpan="2"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}" />
|
||||
<Border
|
||||
x:Name="BorderComp"
|
||||
Grid.Column="0"
|
||||
CornerRadius="2"
|
||||
Margin="1"
|
||||
BorderThickness="0,0,0,0" >
|
||||
<TextBlock Text="{Binding Path=Text,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" Padding="3" />
|
||||
</Border>
|
||||
<Border x:Name="ArrowBorder" Grid.Column="1" >
|
||||
<Path
|
||||
x:Name="Arrow"
|
||||
Stretch="Fill" Width="5" Height="3"
|
||||
Fill="Black"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="M 0 0 L 4 4 L 8 0 Z"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter TargetName="ArrowBorder" Property="Background" Value="{DynamicResource Fluent.Ribbon.Brushes.Button.MouseOver.Background}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</ToggleButton.Template>
|
||||
</ToggleButton>
|
||||
<Popup x:Name="Popup"
|
||||
Placement="Bottom"
|
||||
AllowsTransparency="True"
|
||||
Focusable="False" IsOpen="{TemplateBinding IsDropDownOpen}"
|
||||
PopupAnimation="Slide">
|
||||
<Grid x:Name="DropDown"
|
||||
SnapsToDevicePixels="True"
|
||||
MinWidth="{TemplateBinding ActualWidth}"
|
||||
MaxHeight="{TemplateBinding MaxDropDownHeight}">
|
||||
<Border x:Name="DropDownBorder"
|
||||
BorderThickness="1" Background="{DynamicResource WhiteBrush}"
|
||||
BorderBrush="{DynamicResource GrayBrush8}"/>
|
||||
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True" DataContext="{Binding}">
|
||||
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Popup>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="HasItems" Value="false">
|
||||
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
|
||||
</Trigger>
|
||||
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
|
||||
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsDropDownOpen" Value="true">
|
||||
<Setter TargetName="ToggleButton" Property="Background" Value="{DynamicResource Fluent.Ribbon.Brushes.Button.MouseOver.Background}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</ComboBox.Template>
|
||||
</ComboBox>
|
||||
</UserControl>
|
||||
@@ -1,334 +0,0 @@
|
||||
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;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Collections;
|
||||
using AIStudio.Wpf.ADiagram.Helpers;
|
||||
using Util.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MultiSelectComboBox.xaml
|
||||
/// </summary>
|
||||
public partial class MultiSelectComboBox : UserControl
|
||||
{
|
||||
private ObservableCollection<Node> _nodeList;
|
||||
public MultiSelectComboBox()
|
||||
{
|
||||
InitializeComponent();
|
||||
_nodeList = new ObservableCollection<Node>();
|
||||
}
|
||||
|
||||
#region Dependency Properties
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceProperty =
|
||||
DependencyProperty.Register("ItemsSource", typeof(IList), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
|
||||
new PropertyChangedCallback(MultiSelectComboBox.OnItemsSourceChanged)));
|
||||
|
||||
public static readonly DependencyProperty SelectedItemsProperty =
|
||||
DependencyProperty.Register("SelectedItems", typeof(IList), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
|
||||
new PropertyChangedCallback(MultiSelectComboBox.OnSelectedItemsChanged)));
|
||||
|
||||
public static readonly DependencyProperty SelectedValuesProperty =
|
||||
DependencyProperty.Register("SelectedValues", typeof(IList), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
|
||||
new PropertyChangedCallback(MultiSelectComboBox.OnSelectedValuesChanged)));
|
||||
|
||||
public static readonly DependencyProperty TextProperty =
|
||||
DependencyProperty.Register("Text", typeof(string), typeof(MultiSelectComboBox), new UIPropertyMetadata(string.Empty));
|
||||
|
||||
public static readonly DependencyProperty DefaultTextProperty =
|
||||
DependencyProperty.Register("DefaultText", typeof(string), typeof(MultiSelectComboBox), new UIPropertyMetadata(string.Empty));
|
||||
|
||||
public string DisplayMemberPath { get; set; }
|
||||
|
||||
public string SelectedValuePath { get; set; }
|
||||
|
||||
public IList ItemsSource
|
||||
{
|
||||
get { return (IList)GetValue(ItemsSourceProperty); }
|
||||
set
|
||||
{
|
||||
SetValue(ItemsSourceProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public IList SelectedItems
|
||||
{
|
||||
get { return (IList)GetValue(SelectedItemsProperty); }
|
||||
set
|
||||
{
|
||||
SetValue(SelectedItemsProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public IList SelectedValues
|
||||
{
|
||||
get { return (IList)GetValue(SelectedValuesProperty); }
|
||||
set
|
||||
{
|
||||
SetValue(SelectedValuesProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get { return (string)GetValue(TextProperty); }
|
||||
set { SetValue(TextProperty, value); }
|
||||
}
|
||||
|
||||
public string DefaultText
|
||||
{
|
||||
get { return (string)GetValue(DefaultTextProperty); }
|
||||
set { SetValue(DefaultTextProperty, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
MultiSelectComboBox control = (MultiSelectComboBox)d;
|
||||
control.DisplayInControl();
|
||||
}
|
||||
|
||||
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
MultiSelectComboBox control = (MultiSelectComboBox)d;
|
||||
control.SelectNodes();
|
||||
control.SetText();
|
||||
}
|
||||
|
||||
private static void OnSelectedValuesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
MultiSelectComboBox control = (MultiSelectComboBox)d;
|
||||
control.SelectNodes();
|
||||
control.SetText();
|
||||
}
|
||||
|
||||
private void CheckBox_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CheckBox clickedBox = (CheckBox)sender;
|
||||
|
||||
if (clickedBox.Content.ToString() == "All")
|
||||
{
|
||||
if (clickedBox.IsChecked.Value)
|
||||
{
|
||||
foreach (Node node in _nodeList)
|
||||
{
|
||||
node.IsSelected = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Node node in _nodeList)
|
||||
{
|
||||
node.IsSelected = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
int _selectedCount = 0;
|
||||
foreach (Node s in _nodeList)
|
||||
{
|
||||
if (s.IsSelected && s.Object.ToString() != "All")
|
||||
_selectedCount++;
|
||||
}
|
||||
if (_selectedCount == _nodeList.Count - 1)
|
||||
_nodeList.FirstOrDefault(i => i.Object.ToString() == "All").IsSelected = true;
|
||||
else
|
||||
_nodeList.FirstOrDefault(i => i.Object.ToString() == "All").IsSelected = false;
|
||||
}
|
||||
SetSelectedItems();
|
||||
SetText();
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Methods
|
||||
private void SelectNodes()
|
||||
{
|
||||
if (SelectedItems != null)
|
||||
{
|
||||
foreach (var item in SelectedItems)
|
||||
{
|
||||
Node node = _nodeList.FirstOrDefault(i => i.Object == item);
|
||||
if (node != null)
|
||||
node.IsSelected = true;
|
||||
}
|
||||
}
|
||||
else if (SelectedValues != null)
|
||||
{
|
||||
foreach (var item in SelectedValues)
|
||||
{
|
||||
Node node = _nodeList.FirstOrDefault(i => i.Object != null && i.Object.ToString() != "All" && i.Object.GetPropertyValue(SelectedValuePath) == item);
|
||||
if (node != null)
|
||||
node.IsSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSelectedItems()
|
||||
{
|
||||
if (SelectedItems != null)
|
||||
{
|
||||
SelectedItems.Clear();
|
||||
foreach (Node node in _nodeList)
|
||||
{
|
||||
if (node.IsSelected && node.Object.ToString() != "All")
|
||||
{
|
||||
if (this.ItemsSource.Count > 0)
|
||||
{
|
||||
if (SelectedItems != null)
|
||||
{
|
||||
SelectedItems.Add(node.Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SelectedValues != null)
|
||||
{
|
||||
SelectedValues.Clear();
|
||||
foreach (Node node in _nodeList)
|
||||
{
|
||||
if (node.IsSelected && node.Object.ToString() != "All")
|
||||
{
|
||||
if (this.ItemsSource.Count > 0)
|
||||
{
|
||||
if (SelectedValues != null)
|
||||
{
|
||||
SelectedValues.Add(node.Object.GetPropertyValue(SelectedValuePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayInControl()
|
||||
{
|
||||
_nodeList.Clear();
|
||||
if (this.ItemsSource.Count > 0)
|
||||
_nodeList.Add(new Node("All", DisplayMemberPath));
|
||||
foreach (var item in this.ItemsSource)
|
||||
{
|
||||
Node node = new Node(item, DisplayMemberPath);
|
||||
_nodeList.Add(node);
|
||||
}
|
||||
MultiSelectCombo.ItemsSource = _nodeList;
|
||||
}
|
||||
|
||||
private void SetText()
|
||||
{
|
||||
StringBuilder displayText = new StringBuilder();
|
||||
foreach (Node s in _nodeList)
|
||||
{
|
||||
if (s.IsSelected == true && s.Object.ToString() == "All")
|
||||
{
|
||||
displayText = new StringBuilder();
|
||||
displayText.Append("All");
|
||||
break;
|
||||
}
|
||||
else if (s.IsSelected == true && s.Object.ToString() != "All")
|
||||
{
|
||||
displayText.Append(s.Object);
|
||||
displayText.Append(',');
|
||||
}
|
||||
}
|
||||
this.Text = displayText.ToString().TrimEnd(new char[] { ',' });
|
||||
|
||||
// set DefaultText if nothing else selected
|
||||
if (string.IsNullOrEmpty(this.Text))
|
||||
{
|
||||
this.Text = this.DefaultText;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class Node : INotifyPropertyChanged
|
||||
{
|
||||
#region ctor
|
||||
public Node(object obj, string displayMemberPath)
|
||||
{
|
||||
Object = obj;
|
||||
|
||||
if (!string.IsNullOrEmpty(displayMemberPath) && Object.ContainsProperty(displayMemberPath))
|
||||
Title = Object.GetPropertyValue(displayMemberPath).ToString();
|
||||
else
|
||||
Title = obj.ToString();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
private object _object;
|
||||
public object Object
|
||||
{
|
||||
get
|
||||
{
|
||||
return _object;
|
||||
}
|
||||
set
|
||||
{
|
||||
_object = value;
|
||||
NotifyPropertyChanged("Object");
|
||||
}
|
||||
}
|
||||
|
||||
private string _title;
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return _title;
|
||||
}
|
||||
set
|
||||
{
|
||||
_title = value;
|
||||
NotifyPropertyChanged("Title");
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isSelected;
|
||||
public bool IsSelected
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isSelected;
|
||||
}
|
||||
set
|
||||
{
|
||||
_isSelected = value;
|
||||
NotifyPropertyChanged("IsSelected");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
protected void NotifyPropertyChanged(string propertyName)
|
||||
{
|
||||
if (PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,310 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
public class OutlineText : FrameworkElement
|
||||
{
|
||||
private Pen _pen;
|
||||
|
||||
private FormattedText _formattedText;
|
||||
|
||||
private Geometry _textGeometry;
|
||||
|
||||
private PathGeometry _clipGeometry;
|
||||
|
||||
static OutlineText()
|
||||
{
|
||||
SnapsToDevicePixelsProperty.OverrideMetadata(typeof(OutlineText), new FrameworkPropertyMetadata(true));
|
||||
UseLayoutRoundingProperty.OverrideMetadata(typeof(OutlineText), new FrameworkPropertyMetadata(true));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StrokePositionProperty = DependencyProperty.Register(
|
||||
"StrokePosition", typeof(StrokePosition), typeof(OutlineText), new PropertyMetadata(default(StrokePosition)));
|
||||
|
||||
public StrokePosition StrokePosition
|
||||
{
|
||||
get => (StrokePosition)GetValue(StrokePositionProperty);
|
||||
set => SetValue(StrokePositionProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
|
||||
"Text", typeof(string), typeof(OutlineText), new FrameworkPropertyMetadata(
|
||||
string.Empty,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure |
|
||||
FrameworkPropertyMetadataOptions.AffectsRender, OnFormattedTextInvalidated));
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => (string)GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextAlignmentProperty = DependencyProperty.Register(
|
||||
"TextAlignment", typeof(TextAlignment), typeof(OutlineText),
|
||||
new PropertyMetadata(default(TextAlignment), OnFormattedTextUpdated));
|
||||
|
||||
public TextAlignment TextAlignment
|
||||
{
|
||||
get => (TextAlignment)GetValue(TextAlignmentProperty);
|
||||
set => SetValue(TextAlignmentProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextTrimmingProperty = DependencyProperty.Register(
|
||||
"TextTrimming", typeof(TextTrimming), typeof(OutlineText),
|
||||
new PropertyMetadata(default(TextTrimming), OnFormattedTextInvalidated));
|
||||
|
||||
public TextTrimming TextTrimming
|
||||
{
|
||||
get => (TextTrimming)GetValue(TextTrimmingProperty);
|
||||
set => SetValue(TextTrimmingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register(
|
||||
"TextWrapping", typeof(TextWrapping), typeof(OutlineText),
|
||||
new PropertyMetadata(TextWrapping.NoWrap, OnFormattedTextInvalidated));
|
||||
|
||||
public TextWrapping TextWrapping
|
||||
{
|
||||
get => (TextWrapping)GetValue(TextWrappingProperty);
|
||||
set => SetValue(TextWrappingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
|
||||
"Fill", typeof(Brush), typeof(OutlineText), new PropertyMetadata(Brushes.Black, OnFormattedTextUpdated));
|
||||
|
||||
public Brush Fill
|
||||
{
|
||||
get => (Brush)GetValue(FillProperty);
|
||||
set => SetValue(FillProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
|
||||
"Stroke", typeof(Brush), typeof(OutlineText), new PropertyMetadata(Brushes.Black, OnFormattedTextUpdated));
|
||||
|
||||
public Brush Stroke
|
||||
{
|
||||
get => (Brush)GetValue(StrokeProperty);
|
||||
set => SetValue(StrokeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
|
||||
"StrokeThickness", typeof(double), typeof(OutlineText), new PropertyMetadata(0d, OnFormattedTextUpdated));
|
||||
|
||||
public double StrokeThickness
|
||||
{
|
||||
get => (double)GetValue(StrokeThicknessProperty);
|
||||
set => SetValue(StrokeThicknessProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(
|
||||
typeof(OutlineText),
|
||||
new FrameworkPropertyMetadata(OnFormattedTextUpdated));
|
||||
|
||||
public FontFamily FontFamily
|
||||
{
|
||||
get => (FontFamily)GetValue(FontFamilyProperty);
|
||||
set => SetValue(FontFamilyProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner(
|
||||
typeof(OutlineText),
|
||||
new FrameworkPropertyMetadata(OnFormattedTextUpdated));
|
||||
|
||||
[TypeConverter(typeof(FontSizeConverter))]
|
||||
public double FontSize
|
||||
{
|
||||
get => (double)GetValue(FontSizeProperty);
|
||||
set => SetValue(FontSizeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FontStretchProperty = TextElement.FontStretchProperty.AddOwner(
|
||||
typeof(OutlineText),
|
||||
new FrameworkPropertyMetadata(OnFormattedTextUpdated));
|
||||
|
||||
public FontStretch FontStretch
|
||||
{
|
||||
get => (FontStretch)GetValue(FontStretchProperty);
|
||||
set => SetValue(FontStretchProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FontStyleProperty = TextElement.FontStyleProperty.AddOwner(
|
||||
typeof(OutlineText),
|
||||
new FrameworkPropertyMetadata(OnFormattedTextUpdated));
|
||||
|
||||
public FontStyle FontStyle
|
||||
{
|
||||
get => (FontStyle)GetValue(FontStyleProperty);
|
||||
set => SetValue(FontStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FontWeightProperty = TextElement.FontWeightProperty.AddOwner(
|
||||
typeof(OutlineText),
|
||||
new FrameworkPropertyMetadata(OnFormattedTextUpdated));
|
||||
|
||||
public FontWeight FontWeight
|
||||
{
|
||||
get => (FontWeight)GetValue(FontWeightProperty);
|
||||
set => SetValue(FontWeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextDecorationsProperty = DependencyProperty.Register(
|
||||
"TextDecorations", typeof(TextDecorationCollection), typeof(OutlineText), new PropertyMetadata(null, OnFormattedTextUpdated));
|
||||
public TextDecorationCollection TextDecorations
|
||||
{
|
||||
get => (TextDecorationCollection)GetValue(TextDecorationsProperty);
|
||||
set => SetValue(TextDecorationsProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
EnsureGeometry();
|
||||
|
||||
drawingContext.DrawGeometry(Fill, null, _textGeometry);
|
||||
|
||||
if (StrokePosition == StrokePosition.Outside)
|
||||
{
|
||||
drawingContext.PushClip(_clipGeometry);
|
||||
}
|
||||
else if (StrokePosition == StrokePosition.Inside)
|
||||
{
|
||||
drawingContext.PushClip(_textGeometry);
|
||||
}
|
||||
|
||||
drawingContext.DrawGeometry(null, _pen, _textGeometry);
|
||||
|
||||
if (StrokePosition == StrokePosition.Outside || StrokePosition == StrokePosition.Inside)
|
||||
{
|
||||
drawingContext.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePen()
|
||||
{
|
||||
_pen = new Pen(Stroke, StrokeThickness);
|
||||
|
||||
//if (StrokePosition == StrokePosition.Outside || StrokePosition == StrokePosition.Inside)
|
||||
//{
|
||||
// _pen.Thickness = StrokeThickness * 2;
|
||||
//}
|
||||
}
|
||||
|
||||
private void EnsureFormattedText()
|
||||
{
|
||||
if (_formattedText != null || Text == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if true
|
||||
_formattedText = new FormattedText(
|
||||
Text,
|
||||
CultureInfo.CurrentUICulture,
|
||||
FlowDirection,
|
||||
new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
|
||||
FontSize, Fill);
|
||||
|
||||
#else
|
||||
var source = PresentationSource.FromVisual(this);
|
||||
var dpi = 1.0;
|
||||
if (source?.CompositionTarget != null)
|
||||
{
|
||||
dpi = 96.0 * source.CompositionTarget.TransformToDevice.M11 / 96.0;
|
||||
}
|
||||
_formattedText = new FormattedText(
|
||||
Text,
|
||||
CultureInfo.CurrentUICulture,
|
||||
FlowDirection,
|
||||
new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
|
||||
FontSize, Fill, dpi);
|
||||
#endif
|
||||
|
||||
UpdateFormattedText();
|
||||
}
|
||||
|
||||
private void EnsureGeometry()
|
||||
{
|
||||
if (_textGeometry != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureFormattedText();
|
||||
_textGeometry = _formattedText.BuildGeometry(new Point(0, 0));
|
||||
|
||||
if (StrokePosition == StrokePosition.Outside)
|
||||
{
|
||||
var geometry = new RectangleGeometry(new Rect(0, 0, ActualWidth, ActualHeight));
|
||||
_clipGeometry = Geometry.Combine(geometry, _textGeometry, GeometryCombineMode.Exclude, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFormattedText()
|
||||
{
|
||||
if (_formattedText == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_formattedText.MaxLineCount = TextWrapping == TextWrapping.NoWrap ? 1 : int.MaxValue;
|
||||
_formattedText.TextAlignment = TextAlignment;
|
||||
_formattedText.Trimming = TextTrimming;
|
||||
|
||||
_formattedText.SetFontSize(FontSize);
|
||||
_formattedText.SetFontStyle(FontStyle);
|
||||
_formattedText.SetFontWeight(FontWeight);
|
||||
_formattedText.SetFontFamily(FontFamily);
|
||||
_formattedText.SetFontStretch(FontStretch);
|
||||
_formattedText.SetTextDecorations(TextDecorations);
|
||||
|
||||
}
|
||||
|
||||
private static void OnFormattedTextUpdated(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var outlinedTextBlock = (OutlineText)d;
|
||||
outlinedTextBlock.UpdateFormattedText();
|
||||
outlinedTextBlock._textGeometry = null;
|
||||
|
||||
outlinedTextBlock.InvalidateMeasure();
|
||||
outlinedTextBlock.InvalidateVisual();
|
||||
}
|
||||
|
||||
private static void OnFormattedTextInvalidated(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var outlinedTextBlock = (OutlineText)d;
|
||||
outlinedTextBlock._formattedText = null;
|
||||
outlinedTextBlock._textGeometry = null;
|
||||
|
||||
outlinedTextBlock.InvalidateMeasure();
|
||||
outlinedTextBlock.InvalidateVisual();
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
EnsureFormattedText();
|
||||
|
||||
// constrain the formatted text according to the available size
|
||||
// the Math.Min call is important - without this constraint (which seems arbitrary, but is the maximum allowable text width), things blow up when availableSize is infinite in both directions
|
||||
// the Math.Max call is to ensure we don't hit zero, which will cause MaxTextHeight to throw
|
||||
_formattedText.MaxTextWidth = Math.Min(3579139, availableSize.Width);
|
||||
_formattedText.MaxTextHeight = Math.Max(0.0001d, availableSize.Height);
|
||||
|
||||
UpdatePen();
|
||||
|
||||
// return the desired size
|
||||
return new Size(_formattedText.Width, _formattedText.Height);
|
||||
}
|
||||
}
|
||||
|
||||
public enum StrokePosition
|
||||
{
|
||||
Center,
|
||||
Outside,
|
||||
Inside
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<Window x:Class="AIStudio.Wpf.ADiagram.Controls.PopupWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="{Binding Title}"
|
||||
SizeToContent="WidthAndHeight"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
x:Name="theView">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ContentControl Grid.Row="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Content="{Binding ElementName=theView, Path=DataContext}" />
|
||||
<StackPanel Grid.Row="1"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<Button Content="Ok"
|
||||
IsDefault="True"
|
||||
Click="Ok_Click"
|
||||
Margin="5"
|
||||
Width="100"
|
||||
Height="30" />
|
||||
<Button Content="Cancel"
|
||||
IsCancel="True"
|
||||
Margin="5"
|
||||
Width="100"
|
||||
Height="30" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,33 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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.Shapes;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// PopupWindow.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class PopupWindow : Window
|
||||
{
|
||||
public PopupWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Ok_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.DialogResult = true;
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
<UserControl x:Class="AIStudio.Wpf.ADiagram.Controls.PropertiesView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<Border x:Name="border" BorderThickness="1" BorderBrush="{DynamicResource GrayBrush8}">
|
||||
<Border.Resources>
|
||||
|
||||
<ControlTemplate x:Key="validationErrorTemplate">
|
||||
<DockPanel>
|
||||
<Image Source="/AIStudio.Wpf.ADiagram;component/Images/error.png" Height="16" Width="16"
|
||||
DockPanel.Dock="Right" Margin="-18,0,0,0"
|
||||
ToolTip="{Binding ElementName=adorner,
|
||||
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
|
||||
</Image>
|
||||
<AdornedElementPlaceholder x:Name="adorner"/>
|
||||
</DockPanel>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="gridLineStyle" TargetType="Line">
|
||||
<Setter Property="Stroke" Value="{DynamicResource GrayBrush8}" />
|
||||
<Setter Property="Stretch" Value="Fill" />
|
||||
<Setter Property="Grid.ZIndex" Value="1000" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="gridHorizontalLineStyle" TargetType="Line" BasedOn="{StaticResource gridLineStyle}">
|
||||
<Setter Property="X2" Value="1" />
|
||||
<Setter Property="VerticalAlignment" Value="Bottom" />
|
||||
<Setter Property="Grid.ColumnSpan"
|
||||
Value="{Binding
|
||||
Path=ColumnDefinitions.Count,
|
||||
RelativeSource={RelativeSource AncestorType=Grid}}"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="gridVerticalLineStyle" TargetType="Line" BasedOn="{StaticResource gridLineStyle}">
|
||||
<Setter Property="Y2" Value="1" />
|
||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||
<Setter Property="Grid.RowSpan"
|
||||
Value="{Binding
|
||||
Path=RowDefinitions.Count,
|
||||
RelativeSource={RelativeSource AncestorType=Grid}}"/>
|
||||
</Style>
|
||||
|
||||
</Border.Resources>
|
||||
<DockPanel x:Name="_panel">
|
||||
<Border x:Name="_label" Width="50" Height="16">
|
||||
<TextBlock Text="Empty" TextAlignment="Center" Foreground="Gray"/>
|
||||
</Border>
|
||||
<ScrollViewer x:Name="_gridContainer" VerticalScrollBarVisibility="Auto">
|
||||
<Grid x:Name="_grid">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Line Name="_vLine" Grid.Column="0" Grid.RowSpan="1000" Style="{StaticResource gridVerticalLineStyle}"/>
|
||||
<GridSplitter Name="_splitter" Grid.RowSpan="1000" Margin="0,0,0,0" Width="1"
|
||||
Background="{DynamicResource GrayBrush8}" Grid.ZIndex="10000"/>
|
||||
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</UserControl>
|
||||
@@ -1,228 +0,0 @@
|
||||
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;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for PropertiesView.xaml
|
||||
/// </summary>
|
||||
public partial class PropertiesView : UserControl
|
||||
{
|
||||
#region SelectedObject
|
||||
|
||||
public static readonly DependencyProperty SelectedObjectProperty = DependencyProperty.Register("SelectedObject", typeof(object), typeof(PropertiesView), new UIPropertyMetadata(null, OnSelectedObjectChanged));
|
||||
public object SelectedObject
|
||||
{
|
||||
get
|
||||
{
|
||||
return (object)GetValue(SelectedObjectProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(SelectedObjectProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnSelectedObjectChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
PropertiesView propertyInspector = o as PropertiesView;
|
||||
if (propertyInspector != null)
|
||||
propertyInspector.OnSelectedObjectChanged((object)e.OldValue, (object)e.NewValue);
|
||||
}
|
||||
|
||||
protected virtual void OnSelectedObjectChanged(object oldValue, object newValue)
|
||||
{
|
||||
// We do not want to process the change now if the grid is initializing (ie. BeginInit/EndInit).
|
||||
var obj = oldValue as INotifyPropertyChanged;
|
||||
if (obj != null)
|
||||
obj.PropertyChanged -= PropertyChanged;
|
||||
DisplayProperties();
|
||||
obj = newValue as INotifyPropertyChanged;
|
||||
if (obj != null)
|
||||
obj.PropertyChanged += PropertyChanged;
|
||||
}
|
||||
|
||||
#endregion //SelectedObject
|
||||
|
||||
public static readonly DependencyProperty NeedBrowsableProperty = DependencyProperty.Register("NeedBrowsable", typeof(bool), typeof(PropertiesView), new UIPropertyMetadata(true));
|
||||
public bool NeedBrowsable
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)GetValue(NeedBrowsableProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(NeedBrowsableProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public PropertiesView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Loaded += PropertiesView_Loaded;
|
||||
}
|
||||
|
||||
private void PropertiesView_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DisplayProperties();
|
||||
}
|
||||
|
||||
void PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
DisplayProperties();
|
||||
}
|
||||
|
||||
private void DisplayProperties()
|
||||
{
|
||||
_panel.Children.Clear();
|
||||
ClearGrid();
|
||||
if (SelectedObject != null)
|
||||
{
|
||||
int row = 0;
|
||||
foreach (var prop in SelectedObject.GetType().GetProperties())
|
||||
{
|
||||
var attr = prop.GetCustomAttributes(typeof(BrowsableAttribute), true);
|
||||
if (NeedBrowsable == false && (attr.Length == 0 || (attr[0] as BrowsableAttribute).Browsable))
|
||||
{
|
||||
DisplayProperty(prop, row);
|
||||
row++;
|
||||
}
|
||||
else if(NeedBrowsable == true && (attr.Length > 0 && (attr[0] as BrowsableAttribute).Browsable))
|
||||
{
|
||||
DisplayProperty(prop, row);
|
||||
row++;
|
||||
}
|
||||
}
|
||||
_panel.Children.Add(_gridContainer);
|
||||
}
|
||||
else
|
||||
{
|
||||
_panel.Children.Add(_label);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearGrid()
|
||||
{
|
||||
_grid.RowDefinitions.Clear();
|
||||
for (int i = _grid.Children.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (_grid.Children[i] != _vLine && _grid.Children[i] != _splitter)
|
||||
_grid.Children.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayProperty(PropertyInfo prop, int row)
|
||||
{
|
||||
var rowDef = new RowDefinition();
|
||||
rowDef.Height = new GridLength(Math.Max(20, this.FontSize * 2));
|
||||
_grid.RowDefinitions.Add(rowDef);
|
||||
|
||||
var tb = new TextBlock() { Text = prop.Name };
|
||||
var displayAttr = prop.GetCustomAttributes(typeof(DisplayNameAttribute), true);
|
||||
if (displayAttr.Length > 0 )
|
||||
{
|
||||
tb.Text = (displayAttr[0] as DisplayNameAttribute).DisplayName;
|
||||
}
|
||||
tb.Margin = new Thickness(4);
|
||||
tb.VerticalAlignment = VerticalAlignment.Center;
|
||||
Grid.SetColumn(tb, 0);
|
||||
Grid.SetRow(tb, _grid.RowDefinitions.Count - 1);
|
||||
_grid.Children.Add(tb);
|
||||
|
||||
var line = new Line();
|
||||
line.Style = (Style)border.Resources["gridHorizontalLineStyle"];
|
||||
Grid.SetRow(line, row);
|
||||
_grid.Children.Add(line);
|
||||
|
||||
Style style = null;
|
||||
var styleNameAttr = prop.GetCustomAttributes(typeof(StyleNameAttribute), true);
|
||||
if (styleNameAttr.Length > 0)
|
||||
{
|
||||
style = this.FindResource((styleNameAttr[0] as StyleNameAttribute).Name) as Style;
|
||||
if (style != null)
|
||||
{
|
||||
ContentControl content = new ContentControl();
|
||||
content.Style = style;
|
||||
content.DataContext = SelectedObject;
|
||||
|
||||
Grid.SetColumn(content, 1);
|
||||
Grid.SetRow(content, _grid.RowDefinitions.Count - 1);
|
||||
|
||||
_grid.Children.Add(content);
|
||||
}
|
||||
}
|
||||
|
||||
if (style == null)
|
||||
{
|
||||
var ed = new TextBox();
|
||||
ed.PreviewKeyDown += new KeyEventHandler(ed_KeyDown);
|
||||
ed.Margin = new Thickness(0);
|
||||
ed.VerticalAlignment = VerticalAlignment.Center;
|
||||
ed.BorderThickness = new Thickness(0);
|
||||
Grid.SetColumn(ed, 1);
|
||||
Grid.SetRow(ed, _grid.RowDefinitions.Count - 1);
|
||||
|
||||
var binding = new Binding(prop.Name);
|
||||
binding.Source = SelectedObject;
|
||||
binding.ValidatesOnExceptions = true;
|
||||
binding.Mode = BindingMode.OneWay;
|
||||
if (prop.CanWrite)
|
||||
{
|
||||
var mi = prop.GetSetMethod();
|
||||
if (mi != null && mi.IsPublic)
|
||||
binding.Mode = BindingMode.TwoWay;
|
||||
}
|
||||
ed.SetBinding(TextBox.TextProperty, binding);
|
||||
|
||||
var template = (ControlTemplate)border.Resources["validationErrorTemplate"];
|
||||
Validation.SetErrorTemplate(ed, template);
|
||||
|
||||
_grid.Children.Add(ed);
|
||||
}
|
||||
}
|
||||
|
||||
void ed_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
var ed = sender as TextBox;
|
||||
if (ed != null)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
ed.GetBindingExpression(TextBox.TextProperty).UpdateSource();
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.Escape)
|
||||
ed.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class StyleNameAttribute : Attribute
|
||||
{
|
||||
private string _name;
|
||||
public StyleNameAttribute(string name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,349 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
public class RectangleGridEventArgs
|
||||
{
|
||||
public int Row { get; set; }
|
||||
public int Column { get; set; }
|
||||
public RectangleGridEventArgs(int row, int column)
|
||||
{
|
||||
Row = row;
|
||||
Column = column;
|
||||
}
|
||||
}
|
||||
|
||||
public class RectangleGrid : Grid
|
||||
{
|
||||
public static readonly DependencyProperty RowNumProperty = DependencyProperty.Register("RowNum", typeof(int),
|
||||
typeof(RectangleGrid),
|
||||
new FrameworkPropertyMetadata(4));
|
||||
public int RowNum
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)GetValue(RowNumProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(RowNumProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ColumnNumProperty = DependencyProperty.Register("ColumnNum", typeof(int),
|
||||
typeof(RectangleGrid),
|
||||
new FrameworkPropertyMetadata(4));
|
||||
public int ColumnNum
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)GetValue(ColumnNumProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(ColumnNumProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectRowProperty = DependencyProperty.Register("SelectRow", typeof(int),
|
||||
typeof(RectangleGrid),
|
||||
new FrameworkPropertyMetadata(0));
|
||||
|
||||
public int SelectRow
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)GetValue(SelectRowProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(SelectRowProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectColumnProperty = DependencyProperty.Register("SelectColumn", typeof(int),
|
||||
typeof(RectangleGrid),
|
||||
new FrameworkPropertyMetadata(0));
|
||||
public int SelectColumn
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)GetValue(SelectColumnProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(SelectColumnProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectProperty = DependencyProperty.Register("Select", typeof(RectangleGridEventArgs),
|
||||
typeof(RectangleGrid),
|
||||
new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnSelectChanged)));
|
||||
public RectangleGridEventArgs Select
|
||||
{
|
||||
get
|
||||
{
|
||||
return (RectangleGridEventArgs)GetValue(SelectProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(SelectProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
#region MouseOverBrush 标题栏背景色
|
||||
|
||||
public static readonly DependencyProperty MouseOverBrushProperty = DependencyProperty.Register(
|
||||
"MouseOverBrush", typeof(Brush), typeof(RectangleGrid), new PropertyMetadata(null));
|
||||
|
||||
public Brush MouseOverBrush
|
||||
{
|
||||
get { return (Brush)GetValue(MouseOverBrushProperty); }
|
||||
set { SetValue(MouseOverBrushProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Rectangle[,] rectangles;
|
||||
public RectangleGrid()
|
||||
{
|
||||
this.Loaded += RectangleGrid_Loaded;
|
||||
}
|
||||
|
||||
void RectangleGrid_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Loaded -= RectangleGrid_Loaded;
|
||||
for (int i = 0; i < RowNum; i++)
|
||||
{
|
||||
RowDefinition row = new RowDefinition() { Height = new GridLength(2, GridUnitType.Auto) };
|
||||
this.RowDefinitions.Add(row);
|
||||
}
|
||||
for (int j = 0; j < ColumnNum; j++)
|
||||
{
|
||||
ColumnDefinition col = new ColumnDefinition() { Width = new GridLength(2, GridUnitType.Auto) };
|
||||
this.ColumnDefinitions.Add(col);
|
||||
}
|
||||
|
||||
rectangles = new Rectangle[RowNum, ColumnNum];
|
||||
for (int i = 0; i < rectangles.GetLength(0); i++)
|
||||
{
|
||||
for (int j = 0; j < rectangles.GetLength(1); j++)
|
||||
{
|
||||
Rectangle rectangle = new Rectangle();
|
||||
rectangle.IsHitTestVisible = true;
|
||||
rectangle.SnapsToDevicePixels = true;
|
||||
rectangle.Stroke = new SolidColorBrush(Colors.Black);
|
||||
rectangle.Width = 24;
|
||||
rectangle.Height = 24;
|
||||
rectangle.Margin = new Thickness(2);
|
||||
rectangle.MouseEnter += rectangle_MouseEnter;
|
||||
rectangle.MouseLeave += rectangle_MouseLeave;
|
||||
rectangle.MouseLeftButtonDown += rectangle_MouseLeftButtonDown;
|
||||
rectangle.Fill = new SolidColorBrush(Color.FromArgb(0xff, 0xff, 0xff, 0xff));
|
||||
Grid.SetRow(rectangle, i);
|
||||
Grid.SetColumn(rectangle, j);
|
||||
this.Children.Add(rectangle);
|
||||
|
||||
rectangles[i, j] = rectangle;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rectangle_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
Brush myBrush = new SolidColorBrush(System.Windows.Media.Color.FromArgb(0xff, 0x30, 0x50, 0x68));
|
||||
Brush myBrush2 = new SolidColorBrush(System.Windows.Media.Color.FromArgb(0xff, 0xff, 0xff, 0xff));
|
||||
|
||||
if (MouseOverBrush != null)
|
||||
{
|
||||
myBrush = MouseOverBrush;
|
||||
}
|
||||
|
||||
#region
|
||||
Rectangle rect = sender as Rectangle;
|
||||
var rects = rectangles.Cast<Rectangle>().ToArray();
|
||||
int index = Array.IndexOf(rects, rect);
|
||||
|
||||
int x = index / rectangles.GetLength(1);
|
||||
int y = index % rectangles.GetLength(1);
|
||||
FillRectangle(x, y);
|
||||
#endregion
|
||||
}
|
||||
|
||||
private void FillRectangle(int row, int column)
|
||||
{
|
||||
Brush myBrush = new SolidColorBrush(Color.FromArgb(0xff, 0x30, 0x50, 0x68));
|
||||
Brush myBrush2 = new SolidColorBrush(Color.FromArgb(0xff, 0xff, 0xff, 0xff));
|
||||
|
||||
if (MouseOverBrush != null)
|
||||
{
|
||||
myBrush = MouseOverBrush;
|
||||
}
|
||||
|
||||
for (int i = 0; i < rectangles.GetLength(0); i++)
|
||||
{
|
||||
for (int j = 0; j < rectangles.GetLength(1); j++)
|
||||
{
|
||||
if (i <= row && j <= column)
|
||||
{
|
||||
rectangles[i, j].Fill = myBrush;
|
||||
}
|
||||
else
|
||||
{
|
||||
rectangles[i, j].Fill = myBrush2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rectangle_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void rectangle_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
Rectangle rect = sender as Rectangle;
|
||||
var rects = rectangles.Cast<Rectangle>().ToArray();
|
||||
int index = Array.IndexOf(rects, rect);
|
||||
|
||||
int x = index / rectangles.GetLength(1);
|
||||
int y = index % rectangles.GetLength(1);
|
||||
|
||||
this.SelectRow = x + 1;
|
||||
this.SelectColumn = y + 1;
|
||||
this.Select = new RectangleGridEventArgs(this.SelectRow, this.SelectColumn);
|
||||
}
|
||||
|
||||
private static void OnSelectRowChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
RectangleGrid grid = (RectangleGrid)sender;
|
||||
|
||||
int oldRow = (int)e.OldValue;
|
||||
int newRow = (int)e.NewValue;
|
||||
if (oldRow == 0 || newRow == 0)
|
||||
{
|
||||
grid.FillRectangle((int)e.NewValue, grid.SelectColumn);
|
||||
}
|
||||
|
||||
//避免两次触发
|
||||
var oldArgs = new RectangleGridEventArgs(oldRow, grid.SelectColumn);
|
||||
var newArgs = new RectangleGridEventArgs(newRow, grid.SelectColumn);
|
||||
grid.OnSelectColumnChanged(oldArgs, newArgs);
|
||||
}
|
||||
|
||||
private static void OnSelectColumnChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
RectangleGrid grid = (RectangleGrid)sender;
|
||||
|
||||
int oldColumn = (int)e.OldValue;
|
||||
int newColumn = (int)e.NewValue;
|
||||
|
||||
grid.FillRectangle(grid.SelectRow, (int)e.NewValue);
|
||||
|
||||
var oldArgs = new RectangleGridEventArgs(grid.SelectRow, oldColumn);
|
||||
var newArgs = new RectangleGridEventArgs(grid.SelectRow, newColumn);
|
||||
grid.OnSelectColumnChanged(oldArgs, newArgs);
|
||||
}
|
||||
|
||||
private static void OnSelectChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
RectangleGrid grid = (RectangleGrid)sender;
|
||||
|
||||
RectangleGridEventArgs oldArgs = e.OldValue as RectangleGridEventArgs;
|
||||
RectangleGridEventArgs newArgs = e.NewValue as RectangleGridEventArgs;
|
||||
|
||||
//grid.FillRectangle(newArgs.Row, newArgs.Column);
|
||||
|
||||
grid.OnSelectColumnChanged(oldArgs, newArgs);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent SelectRowColumnChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("SelectRowColumnChanged", RoutingStrategy.Bubble,
|
||||
typeof(RoutedPropertyChangedEventHandler<RectangleGridEventArgs>), typeof(RectangleGrid));
|
||||
|
||||
public event RoutedPropertyChangedEventHandler<RectangleGridEventArgs> SelectRowColumnChanged
|
||||
{
|
||||
add { AddHandler(SelectRowColumnChangedEvent, value); }
|
||||
remove { RemoveHandler(SelectRowColumnChangedEvent, value); }
|
||||
}
|
||||
|
||||
private void OnSelectColumnChanged(RectangleGridEventArgs oldargs, RectangleGridEventArgs newargs)
|
||||
{
|
||||
RoutedPropertyChangedEventArgs<RectangleGridEventArgs> args = new RoutedPropertyChangedEventArgs<RectangleGridEventArgs>(oldargs, newargs);
|
||||
args.RoutedEvent = RectangleGrid.SelectRowColumnChangedEvent;
|
||||
RaiseEvent(args);
|
||||
|
||||
switch (Command)
|
||||
{
|
||||
case null:
|
||||
return;
|
||||
case RoutedCommand command:
|
||||
command.Execute(CommandParameter, CommandTarget);
|
||||
break;
|
||||
default:
|
||||
Command.Execute(CommandParameter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
|
||||
"Command", typeof(ICommand), typeof(RectangleGrid), new PropertyMetadata(default(ICommand), OnCommandChanged));
|
||||
|
||||
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (RectangleGrid)d;
|
||||
if (e.OldValue is ICommand oldCommand)
|
||||
{
|
||||
oldCommand.CanExecuteChanged -= ctl.CanExecuteChanged;
|
||||
}
|
||||
if (e.NewValue is ICommand newCommand)
|
||||
{
|
||||
newCommand.CanExecuteChanged += ctl.CanExecuteChanged;
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand Command
|
||||
{
|
||||
get => (ICommand)GetValue(CommandProperty);
|
||||
set => SetValue(CommandProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
|
||||
"CommandParameter", typeof(object), typeof(RectangleGrid), new PropertyMetadata(default(object)));
|
||||
|
||||
public object CommandParameter
|
||||
{
|
||||
get => GetValue(CommandParameterProperty);
|
||||
set => SetValue(CommandParameterProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register(
|
||||
"CommandTarget", typeof(IInputElement), typeof(RectangleGrid), new PropertyMetadata(default(IInputElement)));
|
||||
|
||||
public IInputElement CommandTarget
|
||||
{
|
||||
get => (IInputElement)GetValue(CommandTargetProperty);
|
||||
set => SetValue(CommandTargetProperty, value);
|
||||
}
|
||||
|
||||
private void CanExecuteChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (Command == null) return;
|
||||
|
||||
IsEnabled = Command is RoutedCommand command
|
||||
? command.CanExecute(CommandParameter, CommandTarget)
|
||||
: Command.CanExecute(CommandParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:sys="clr-namespace:System;assembly=System.Runtime"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/Util.Controls.Handy;component/Style/Themes/ScrollViewer.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<ControlTemplate x:Key="ScrollViewerBaseControlTemplate" TargetType="controls:ScrollViewer">
|
||||
<ControlTemplate.Resources>
|
||||
<Storyboard x:Key="Storyboard1">
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_VerticalScrollBar">
|
||||
<EasingDoubleKeyFrame KeyTime="0:0:.1" Value=".8"/>
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_HorizontalScrollBar">
|
||||
<EasingDoubleKeyFrame KeyTime="0:0:.1" Value=".8"/>
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
<Storyboard x:Key="Storyboard2">
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_VerticalScrollBar">
|
||||
<EasingDoubleKeyFrame KeyTime="0:0:.2" Value="0"/>
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_HorizontalScrollBar">
|
||||
<EasingDoubleKeyFrame KeyTime="0:0:.2" Value="0"/>
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</ControlTemplate.Resources>
|
||||
<Grid x:Name="Grid" Background="{TemplateBinding Background}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Grid.RowSpan="2" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" Margin="{TemplateBinding Padding}" Grid.Row="0"/>
|
||||
<ScrollBar x:Name="PART_VerticalScrollBar" Opacity="0" Style="{StaticResource ScrollBarBaseStyle}" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="0" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
|
||||
<ScrollBar x:Name="PART_HorizontalScrollBar" Opacity="0" Style="{StaticResource ScrollBarBaseStyle}" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="0" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding IsMouseOver,RelativeSource={RelativeSource Self}}" Value="True">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard Storyboard="{StaticResource Storyboard2}"/>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="ScrollViewerBaseStyle" TargetType="controls:ScrollViewer">
|
||||
<Setter Property="VerticalScrollBarVisibility" Value="Auto"/>
|
||||
<Setter Property="Focusable" Value="False"/>
|
||||
<Setter Property="Template" Value="{StaticResource ScrollViewerBaseControlTemplate}"/>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -1,237 +0,0 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
public class ScrollViewer : System.Windows.Controls.ScrollViewer
|
||||
{
|
||||
private double _totalVerticalOffset;
|
||||
|
||||
private double _totalHorizontalOffset;
|
||||
|
||||
private bool _isRunning;
|
||||
|
||||
/// <summary>
|
||||
/// 滚动方向
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
"Orientation", typeof(Orientation), typeof(ScrollViewer), new PropertyMetadata(Orientation.Vertical));
|
||||
|
||||
/// <summary>
|
||||
/// 滚动方向
|
||||
/// </summary>
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => (Orientation)GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否响应鼠标滚轮操作
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CanMouseWheelProperty = DependencyProperty.Register(
|
||||
"CanMouseWheel", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(true));
|
||||
|
||||
/// <summary>
|
||||
/// 是否响应鼠标滚轮操作
|
||||
/// </summary>
|
||||
public bool CanMouseWheel
|
||||
{
|
||||
get => (bool)GetValue(CanMouseWheelProperty);
|
||||
set => SetValue(CanMouseWheelProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
{
|
||||
if (!CanMouseWheel) return;
|
||||
|
||||
if (!IsInertiaEnabled)
|
||||
{
|
||||
if (Orientation == Orientation.Vertical)
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
_totalHorizontalOffset = HorizontalOffset;
|
||||
CurrentHorizontalOffset = HorizontalOffset;
|
||||
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
|
||||
CurrentHorizontalOffset = _totalHorizontalOffset;
|
||||
}
|
||||
return;
|
||||
}
|
||||
e.Handled = true;
|
||||
|
||||
if (Orientation == Orientation.Vertical)
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_totalVerticalOffset = VerticalOffset;
|
||||
CurrentVerticalOffset = VerticalOffset;
|
||||
}
|
||||
_totalVerticalOffset = Math.Min(Math.Max(0, _totalVerticalOffset - e.Delta), ScrollableHeight);
|
||||
ScrollToVerticalOffsetInternal(_totalVerticalOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_totalHorizontalOffset = HorizontalOffset;
|
||||
CurrentHorizontalOffset = HorizontalOffset;
|
||||
}
|
||||
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
|
||||
ScrollToHorizontalOffsetInternal(_totalHorizontalOffset);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ScrollToTopInternal(double milliseconds = 500)
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_totalVerticalOffset = VerticalOffset;
|
||||
CurrentVerticalOffset = VerticalOffset;
|
||||
}
|
||||
ScrollToVerticalOffsetInternal(0, milliseconds);
|
||||
}
|
||||
|
||||
internal void ScrollToVerticalOffsetInternal(double offset, double milliseconds = 500)
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(offset, milliseconds);
|
||||
animation.EasingFunction = new CubicEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
};
|
||||
animation.FillBehavior = FillBehavior.Stop;
|
||||
animation.Completed += (s, e1) =>
|
||||
{
|
||||
CurrentVerticalOffset = offset;
|
||||
_isRunning = false;
|
||||
};
|
||||
_isRunning = true;
|
||||
|
||||
BeginAnimation(CurrentVerticalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
internal void ScrollToHorizontalOffsetInternal(double offset, double milliseconds = 500)
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(offset, milliseconds);
|
||||
animation.EasingFunction = new CubicEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
};
|
||||
animation.FillBehavior = FillBehavior.Stop;
|
||||
animation.Completed += (s, e1) =>
|
||||
{
|
||||
CurrentHorizontalOffset = offset;
|
||||
_isRunning = false;
|
||||
};
|
||||
_isRunning = true;
|
||||
|
||||
BeginAnimation(CurrentHorizontalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) =>
|
||||
IsPenetrating ? null : base.HitTestCore(hitTestParameters);
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持惯性
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsInertiaEnabledProperty = DependencyProperty.RegisterAttached(
|
||||
"IsInertiaEnabled", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(false));
|
||||
|
||||
public static void SetIsInertiaEnabled(DependencyObject element, bool value)
|
||||
{
|
||||
element.SetValue(IsInertiaEnabledProperty, value);
|
||||
}
|
||||
|
||||
public static bool GetIsInertiaEnabled(DependencyObject element)
|
||||
{
|
||||
return (bool)element.GetValue(IsInertiaEnabledProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持惯性
|
||||
/// </summary>
|
||||
public bool IsInertiaEnabled
|
||||
{
|
||||
get => (bool)GetValue(IsInertiaEnabledProperty);
|
||||
set => SetValue(IsInertiaEnabledProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 控件是否可以穿透点击
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsPenetratingProperty = DependencyProperty.RegisterAttached(
|
||||
"IsPenetrating", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// 控件是否可以穿透点击
|
||||
/// </summary>
|
||||
public bool IsPenetrating
|
||||
{
|
||||
get => (bool)GetValue(IsPenetratingProperty);
|
||||
set => SetValue(IsPenetratingProperty, value);
|
||||
}
|
||||
|
||||
public static void SetIsPenetrating(DependencyObject element, bool value)
|
||||
{
|
||||
element.SetValue(IsPenetratingProperty, value);
|
||||
}
|
||||
|
||||
public static bool GetIsPenetrating(DependencyObject element)
|
||||
{
|
||||
return (bool)element.GetValue(IsPenetratingProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前垂直滚动偏移
|
||||
/// </summary>
|
||||
internal static readonly DependencyProperty CurrentVerticalOffsetProperty = DependencyProperty.Register(
|
||||
"CurrentVerticalOffset", typeof(double), typeof(ScrollViewer), new PropertyMetadata(0d, OnCurrentVerticalOffsetChanged));
|
||||
|
||||
private static void OnCurrentVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is ScrollViewer ctl && e.NewValue is double v)
|
||||
{
|
||||
ctl.ScrollToVerticalOffset(v);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前垂直滚动偏移
|
||||
/// </summary>
|
||||
internal double CurrentVerticalOffset
|
||||
{
|
||||
// ReSharper disable once UnusedMember.Local
|
||||
get => (double)GetValue(CurrentVerticalOffsetProperty);
|
||||
set => SetValue(CurrentVerticalOffsetProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前水平滚动偏移
|
||||
/// </summary>
|
||||
internal static readonly DependencyProperty CurrentHorizontalOffsetProperty = DependencyProperty.Register(
|
||||
"CurrentHorizontalOffset", typeof(double), typeof(ScrollViewer), new PropertyMetadata(0d, OnCurrentHorizontalOffsetChanged));
|
||||
|
||||
private static void OnCurrentHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is ScrollViewer ctl && e.NewValue is double v)
|
||||
{
|
||||
ctl.ScrollToHorizontalOffset(v);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前水平滚动偏移
|
||||
/// </summary>
|
||||
internal double CurrentHorizontalOffset
|
||||
{
|
||||
get => (double)GetValue(CurrentHorizontalOffsetProperty);
|
||||
set => SetValue(CurrentHorizontalOffsetProperty, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
<UserControl x:Class="AIStudio.Wpf.ADiagram.Controls.SliderRotation"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
Name="sliderRotation"
|
||||
Foreground="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}" BorderBrush="{DynamicResource BlackBrush}" >
|
||||
<Viewbox>
|
||||
<Grid>
|
||||
<Canvas Name="canvas" Width="80" Height="80" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<Ellipse Height="80" Width="80" Name="ellipseBack"
|
||||
Stroke="{x:Null}"
|
||||
Fill="{Binding ElementName=sliderRotation, Path=BorderBrush}"
|
||||
MouseLeave="ellipseBack_MouseLeave"
|
||||
MouseMove="ellipseBack_MouseMove"
|
||||
MouseLeftButtonUp="ellipseBack_MouseUp"
|
||||
MouseLeftButtonDown="ellipseBack_MouseDown"
|
||||
StrokeThickness="0.5">
|
||||
<!--<Ellipse.Effect>-->
|
||||
<!--Effect:外部光圈-->
|
||||
<!--
|
||||
<DropShadowEffect Direction="270" Color="Black" Opacity="0.5" BlurRadius="3" ShadowDepth="1"/>
|
||||
</Ellipse.Effect>-->
|
||||
</Ellipse>
|
||||
<Ellipse Height="20" Name="handle" Stroke="#20000000" Width="20" Fill="{Binding ElementName=sliderRotation, Path=Foreground}" RenderTransformOrigin="0.5,2"
|
||||
IsHitTestVisible="False" Margin="30,0,0,0">
|
||||
<Ellipse.RenderTransform>
|
||||
<RotateTransform x:Name="rotate" Angle="{Binding ElementName=sliderRotation, Path=Value}"/>
|
||||
<!--RotateTransform:能够让某对象产生旋转变化,根据中心点进行顺时针旋转或逆时针旋转。-->
|
||||
</Ellipse.RenderTransform>
|
||||
</Ellipse>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
</UserControl>
|
||||
@@ -1,140 +0,0 @@
|
||||
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 AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// SliderRotation.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class SliderRotation : UserControl
|
||||
{
|
||||
#region 私有属性
|
||||
private Point cen; //中心点
|
||||
private Point first; //初始状态位置
|
||||
private Point second; //
|
||||
private bool flag = false;
|
||||
#endregion
|
||||
#region 公有属性
|
||||
/// <summary>
|
||||
/// 获取或设置Value数值
|
||||
/// </summary>
|
||||
public double Value
|
||||
{
|
||||
get { return (double)GetValue(ValueProperty); }
|
||||
set { SetValue(ValueProperty, value); }
|
||||
}
|
||||
public static readonly DependencyProperty ValueProperty = DependencyProperty.RegisterAttached(
|
||||
"Value",
|
||||
typeof(double),
|
||||
typeof(SliderRotation),
|
||||
new FrameworkPropertyMetadata((double)0, new PropertyChangedCallback(ValuePropertyChangedCallback)));
|
||||
|
||||
#endregion
|
||||
public SliderRotation()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
private static void ValuePropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs arg)
|
||||
{
|
||||
if (sender != null && sender is SliderRotation)
|
||||
{
|
||||
SliderRotation sliderRotation = sender as SliderRotation;
|
||||
RoutedPropertyChangedEventArgs<object> valueArg =
|
||||
new RoutedPropertyChangedEventArgs<object>(arg.OldValue, arg.NewValue, ValueChangedEvent);
|
||||
sliderRotation.RaiseEvent(valueArg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region 事件路由
|
||||
public event RoutedPropertyChangedEventHandler<object> ValueChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
this.AddHandler(ValueChangedEvent, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
this.RemoveHandler(ValueChangedEvent, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent(
|
||||
"ValueChanged",
|
||||
RoutingStrategy.Bubble,
|
||||
typeof(RoutedPropertyChangedEventHandler<object>),
|
||||
typeof(SliderRotation));
|
||||
#endregion
|
||||
|
||||
private double GetAngle(Point point) //获取点到中心的角度 构造平面直角坐标系 计算点在该坐标系与y轴(正方向)的夹角
|
||||
{
|
||||
const double M_PI = 3.1415926535897;
|
||||
if (point.X >= 0)
|
||||
{
|
||||
double hypotenuse = Math.Sqrt(point.X * point.X + point.Y * point.Y);
|
||||
return Math.Acos(point.Y / hypotenuse) * 180 / M_PI;
|
||||
}
|
||||
else
|
||||
{
|
||||
double hypotenuse = Math.Sqrt(point.X * point.X + point.Y * point.Y);
|
||||
return 360 - Math.Acos(point.Y / hypotenuse) * 180 / M_PI;
|
||||
}
|
||||
}
|
||||
private void ellipseBack_MouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
flag = true;
|
||||
cen = new Point(ellipseBack.Width / 2, ellipseBack.Height / 2);
|
||||
first = new Point(e.GetPosition(canvas).X - cen.X, cen.Y - e.GetPosition(canvas).Y);
|
||||
}
|
||||
|
||||
private void ellipseBack_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
flag = false;
|
||||
}
|
||||
private void ellipseBack_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
flag = false;
|
||||
}
|
||||
private void ellipseBack_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
e.Handled = true; //停止路由事件向上传递
|
||||
if (flag)
|
||||
{
|
||||
second = new Point(e.GetPosition(canvas).X - cen.X, cen.Y - e.GetPosition(canvas).Y); //确定鼠标移动的点坐标(相对中心点的位置)
|
||||
|
||||
if (second == new Point(0, 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
double anglePointToPoint = GetAngle(second) - GetAngle(first); //得到鼠标移动之前与鼠标移动之后之间的夹角
|
||||
first = second;
|
||||
if (Math.Abs(anglePointToPoint) > 90) //夹角如果大于90度忽略(大于90度的夹角有可能是计算错误得出来的)
|
||||
{
|
||||
anglePointToPoint = 0;
|
||||
}
|
||||
|
||||
var angle = Value + anglePointToPoint;
|
||||
if (angle < 0)
|
||||
{
|
||||
angle += 360;
|
||||
}
|
||||
angle = angle % 360;
|
||||
Value = Math.Round(angle, 0); //计算出旋转角度
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime"
|
||||
xmlns:interactivity="clr-namespace:Util.Controls.Handy.Interactivity">
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/Util.Controls.Handy;component/Style/Basic/Paths.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/Util.Controls.Handy;component/Style/Basic/Converters.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/Util.Controls.Handy;component/Style/Themes/Button.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/Util.Controls.Handy;component/Style/Themes/RepeatButton.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/Util.Controls.Handy;component/Style/Themes/ToggleButton.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<ContextMenu x:Key="TabItemMenu" x:Shared="False">
|
||||
<MenuItem Command="interactivity:ControlCommands.Close" Header="Close"/>
|
||||
<MenuItem Command="interactivity:ControlCommands.CloseAll" Header="CloseAll"/>
|
||||
<MenuItem Command="interactivity:ControlCommands.CloseOther" Header="CloseOther"/>
|
||||
</ContextMenu>
|
||||
|
||||
<Style TargetType="controls:TabItem">
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource MahApps.Brushes.Text}"/>
|
||||
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.ThemeBackground}"/>
|
||||
<Setter Property="BorderThickness" Value="1,0,1,1"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource MahApps.Brushes.Control.Border}"/>
|
||||
<Setter Property="Margin" Value="0"/>
|
||||
<Setter Property="Padding" Value="10,0,0,0"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="Menu" Value="{StaticResource TabItemMenu}"/>
|
||||
<Setter Property="controls:IconElement.Width" Value="16"/>
|
||||
<Setter Property="controls:IconElement.Height" Value="16"/>
|
||||
<Setter Property="HeaderTemplate">
|
||||
<Setter.Value>
|
||||
<DataTemplate>
|
||||
<TextBlock Background="Transparent" Text="{Binding Header,RelativeSource={RelativeSource AncestorType=controls:TabItem}}"/>
|
||||
</DataTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:TabItem">
|
||||
<Grid x:Name="templateRoot" SnapsToDevicePixels="true" ContextMenu="{TemplateBinding Menu}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border Grid.ColumnSpan="3" BorderThickness="{TemplateBinding BorderThickness}" x:Name="mainBorder" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" Margin="0">
|
||||
<Border Margin="0,0,0,-1" x:Name="innerBorder" Background="{DynamicResource MahApps.Brushes.Gray8}" Visibility="Collapsed"/>
|
||||
</Border>
|
||||
<Path x:Name="PathMain" Margin="10,0,0,0" Grid.Column="0" Width="{TemplateBinding controls:IconElement.Width}" Height="{TemplateBinding controls:IconElement.Height}" Fill="{TemplateBinding Foreground}" SnapsToDevicePixels="True" Stretch="Uniform" Data="{TemplateBinding controls:IconElement.Geometry}"/>
|
||||
<ContentPresenter Grid.Column="1" x:Name="contentPresenter" ContentSource="Header" Focusable="False" HorizontalAlignment="Stretch" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
|
||||
<Border Name="BorderMask" Grid.Column="1" HorizontalAlignment="Right" Width="20" Background="{TemplateBinding Background}">
|
||||
<Border.OpacityMask>
|
||||
<LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
|
||||
<GradientStop Color="White" Offset="1"/>
|
||||
<GradientStop Offset="0"/>
|
||||
</LinearGradientBrush>
|
||||
</Border.OpacityMask>
|
||||
</Border>
|
||||
<Button Grid.Column="2" Focusable="False" Command="interactivity:ControlCommands.Close" Visibility="{TemplateBinding ShowCloseButton,Converter={StaticResource Boolean2VisibilityConverter}}" Background="Transparent" Style="{StaticResource ButtonCustom}" Width="28">
|
||||
<Path Fill="{DynamicResource MahApps.Brushes.Text}" Width="8" Height="8" Style="{StaticResource ClosePathStyle}"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsSelected" Value="true">
|
||||
<Setter Property="Panel.ZIndex" Value="1"/>
|
||||
<Setter Property="Visibility" TargetName="innerBorder" Value="Visible"/>
|
||||
<Setter Property="Background" TargetName="BorderMask" Value="{DynamicResource MahApps.Brushes.Gray8}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="controls:IconElement.Geometry" Value="{x:Null}">
|
||||
<Setter Property="Visibility" Value="Collapsed" TargetName="PathMain"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<ControlTemplate x:Key="TabControlPlusTemplate" TargetType="controls:TabControl">
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
|
||||
<Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition x:Name="ColumnDefinition0"/>
|
||||
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border Background="{TemplateBinding Background}" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource MahApps.Brushes.Control.Border}">
|
||||
<controls:TabPanel MinHeight="{TemplateBinding TabItemHeight}" TabItemHeight="{TemplateBinding TabItemHeight}" TabItemWidth="{TemplateBinding TabItemWidth}" IsTabFillEnabled="{TemplateBinding IsTabFillEnabled}" Margin="0,0,-1,-1" x:Name="PART_HeaderPanel" HorizontalAlignment="Left" Background="{DynamicResource SecondaryTextBrush}" IsItemsHost="true" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:FluidMoveBehavior AppliesTo="Children" Duration="{Binding FluidMoveDuration,ElementName=PART_HeaderPanel}">
|
||||
<interactivity:FluidMoveBehavior.EaseX>
|
||||
<CubicEase EasingMode="EaseOut"/>
|
||||
</interactivity:FluidMoveBehavior.EaseX>
|
||||
</interactivity:FluidMoveBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</controls:TabPanel>
|
||||
</Border>
|
||||
<Border x:Name="contentPanel" Background="{DynamicResource MahApps.Brushes.ThemeBackground}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
|
||||
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
|
||||
</Border>
|
||||
<Border Visibility="{Binding Visibility,ElementName=PART_OverflowButton}" Margin="0,-1,0,0" Grid.Row="0" Grid.Column="0" BorderThickness="1,0,0,1" BorderBrush="{DynamicResource MahApps.Brushes.Control.Border}" Background="{DynamicResource MahApps.Brushes.Gray8}" HorizontalAlignment="Right">
|
||||
<controls:ContextMenuToggleButton x:Name="PART_OverflowButton" Visibility="Collapsed" Style="{StaticResource ToggleButtonIconTransparent}" controls:IconSwitchElement.Geometry="{StaticResource DownGeometry}" controls:IconSwitchElement.GeometrySelected="{StaticResource UpGeometry}"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="TabControlPlusScrollableTemplate" TargetType="controls:TabControl">
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
|
||||
<Grid x:Name="templateRoot" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border Visibility="{TemplateBinding ShowScrollButton,Converter={StaticResource Boolean2VisibilityConverter}}" Margin="0,-1,0,0" Grid.Row="0" Grid.Column="0" BorderThickness="0,0,1,1" BorderBrush="{DynamicResource MahApps.Brushes.Control.Border}" Background="{DynamicResource MahApps.Brushes.Gray8}" HorizontalAlignment="Left" Panel.ZIndex="2">
|
||||
<Border.CacheMode>
|
||||
<BitmapCache SnapsToDevicePixels="True"/>
|
||||
</Border.CacheMode>
|
||||
<RepeatButton Focusable="False" Style="{StaticResource RepeatButtonIcon}" Padding="8" controls:IconElement.Geometry="{StaticResource LeftGeometry}" Foreground="{DynamicResource MahApps.Brushes.Text}" Background="{DynamicResource MahApps.Brushes.ThemeBackground}" x:Name="PART_ScrollButtonLeft"/>
|
||||
</Border>
|
||||
<controls:ScrollViewer HorizontalScrollBarVisibility="Hidden" CanMouseWheel="True" Orientation="Horizontal" IsInertiaEnabled="True" Grid.Row="0" Grid.Column="1" IsDeferredScrollingEnabled="True" x:Name="PART_OverflowScrollviewer">
|
||||
<Border Background="{TemplateBinding Background}" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource MahApps.Brushes.Control.Border}" Name="PART_HeaderBorder">
|
||||
<controls:TabPanel MinHeight="{TemplateBinding TabItemHeight}" TabItemHeight="{TemplateBinding TabItemHeight}" TabItemWidth="{TemplateBinding TabItemWidth}" IsTabFillEnabled="{TemplateBinding IsTabFillEnabled}" Margin="0,0,-1,-1" x:Name="PART_HeaderPanel" HorizontalAlignment="Left" Background="{DynamicResource SecondaryTextBrush}" IsItemsHost="true" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<interactivity:FluidMoveBehavior AppliesTo="Children" Duration="{Binding FluidMoveDuration,ElementName=PART_HeaderPanel}">
|
||||
<interactivity:FluidMoveBehavior.EaseX>
|
||||
<CubicEase EasingMode="EaseOut"/>
|
||||
</interactivity:FluidMoveBehavior.EaseX>
|
||||
</interactivity:FluidMoveBehavior>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</controls:TabPanel>
|
||||
</Border>
|
||||
</controls:ScrollViewer>
|
||||
<Border Margin="0,-1,0,0" Grid.Row="0" Grid.Column="2" BorderThickness="1,0,0,1" BorderBrush="{DynamicResource MahApps.Brushes.Control.Border}" Background="{DynamicResource MahApps.Brushes.Gray8}" HorizontalAlignment="Right">
|
||||
<Border.CacheMode>
|
||||
<BitmapCache SnapsToDevicePixels="True"/>
|
||||
</Border.CacheMode>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<RepeatButton Focusable="False" Visibility="{TemplateBinding ShowScrollButton,Converter={StaticResource Boolean2VisibilityConverter}}" Style="{StaticResource RepeatButtonIcon}" BorderBrush="{DynamicResource MahApps.Brushes.Control.Border}" Padding="8" controls:IconElement.Geometry="{StaticResource RightGeometry}" Foreground="{DynamicResource MahApps.Brushes.Text}" Background="{DynamicResource MahApps.Brushes.ThemeBackground}" x:Name="PART_ScrollButtonRight"/>
|
||||
<Border Visibility="{Binding Visibility,ElementName=PART_OverflowButton}" Width="1" Background="{DynamicResource MahApps.Brushes.Control.Border}"/>
|
||||
<controls:ContextMenuToggleButton x:Name="PART_OverflowButton" Visibility="Collapsed" Style="{StaticResource ToggleButtonIconTransparent}" controls:IconSwitchElement.Geometry="{StaticResource DownGeometry}" controls:IconSwitchElement.GeometrySelected="{StaticResource UpGeometry}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border x:Name="contentPanel" Background="{DynamicResource MahApps.Brushes.ThemeBackground}" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
|
||||
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style TargetType="controls:TabControl">
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="Background" Value="{DynamicResource MahApps.Brushes.Gray8}"/>
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource MahApps.Brushes.Control.Border}"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Template" Value="{StaticResource TabControlPlusTemplate}"/>
|
||||
<Style.Triggers>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsScrollable" Value="True"/>
|
||||
<Condition Property="IsTabFillEnabled" Value="False"/>
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter Property="Template" Value="{StaticResource TabControlPlusScrollableTemplate}"/>
|
||||
</MultiTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,443 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
[TemplatePart(Name = OverflowButtonKey, Type = typeof(ContextMenuToggleButton))]
|
||||
[TemplatePart(Name = HeaderPanelKey, Type = typeof(TabPanel))]
|
||||
[TemplatePart(Name = OverflowScrollviewer, Type = typeof(ScrollViewer))]
|
||||
[TemplatePart(Name = ScrollButtonLeft, Type = typeof(ButtonBase))]
|
||||
[TemplatePart(Name = ScrollButtonRight, Type = typeof(ButtonBase))]
|
||||
[TemplatePart(Name = HeaderBorder, Type = typeof(System.Windows.Controls.Border))]
|
||||
public class TabControl : System.Windows.Controls.TabControl
|
||||
{
|
||||
private const string OverflowButtonKey = "PART_OverflowButton";
|
||||
|
||||
private const string HeaderPanelKey = "PART_HeaderPanel";
|
||||
|
||||
private const string OverflowScrollviewer = "PART_OverflowScrollviewer";
|
||||
|
||||
private const string ScrollButtonLeft = "PART_ScrollButtonLeft";
|
||||
|
||||
private const string ScrollButtonRight = "PART_ScrollButtonRight";
|
||||
|
||||
private const string HeaderBorder = "PART_HeaderBorder";
|
||||
|
||||
private ContextMenuToggleButton _buttonOverflow;
|
||||
|
||||
internal TabPanel HeaderPanel { get; private set; }
|
||||
|
||||
private ScrollViewer _scrollViewerOverflow;
|
||||
|
||||
private ButtonBase _buttonScrollLeft;
|
||||
|
||||
private ButtonBase _buttonScrollRight;
|
||||
|
||||
private System.Windows.Controls.Border _headerBorder;
|
||||
|
||||
/// <summary>
|
||||
/// 是否为内部操作
|
||||
/// </summary>
|
||||
internal bool IsInternalAction;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用动画
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsAnimationEnabledProperty = DependencyProperty.Register(
|
||||
"IsAnimationEnabled", typeof(bool), typeof(TabControl), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用动画
|
||||
/// </summary>
|
||||
public bool IsAnimationEnabled
|
||||
{
|
||||
get => (bool)GetValue(IsAnimationEnabledProperty);
|
||||
set => SetValue(IsAnimationEnabledProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否可以拖动
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsDraggableProperty = DependencyProperty.Register(
|
||||
"IsDraggable", typeof(bool), typeof(TabControl), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// 是否可以拖动
|
||||
/// </summary>
|
||||
public bool IsDraggable
|
||||
{
|
||||
get => (bool)GetValue(IsDraggableProperty);
|
||||
set => SetValue(IsDraggableProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示关闭按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowCloseButtonProperty = DependencyProperty.RegisterAttached(
|
||||
"ShowCloseButton", typeof(bool), typeof(TabControl), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetShowCloseButton(DependencyObject element, bool value)
|
||||
=> element.SetValue(ShowCloseButtonProperty, value);
|
||||
|
||||
public static bool GetShowCloseButton(DependencyObject element)
|
||||
=> (bool) element.GetValue(ShowCloseButtonProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示关闭按钮
|
||||
/// </summary>
|
||||
public bool ShowCloseButton
|
||||
{
|
||||
get => (bool)GetValue(ShowCloseButtonProperty);
|
||||
set => SetValue(ShowCloseButtonProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示上下文菜单
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowContextMenuProperty = DependencyProperty.RegisterAttached(
|
||||
"ShowContextMenu", typeof(bool), typeof(TabControl), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetShowContextMenu(DependencyObject element, bool value)
|
||||
=> element.SetValue(ShowContextMenuProperty, value);
|
||||
|
||||
public static bool GetShowContextMenu(DependencyObject element)
|
||||
=> (bool) element.GetValue(ShowContextMenuProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示上下文菜单
|
||||
/// </summary>
|
||||
public bool ShowContextMenu
|
||||
{
|
||||
get => (bool)GetValue(ShowContextMenuProperty);
|
||||
set => SetValue(ShowContextMenuProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否将标签填充
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsTabFillEnabledProperty = DependencyProperty.Register(
|
||||
"IsTabFillEnabled", typeof(bool), typeof(TabControl), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// 是否将标签填充
|
||||
/// </summary>
|
||||
public bool IsTabFillEnabled
|
||||
{
|
||||
get => (bool)GetValue(IsTabFillEnabledProperty);
|
||||
set => SetValue(IsTabFillEnabledProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标签宽度
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TabItemWidthProperty = DependencyProperty.Register(
|
||||
"TabItemWidth", typeof(double), typeof(TabControl), new PropertyMetadata(200.0));
|
||||
|
||||
/// <summary>
|
||||
/// 标签宽度
|
||||
/// </summary>
|
||||
public double TabItemWidth
|
||||
{
|
||||
get => (double)GetValue(TabItemWidthProperty);
|
||||
set => SetValue(TabItemWidthProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标签高度
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TabItemHeightProperty = DependencyProperty.Register(
|
||||
"TabItemHeight", typeof(double), typeof(TabControl), new PropertyMetadata(30.0));
|
||||
|
||||
/// <summary>
|
||||
/// 标签高度
|
||||
/// </summary>
|
||||
public double TabItemHeight
|
||||
{
|
||||
get => (double)GetValue(TabItemHeightProperty);
|
||||
set => SetValue(TabItemHeightProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否可以滚动
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsScrollableProperty = DependencyProperty.Register(
|
||||
"IsScrollable", typeof(bool), typeof(TabControl), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// 是否可以滚动
|
||||
/// </summary>
|
||||
public bool IsScrollable
|
||||
{
|
||||
get => (bool) GetValue(IsScrollableProperty);
|
||||
set => SetValue(IsScrollableProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示溢出按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowOverflowButtonProperty = DependencyProperty.Register(
|
||||
"ShowOverflowButton", typeof(bool), typeof(TabControl), new PropertyMetadata(true));
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示溢出按钮
|
||||
/// </summary>
|
||||
public bool ShowOverflowButton
|
||||
{
|
||||
get => (bool) GetValue(ShowOverflowButtonProperty);
|
||||
set => SetValue(ShowOverflowButtonProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示滚动按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowScrollButtonProperty = DependencyProperty.Register(
|
||||
"ShowScrollButton", typeof(bool), typeof(TabControl), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示滚动按钮
|
||||
/// </summary>
|
||||
public bool ShowScrollButton
|
||||
{
|
||||
get => (bool) GetValue(ShowScrollButtonProperty);
|
||||
set => SetValue(ShowScrollButtonProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 可见的标签数量
|
||||
/// </summary>
|
||||
private int _itemShowCount;
|
||||
|
||||
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
base.OnItemsChanged(e);
|
||||
|
||||
if (HeaderPanel == null)
|
||||
{
|
||||
IsInternalAction = false;
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateOverflowButton();
|
||||
|
||||
if (IsInternalAction)
|
||||
{
|
||||
IsInternalAction = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsAnimationEnabled)
|
||||
{
|
||||
HeaderPanel.SetCurrentValue(TabPanel.FluidMoveDurationProperty, new Duration(TimeSpan.FromMilliseconds(200)));
|
||||
}
|
||||
else
|
||||
{
|
||||
HeaderPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
|
||||
}
|
||||
|
||||
if (e.Action == NotifyCollectionChangedAction.Add)
|
||||
{
|
||||
for (var i = 0; i < Items.Count; i++)
|
||||
{
|
||||
if (!(ItemContainerGenerator.ContainerFromIndex(i) is TabItem item)) return;
|
||||
item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
item.TabPanel = HeaderPanel;
|
||||
}
|
||||
}
|
||||
|
||||
_headerBorder?.InvalidateMeasure();
|
||||
|
||||
IsInternalAction = false;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_buttonOverflow != null)
|
||||
{
|
||||
if (_buttonOverflow.Menu != null)
|
||||
{
|
||||
_buttonOverflow.Menu.Closed -= Menu_Closed;
|
||||
_buttonOverflow.Menu = null;
|
||||
}
|
||||
|
||||
_buttonOverflow.Click -= ButtonOverflow_Click;
|
||||
}
|
||||
|
||||
if (_buttonScrollLeft != null) _buttonScrollLeft.Click -= ButtonScrollLeft_Click;
|
||||
if (_buttonScrollRight != null) _buttonScrollRight.Click -= ButtonScrollRight_Click;
|
||||
|
||||
base.OnApplyTemplate();
|
||||
HeaderPanel = GetTemplateChild(HeaderPanelKey) as TabPanel;
|
||||
|
||||
if (IsTabFillEnabled) return;
|
||||
|
||||
_buttonOverflow = GetTemplateChild(OverflowButtonKey) as ContextMenuToggleButton;
|
||||
_scrollViewerOverflow = GetTemplateChild(OverflowScrollviewer) as ScrollViewer;
|
||||
_buttonScrollLeft = GetTemplateChild(ScrollButtonLeft) as ButtonBase;
|
||||
_buttonScrollRight = GetTemplateChild(ScrollButtonRight) as ButtonBase;
|
||||
_headerBorder = GetTemplateChild(HeaderBorder) as System.Windows.Controls.Border;
|
||||
|
||||
if (_buttonScrollLeft != null) _buttonScrollLeft.Click += ButtonScrollLeft_Click;
|
||||
if (_buttonScrollRight != null) _buttonScrollRight.Click += ButtonScrollRight_Click;
|
||||
|
||||
if (_buttonOverflow != null)
|
||||
{
|
||||
var menu = new System.Windows.Controls.ContextMenu
|
||||
{
|
||||
Placement = PlacementMode.Bottom,
|
||||
PlacementTarget = _buttonOverflow
|
||||
};
|
||||
menu.Closed += Menu_Closed;
|
||||
_buttonOverflow.Menu = menu;
|
||||
_buttonOverflow.Click += ButtonOverflow_Click;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
UpdateOverflowButton();
|
||||
}
|
||||
|
||||
private void UpdateOverflowButton()
|
||||
{
|
||||
if (!IsTabFillEnabled)
|
||||
{
|
||||
_itemShowCount = (int)(ActualWidth / TabItemWidth);
|
||||
if (_buttonOverflow != null)
|
||||
{
|
||||
_buttonOverflow.Visibility = (ShowOverflowButton && Items.Count > 0 && Items.Count >= _itemShowCount) ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Menu_Closed(object sender, RoutedEventArgs e) => _buttonOverflow.IsChecked = false;
|
||||
|
||||
private void ButtonScrollRight_Click(object sender, RoutedEventArgs e) =>
|
||||
_scrollViewerOverflow.ScrollToHorizontalOffsetInternal(Math.Min(
|
||||
_scrollViewerOverflow.CurrentHorizontalOffset + TabItemWidth, _scrollViewerOverflow.ScrollableWidth));
|
||||
|
||||
private void ButtonScrollLeft_Click(object sender, RoutedEventArgs e) =>
|
||||
_scrollViewerOverflow.ScrollToHorizontalOffsetInternal(Math.Max(
|
||||
_scrollViewerOverflow.CurrentHorizontalOffset - TabItemWidth, 0));
|
||||
|
||||
private void ButtonOverflow_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_buttonOverflow.IsChecked == true)
|
||||
{
|
||||
_buttonOverflow.Menu.Items.Clear();
|
||||
for (var i = 0; i < Items.Count; i++)
|
||||
{
|
||||
if(!(ItemContainerGenerator.ContainerFromIndex(i) is TabItem item)) continue;
|
||||
|
||||
var menuItem = new System.Windows.Controls.MenuItem
|
||||
{
|
||||
HeaderStringFormat = ItemStringFormat,
|
||||
HeaderTemplate = ItemTemplate,
|
||||
HeaderTemplateSelector = ItemTemplateSelector,
|
||||
Header = item.Header,
|
||||
Width = TabItemWidth,
|
||||
IsChecked = item.IsSelected,
|
||||
IsCheckable = true
|
||||
};
|
||||
|
||||
menuItem.Click += delegate
|
||||
{
|
||||
_buttonOverflow.IsChecked = false;
|
||||
|
||||
var list = GetActualList();
|
||||
if (list == null) return;
|
||||
|
||||
var actualItem = ItemContainerGenerator.ItemFromContainer(item);
|
||||
if (actualItem == null) return;
|
||||
|
||||
var index = list.IndexOf(actualItem);
|
||||
if (index >= _itemShowCount)
|
||||
{
|
||||
list.Remove(actualItem);
|
||||
list.Insert(0, actualItem);
|
||||
if (IsAnimationEnabled)
|
||||
{
|
||||
HeaderPanel.SetCurrentValue(TabPanel.FluidMoveDurationProperty, new Duration(TimeSpan.FromMilliseconds(200)));
|
||||
}
|
||||
else
|
||||
{
|
||||
HeaderPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
|
||||
}
|
||||
HeaderPanel.ForceUpdate = true;
|
||||
HeaderPanel.Measure(new Size(HeaderPanel.DesiredSize.Width, ActualHeight));
|
||||
HeaderPanel.ForceUpdate = false;
|
||||
SetCurrentValue(SelectedIndexProperty, 0);
|
||||
}
|
||||
|
||||
item.IsSelected = true;
|
||||
};
|
||||
_buttonOverflow.Menu.Items.Add(menuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal double GetHorizontalOffset() => _scrollViewerOverflow?.CurrentHorizontalOffset ?? 0;
|
||||
|
||||
internal void UpdateScroll() => _scrollViewerOverflow?.RaiseEvent(new MouseWheelEventArgs(Mouse.PrimaryDevice, Environment.TickCount, 0)
|
||||
{
|
||||
RoutedEvent = MouseWheelEvent
|
||||
});
|
||||
|
||||
internal void CloseAllItems() => CloseOtherItems(null);
|
||||
|
||||
internal void CloseOtherItems(TabItem currentItem)
|
||||
{
|
||||
var actualItem = currentItem != null ? ItemContainerGenerator.ItemFromContainer(currentItem) : null;
|
||||
|
||||
var list = GetActualList();
|
||||
if (list == null) return;
|
||||
|
||||
IsInternalAction = true;
|
||||
|
||||
for (var i = 0; i < Items.Count; i++)
|
||||
{
|
||||
var item = list[i];
|
||||
if (!Equals(item, actualItem) && item != null)
|
||||
{
|
||||
var argsClosing = new CancelRoutedEventArgs(TabItem.ClosingEvent, item);
|
||||
|
||||
if (!(ItemContainerGenerator.ContainerFromItem(item) is TabItem tabItem)) continue;
|
||||
|
||||
tabItem.RaiseEvent(argsClosing);
|
||||
if (argsClosing.Cancel) return;
|
||||
|
||||
tabItem.RaiseEvent(new RoutedEventArgs(TabItem.ClosedEvent, item));
|
||||
list.Remove(item);
|
||||
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
SetCurrentValue(SelectedIndexProperty, Items.Count == 0 ? -1 : 0);
|
||||
}
|
||||
|
||||
internal IList GetActualList()
|
||||
{
|
||||
IList list;
|
||||
if (ItemsSource != null)
|
||||
{
|
||||
list = ItemsSource as IList;
|
||||
}
|
||||
else
|
||||
{
|
||||
list = Items;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is TabItem;
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new TabItem();
|
||||
}
|
||||
}
|
||||
@@ -1,467 +0,0 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
public class TabItem : System.Windows.Controls.TabItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 动画速度
|
||||
/// </summary>
|
||||
private const int AnimationSpeed = 150;
|
||||
|
||||
/// <summary>
|
||||
/// 选项卡是否处于拖动状态
|
||||
/// </summary>
|
||||
private static bool ItemIsDragging;
|
||||
|
||||
/// <summary>
|
||||
/// 选项卡是否等待被拖动
|
||||
/// </summary>
|
||||
private bool _isWaiting;
|
||||
|
||||
/// <summary>
|
||||
/// 拖动中的选项卡坐标
|
||||
/// </summary>
|
||||
private Point _dragPoint;
|
||||
|
||||
/// <summary>
|
||||
/// 鼠标按下时选项卡位置
|
||||
/// </summary>
|
||||
private int _mouseDownIndex;
|
||||
|
||||
/// <summary>
|
||||
/// 鼠标按下时选项卡横向偏移
|
||||
/// </summary>
|
||||
private double _mouseDownOffsetX;
|
||||
|
||||
/// <summary>
|
||||
/// 鼠标按下时的坐标
|
||||
/// </summary>
|
||||
private Point _mouseDownPoint;
|
||||
|
||||
/// <summary>
|
||||
/// 右侧可移动的最大值
|
||||
/// </summary>
|
||||
private double _maxMoveRight;
|
||||
|
||||
/// <summary>
|
||||
/// 左侧可移动的最大值
|
||||
/// </summary>
|
||||
private double _maxMoveLeft;
|
||||
|
||||
/// <summary>
|
||||
/// 选项卡宽度
|
||||
/// </summary>
|
||||
public double ItemWidth { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 选项卡拖动等待距离(在鼠标移动了超过20个像素无关单位后,选项卡才开始被拖动)
|
||||
/// </summary>
|
||||
private const double WaitLength = 20;
|
||||
|
||||
/// <summary>
|
||||
/// 选项卡是否处于拖动状态
|
||||
/// </summary>
|
||||
private bool _isDragging;
|
||||
|
||||
/// <summary>
|
||||
/// 选项卡是否已经被拖动
|
||||
/// </summary>
|
||||
private bool _isDragged;
|
||||
|
||||
/// <summary>
|
||||
/// 目标横向位移
|
||||
/// </summary>
|
||||
internal double TargetOffsetX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前编号
|
||||
/// </summary>
|
||||
private int _currentIndex;
|
||||
|
||||
/// <summary>
|
||||
/// 标签容器横向滚动距离
|
||||
/// </summary>
|
||||
private double _scrollHorizontalOffset;
|
||||
|
||||
private TabPanel _tabPanel;
|
||||
|
||||
/// <summary>
|
||||
/// 标签容器
|
||||
/// </summary>
|
||||
internal TabPanel TabPanel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_tabPanel == null && TabControlParent != null)
|
||||
{
|
||||
_tabPanel = TabControlParent.HeaderPanel;
|
||||
}
|
||||
|
||||
return _tabPanel;
|
||||
}
|
||||
set => _tabPanel = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前编号
|
||||
/// </summary>
|
||||
internal int CurrentIndex
|
||||
{
|
||||
get => _currentIndex;
|
||||
set
|
||||
{
|
||||
if (_currentIndex == value || value < 0) return;
|
||||
var oldIndex = _currentIndex;
|
||||
_currentIndex = value;
|
||||
UpdateItemOffsetX(oldIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示关闭按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowCloseButtonProperty =
|
||||
TabControl.ShowCloseButtonProperty.AddOwner(typeof(TabItem));
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示关闭按钮
|
||||
/// </summary>
|
||||
public bool ShowCloseButton
|
||||
{
|
||||
get => (bool)GetValue(ShowCloseButtonProperty);
|
||||
set => SetValue(ShowCloseButtonProperty, value);
|
||||
}
|
||||
|
||||
public static void SetShowCloseButton(DependencyObject element, bool value)
|
||||
=> element.SetValue(ShowCloseButtonProperty, value);
|
||||
|
||||
public static bool GetShowCloseButton(DependencyObject element)
|
||||
=> (bool)element.GetValue(ShowCloseButtonProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示上下文菜单
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowContextMenuProperty =
|
||||
TabControl.ShowContextMenuProperty.AddOwner(typeof(TabItem), new FrameworkPropertyMetadata(OnShowContextMenuChanged));
|
||||
|
||||
private static void OnShowContextMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (TabItem) d;
|
||||
if (ctl.Menu != null)
|
||||
{
|
||||
var show = (bool)e.NewValue;
|
||||
ctl.Menu.IsEnabled = show;
|
||||
ctl.Menu.Show(show);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示上下文菜单
|
||||
/// </summary>
|
||||
public bool ShowContextMenu
|
||||
{
|
||||
get => (bool) GetValue(ShowContextMenuProperty);
|
||||
set => SetValue(ShowContextMenuProperty, value);
|
||||
}
|
||||
|
||||
public static void SetShowContextMenu(DependencyObject element, bool value)
|
||||
=> element.SetValue(ShowContextMenuProperty, value);
|
||||
|
||||
public static bool GetShowContextMenu(DependencyObject element)
|
||||
=> (bool)element.GetValue(ShowContextMenuProperty);
|
||||
|
||||
public static readonly DependencyProperty MenuProperty = DependencyProperty.Register(
|
||||
"Menu", typeof(System.Windows.Controls.ContextMenu), typeof(TabItem), new PropertyMetadata(default(System.Windows.Controls.ContextMenu), OnMenuChanged));
|
||||
|
||||
private static void OnMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (TabItem) d;
|
||||
ctl.OnMenuChanged(e.NewValue as System.Windows.Controls.ContextMenu);
|
||||
}
|
||||
|
||||
private void OnMenuChanged(System.Windows.Controls.ContextMenu menu)
|
||||
{
|
||||
if (IsLoaded && menu != null)
|
||||
{
|
||||
var parent = TabControlParent;
|
||||
if (parent == null) return;
|
||||
|
||||
var item = parent.ItemContainerGenerator.ItemFromContainer(this);
|
||||
|
||||
menu.DataContext = item;
|
||||
menu.SetBinding(IsEnabledProperty, new Binding(ShowContextMenuProperty.Name)
|
||||
{
|
||||
Source = this
|
||||
});
|
||||
menu.SetBinding(VisibilityProperty, new Binding(ShowContextMenuProperty.Name)
|
||||
{
|
||||
Source = this,
|
||||
Converter = ResourceHelper.GetResource<IValueConverter>("Boolean2VisibilityConverter")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public System.Windows.Controls.ContextMenu Menu
|
||||
{
|
||||
get => (System.Windows.Controls.ContextMenu) GetValue(MenuProperty);
|
||||
set => SetValue(MenuProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新选项卡横向偏移
|
||||
/// </summary>
|
||||
/// <param name="oldIndex"></param>
|
||||
private void UpdateItemOffsetX(int oldIndex)
|
||||
{
|
||||
if (!_isDragging) return;
|
||||
var moveItem = TabPanel.ItemDic[CurrentIndex];
|
||||
moveItem.CurrentIndex -= CurrentIndex - oldIndex;
|
||||
var offsetX = moveItem.TargetOffsetX;
|
||||
var resultX = offsetX + (oldIndex - CurrentIndex) * ItemWidth;
|
||||
TabPanel.ItemDic[CurrentIndex] = this;
|
||||
TabPanel.ItemDic[moveItem.CurrentIndex] = moveItem;
|
||||
moveItem.CreateAnimation(offsetX, resultX);
|
||||
}
|
||||
|
||||
public TabItem()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Close, (s, e) => Close()));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.CloseAll,
|
||||
(s, e) => { TabControlParent.CloseAllItems(); }));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.CloseOther,
|
||||
(s, e) => { TabControlParent.CloseOtherItems(this); }));
|
||||
|
||||
Loaded += (s, e) => OnMenuChanged(Menu);
|
||||
}
|
||||
|
||||
private Util.Controls.Handy.TabControls.TabControl TabControlParent => System.Windows.Controls.ItemsControl.ItemsControlFromItemContainer(this) as TabControl;
|
||||
|
||||
protected override void OnMouseRightButtonDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseRightButtonDown(e);
|
||||
IsSelected = true;
|
||||
Focus();
|
||||
}
|
||||
|
||||
protected override void OnHeaderChanged(object oldHeader, object newHeader)
|
||||
{
|
||||
base.OnHeaderChanged(oldHeader, newHeader);
|
||||
|
||||
if (TabPanel != null)
|
||||
{
|
||||
TabPanel.ForceUpdate = true;
|
||||
InvalidateMeasure();
|
||||
TabPanel.ForceUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Close()
|
||||
{
|
||||
var parent = TabControlParent;
|
||||
if (parent == null) return;
|
||||
|
||||
var item = parent.ItemContainerGenerator.ItemFromContainer(this);
|
||||
|
||||
var argsClosing = new CancelRoutedEventArgs(ClosingEvent, item);
|
||||
RaiseEvent(argsClosing);
|
||||
if (argsClosing.Cancel) return;
|
||||
|
||||
TabPanel.SetCurrentValue(TabPanel.FluidMoveDurationProperty, parent.IsAnimationEnabled
|
||||
? new Duration(TimeSpan.FromMilliseconds(200))
|
||||
: new Duration(TimeSpan.FromMilliseconds(1)));
|
||||
|
||||
parent.IsInternalAction = true;
|
||||
RaiseEvent(new RoutedEventArgs(ClosedEvent, item));
|
||||
|
||||
var list = parent.GetActualList();
|
||||
list?.Remove(item);
|
||||
}
|
||||
|
||||
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseLeftButtonDown(e);
|
||||
|
||||
var parent = TabControlParent;
|
||||
if (parent == null) return;
|
||||
|
||||
if (parent.IsDraggable && !ItemIsDragging && !_isDragging)
|
||||
{
|
||||
parent.UpdateScroll();
|
||||
TabPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
|
||||
_mouseDownOffsetX = RenderTransform.Value.OffsetX;
|
||||
_scrollHorizontalOffset = parent.GetHorizontalOffset();
|
||||
var mx = TranslatePoint(new Point(), parent).X + _scrollHorizontalOffset;
|
||||
_mouseDownIndex = CalLocationIndex(mx);
|
||||
var subIndex = _mouseDownIndex - CalLocationIndex(_scrollHorizontalOffset);
|
||||
_maxMoveLeft = -subIndex * ItemWidth;
|
||||
_maxMoveRight = parent.ActualWidth - ActualWidth + _maxMoveLeft;
|
||||
|
||||
_isDragging = true;
|
||||
ItemIsDragging = true;
|
||||
_isWaiting = true;
|
||||
_dragPoint = e.GetPosition(parent);
|
||||
_dragPoint = new Point(_dragPoint.X + _scrollHorizontalOffset, _dragPoint.Y);
|
||||
_mouseDownPoint = _dragPoint;
|
||||
CaptureMouse();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
if (ItemIsDragging && _isDragging)
|
||||
{
|
||||
var parent = TabControlParent;
|
||||
if (parent == null) return;
|
||||
|
||||
var subX = TranslatePoint(new Point(), parent).X + _scrollHorizontalOffset;
|
||||
CurrentIndex = CalLocationIndex(subX);
|
||||
|
||||
var p = e.GetPosition(parent);
|
||||
p = new Point(p.X + _scrollHorizontalOffset, p.Y);
|
||||
|
||||
var subLeft = p.X - _dragPoint.X;
|
||||
var totalLeft = p.X - _mouseDownPoint.X;
|
||||
|
||||
if (Math.Abs(subLeft) <= WaitLength && _isWaiting) return;
|
||||
|
||||
_isWaiting = false;
|
||||
_isDragged = true;
|
||||
|
||||
var left = subLeft + RenderTransform.Value.OffsetX;
|
||||
if (totalLeft < _maxMoveLeft)
|
||||
{
|
||||
left = _maxMoveLeft + _mouseDownOffsetX;
|
||||
}
|
||||
else if (totalLeft > _maxMoveRight)
|
||||
{
|
||||
left = _maxMoveRight + _mouseDownOffsetX;
|
||||
}
|
||||
|
||||
var t = new TranslateTransform(left, 0);
|
||||
RenderTransform = t;
|
||||
_dragPoint = p;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseLeftButtonUp(e);
|
||||
|
||||
ReleaseMouseCapture();
|
||||
|
||||
if (_isDragged)
|
||||
{
|
||||
var parent = TabControlParent;
|
||||
if (parent == null) return;
|
||||
|
||||
var subX = TranslatePoint(new Point(), parent).X + _scrollHorizontalOffset;
|
||||
var index = CalLocationIndex(subX);
|
||||
var left = index * ItemWidth;
|
||||
var offsetX = RenderTransform.Value.OffsetX;
|
||||
CreateAnimation(offsetX, offsetX - subX + left, index);
|
||||
}
|
||||
|
||||
_isDragging = false;
|
||||
ItemIsDragging = false;
|
||||
_isDragged = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建动画
|
||||
/// </summary>
|
||||
internal void CreateAnimation(double offsetX, double resultX, int index = -1)
|
||||
{
|
||||
var parent = TabControlParent;
|
||||
|
||||
void AnimationCompleted()
|
||||
{
|
||||
RenderTransform = new TranslateTransform(resultX, 0);
|
||||
if (index == -1) return;
|
||||
|
||||
var list = parent.GetActualList();
|
||||
if (list == null) return;
|
||||
|
||||
var item = parent.ItemContainerGenerator.ItemFromContainer(this);
|
||||
if (item == null) return;
|
||||
|
||||
TabPanel.CanUpdate = false;
|
||||
parent.IsInternalAction = true;
|
||||
|
||||
list.Remove(item);
|
||||
parent.IsInternalAction = true;
|
||||
list.Insert(index, item);
|
||||
TabPanel.CanUpdate = true;
|
||||
TabPanel.ForceUpdate = true;
|
||||
TabPanel.Measure(new Size(TabPanel.DesiredSize.Width, ActualHeight));
|
||||
TabPanel.ForceUpdate = false;
|
||||
|
||||
Focus();
|
||||
IsSelected = true;
|
||||
|
||||
if (!IsMouseCaptured)
|
||||
{
|
||||
parent.SetCurrentValue(Selector.SelectedIndexProperty, _currentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
TargetOffsetX = resultX;
|
||||
if (!parent.IsAnimationEnabled)
|
||||
{
|
||||
AnimationCompleted();
|
||||
return;
|
||||
}
|
||||
|
||||
var animation = AnimationHelper.CreateAnimation(resultX, AnimationSpeed);
|
||||
animation.FillBehavior = FillBehavior.Stop;
|
||||
animation.Completed += (s1, e1) => AnimationCompleted();
|
||||
var f = new TranslateTransform(offsetX, 0);
|
||||
RenderTransform = f;
|
||||
f.BeginAnimation(TranslateTransform.XProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算选项卡当前合适的位置编号
|
||||
/// </summary>
|
||||
/// <param name="left"></param>
|
||||
/// <returns></returns>
|
||||
private int CalLocationIndex(double left)
|
||||
{
|
||||
if (_isWaiting)
|
||||
{
|
||||
return CurrentIndex;
|
||||
}
|
||||
|
||||
var maxIndex = TabControlParent.Items.Count - 1;
|
||||
var div = (int)(left / ItemWidth);
|
||||
var rest = left % ItemWidth;
|
||||
var result = rest / ItemWidth > .5 ? div + 1 : div;
|
||||
|
||||
return result > maxIndex ? maxIndex : result;
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent ClosingEvent = EventManager.RegisterRoutedEvent("Closing", RoutingStrategy.Bubble, typeof(EventHandler), typeof(TabItem));
|
||||
|
||||
public event EventHandler Closing
|
||||
{
|
||||
add => AddHandler(ClosingEvent, value);
|
||||
remove => RemoveHandler(ClosingEvent, value);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent ClosedEvent = EventManager.RegisterRoutedEvent("Closed", RoutingStrategy.Bubble, typeof(EventHandler), typeof(TabItem));
|
||||
|
||||
public event EventHandler Closed
|
||||
{
|
||||
add => AddHandler(ClosedEvent, value);
|
||||
remove => RemoveHandler(ClosedEvent, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
public class TabPanel : System.Windows.Controls.Panel
|
||||
{
|
||||
private int _itemCount;
|
||||
|
||||
/// <summary>
|
||||
/// 是否可以更新
|
||||
/// </summary>
|
||||
internal bool CanUpdate = true;
|
||||
|
||||
/// <summary>
|
||||
/// 选项卡字典
|
||||
/// </summary>
|
||||
internal Dictionary<int, TabItem> ItemDic = new Dictionary<int, TabItem>();
|
||||
|
||||
/// <summary>
|
||||
/// 流式行为持续时间
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty FluidMoveDurationProperty = DependencyProperty.Register(
|
||||
"FluidMoveDuration", typeof(Duration), typeof(TabPanel), new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(200))));
|
||||
|
||||
/// <summary>
|
||||
/// 流式行为持续时间
|
||||
/// </summary>
|
||||
public Duration FluidMoveDuration
|
||||
{
|
||||
get => (Duration)GetValue(FluidMoveDurationProperty);
|
||||
set => SetValue(FluidMoveDurationProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否将标签填充
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsTabFillEnabledProperty = DependencyProperty.Register(
|
||||
"IsTabFillEnabled", typeof(bool), typeof(TabPanel), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 是否将标签填充
|
||||
/// </summary>
|
||||
public bool IsTabFillEnabled
|
||||
{
|
||||
get => (bool)GetValue(IsTabFillEnabledProperty);
|
||||
set => SetValue(IsTabFillEnabledProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标签宽度
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TabItemWidthProperty = DependencyProperty.Register(
|
||||
"TabItemWidth", typeof(double), typeof(TabPanel), new PropertyMetadata(200.0));
|
||||
|
||||
/// <summary>
|
||||
/// 标签宽度
|
||||
/// </summary>
|
||||
public double TabItemWidth
|
||||
{
|
||||
get => (double)GetValue(TabItemWidthProperty);
|
||||
set => SetValue(TabItemWidthProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标签高度
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TabItemHeightProperty = DependencyProperty.Register(
|
||||
"TabItemHeight", typeof(double), typeof(TabPanel), new PropertyMetadata(30.0));
|
||||
|
||||
/// <summary>
|
||||
/// 标签高度
|
||||
/// </summary>
|
||||
public double TabItemHeight
|
||||
{
|
||||
get => (double)GetValue(TabItemHeightProperty);
|
||||
set => SetValue(TabItemHeightProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否可以强制更新
|
||||
/// </summary>
|
||||
internal bool ForceUpdate;
|
||||
|
||||
private Size _oldSize;
|
||||
|
||||
/// <summary>
|
||||
/// 是否已经加载
|
||||
/// </summary>
|
||||
private bool _isLoaded;
|
||||
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
if ((_itemCount == InternalChildren.Count || !CanUpdate) && !ForceUpdate) return _oldSize;
|
||||
constraint.Height = TabItemHeight;
|
||||
_itemCount = InternalChildren.Count;
|
||||
|
||||
var size = new Size();
|
||||
|
||||
ItemDic.Clear();
|
||||
|
||||
var count = InternalChildren.Count;
|
||||
if (count == 0)
|
||||
{
|
||||
_oldSize = new Size();
|
||||
return _oldSize;
|
||||
}
|
||||
constraint.Width += InternalChildren.Count;
|
||||
|
||||
var itemWidth = .0;
|
||||
var arr = new int[count];
|
||||
|
||||
if (!IsTabFillEnabled)
|
||||
{
|
||||
itemWidth = TabItemWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TemplatedParent is TabControl tabControl)
|
||||
{
|
||||
arr = ArithmeticHelper.DivideInt2Arr((int)tabControl.ActualWidth + InternalChildren.Count, count);
|
||||
}
|
||||
}
|
||||
|
||||
for (var index = 0; index < count; index++)
|
||||
{
|
||||
if (IsTabFillEnabled)
|
||||
{
|
||||
itemWidth = arr[index];
|
||||
}
|
||||
if (InternalChildren[index] is TabItem tabItem)
|
||||
{
|
||||
tabItem.RenderTransform = new TranslateTransform();
|
||||
tabItem.MaxWidth = itemWidth;
|
||||
var rect = new Rect
|
||||
{
|
||||
X = size.Width - tabItem.BorderThickness.Left,
|
||||
Width = itemWidth,
|
||||
Height = TabItemHeight
|
||||
};
|
||||
tabItem.Arrange(rect);
|
||||
tabItem.ItemWidth = itemWidth - tabItem.BorderThickness.Left;
|
||||
tabItem.CurrentIndex = index;
|
||||
tabItem.TargetOffsetX = 0;
|
||||
ItemDic[index] = tabItem;
|
||||
size.Width += tabItem.ItemWidth;
|
||||
}
|
||||
}
|
||||
size.Height = constraint.Height;
|
||||
_oldSize = size;
|
||||
return _oldSize;
|
||||
}
|
||||
|
||||
public TabPanel()
|
||||
{
|
||||
Loaded += (s, e) =>
|
||||
{
|
||||
if (_isLoaded) return;
|
||||
ForceUpdate = true;
|
||||
Measure(new Size(DesiredSize.Width, ActualHeight));
|
||||
ForceUpdate = false;
|
||||
foreach (var item in ItemDic.Values)
|
||||
{
|
||||
item.TabPanel = this;
|
||||
}
|
||||
_isLoaded = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,619 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// A ruler control which supports both centimeters and inches. In order to use it vertically, change the <see cref="Marks">Marks</see> property to <c>Up</c> and rotate it ninety degrees.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Contributions from <see
|
||||
/// cref="http://www.orbifold.net/default/?p=2295&cpage=1#comment-61500">Raf
|
||||
/// Lenfers</see>
|
||||
/// </remarks>
|
||||
public class Ruler : FrameworkElement
|
||||
{
|
||||
#region Fields
|
||||
private double SegmentHeight;
|
||||
private readonly Pen p = new Pen(Brushes.Black, 1.0);
|
||||
private readonly Pen ThinPen = new Pen(Brushes.Black, 0.5);
|
||||
private readonly Pen BorderPen = new Pen(Brushes.Gray, 1.0);
|
||||
private readonly Pen RedPen = new Pen(Brushes.Red, 2.0);
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
#region Background
|
||||
public Brush Background
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Brush)GetValue(BackgroundProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(BackgroundProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the Length dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty BackgroundProperty =
|
||||
DependencyProperty.Register(
|
||||
"Background",
|
||||
typeof(Brush),
|
||||
typeof(Ruler),
|
||||
new FrameworkPropertyMetadata(new SolidColorBrush(Colors.White), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
#endregion
|
||||
|
||||
#region Length
|
||||
/// <summary>
|
||||
/// Gets or sets the length of the ruler. If the <see cref="AutoSize"/> property is set to false (default) this
|
||||
/// is a fixed length. Otherwise the length is calculated based on the actual width of the ruler.
|
||||
/// </summary>
|
||||
public double Length
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.AutoSize)
|
||||
{
|
||||
return (double)(Unit == Unit.Cm ? DipHelper.DipToCm(this.ActualWidth) : DipHelper.DipToInch(this.ActualWidth)) / this.Zoom;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (double)GetValue(LengthProperty);
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(LengthProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the Length dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty LengthProperty =
|
||||
DependencyProperty.Register(
|
||||
"Length",
|
||||
typeof(double),
|
||||
typeof(Ruler),
|
||||
new FrameworkPropertyMetadata(20D, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
#endregion
|
||||
|
||||
#region AutoSize
|
||||
/// <summary>
|
||||
/// Gets or sets the AutoSize behavior of the ruler.
|
||||
/// false (default): the lenght of the ruler results from the <see cref="Length"/> property. If the window size is changed, e.g. wider
|
||||
/// than the rulers length, free space is shown at the end of the ruler. No rescaling is done.
|
||||
/// true : the length of the ruler is always adjusted to its actual width. This ensures that the ruler is shown
|
||||
/// for the actual width of the window.
|
||||
/// </summary>
|
||||
public bool AutoSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)GetValue(AutoSizeProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(AutoSizeProperty, value);
|
||||
this.InvalidateVisual();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the AutoSize dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty AutoSizeProperty =
|
||||
DependencyProperty.Register(
|
||||
"AutoSize",
|
||||
typeof(bool),
|
||||
typeof(Ruler),
|
||||
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
#endregion
|
||||
|
||||
#region Zoom
|
||||
/// <summary>
|
||||
/// Gets or sets the zoom factor for the ruler. The default value is 1.0.
|
||||
/// </summary>
|
||||
public double Zoom
|
||||
{
|
||||
get
|
||||
{
|
||||
return (double)GetValue(ZoomProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(ZoomProperty, value);
|
||||
this.InvalidateVisual();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the Zoom dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ZoomProperty =
|
||||
DependencyProperty.Register("Zoom", typeof(double), typeof(Ruler),
|
||||
new FrameworkPropertyMetadata((double)1.0,
|
||||
FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Chip
|
||||
|
||||
/// <summary>
|
||||
/// Chip Dependency Property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ChipProperty =
|
||||
DependencyProperty.Register("Chip", typeof(double), typeof(Ruler),
|
||||
new FrameworkPropertyMetadata((double)-1000,
|
||||
FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
/// <summary>
|
||||
/// Sets the location of the chip in the units of the ruler.
|
||||
/// So, to set the chip to 10 in cm units the chip needs to be set to 10.
|
||||
/// Use the <see cref="DipHelper"/> class for conversions.
|
||||
/// </summary>
|
||||
public double Chip
|
||||
{
|
||||
get { return (double)GetValue(ChipProperty); }
|
||||
set { SetValue(ChipProperty, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CountShift
|
||||
|
||||
/// <summary>
|
||||
/// CountShift Dependency Property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CountShiftProperty =
|
||||
DependencyProperty.Register("CountShift", typeof(double), typeof(Ruler),
|
||||
new FrameworkPropertyMetadata(0d,
|
||||
FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
/// <summary>
|
||||
/// By default the counting of inches or cm starts at zero, this property allows you to shift
|
||||
/// the counting.
|
||||
/// </summary>
|
||||
public double CountShift
|
||||
{
|
||||
get { return (double)GetValue(CountShiftProperty); }
|
||||
set { SetValue(CountShiftProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Marks
|
||||
|
||||
/// <summary>
|
||||
/// Marks Dependency Property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MarksProperty =
|
||||
DependencyProperty.Register("Marks", typeof(MarksLocation), typeof(Ruler),
|
||||
new FrameworkPropertyMetadata(MarksLocation.Up,
|
||||
FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets where the marks are shown in the ruler.
|
||||
/// </summary>
|
||||
public MarksLocation Marks
|
||||
{
|
||||
get { return (MarksLocation)GetValue(MarksProperty); }
|
||||
set { SetValue(MarksProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unit
|
||||
/// <summary>
|
||||
/// Gets or sets the unit of the ruler.
|
||||
/// Default value is Unit.Cm.
|
||||
/// </summary>
|
||||
public Unit Unit
|
||||
{
|
||||
get { return (Unit)GetValue(UnitProperty); }
|
||||
set { SetValue(UnitProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the Unit dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty UnitProperty =
|
||||
DependencyProperty.Register(
|
||||
"Unit",
|
||||
typeof(Unit),
|
||||
typeof(Ruler),
|
||||
new FrameworkPropertyMetadata(Unit.Cm, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
static Ruler()
|
||||
{
|
||||
HeightProperty.OverrideMetadata(typeof(Ruler), new FrameworkPropertyMetadata(20.0));
|
||||
}
|
||||
public Ruler()
|
||||
{
|
||||
SegmentHeight = this.Height - 10;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
/// <summary>
|
||||
/// Participates in rendering operations.
|
||||
/// </summary>
|
||||
/// <param name="drawingContext">The drawing instructions for a specific element. This context is provided to the layout system.</param>
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
base.OnRender(drawingContext);
|
||||
|
||||
var rect = new Rect(0, 0, RenderSize.Width, RenderSize.Height);
|
||||
drawingContext.DrawRectangle(Background, null, rect);
|
||||
|
||||
double xDest = (Unit == Unit.Cm ? DipHelper.CmToDip(Length) : DipHelper.InchToDip(Length)) * this.Zoom;
|
||||
drawingContext.DrawRectangle(null, BorderPen, new Rect(new Point(0.0, 0.0), new Point(xDest, Height)));
|
||||
double chip = Unit == Unit.Cm ? DipHelper.CmToDip(Chip) : DipHelper.InchToDip(Chip);
|
||||
drawingContext.DrawLine(RedPen, new Point(chip, 0), new Point(chip, Height));
|
||||
|
||||
//画偏移位置之前的
|
||||
if (CountShift < 0)
|
||||
{
|
||||
for (double dUnit = -CountShift; dUnit > -1; dUnit--)
|
||||
{
|
||||
double d;
|
||||
if (Unit == Unit.Cm)
|
||||
{
|
||||
d = DipHelper.CmToDip(dUnit) * this.Zoom;
|
||||
if (dUnit < Length)
|
||||
{
|
||||
for (int i = 1; i <= 9; i++)
|
||||
{
|
||||
if (i != 5)
|
||||
{
|
||||
double dMm = DipHelper.CmToDip(dUnit + 0.1 * i) * this.Zoom;
|
||||
if (Marks == MarksLocation.Up)
|
||||
drawingContext.DrawLine(ThinPen, new Point(dMm, 0), new Point(dMm, SegmentHeight / 3.0));
|
||||
else
|
||||
drawingContext.DrawLine(ThinPen, new Point(dMm, Height), new Point(dMm, Height - SegmentHeight / 3.0));
|
||||
}
|
||||
}
|
||||
double dMiddle = DipHelper.CmToDip(dUnit + 0.5) * this.Zoom;
|
||||
if (Marks == MarksLocation.Up)
|
||||
drawingContext.DrawLine(p, new Point(dMiddle, 0), new Point(dMiddle, SegmentHeight * 2.0 / 3.0));
|
||||
else
|
||||
drawingContext.DrawLine(p, new Point(dMiddle, Height), new Point(dMiddle, Height - SegmentHeight * 2.0 / 3.0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
d = DipHelper.InchToDip(dUnit) * this.Zoom;
|
||||
if (dUnit < Length)
|
||||
{
|
||||
if (Marks == MarksLocation.Up)
|
||||
{
|
||||
double dQuarter = DipHelper.InchToDip(dUnit + 0.25) * this.Zoom;
|
||||
drawingContext.DrawLine(ThinPen, new Point(dQuarter, 0),
|
||||
new Point(dQuarter, SegmentHeight / 3.0));
|
||||
double dMiddle = DipHelper.InchToDip(dUnit + 0.5) * this.Zoom;
|
||||
drawingContext.DrawLine(p, new Point(dMiddle, 0),
|
||||
new Point(dMiddle, SegmentHeight * 2D / 3D));
|
||||
double d3Quarter = DipHelper.InchToDip(dUnit + 0.75) * this.Zoom;
|
||||
drawingContext.DrawLine(ThinPen, new Point(d3Quarter, 0),
|
||||
new Point(d3Quarter, SegmentHeight / 3.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
double dQuarter = DipHelper.InchToDip(dUnit + 0.25) * this.Zoom;
|
||||
drawingContext.DrawLine(ThinPen, new Point(dQuarter, Height),
|
||||
new Point(dQuarter, Height - SegmentHeight / 3.0));
|
||||
double dMiddle = DipHelper.InchToDip(dUnit + 0.5) * this.Zoom;
|
||||
drawingContext.DrawLine(p, new Point(dMiddle, Height),
|
||||
new Point(dMiddle, Height - SegmentHeight * 2D / 3D));
|
||||
double d3Quarter = DipHelper.InchToDip(dUnit + 0.75) * this.Zoom;
|
||||
drawingContext.DrawLine(ThinPen, new Point(d3Quarter, Height),
|
||||
new Point(d3Quarter, Height - SegmentHeight / 3.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Marks == MarksLocation.Up)
|
||||
drawingContext.DrawLine(p, new Point(d, 0), new Point(d, SegmentHeight));
|
||||
else
|
||||
drawingContext.DrawLine(p, new Point(d, Height), new Point(d, Height - SegmentHeight));
|
||||
|
||||
|
||||
if ((dUnit != 0.0) && (dUnit < Length))
|
||||
{
|
||||
FormattedText ft = new FormattedText(
|
||||
(Math.Round(dUnit + CountShift,0)).ToString(CultureInfo.CurrentCulture),
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
new Typeface("Arial"),
|
||||
DipHelper.PtToDip(6),
|
||||
Brushes.DimGray);
|
||||
ft.SetFontWeight(FontWeights.Regular);
|
||||
ft.TextAlignment = TextAlignment.Center;
|
||||
|
||||
if (Marks == MarksLocation.Up)
|
||||
drawingContext.DrawText(ft, new Point(d, Height - ft.Height));
|
||||
else
|
||||
drawingContext.DrawText(ft, new Point(d, Height - SegmentHeight - ft.Height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//画偏移位置之后的
|
||||
for (double dUnit = -CountShift; dUnit <= Length; dUnit++)
|
||||
{
|
||||
double d;
|
||||
if (Unit == Unit.Cm)
|
||||
{
|
||||
d = DipHelper.CmToDip(dUnit) * this.Zoom;
|
||||
if (dUnit < Length)
|
||||
{
|
||||
for (int i = 1; i <= 9; i++)
|
||||
{
|
||||
if (i != 5)
|
||||
{
|
||||
double dMm = DipHelper.CmToDip(dUnit + 0.1 * i) * this.Zoom;
|
||||
if (Marks == MarksLocation.Up)
|
||||
drawingContext.DrawLine(ThinPen, new Point(dMm, 0), new Point(dMm, SegmentHeight / 3.0));
|
||||
else
|
||||
drawingContext.DrawLine(ThinPen, new Point(dMm, Height), new Point(dMm, Height - SegmentHeight / 3.0));
|
||||
}
|
||||
}
|
||||
double dMiddle = DipHelper.CmToDip(dUnit + 0.5) * this.Zoom;
|
||||
if (Marks == MarksLocation.Up)
|
||||
drawingContext.DrawLine(p, new Point(dMiddle, 0), new Point(dMiddle, SegmentHeight * 2.0 / 3.0));
|
||||
else
|
||||
drawingContext.DrawLine(p, new Point(dMiddle, Height), new Point(dMiddle, Height - SegmentHeight * 2.0 / 3.0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
d = DipHelper.InchToDip(dUnit) * this.Zoom;
|
||||
if (dUnit < Length)
|
||||
{
|
||||
if (Marks == MarksLocation.Up)
|
||||
{
|
||||
double dQuarter = DipHelper.InchToDip(dUnit + 0.25) * this.Zoom;
|
||||
drawingContext.DrawLine(ThinPen, new Point(dQuarter, 0),
|
||||
new Point(dQuarter, SegmentHeight / 3.0));
|
||||
double dMiddle = DipHelper.InchToDip(dUnit + 0.5) * this.Zoom;
|
||||
drawingContext.DrawLine(p, new Point(dMiddle, 0),
|
||||
new Point(dMiddle, SegmentHeight * 2D / 3D));
|
||||
double d3Quarter = DipHelper.InchToDip(dUnit + 0.75) * this.Zoom;
|
||||
drawingContext.DrawLine(ThinPen, new Point(d3Quarter, 0),
|
||||
new Point(d3Quarter, SegmentHeight / 3.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
double dQuarter = DipHelper.InchToDip(dUnit + 0.25) * this.Zoom;
|
||||
drawingContext.DrawLine(ThinPen, new Point(dQuarter, Height),
|
||||
new Point(dQuarter, Height - SegmentHeight / 3.0));
|
||||
double dMiddle = DipHelper.InchToDip(dUnit + 0.5) * this.Zoom;
|
||||
drawingContext.DrawLine(p, new Point(dMiddle, Height),
|
||||
new Point(dMiddle, Height - SegmentHeight * 2D / 3D));
|
||||
double d3Quarter = DipHelper.InchToDip(dUnit + 0.75) * this.Zoom;
|
||||
drawingContext.DrawLine(ThinPen, new Point(d3Quarter, Height),
|
||||
new Point(d3Quarter, Height - SegmentHeight / 3.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Marks == MarksLocation.Up)
|
||||
drawingContext.DrawLine(p, new Point(d, 0), new Point(d, SegmentHeight));
|
||||
else
|
||||
drawingContext.DrawLine(p, new Point(d, Height), new Point(d, Height - SegmentHeight));
|
||||
|
||||
|
||||
if ((dUnit != 0.0) && (dUnit < Length))
|
||||
{
|
||||
FormattedText ft = new FormattedText(
|
||||
(Math.Round(dUnit + CountShift,0)).ToString(CultureInfo.CurrentCulture),
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
new Typeface("Arial"),
|
||||
DipHelper.PtToDip(6),
|
||||
Brushes.DimGray);
|
||||
ft.SetFontWeight(FontWeights.Regular);
|
||||
ft.TextAlignment = TextAlignment.Center;
|
||||
|
||||
if (Marks == MarksLocation.Up)
|
||||
drawingContext.DrawText(ft, new Point(d, Height - ft.Height));
|
||||
else
|
||||
drawingContext.DrawText(ft, new Point(d, Height - SegmentHeight - ft.Height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Measures an instance during the first layout pass prior to arranging it.
|
||||
/// </summary>
|
||||
/// <param name="availableSize">A maximum Size to not exceed.</param>
|
||||
/// <returns>The maximum Size for the instance.</returns>
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
return base.MeasureOverride(availableSize);
|
||||
//Size desiredSize;
|
||||
//if (Unit == Unit.Cm)
|
||||
//{
|
||||
// desiredSize = new Size(DipHelper.CmToDip(Length), Height);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// desiredSize = new Size(DipHelper.InchToDip(Length), Height);
|
||||
//}
|
||||
//return desiredSize;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The unit type of the ruler.
|
||||
/// </summary>
|
||||
public enum Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// the unit is Centimeter.
|
||||
/// </summary>
|
||||
Cm,
|
||||
|
||||
/// <summary>
|
||||
/// The unit is Inch.
|
||||
/// </summary>
|
||||
Inch
|
||||
};
|
||||
|
||||
public enum MarksLocation
|
||||
{
|
||||
Up, Down
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A helper class for DIP (Device Independent Pixels) conversion and scaling operations.
|
||||
/// </summary>
|
||||
public static class DipHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts millimeters to DIP (Device Independant Pixels).
|
||||
/// </summary>
|
||||
/// <param name="mm">A millimeter value.</param>
|
||||
/// <returns>A DIP value.</returns>
|
||||
public static double MmToDip(double mm)
|
||||
{
|
||||
return CmToDip(mm / 10.0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts centimeters to DIP (Device Independant Pixels).
|
||||
/// </summary>
|
||||
/// <param name="cm">A centimeter value.</param>
|
||||
/// <returns>A DIP value.</returns>
|
||||
public static double CmToDip(double cm)
|
||||
{
|
||||
return (cm * 96.0 / 2.54);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts inches to DIP (Device Independant Pixels).
|
||||
/// </summary>
|
||||
/// <param name="inch">An inch value.</param>
|
||||
/// <returns>A DIP value.</returns>
|
||||
public static double InchToDip(double inch)
|
||||
{
|
||||
return (inch * 96.0);
|
||||
}
|
||||
public static double DipToInch(double dip)
|
||||
{
|
||||
return dip / 96D;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts font points to DIP (Device Independant Pixels).
|
||||
/// </summary>
|
||||
/// <param name="pt">A font point value.</param>
|
||||
/// <returns>A DIP value.</returns>
|
||||
public static double PtToDip(double pt)
|
||||
{
|
||||
return (pt * 96.0 / 72.0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts DIP (Device Independant Pixels) to centimeters.
|
||||
/// </summary>
|
||||
/// <param name="dip">A DIP value.</param>
|
||||
/// <returns>A centimeter value.</returns>
|
||||
public static double DipToCm(double dip)
|
||||
{
|
||||
return (dip * 2.54 / 96.0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts DIP (Device Independant Pixels) to millimeters.
|
||||
/// </summary>
|
||||
/// <param name="dip">A DIP value.</param>
|
||||
/// <returns>A millimeter value.</returns>
|
||||
public static double DipToMm(double dip)
|
||||
{
|
||||
return DipToCm(dip) * 10.0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the system DPI scale factor (compared to 96 dpi).
|
||||
/// From http://blogs.msdn.com/jaimer/archive/2007/03/07/getting-system-dpi-in-wpf-app.aspx
|
||||
/// Should not be called before the Loaded event (else XamlException mat throw)
|
||||
/// </summary>
|
||||
/// <returns>A Point object containing the X- and Y- scale factor.</returns>
|
||||
private static Point GetSystemDpiFactor()
|
||||
{
|
||||
PresentationSource source = PresentationSource.FromVisual(Application.Current.MainWindow);
|
||||
Matrix m = source.CompositionTarget.TransformToDevice;
|
||||
return new Point(m.M11, m.M22);
|
||||
}
|
||||
|
||||
private const double DpiBase = 96.0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the system configured DPI.
|
||||
/// </summary>
|
||||
/// <returns>A Point object containing the X- and Y- DPI.</returns>
|
||||
public static Point GetSystemDpi()
|
||||
{
|
||||
Point sysDpiFactor = GetSystemDpiFactor();
|
||||
return new Point(
|
||||
sysDpiFactor.X * DpiBase,
|
||||
sysDpiFactor.Y * DpiBase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the physical pixel density (DPI) of the screen.
|
||||
/// </summary>
|
||||
/// <param name="diagonalScreenSize">Size - in inch - of the diagonal of the screen.</param>
|
||||
/// <returns>A Point object containing the X- and Y- DPI.</returns>
|
||||
public static Point GetPhysicalDpi(double diagonalScreenSize)
|
||||
{
|
||||
Point sysDpiFactor = GetSystemDpiFactor();
|
||||
double pixelScreenWidth = SystemParameters.PrimaryScreenWidth * sysDpiFactor.X;
|
||||
double pixelScreenHeight = SystemParameters.PrimaryScreenHeight * sysDpiFactor.Y;
|
||||
double formatRate = pixelScreenWidth / pixelScreenHeight;
|
||||
|
||||
double inchHeight = diagonalScreenSize / Math.Sqrt(formatRate * formatRate + 1.0);
|
||||
double inchWidth = formatRate * inchHeight;
|
||||
|
||||
double xDpi = Math.Round(pixelScreenWidth / inchWidth);
|
||||
double yDpi = Math.Round(pixelScreenHeight / inchHeight);
|
||||
|
||||
return new Point(xDpi, yDpi);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a DPI into a scale factor (compared to system DPI).
|
||||
/// </summary>
|
||||
/// <param name="dpi">A Point object containing the X- and Y- DPI to convert.</param>
|
||||
/// <returns>A Point object containing the X- and Y- scale factor.</returns>
|
||||
public static Point DpiToScaleFactor(Point dpi)
|
||||
{
|
||||
Point sysDpi = GetSystemDpi();
|
||||
return new Point(
|
||||
dpi.X / sysDpi.X,
|
||||
dpi.Y / sysDpi.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scale factor to apply to a WPF application
|
||||
/// so that 96 DIP always equals 1 inch on the screen (whatever the system DPI).
|
||||
/// </summary>
|
||||
/// <param name="diagonalScreenSize">Size - in inch - of the diagonal of the screen</param>
|
||||
/// <returns>A Point object containing the X- and Y- scale factor.</returns>
|
||||
public static Point GetScreenIndependentScaleFactor(double diagonalScreenSize)
|
||||
{
|
||||
return DpiToScaleFactor(GetPhysicalDpi(diagonalScreenSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class BoolVisibilityConverter : IValueConverter
|
||||
{
|
||||
#region IValueConverter Members
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var visibility = value as bool?;
|
||||
var visible = parameter as string;
|
||||
|
||||
if (visibility != null && visible != null)
|
||||
{
|
||||
if (visibility == true && visible == "true")
|
||||
{
|
||||
return Visibility.Visible;
|
||||
}
|
||||
if (visibility == false && visible == "false")
|
||||
{
|
||||
return Visibility.Visible;
|
||||
}
|
||||
}
|
||||
else if (visibility != null)
|
||||
{
|
||||
if (visibility == true)
|
||||
{
|
||||
return Visibility.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class Boolean2VisibilityReConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value != null && (bool)value ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class ConverterBoolToValueMap : MarkupExtension, IValueConverter
|
||||
{
|
||||
public override object ProvideValue(System.IServiceProvider serviceProvider)
|
||||
{
|
||||
return new ConverterBoolToValueMap
|
||||
{
|
||||
FromType = this.FromType ?? typeof(char),
|
||||
TargetType = this.TargetType ?? typeof(bool),
|
||||
Parameter = this.Parameter
|
||||
};
|
||||
}
|
||||
|
||||
public object Parameter
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Type TargetType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Type FromType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
#region IValueConverter Members
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
var result = DependencyProperty.UnsetValue;
|
||||
if (value == null) return result;
|
||||
if (value is bool)
|
||||
{
|
||||
if ((bool)value)
|
||||
result = parameter;
|
||||
else
|
||||
result = this.Parameter;
|
||||
if (result == null || string.IsNullOrWhiteSpace(result.ToString()))
|
||||
return DependencyProperty.UnsetValue;
|
||||
//处理枚举类型
|
||||
if (targetType.IsEnum)
|
||||
result = Enum.Parse(targetType, result as string);
|
||||
else if (targetType.IsValueType)
|
||||
{
|
||||
if (targetType == typeof(Int32))
|
||||
result = System.Convert.ToInt32(result);
|
||||
else if (targetType == typeof(Int16))
|
||||
result = System.Convert.ToInt16(result);
|
||||
else if (targetType == typeof(char))
|
||||
result = result.ToString().First();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value == null || parameter == null)
|
||||
return false;
|
||||
|
||||
if (object.Equals(value, parameter))
|
||||
return true;
|
||||
|
||||
return string.Equals(value.ToString(), parameter.ToString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class ConverterValueMapSetToVisibility : MarkupExtension, IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value == null || parameter == null)
|
||||
return DependencyProperty.UnsetValue;
|
||||
|
||||
IEnumerable<string> checkList = parameter.ToString().Split('^');
|
||||
|
||||
bool equal = checkList.Contains(value.ToString());
|
||||
|
||||
if (equal)
|
||||
return Visibility.Visible;
|
||||
else
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override object ProvideValue(System.IServiceProvider serviceProvider)
|
||||
{
|
||||
return new ConverterValueMapSetToVisibility
|
||||
{
|
||||
FromType = this.FromType ?? typeof(char),
|
||||
TargetType = this.TargetType ?? typeof(bool),
|
||||
Parameter = this.Parameter
|
||||
};
|
||||
}
|
||||
public object Parameter
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Type TargetType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Type FromType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class ConverterValueMapToBool : MarkupExtension, IValueConverter
|
||||
{
|
||||
public override object ProvideValue(System.IServiceProvider serviceProvider)
|
||||
{
|
||||
return new ConverterValueMapToBool
|
||||
{
|
||||
FromType = this.FromType ?? typeof(char),
|
||||
TargetType = this.TargetType ?? typeof(bool),
|
||||
Parameter = this.Parameter
|
||||
};
|
||||
}
|
||||
|
||||
public object Parameter
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Type TargetType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Type FromType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
#region IValueConverter Members
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value == null || parameter == null)
|
||||
return false;
|
||||
|
||||
if (object.Equals(value, parameter))
|
||||
return true;
|
||||
|
||||
return string.Equals(value.ToString(), parameter.ToString());
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
var result = DependencyProperty.UnsetValue;
|
||||
if (value == null) return result;
|
||||
if (value is bool)
|
||||
{
|
||||
if ((bool)value)
|
||||
result = parameter;
|
||||
else
|
||||
result = this.Parameter;
|
||||
if (result == null || string.IsNullOrWhiteSpace(result.ToString()))
|
||||
return DependencyProperty.UnsetValue;
|
||||
//处理枚举类型
|
||||
if (targetType.IsEnum)
|
||||
result = Enum.Parse(targetType, result as string);
|
||||
else if (targetType.IsValueType)
|
||||
{
|
||||
if (targetType == typeof(Int32))
|
||||
result = System.Convert.ToInt32(result);
|
||||
else if (targetType == typeof(Int16))
|
||||
result = System.Convert.ToInt16(result);
|
||||
else if (targetType == typeof(char))
|
||||
result = result.ToString().First();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class ConverterValueMapToVisibility : MarkupExtension, IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value == null || parameter == null)
|
||||
return DependencyProperty.UnsetValue;
|
||||
bool equal = string.Equals(value.ToString(), parameter.ToString());
|
||||
|
||||
//true = Visible
|
||||
if (equal)
|
||||
return Visibility.Visible;
|
||||
else
|
||||
return this.Parameter != null && this.Parameter.ToString().ToLower() == Visibility.Hidden.ToString().ToLower() ? Visibility.Hidden : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override object ProvideValue(System.IServiceProvider serviceProvider)
|
||||
{
|
||||
return new ConverterValueMapToVisibility
|
||||
{
|
||||
FromType = this.FromType ?? typeof(char),
|
||||
TargetType = this.TargetType ?? typeof(bool),
|
||||
Parameter = this.Parameter
|
||||
};
|
||||
}
|
||||
public object Parameter
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Type TargetType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Type FromType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class ConverterValueSetToOppositeVisibility : MarkupExtension, IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value == null || parameter == null)
|
||||
return DependencyProperty.UnsetValue;
|
||||
|
||||
IEnumerable<string> checkList = parameter.ToString().Split('^');
|
||||
|
||||
bool equal = checkList.Contains(value.ToString());
|
||||
|
||||
if (equal)
|
||||
return Visibility.Collapsed;
|
||||
else
|
||||
return Visibility.Visible;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override object ProvideValue(System.IServiceProvider serviceProvider)
|
||||
{
|
||||
return new ConverterValueSetToOppositeVisibility
|
||||
{
|
||||
FromType = this.FromType ?? typeof(char),
|
||||
TargetType = this.TargetType ?? typeof(bool),
|
||||
Parameter = this.Parameter
|
||||
};
|
||||
}
|
||||
public object Parameter
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Type TargetType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Type FromType
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using AIStudio.Wpf.ADiagram.Controls;
|
||||
using Util.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class CountShiftConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (values != null && values.Length > 2)
|
||||
{
|
||||
var diagram = values[0] as Util.DiagramDesigner.DiagramControl;
|
||||
var zoomValue = (double)values[1];
|
||||
var pageunit = (PageUnit)values[2];
|
||||
var unit = Unit.Cm;
|
||||
if (pageunit > PageUnit.km)
|
||||
{
|
||||
unit = Unit.Inch;
|
||||
}
|
||||
Vector vector = System.Windows.Media.VisualTreeHelper.GetOffset(diagram);
|
||||
|
||||
if (parameter?.ToString() == "Y")
|
||||
{
|
||||
var value = 0 - (unit == Unit.Cm? DipHelper.DipToCm(vector.Y - 20) : DipHelper.DipToInch(vector.Y - 20))/ zoomValue;
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = 0 - (unit == Unit.Cm ? DipHelper.DipToCm(vector.X - 20) : DipHelper.DipToInch(vector.X - 20)) / zoomValue;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class DoubleToThickness : IValueConverter
|
||||
{
|
||||
public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
if (parameter != null)
|
||||
{
|
||||
switch (parameter.ToString())
|
||||
{
|
||||
case "Left":
|
||||
return new Thickness(System.Convert.ToDouble(value), 0, 0, 0);
|
||||
|
||||
case "Top":
|
||||
return new Thickness(0, System.Convert.ToDouble(value), 0, 0);
|
||||
|
||||
case "Right":
|
||||
return new Thickness(0, 0, System.Convert.ToDouble(value), 0);
|
||||
|
||||
case "Buttom":
|
||||
return new Thickness(0, 0, 0, System.Convert.ToDouble(value));
|
||||
|
||||
case "LeftTop":
|
||||
return new Thickness(System.Convert.ToDouble(value), System.Convert.ToDouble(value), 0, 0);
|
||||
|
||||
case "LeftButtom":
|
||||
return new Thickness(System.Convert.ToDouble(value), 0, 0, System.Convert.ToDouble(value));
|
||||
|
||||
case "RightTop":
|
||||
return new Thickness(0, System.Convert.ToDouble(value), System.Convert.ToDouble(value), 0);
|
||||
|
||||
case "RigthButtom":
|
||||
return new Thickness(0, 0, System.Convert.ToDouble(value), System.Convert.ToDouble(value));
|
||||
|
||||
case "LeftRight":
|
||||
return new Thickness(System.Convert.ToDouble(value), 0, System.Convert.ToDouble(value), 0);
|
||||
|
||||
case "TopButtom":
|
||||
return new Thickness(0, System.Convert.ToDouble(value), 0, System.Convert.ToDouble(value));
|
||||
|
||||
default:
|
||||
return new Thickness(System.Convert.ToDouble(value));
|
||||
}
|
||||
}
|
||||
return new Thickness(System.Convert.ToDouble(value));
|
||||
}
|
||||
return new Thickness(0);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
if (parameter != null)
|
||||
{
|
||||
switch (parameter.ToString())
|
||||
{
|
||||
case "Left":
|
||||
return ((Thickness)value).Left;
|
||||
|
||||
case "Top":
|
||||
return ((Thickness)value).Top;
|
||||
|
||||
case "Right":
|
||||
return ((Thickness)value).Right;
|
||||
|
||||
case "Buttom":
|
||||
return ((Thickness)value).Bottom;
|
||||
|
||||
default:
|
||||
return ((Thickness)value).Left;
|
||||
}
|
||||
}
|
||||
return ((Thickness)value).Left;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/**************************************************************************************
|
||||
|
||||
Toolkit for WPF
|
||||
|
||||
Copyright (C) 2007-2016 Xceed Software Inc.
|
||||
|
||||
This program is provided to you under the terms of the Microsoft Public
|
||||
License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
|
||||
|
||||
For more features, controls, and fast professional support,
|
||||
pick up the Plus Edition at https://xceed.com/xceed-toolkit-plus-for-wpf/
|
||||
|
||||
Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids
|
||||
|
||||
************************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
class HtmlColorConverter : IValueConverter
|
||||
{
|
||||
#region IValueConverter Members
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if ((value != null) && value is System.Windows.Media.Color)
|
||||
return new SolidColorBrush((System.Windows.Media.Color)value);
|
||||
if ((value != null) && value is string str)
|
||||
{
|
||||
BrushConverter brushConverter = new BrushConverter();
|
||||
return (Brush)brushConverter.ConvertFromString(str);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
using System.Windows.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class IndentConverter : IValueConverter
|
||||
{
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
double colunwidth = 10;
|
||||
double left = 0.0;
|
||||
|
||||
|
||||
UIElement element = value as TreeViewItem;
|
||||
while (element.GetType() != typeof(TreeView))
|
||||
{
|
||||
element = (UIElement)VisualTreeHelper.GetParent(element);
|
||||
if (element.GetType() == typeof(TreeViewItem))
|
||||
left += colunwidth;
|
||||
}
|
||||
return new Thickness(left, 0, 0, 0);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
//选中项索引转换成可见项
|
||||
public class IntVisibilityConverter : MarkupExtension, IValueConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the value for the target property of this markup extension.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">Object that can provide services for the markup extension.</param>
|
||||
/// <returns>Reference to the instance of this Int32IndexToNumberConverter.</returns>
|
||||
public override object ProvideValue(System.IServiceProvider serviceProvider)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
|
||||
if (value is int && parameter is string) //与参数相同则显示
|
||||
{
|
||||
if (parameter.ToString().Contains("^"))
|
||||
{
|
||||
var paras = parameter.ToString().Split('^');
|
||||
foreach(var para in paras)
|
||||
{
|
||||
if (value.ToString() == para)
|
||||
{
|
||||
return Visibility.Visible;
|
||||
}
|
||||
}
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value.ToString() == (string)parameter)
|
||||
{
|
||||
return Visibility.Visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (value is int) //无参数,则大于0显示
|
||||
{
|
||||
if ((int)value > 0)
|
||||
{
|
||||
return Visibility.Visible;
|
||||
}
|
||||
}
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class NullableToBooleanConverter : IValueConverter
|
||||
{
|
||||
public bool NullValue { get; set; } = false;
|
||||
public bool NotNullValue { get; set; } = true;
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value == null ? NullValue : NotNullValue;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return Binding.DoNothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class NullableToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public Visibility NullValue { get; set; } = Visibility.Collapsed;
|
||||
public Visibility NotNullValue { get; set; } = Visibility.Visible;
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value == null ? NullValue : NotNullValue;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return Binding.DoNothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class NumberConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value == null)
|
||||
return 0.ToString("00");
|
||||
return (System.Convert.ToInt32(value) + 1).ToString("00");
|
||||
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using AIStudio.Wpf.ADiagram.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
using Util.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class RulerUnitConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value is PageUnit pageunit)
|
||||
{
|
||||
if (pageunit > PageUnit.km)
|
||||
{
|
||||
return Unit.Inch;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Unit.Cm;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class StringPathConverter : IValueConverter
|
||||
{
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value is string)
|
||||
{
|
||||
Geometry geo = Geometry.Parse(value as string);
|
||||
return geo;
|
||||
//GeometryConverter gc = new GeometryConverter();
|
||||
//return (Geometry)gc.ConvertFromString(value as string);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a Thickness to a new Thickness. It's possible to ignore a side With the IgnoreThicknessSide property.
|
||||
/// </summary>
|
||||
public class ThicknessBindingConverter : IValueConverter
|
||||
{
|
||||
public IgnoreThicknessSideType IgnoreThicknessSide { get; set; }
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is Thickness)
|
||||
{
|
||||
// yes, we can override it with the parameter value
|
||||
if (parameter is IgnoreThicknessSideType)
|
||||
{
|
||||
this.IgnoreThicknessSide = (IgnoreThicknessSideType)parameter;
|
||||
}
|
||||
var orgThickness = (Thickness)value;
|
||||
switch (this.IgnoreThicknessSide)
|
||||
{
|
||||
case IgnoreThicknessSideType.Left:
|
||||
return new Thickness(0, orgThickness.Top, orgThickness.Right, orgThickness.Bottom);
|
||||
case IgnoreThicknessSideType.Top:
|
||||
return new Thickness(orgThickness.Left, 0, orgThickness.Right, orgThickness.Bottom);
|
||||
case IgnoreThicknessSideType.Right:
|
||||
return new Thickness(orgThickness.Left, orgThickness.Top, 0, orgThickness.Bottom);
|
||||
case IgnoreThicknessSideType.Bottom:
|
||||
return new Thickness(orgThickness.Left, orgThickness.Top, orgThickness.Right, 0);
|
||||
default:
|
||||
return orgThickness;
|
||||
}
|
||||
}
|
||||
return default(Thickness);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
// for now no back converting
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
}
|
||||
|
||||
public enum IgnoreThicknessSideType
|
||||
{
|
||||
/// <summary>
|
||||
/// Use all sides.
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// Ignore the left side.
|
||||
/// </summary>
|
||||
Left,
|
||||
/// <summary>
|
||||
/// Ignore the top side.
|
||||
/// </summary>
|
||||
Top,
|
||||
/// <summary>
|
||||
/// Ignore the right side.
|
||||
/// </summary>
|
||||
Right,
|
||||
/// <summary>
|
||||
/// Ignore the bottom side.
|
||||
/// </summary>
|
||||
Bottom
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Converters
|
||||
{
|
||||
public class ThicknessToDoubleConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return ((Thickness)value).Left;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
}
|
||||
|
||||
internal class DoubleToRightMarginConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return new Thickness(0, 0, ((double)value), 0);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
}
|
||||
|
||||
internal class DoubleToLeftMarginConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return new Thickness(((double)value), 0, 0, 0);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
}
|
||||
|
||||
internal class DoubleToLeftRightMarginConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return new Thickness((double)value, 0, (double)value, 0);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,364 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Util.DiagramDesigner;
|
||||
using Expression = org.mariuszgromada.math.mxparser.Expression;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
|
||||
{
|
||||
public static class FlowchartService
|
||||
{
|
||||
static FlowchartService()
|
||||
{
|
||||
Users = new List<SelectOption>()
|
||||
{
|
||||
new SelectOption(){ value = "操作员1",text = "操作员1" },
|
||||
new SelectOption(){ value = "操作员2",text = "操作员2" },
|
||||
new SelectOption(){ value = "Admin",text = "Admin" },
|
||||
};
|
||||
|
||||
Roles = new List<SelectOption>()
|
||||
{
|
||||
new SelectOption(){ value = "操作员",text = "操作员" },
|
||||
new SelectOption(){ value = "管理员",text = "管理员" },
|
||||
};
|
||||
}
|
||||
|
||||
private static List<SelectOption> _users;
|
||||
public static List<SelectOption> Users
|
||||
{
|
||||
get { return _users; }
|
||||
set
|
||||
{
|
||||
_users = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<SelectOption> _roles;
|
||||
public static List<SelectOption> Roles
|
||||
{
|
||||
get { return _roles; }
|
||||
set
|
||||
{
|
||||
_roles = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 流程数据
|
||||
/// </summary>
|
||||
public static List<FlowNode> FlowNodes { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 初始化数据
|
||||
/// </summary>
|
||||
/// <param name="json"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static void InitOAData(List<FlowNode> oASteps, List<ConnectorViewModel> connectors)
|
||||
{
|
||||
foreach (var edge in connectors)
|
||||
{
|
||||
var source = oASteps.FirstOrDefault(p => p.BottomConnector == edge.SourceConnectorInfo || p.LeftConnector == edge.SourceConnectorInfo || p.RightConnector == edge.SourceConnectorInfo);
|
||||
if (source != null)
|
||||
{
|
||||
if (source.Kind == NodeKinds.Decide)
|
||||
{
|
||||
source.SelectNextStep.Add((edge.SinkConnectorInfo as FullyCreatedConnectorInfo).DataItem.Id.ToString(), "data.Flag" + edge.Text);
|
||||
}
|
||||
else if (source.Kind == NodeKinds.COBegin)
|
||||
{
|
||||
source.SelectNextStep.Add((edge.SinkConnectorInfo as FullyCreatedConnectorInfo).DataItem.Id.ToString(), "True");
|
||||
}
|
||||
else
|
||||
{
|
||||
source.NextStepId = (edge.SinkConnectorInfo as FullyCreatedConnectorInfo).DataItem.Id.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var step in oASteps)
|
||||
{
|
||||
//恢复指向上一个节点
|
||||
if (!string.IsNullOrEmpty(step.NextStepId))
|
||||
{
|
||||
var nextstep = oASteps.FirstOrDefault(p => p.Id.ToString() == step.NextStepId);
|
||||
if (nextstep == null)
|
||||
throw new Exception(string.Format("流程异常,无法找到{0}的下一个流程节点{1}", step.Id, step.NextStepId));
|
||||
if (nextstep.Kind == NodeKinds.Decide)
|
||||
{
|
||||
var nsteps = oASteps.Where(p => nextstep.SelectNextStep.Any(q => p.Id.ToString() == q.Key));
|
||||
if (nsteps == null || nsteps.Count() == 0)
|
||||
throw new Exception(string.Format("流程异常,无法找到{0}的下一个流程节点{1}", step.Id, step.NextStepId));
|
||||
|
||||
//跳过Decide指向下面的子节点
|
||||
foreach (var nstep in nsteps)
|
||||
{
|
||||
if (nstep.PreStepId == null)
|
||||
nstep.PreStepId = new List<string>();
|
||||
nstep.PreStepId.Add(step.Id.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nextstep.PreStepId == null)
|
||||
nextstep.PreStepId = new List<string>();
|
||||
nextstep.PreStepId.Add(step.Id.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var oAStartStep = oASteps.Single(p => p.Kind == NodeKinds.Start);
|
||||
if (string.IsNullOrEmpty(oAStartStep.NextStepId))
|
||||
{
|
||||
throw new Exception("开始节点没有下一个节点");
|
||||
}
|
||||
|
||||
string nextstepid = oAStartStep.NextStepId;
|
||||
FlowNodes = InitStep(oASteps, nextstepid);
|
||||
FlowNodes.Insert(0, oAStartStep);
|
||||
|
||||
Approve(oAStartStep, 100);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 初始化步骤
|
||||
/// </summary>
|
||||
/// <param name="oASteps"></param>
|
||||
/// <param name="nextstepid"></param>
|
||||
/// <returns></returns>
|
||||
public static List<FlowNode> InitStep(List<FlowNode> oASteps, string nextstepid)
|
||||
{
|
||||
List<FlowNode> outsteps = new List<FlowNode>();
|
||||
List<string> nextids = new List<string>();
|
||||
var step = oASteps.FirstOrDefault(p => p.Id.ToString() == nextstepid);
|
||||
if (step != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(step.NextStepId))
|
||||
{
|
||||
nextids.Add(step.NextStepId);
|
||||
}
|
||||
else if (step.SelectNextStep != null && step.SelectNextStep.Count > 0)
|
||||
{
|
||||
nextids.AddRange(step.SelectNextStep.Keys);
|
||||
}
|
||||
|
||||
outsteps.Add(step);
|
||||
oASteps.Remove(step);
|
||||
}
|
||||
|
||||
int index = outsteps.IndexOf(step);
|
||||
|
||||
nextids.Reverse();
|
||||
foreach (var next in nextids)
|
||||
{
|
||||
outsteps.InsertRange(index + 1, InitStep(oASteps, next));
|
||||
}
|
||||
return outsteps;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 审批动作,因为是客户端模拟,假设每次都是该节点的审批人进行的操作
|
||||
/// </summary>
|
||||
/// <param name="flowNode"></param>
|
||||
/// <param name="status"></param>
|
||||
/// <param name="remark"></param>
|
||||
public static void Approve(FlowNode flowNode, int status, string remark = null)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case 100:
|
||||
if (flowNode is MiddleFlowNode middleFlowNode)
|
||||
{
|
||||
if (string.IsNullOrEmpty(flowNode.Remark))
|
||||
{
|
||||
remark = "审批人:" + remark;
|
||||
}
|
||||
else
|
||||
{
|
||||
remark = flowNode.Remark + "\r审批人:" + remark;
|
||||
}
|
||||
|
||||
if (middleFlowNode.ActType == "and")//如果是与签,那么要都审批通过
|
||||
{
|
||||
if (middleFlowNode.UserIds != null && middleFlowNode.UserIds.Count > 1)
|
||||
{
|
||||
//实际情况不是这样的,这里只是演示,简化。
|
||||
int count = remark.Split("审批人:", StringSplitOptions.RemoveEmptyEntries).Length;
|
||||
if (middleFlowNode.UserIds.Count != count)
|
||||
{
|
||||
SetStatus(flowNode, 1, remark);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (middleFlowNode.RoleIds != null && middleFlowNode.RoleIds.Count > 1)
|
||||
{
|
||||
//实际情况不是这样的,这里只是演示,简化。
|
||||
int count = remark.Split("审批人:", StringSplitOptions.RemoveEmptyEntries).Length;
|
||||
if (middleFlowNode.RoleIds.Count != count)
|
||||
{
|
||||
SetStatus(flowNode, 1, remark);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SetStatus(flowNode, status, remark);
|
||||
if (!string.IsNullOrEmpty(flowNode.NextStepId))
|
||||
{
|
||||
Next(flowNode.NextStepId);
|
||||
}
|
||||
else if (flowNode.SelectNextStep != null && flowNode.SelectNextStep.Count > 0)
|
||||
{
|
||||
foreach (var step in flowNode.SelectNextStep)
|
||||
{
|
||||
Next(step.Key);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (Pre(flowNode))
|
||||
{
|
||||
SetStatus(flowNode, status, remark);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("该节点不支持驳回上一级");
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
SetStatus(flowNode, status, remark);
|
||||
FlowNodes.ForEach(p => { if (p.Status == 100) p.Status = 0; });
|
||||
Approve(FlowNodes[0], 100);
|
||||
MessageBox.Show("流程重新开始");
|
||||
break;
|
||||
case 4:
|
||||
SetStatus(flowNode, status, remark);
|
||||
MessageBox.Show("流程否决");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流向下一个节点
|
||||
/// </summary>
|
||||
/// <param name="stepid"></param>
|
||||
public static void Next(string stepid)
|
||||
{
|
||||
FlowNode nextNode = FlowNodes.FirstOrDefault(p => p.Id.ToString() == stepid);
|
||||
SetStatus(nextNode, 1);
|
||||
|
||||
switch (nextNode.Kind)
|
||||
{
|
||||
case NodeKinds.Start:
|
||||
SetStatus(nextNode, 100);
|
||||
Next(nextNode.NextStepId);
|
||||
break;
|
||||
case NodeKinds.End:
|
||||
SetStatus(nextNode, 100);
|
||||
MessageBox.Show("流程完成");
|
||||
break;
|
||||
case NodeKinds.Decide:
|
||||
foreach (var step in nextNode.SelectNextStep)
|
||||
{
|
||||
try
|
||||
{
|
||||
//按条件选择一个分支
|
||||
string express = step.Value.Replace("data.Flag", nextNode.Text);
|
||||
Expression e = new Expression(express);
|
||||
var result = e.calculate();
|
||||
if (result == 1)
|
||||
{
|
||||
SetStatus(nextNode, 100);
|
||||
Next(step.Key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
//如果表达式错了,就按第一个处理
|
||||
Next(nextNode.SelectNextStep.FirstOrDefault().Key);
|
||||
break;
|
||||
case NodeKinds.COBegin:
|
||||
foreach (var step in nextNode.SelectNextStep)//启动各个分支
|
||||
{
|
||||
SetStatus(nextNode, 100);
|
||||
Next(step.Key);
|
||||
}
|
||||
break;
|
||||
case NodeKinds.COEnd:
|
||||
foreach (var prestep in nextNode.PreStepId)
|
||||
{
|
||||
var step = FlowNodes.FirstOrDefault(p => p.Id.ToString() == prestep);
|
||||
if (step.Status != 100)//如果并行分支没有都完成,那么并行结束节点也未完成
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
SetStatus(nextNode, 100);
|
||||
Next(nextNode.NextStepId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流向上一个节点
|
||||
/// </summary>
|
||||
/// <param name="flowNode"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Pre(FlowNode flowNode)
|
||||
{
|
||||
if (flowNode.PreStepId != null && flowNode.PreStepId.Count == 1)
|
||||
{
|
||||
FlowNode preNode = FlowNodes.FirstOrDefault(p => p.Id.ToString() == flowNode.PreStepId[0]);
|
||||
if (preNode.Kind == NodeKinds.Middle)
|
||||
{
|
||||
SetStatus(preNode, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置颜色
|
||||
/// </summary>
|
||||
/// <param name="flowNode"></param>
|
||||
/// <param name="status"></param>
|
||||
/// <param name="remark"></param>
|
||||
public static void SetStatus(FlowNode flowNode, int status, string remark = null)
|
||||
{
|
||||
flowNode.Status = status;
|
||||
flowNode.Remark = remark;
|
||||
switch (status)
|
||||
{
|
||||
case 100:
|
||||
flowNode.Color = Colors.Green.ToString();
|
||||
break;
|
||||
case 0:
|
||||
flowNode.Color = Colors.Yellow.ToString();
|
||||
break;
|
||||
case 1:
|
||||
flowNode.Color = Colors.Orange.ToString();
|
||||
break;
|
||||
case 2:
|
||||
flowNode.Color = Colors.Red.ToString();
|
||||
break;
|
||||
case 3:
|
||||
flowNode.Color = Colors.Red.ToString();
|
||||
break;
|
||||
case 4:
|
||||
flowNode.Color = Colors.Red.ToString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using System.Xml.Serialization;
|
||||
using Util.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
|
||||
{
|
||||
public class FlowNodeDesignerItem : DesignerItemBase
|
||||
{
|
||||
public FlowNodeDesignerItem()
|
||||
{
|
||||
|
||||
}
|
||||
public FlowNodeDesignerItem(FlowNode item) : base(item)
|
||||
{
|
||||
if (item is MiddleFlowNode middleFlow)
|
||||
{
|
||||
UserIds = middleFlow.UserIds;
|
||||
RoleIds = middleFlow.RoleIds;
|
||||
ActType = middleFlow.ActType;
|
||||
}
|
||||
Color = item.Color;
|
||||
Kind = item.Kind;
|
||||
StateImage = item.StateImage;
|
||||
}
|
||||
|
||||
[XmlArray]
|
||||
public List<string> UserIds { get; set; }
|
||||
|
||||
[XmlArray]
|
||||
public List<string> RoleIds { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public string ActType { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public string Color { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public NodeKinds Kind { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public string StateImage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
|
||||
{
|
||||
public enum NodeKinds
|
||||
{
|
||||
[Description("节点")]
|
||||
Normal = 0,
|
||||
[Description("开始")]
|
||||
Start = 1,
|
||||
[Description("结束")]
|
||||
End = 2,
|
||||
[Description("中间节点")]
|
||||
Middle = 3,
|
||||
[Description("条件节点")]
|
||||
Decide = 4,
|
||||
[Description("并行开始")]
|
||||
COBegin = 5,
|
||||
[Description("并行结束")]
|
||||
COEnd = 6,
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
|
||||
{
|
||||
/// <summary>
|
||||
/// 前端SelectOption
|
||||
/// </summary>
|
||||
public class SelectOption
|
||||
{
|
||||
public string value { get; set; }
|
||||
public string text { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
using AIStudio.Wpf.ADiagram.Helpers;
|
||||
using AIStudio.Wpf.ADiagram.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Util.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
|
||||
{
|
||||
public class FlowNode : DesignerItemViewModelBase
|
||||
{
|
||||
protected IUIVisualizerService visualiserService;
|
||||
|
||||
public FlowNode(NodeKinds kind) : base()
|
||||
{
|
||||
Kind = kind;
|
||||
Text = Kind.GetDescription();
|
||||
ItemWidth = 80;
|
||||
ItemHeight = 40;
|
||||
|
||||
}
|
||||
|
||||
public FlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
ShowRotate = false;
|
||||
ShowText = true;
|
||||
IsReadOnlyText = true;
|
||||
|
||||
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
|
||||
}
|
||||
|
||||
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
|
||||
{
|
||||
base.LoadDesignerItemViewModel(parent, designerbase);
|
||||
|
||||
FlowNodeDesignerItem designer = designerbase as FlowNodeDesignerItem;
|
||||
this.Color = designer.Color;
|
||||
this.Kind = designer.Kind;
|
||||
this.StateImage = designer.StateImage;
|
||||
|
||||
if (this is MiddleFlowNode middle)
|
||||
{
|
||||
middle.UserIds = designer.UserIds;
|
||||
middle.RoleIds = designer.RoleIds;
|
||||
middle.ActType = designer.ActType;
|
||||
}
|
||||
}
|
||||
|
||||
private string _color;
|
||||
[Browsable(true)]
|
||||
public string Color
|
||||
{
|
||||
get { return _color; }
|
||||
set
|
||||
{
|
||||
SetProperty(ref _color, value);
|
||||
}
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
public NodeKinds Kind { get; set; }
|
||||
|
||||
[Browsable(false)]
|
||||
public string StateImage { get; set; }
|
||||
|
||||
#region 没有存起来,仅仅测试使用,实际这些代码应该都在服务端
|
||||
private int _status;
|
||||
|
||||
public int Status
|
||||
{
|
||||
get { return _status; }
|
||||
set
|
||||
{
|
||||
SetProperty(ref _status, value);
|
||||
}
|
||||
}
|
||||
|
||||
private string _remark;
|
||||
public string Remark
|
||||
{
|
||||
get { return _remark; }
|
||||
set
|
||||
{
|
||||
SetProperty(ref _remark, value);
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> PreStepId { get; set; }
|
||||
public string NextStepId { get; set; }
|
||||
public Dictionary<string, string> SelectNextStep { get; set; } = new Dictionary<string, string>();
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class StartFlowNode : FlowNode
|
||||
{
|
||||
public StartFlowNode() : base(NodeKinds.Start)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public StartFlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class EndFlowNode : FlowNode
|
||||
{
|
||||
public EndFlowNode() : base(NodeKinds.End)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EndFlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class DecideFlowNode : FlowNode
|
||||
{
|
||||
public DecideFlowNode() : base(NodeKinds.Decide)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DecideFlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class COBeginFlowNode : FlowNode
|
||||
{
|
||||
public COBeginFlowNode() : base(NodeKinds.COBegin)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public COBeginFlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class COEndFlowNode : FlowNode
|
||||
{
|
||||
public COEndFlowNode() : base(NodeKinds.COEnd)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public COEndFlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Models"
|
||||
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
|
||||
xmlns:demo="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Flowchart"
|
||||
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters">
|
||||
<converter:HtmlColorConverter x:Key="HtmlColorConverter"/>
|
||||
<s:ColorBrushConverter x:Key="ColorBrushConverter"/>
|
||||
|
||||
<ControlTemplate x:Key="NormalNodeStyle" TargetType="{x:Type ContentControl}">
|
||||
<Grid>
|
||||
<Border BorderThickness="1" BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
|
||||
<Grid>
|
||||
<Border HorizontalAlignment="Left" Width="3" Background="{Binding Color}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="StartNodeStyle" TargetType="{x:Type ContentControl}">
|
||||
<Grid>
|
||||
<Border CornerRadius="3" BorderThickness="1" BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
|
||||
<Grid>
|
||||
<Border HorizontalAlignment="Left" CornerRadius="3,0,0,3" Width="3" Background="{Binding Color}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="EndNodeStyle" TargetType="{x:Type ContentControl}">
|
||||
<Grid>
|
||||
<Border CornerRadius="3" BorderThickness="1" BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
|
||||
<Grid>
|
||||
<Border HorizontalAlignment="Left" CornerRadius="3,0,0,3" Width="3" Background="{Binding Color}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="MiddleNodeStyle" TargetType="{x:Type ContentControl}">
|
||||
<Grid>
|
||||
<Border BorderThickness="1" BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
|
||||
<Grid>
|
||||
<Border HorizontalAlignment="Left" Width="3" Background="{Binding Color}"/>
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
<TextBlock Text="{Binding Remark}" FontSize="9" RenderTransformOrigin="1,0.5" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="2">
|
||||
<TextBlock.RenderTransform>
|
||||
<TranslateTransform X="{Binding ItemWidth}"/>
|
||||
</TextBlock.RenderTransform>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="DecideNodeStyle" TargetType="{x:Type ContentControl}">
|
||||
<Grid>
|
||||
<Path Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" StrokeThickness="1" Stretch="Fill" Data="M 0,0.25 L 0.5 0 L 1,0.25 L 0.5,0.5 Z"></Path>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
|
||||
<ControlTemplate x:Key="COBeginNodeStyle" TargetType="{x:Type ContentControl}">
|
||||
<Grid>
|
||||
<Border BorderThickness="1" BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
|
||||
<Grid>
|
||||
<Border HorizontalAlignment="Left" Width="3" Background="{Binding Color}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="COEndNodeStyle" TargetType="{x:Type ContentControl}">
|
||||
<Grid>
|
||||
<Border BorderThickness="1" BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}">
|
||||
<Grid>
|
||||
<Border HorizontalAlignment="Left" Width="3" Background="{Binding Color}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="CustomFlowNodeStyle" TargetType="{x:Type ContentControl}">
|
||||
<Setter Property="Template" Value="{StaticResource NormalNodeStyle}" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Start">
|
||||
<Setter Property="Template" Value="{StaticResource StartNodeStyle}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="End">
|
||||
<Setter Property="Template" Value="{StaticResource EndNodeStyle}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Middle">
|
||||
<Setter Property="Template" Value="{StaticResource MiddleNodeStyle}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="Decide">
|
||||
<Setter Property="Template" Value="{StaticResource DecideNodeStyle}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="COBegin">
|
||||
<Setter Property="Template" Value="{StaticResource COBeginNodeStyle}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Kind}" Value="COEnd">
|
||||
<Setter Property="Template" Value="{StaticResource COEndNodeStyle}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
|
||||
<DataTemplate DataType="{x:Type model:FlowchartToolBoxData}">
|
||||
<Grid Width="{Binding Width}" Height="{Binding Height}">
|
||||
<Rectangle Name="Border"
|
||||
StrokeThickness="1"
|
||||
StrokeDashArray="2"
|
||||
Fill="Transparent"
|
||||
SnapsToDevicePixels="true"/>
|
||||
<Viewbox Stretch="Fill">
|
||||
<Grid>
|
||||
<ContentControl Style="{StaticResource CustomFlowNodeStyle}" Margin="2"/>
|
||||
<TextBlock Text="{Binding Text}" Margin="5" Foreground="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
<DataTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter TargetName="Border" Property="Stroke" Value="Gray"/>
|
||||
</Trigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type demo:FlowNode}">
|
||||
<Grid IsHitTestVisible="False">
|
||||
<ContentControl Style="{StaticResource CustomFlowNodeStyle}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type demo:MiddleFlowNodeData}">
|
||||
<Grid Background="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<StackPanel Margin="5" Orientation="Horizontal" >
|
||||
<RadioButton Margin="3" IsChecked="{Binding Status,Converter={converter:ConverterValueMapToBool Parameter=100}, ConverterParameter=100}" Content="通过"/>
|
||||
<RadioButton Margin="3" IsChecked="{Binding Status,Converter={converter:ConverterValueMapToBool Parameter=2}, ConverterParameter=2}" Content="驳回上一级"/>
|
||||
<RadioButton Margin="3" IsChecked="{Binding Status,Converter={converter:ConverterValueMapToBool Parameter=3}, ConverterParameter=3}" Content="驳回重提"/>
|
||||
<RadioButton Margin="3" IsChecked="{Binding Status,Converter={converter:ConverterValueMapToBool Parameter=4}, ConverterParameter=4}" Content="否决"/>
|
||||
</StackPanel>
|
||||
<TextBox Height="28" Margin="5" Text="{Binding Remark}" VerticalContentAlignment="Center"></TextBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,77 +0,0 @@
|
||||
using AIStudio.Wpf.ADiagram.Controls;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using Util.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
|
||||
{
|
||||
public class MiddleFlowNode : FlowNode
|
||||
{
|
||||
public MiddleFlowNode() : base(NodeKinds.Middle)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MiddleFlowNode(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private List<string> _userIds = new List<string>();
|
||||
[Browsable(true)]
|
||||
[StyleName("UserIdsStyle")]
|
||||
public List<string> UserIds
|
||||
{
|
||||
get { return _userIds; }
|
||||
set
|
||||
{
|
||||
SetProperty(ref _userIds, value);
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> _roleIds = new List<string>();
|
||||
[Browsable(true)]
|
||||
[StyleName("RoleIdsStyle")]
|
||||
public List<string> RoleIds
|
||||
{
|
||||
get { return _roleIds; }
|
||||
set
|
||||
{
|
||||
SetProperty(ref _roleIds, value);
|
||||
}
|
||||
}
|
||||
|
||||
private string _actType;
|
||||
[Browsable(true)]
|
||||
[StyleName("ActTypeStyle")]
|
||||
public string ActType
|
||||
{
|
||||
get { return _actType; }
|
||||
set
|
||||
{
|
||||
SetProperty(ref _actType, value);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ExecuteEditCommand(object param)
|
||||
{
|
||||
if (IsReadOnly == true) return;
|
||||
|
||||
if (Status == 1)
|
||||
{
|
||||
MiddleFlowNodeData data = new MiddleFlowNodeData();
|
||||
if (visualiserService.ShowDialog(data) == true)
|
||||
{
|
||||
FlowchartService.Approve(this, data.Status, data.Remark);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("该节点不能进行审批!!!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using AIStudio.Wpf.ADiagram.Models;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Flowchart
|
||||
{
|
||||
public class MiddleFlowNodeData : TitleBindableBase
|
||||
{
|
||||
public MiddleFlowNodeData()
|
||||
{
|
||||
Title = "审批";
|
||||
}
|
||||
|
||||
private int _status = 100;
|
||||
public int Status
|
||||
{
|
||||
get
|
||||
{
|
||||
return _status;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _status, value);
|
||||
}
|
||||
}
|
||||
|
||||
private string _remark;
|
||||
public string Remark
|
||||
{
|
||||
get
|
||||
{
|
||||
return _remark;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _remark, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Util.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Logical
|
||||
{
|
||||
public class LinkPoint: BindableBase
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
private double _value;
|
||||
public double Value
|
||||
{
|
||||
get { return _value; }
|
||||
set
|
||||
{
|
||||
SetProperty(ref _value, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Logical
|
||||
{
|
||||
public static class LogicalService
|
||||
{
|
||||
public static List<LinkPoint> LinkPoint { get; set; }
|
||||
|
||||
static LogicalService()
|
||||
{
|
||||
LinkPoint = new List<LinkPoint>();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
LinkPoint.Add(new Logical.LinkPoint { Id = Guid.NewGuid(), Name = $"测点{i}", Value = i });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Logical
|
||||
{
|
||||
public class LogicalGateItem : LogicalGateDesignerItemBase
|
||||
{
|
||||
public LogicalGateItem()
|
||||
{
|
||||
|
||||
}
|
||||
public LogicalGateItem(LogicalGateItemViewModel item) : base(item)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using AIStudio.Wpf.ADiagram.Models;
|
||||
using Util.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Logical
|
||||
{
|
||||
/// <summary>
|
||||
/// This is passed to the PopupWindow.xaml window, where a DataTemplate is used to provide the
|
||||
/// ContentControl with the look for this data. This class is also used to allow
|
||||
/// the popup to be cancelled without applying any changes to the calling ViewModel
|
||||
/// whos data will be updated if the PopupWindow.xaml window is closed successfully
|
||||
/// </summary>
|
||||
public class LinkPointDesignerItemData : TitleBindableBase
|
||||
{
|
||||
public LinkPointDesignerItemData(LinkPoint linkPoint)
|
||||
{
|
||||
this.LinkPoint = linkPoint;
|
||||
}
|
||||
|
||||
private LinkPoint _linkPoint;
|
||||
public LinkPoint LinkPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
return _linkPoint;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _linkPoint, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
using Util.DiagramDesigner;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using AIStudio.Wpf.ADiagram.Models;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Logical
|
||||
{
|
||||
/// <summary>
|
||||
/// This is passed to the PopupWindow.xaml window, where a DataTemplate is used to provide the
|
||||
/// ContentControl with the look for this data. This class is also used to allow
|
||||
/// the popup to be cancelled without applying any changes to the calling ViewModel
|
||||
/// whos data will be updated if the PopupWindow.xaml window is closed successfully
|
||||
/// </summary>
|
||||
public class LogicalGateItemData : TitleBindableBase
|
||||
{
|
||||
public LogicalGateItemData(IEnumerable<FullyCreatedConnectorInfo> inputvalues)
|
||||
{
|
||||
this.InputValues = new ObservableCollection<FullyCreatedConnectorInfo>(inputvalues);
|
||||
}
|
||||
|
||||
private ObservableCollection<FullyCreatedConnectorInfo> _inputValues;
|
||||
public ObservableCollection<FullyCreatedConnectorInfo> InputValues
|
||||
{
|
||||
get
|
||||
{
|
||||
return _inputValues;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _inputValues, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,745 +0,0 @@
|
||||
using AIStudio.Wpf.ADiagram.Services;
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Logical
|
||||
{
|
||||
public class LogicalGateItemViewModel : LogicalGateItemViewModelBase
|
||||
{
|
||||
protected IUIVisualizerService visualiserService;
|
||||
public LogicalGateItemViewModel(LogicalType logicalType) : base(logicalType)
|
||||
{
|
||||
ColorViewModel.FillColor.Color = Colors.Orange;
|
||||
}
|
||||
|
||||
public LogicalGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
|
||||
}
|
||||
|
||||
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
|
||||
{
|
||||
base.LoadDesignerItemViewModel(parent, designerbase);
|
||||
|
||||
LogicalGateDesignerItemBase designer = designerbase as LogicalGateDesignerItemBase;
|
||||
this.Value = designer.Value;
|
||||
}
|
||||
|
||||
|
||||
protected override void ExecuteEditCommand(object parameter)
|
||||
{
|
||||
if (LogicalType == LogicalType.Constant)
|
||||
{
|
||||
ValueDesignerItemData data = new ValueDesignerItemData(Value);
|
||||
if (visualiserService.ShowDialog(data) == true)
|
||||
{
|
||||
this.Value = data.Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogicalGateItemData data = new LogicalGateItemData(Input.Values);
|
||||
if (visualiserService.ShowDialog(data) == true)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AddGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public AddGateItemViewModel() : base(LogicalType.ADD)
|
||||
{
|
||||
}
|
||||
|
||||
public AddGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class SubtractGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public SubtractGateItemViewModel() : base(LogicalType.SUB)
|
||||
{
|
||||
}
|
||||
|
||||
public SubtractGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class MultiplyGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public MultiplyGateItemViewModel() : base(LogicalType.MUL)
|
||||
{
|
||||
}
|
||||
|
||||
public MultiplyGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class DivideGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
|
||||
public DivideGateItemViewModel() : base(LogicalType.DIV)
|
||||
{
|
||||
}
|
||||
|
||||
public DivideGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class AverageGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public AverageGateItemViewModel() : base(LogicalType.AVE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public AverageGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class MODGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public MODGateItemViewModel() : base(LogicalType.MOD)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MODGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class ANDGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public ANDGateItemViewModel() : base(LogicalType.AND)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ANDGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class ORGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public ORGateItemViewModel() : base(LogicalType.OR)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ORGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class XORGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public XORGateItemViewModel() : base(LogicalType.XOR)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public XORGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class NOTGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public NOTGateItemViewModel() : base(LogicalType.NOT)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public NOTGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class SHLGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public SHLGateItemViewModel() : base(LogicalType.SHL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SHLGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class SHRGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public SHRGateItemViewModel() : base(LogicalType.SHR)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SHRGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class ROLGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public ROLGateItemViewModel() : base(LogicalType.ROL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ROLGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class RORGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public RORGateItemViewModel() : base(LogicalType.ROR)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public RORGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class SELGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public SELGateItemViewModel() : base(LogicalType.SEL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SELGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class MAXGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public MAXGateItemViewModel() : base(LogicalType.MAX)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MAXGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class MINGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public MINGateItemViewModel() : base(LogicalType.MIN)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MINGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class LIMITGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public LIMITGateItemViewModel() : base(LogicalType.LIMIT)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public LIMITGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class GTGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public GTGateItemViewModel() : base(LogicalType.GT)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public GTGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class LTGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public LTGateItemViewModel() : base(LogicalType.GT)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public LTGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class GEGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public GEGateItemViewModel() : base(LogicalType.GE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public GEGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class LEGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public LEGateItemViewModel() : base(LogicalType.LE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public LEGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class EQGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public EQGateItemViewModel() : base(LogicalType.LE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EQGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class NEGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public NEGateItemViewModel() : base(LogicalType.NE)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public NEGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class ABSGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public ABSGateItemViewModel() : base(LogicalType.ABS)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ABSGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class SQRTGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public SQRTGateItemViewModel() : base(LogicalType.SQRT)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SQRTGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class LNGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public LNGateItemViewModel() : base(LogicalType.LN)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public LNGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class LOGGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public LOGGateItemViewModel() : base(LogicalType.LOG)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public LOGGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class EXPGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public EXPGateItemViewModel() : base(LogicalType.EXP)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EXPGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class SINGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public SINGateItemViewModel() : base(LogicalType.SIN)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SINGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class COSGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public COSGateItemViewModel() : base(LogicalType.COS)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public COSGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class TANGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public TANGateItemViewModel() : base(LogicalType.TAN)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public TANGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class ASINGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public ASINGateItemViewModel() : base(LogicalType.ASIN)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ASINGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class ACOSGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public ACOSGateItemViewModel() : base(LogicalType.ACOS)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ACOSGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class ATANGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public ATANGateItemViewModel() : base(LogicalType.ATAN)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ATANGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class EXPTGateItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public EXPTGateItemViewModel() : base(LogicalType.EXPT)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EXPTGateItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class ConstantDesignerItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public ConstantDesignerItemViewModel() : base(LogicalType.Constant)
|
||||
{
|
||||
ItemHeight = 28;
|
||||
}
|
||||
|
||||
public ConstantDesignerItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class InputItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public InputItemViewModel() : base(LogicalType.Input)
|
||||
{
|
||||
ItemHeight = 28;
|
||||
}
|
||||
|
||||
public InputItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
|
||||
{
|
||||
base.LoadDesignerItemViewModel(parent, designerbase);
|
||||
|
||||
LogicalGateDesignerItemBase designer = designerbase as LogicalGateDesignerItemBase;
|
||||
this.Value = designer.Value;
|
||||
LinkPoint = LogicalService.LinkPoint.FirstOrDefault(p => p.Id.ToString() == designer.Icon); //不想新增字段了,就用这个Icon保存自定义测点的Id吧。
|
||||
if (LinkPoint != null)
|
||||
{
|
||||
LinkPoint.Value = designer.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private LinkPoint _linkPoint;
|
||||
public LinkPoint LinkPoint
|
||||
{
|
||||
get { return _linkPoint; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _linkPoint, value))
|
||||
{
|
||||
Icon = _linkPoint?.Id.ToString();//不想新增字段了,就用这个Icon保存自定义测点的Id吧。
|
||||
Text = _linkPoint?.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ExecuteEditCommand(object parameter)
|
||||
{
|
||||
LinkPointDesignerItemData data = new LinkPointDesignerItemData(LinkPoint);
|
||||
if (visualiserService.ShowDialog(data) == true)
|
||||
{
|
||||
this.LinkPoint = data.LinkPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class OutputItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
public OutputItemViewModel() : base(LogicalType.Output)
|
||||
{
|
||||
ItemHeight = 28;
|
||||
}
|
||||
|
||||
public OutputItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
|
||||
{
|
||||
base.LoadDesignerItemViewModel(parent, designerbase);
|
||||
|
||||
LogicalGateDesignerItemBase designer = designerbase as LogicalGateDesignerItemBase;
|
||||
this.Value = designer.Value;
|
||||
LinkPoint = LogicalService.LinkPoint.FirstOrDefault(p => p.Id.ToString() == designer.Icon); //不想新增字段了,就用这个Icon保存自定义测点的Id吧。
|
||||
if (LinkPoint != null)
|
||||
{
|
||||
LinkPoint.Value = designer.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private LinkPoint _linkPoint;
|
||||
public LinkPoint LinkPoint
|
||||
{
|
||||
get { return _linkPoint; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _linkPoint, value))
|
||||
{
|
||||
Icon = _linkPoint?.Id.ToString();//不想新增字段了,就用这个Icon保存自定义测点的Id吧。
|
||||
Text = _linkPoint?.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ExecuteEditCommand(object parameter)
|
||||
{
|
||||
LinkPointDesignerItemData data = new LinkPointDesignerItemData(LinkPoint);
|
||||
if (visualiserService.ShowDialog(data) == true)
|
||||
{
|
||||
this.LinkPoint = data.LinkPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TimerDesignerItemViewModel : LogicalGateItemViewModel
|
||||
{
|
||||
private System.Timers.Timer readDataTimer = new System.Timers.Timer();
|
||||
public Action Do;
|
||||
|
||||
public TimerDesignerItemViewModel() : base(LogicalType.Time)
|
||||
{
|
||||
ItemHeight = 32;
|
||||
ItemWidth = 32;
|
||||
Value = 1;
|
||||
Start();
|
||||
BuildMenuOptions();
|
||||
}
|
||||
|
||||
public TimerDesignerItemViewModel(IDiagramViewModel parent, LogicalGateDesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
BuildMenuOptions();
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
MenuItemCommand = new SimpleCommand(ExecuteMenuItemCommand);
|
||||
base.Init();
|
||||
|
||||
readDataTimer.Elapsed += timeCycle;
|
||||
readDataTimer.Interval = 1000;
|
||||
}
|
||||
|
||||
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
|
||||
{
|
||||
base.LoadDesignerItemViewModel(parent, designerbase);
|
||||
|
||||
if (IsEnabled)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
IsEnabled = true;
|
||||
Output[0].ColorViewModel.FillColor.Color = Colors.Green;
|
||||
readDataTimer.Start();
|
||||
}
|
||||
|
||||
private void Stop()
|
||||
{
|
||||
IsEnabled = false;
|
||||
Output[0].ColorViewModel.FillColor.Color = Colors.Red;
|
||||
readDataTimer.Stop();
|
||||
}
|
||||
|
||||
private void ExecuteMenuItemCommand(object obj)
|
||||
{
|
||||
if ((obj as CinchMenuItem).IsChecked == true)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleCommand MenuItemCommand { get; private set; }
|
||||
private void BuildMenuOptions()
|
||||
{
|
||||
menuOptions = new ObservableCollection<CinchMenuItem>();
|
||||
CinchMenuItem menuItem = new CinchMenuItem();
|
||||
menuItem.Text = "启动";
|
||||
menuItem.IsCheckable = true;
|
||||
menuItem.IsChecked = IsEnabled;
|
||||
menuItem.Command = MenuItemCommand;
|
||||
menuItem.CommandParameter = menuItem;
|
||||
menuOptions.Add(menuItem);
|
||||
}
|
||||
|
||||
protected override void ExecuteEditCommand(object parameter)
|
||||
{
|
||||
ValueDesignerItemData data = new ValueDesignerItemData(Value);
|
||||
if (visualiserService.ShowDialog(data) == true)
|
||||
{
|
||||
this.Value = data.Value;
|
||||
readDataTimer.Interval = this.Value * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
private void timeCycle(object sender, EventArgs e)
|
||||
{
|
||||
Output.FirstOrDefault().Value.ConnectorValue += Value;
|
||||
if (Do != null)
|
||||
{
|
||||
Do();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
|
||||
readDataTimer.Dispose();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Logical"
|
||||
xmlns:gif="http://wpfanimatedgif.codeplex.com"
|
||||
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
|
||||
xmlns:dd="https://astudio.github.io/diagram"
|
||||
xmlns:Fluent="urn:fluent-ribbon"
|
||||
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
|
||||
|
||||
<converter:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
|
||||
<converter:DoubleToThickness x:Key="DoubleToThickness"/>
|
||||
<s:ColorBrushConverter x:Key="ColorBrushConverter"/>
|
||||
|
||||
<DataTemplate DataType="{x:Type model:LogicalGateItemViewModel}">
|
||||
<Grid IsHitTestVisible="False">
|
||||
<Rectangle StrokeThickness="1" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
|
||||
<TextBlock Text="{Binding LogicalType}" Foreground="{Binding FontViewModel.FontColor,Converter={StaticResource ColorBrushConverter}}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5"/>
|
||||
<TextBlock Text="{Binding OrderNumber,StringFormat={}{0}#}" Foreground="Blue" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="2"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type model:LogicalGateItemData}">
|
||||
<Grid Background="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
|
||||
<ListBox ItemsSource="{Binding InputValues}" AlternationCount="{Binding InputValues.Count}" Background="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="输入" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplatedParent.(ItemsControl.AlternationIndex)}" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBox Width="100" Text="{Binding ConnectorValue,Mode=TwoWay}"></TextBox>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type model:ConstantDesignerItemViewModel}">
|
||||
<Grid IsHitTestVisible="False">
|
||||
<Rectangle StrokeThickness="1" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
|
||||
<TextBlock Text="{Binding Value}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type model:ValueDesignerItemData}">
|
||||
<Grid Background="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="Value"
|
||||
Margin="5" />
|
||||
<TextBox Grid.Column="1"
|
||||
Text="{Binding Value}" VerticalAlignment="Center"
|
||||
Margin="5"
|
||||
FontSize="12"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type model:LinkPointDesignerItemData}">
|
||||
<Grid Background="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="LinkPoint"
|
||||
Margin="5" />
|
||||
<ComboBox Grid.Column="1"
|
||||
SelectedItem="{Binding LinkPoint}" ItemsSource="{x:Static model:LogicalService.LinkPoint}" VerticalAlignment="Center" DisplayMemberPath="Name"
|
||||
Margin="5"
|
||||
FontSize="12"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
|
||||
<DataTemplate DataType="{x:Type model:InputItemViewModel}">
|
||||
<Grid IsHitTestVisible="False">
|
||||
<Rectangle StrokeThickness="1" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
|
||||
<TextBlock Text="{Binding Text,TargetNullValue='[Null]'}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type model:OutputItemViewModel}">
|
||||
<Grid IsHitTestVisible="False">
|
||||
<Rectangle StrokeThickness="1" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
|
||||
<TextBlock Text="{Binding Text,TargetNullValue='[Null]'}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type model:TimerDesignerItemViewModel}">
|
||||
<Grid IsHitTestVisible="False">
|
||||
<Ellipse StrokeThickness="1" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
|
||||
<TextBlock Text="{Binding Value,StringFormat={}{0}s}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,32 +0,0 @@
|
||||
using AIStudio.Wpf.ADiagram.Models;
|
||||
using Util.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Logical
|
||||
{
|
||||
/// <summary>
|
||||
/// This is passed to the PopupWindow.xaml window, where a DataTemplate is used to provide the
|
||||
/// ContentControl with the look for this data. This class is also used to allow
|
||||
/// the popup to be cancelled without applying any changes to the calling ViewModel
|
||||
/// whos data will be updated if the PopupWindow.xaml window is closed successfully
|
||||
/// </summary>
|
||||
public class ValueDesignerItemData : TitleBindableBase
|
||||
{
|
||||
public ValueDesignerItemData(double value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
private double _value;
|
||||
public double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _value, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Util.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
public class PathDesignerItem : DesignerItemBase
|
||||
{
|
||||
public PathDesignerItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PathDesignerItem(DesignerItemViewModelBase item) : base(item) { }
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
public class PersistDesignerItem : DesignerItemBase
|
||||
{
|
||||
public PersistDesignerItem()
|
||||
{
|
||||
|
||||
}
|
||||
public PersistDesignerItem(PersistDesignerItemViewModel item) : base(item)
|
||||
{
|
||||
this.HostUrl = item.HostUrl;
|
||||
}
|
||||
|
||||
[XmlAttribute]
|
||||
public string HostUrl { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
public class SettingsDesignerItem : DesignerItemBase
|
||||
{
|
||||
public SettingsDesignerItem()
|
||||
{
|
||||
|
||||
}
|
||||
public SettingsDesignerItem(SettingsDesignerItemViewModel item) : base(item)
|
||||
{
|
||||
this.Setting = item.Setting;
|
||||
}
|
||||
|
||||
public string Setting { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using AIStudio.Wpf.ADiagram.Commands;
|
||||
using System.Windows.Input;
|
||||
using AIStudio.Wpf.ADiagram.Models;
|
||||
using ZXing;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
public class BarcodeDesignerItemData : TitleBindableBase
|
||||
{
|
||||
public BarcodeDesignerItemData()
|
||||
{
|
||||
|
||||
}
|
||||
public BarcodeDesignerItemData(BarcodeDesignerItemViewModel item)
|
||||
{
|
||||
this.Title = "二维码";
|
||||
this.Text = item.Text;
|
||||
this.Icon = item.Icon;
|
||||
this.Margin = item.Margin;
|
||||
this.Format = item.Format;
|
||||
}
|
||||
|
||||
public BarcodeFormat Format { get; set; }
|
||||
|
||||
private string _text;
|
||||
public string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
return _text;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _text, value);
|
||||
}
|
||||
}
|
||||
|
||||
private double _margin;
|
||||
|
||||
public double Margin
|
||||
{
|
||||
get
|
||||
{
|
||||
return _margin;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _margin, value);
|
||||
}
|
||||
}
|
||||
|
||||
private string _icon;
|
||||
public string Icon
|
||||
{
|
||||
get
|
||||
{
|
||||
return _icon;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _icon, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ICommand _iploadCommand;
|
||||
public ICommand UploadCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._iploadCommand ?? (this._iploadCommand = new DelegateCommand(() => this.Upload()));
|
||||
}
|
||||
}
|
||||
|
||||
private void Upload()
|
||||
{
|
||||
Microsoft.Win32.OpenFileDialog openFile = new Microsoft.Win32.OpenFileDialog();
|
||||
openFile.Filter = "图片|*.bmp;*.jpg;*.jpeg;*.gif;*.png";
|
||||
|
||||
if (openFile.ShowDialog() == true)
|
||||
{
|
||||
Icon = openFile.FileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
using AIStudio.Wpf.ADiagram.Services;
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows;
|
||||
using System.Globalization;
|
||||
using ZXing;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
public class BarcodeDesignerItemViewModel : DesignerItemViewModelBase
|
||||
{
|
||||
private IUIVisualizerService visualiserService;
|
||||
|
||||
public BarcodeDesignerItemViewModel() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public BarcodeDesignerItemViewModel(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
base.Init();
|
||||
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
|
||||
|
||||
}
|
||||
|
||||
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
|
||||
{
|
||||
base.LoadDesignerItemViewModel(parent, designerbase);
|
||||
|
||||
Format = (BarcodeFormat)Enum.Parse(typeof(BarcodeFormat), (designerbase as DesignerItemBase).Reserve.ToString());
|
||||
ShowText = false;
|
||||
}
|
||||
|
||||
public void AutoSize()
|
||||
{
|
||||
ItemWidth = 140;
|
||||
ItemHeight = 140;
|
||||
}
|
||||
|
||||
protected override void ExecuteEditCommand(object parameter)
|
||||
{
|
||||
EditData();
|
||||
}
|
||||
|
||||
public override bool InitData()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Icon))
|
||||
return EditData();
|
||||
return true;
|
||||
}
|
||||
|
||||
public BarcodeFormat Format { get; set; } = BarcodeFormat.QR_CODE;
|
||||
|
||||
public override bool EditData()
|
||||
{
|
||||
if (IsReadOnly == true) return false;
|
||||
|
||||
BarcodeDesignerItemData data = new BarcodeDesignerItemData(this);
|
||||
if (visualiserService.ShowDialog(data) == true)
|
||||
{
|
||||
bool needauto = Text == null;
|
||||
Text = data.Text;
|
||||
ShowText = false;
|
||||
Icon = data.Icon;
|
||||
Margin = data.Margin;
|
||||
if (needauto)
|
||||
{
|
||||
AutoSize();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Others"
|
||||
xmlns:gif="http://wpfanimatedgif.codeplex.com"
|
||||
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
|
||||
xmlns:dd="https://astudio.github.io/diagram"
|
||||
xmlns:Fluent="urn:fluent-ribbon"
|
||||
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
|
||||
|
||||
<converter:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
|
||||
<converter:DoubleToThickness x:Key="DoubleToThickness"/>
|
||||
<s:ColorBrushConverter x:Key="ColorBrushConverter"/>
|
||||
|
||||
|
||||
<DataTemplate DataType="{x:Type model:BarcodeDesignerItemViewModel}">
|
||||
<Viewbox Stretch="Fill" IsHitTestVisible="False">
|
||||
<controls:Barcode Width="{Binding ItemWidth}" Height="{Binding ItemHeight}" Padding="{Binding Margin,Converter={StaticResource DoubleToThickness}}" Text="{Binding Text}" Icon="{Binding Icon}" Format="{Binding Format}"/>
|
||||
</Viewbox>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- DataTemplate for Popup look and feel -->
|
||||
<DataTemplate DataType="{x:Type model:BarcodeDesignerItemData}">
|
||||
<Grid Width="550">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="20" />
|
||||
</Grid.RowDefinitions>
|
||||
<Label Grid.Row="0"
|
||||
Content="网页链接"
|
||||
Margin="5" />
|
||||
<DockPanel Grid.Row="1" >
|
||||
<Border BorderThickness="1" BorderBrush="Black" Margin="5" DockPanel.Dock="Right">
|
||||
<controls:Barcode Text="{Binding Text}" Icon="{Binding Icon}" Format="{Binding Format}" Width="140" Height="140" Padding="{Binding Margin,Converter={StaticResource DoubleToThickness}}" />
|
||||
</Border>
|
||||
<TextBox Text="{Binding Text,UpdateSourceTrigger=PropertyChanged}" TextWrapping="Wrap" DockPanel.Dock="Left" Margin="5"/>
|
||||
</DockPanel>
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal">
|
||||
<TextBlock Text="边界:" Margin="5" HorizontalAlignment="Center"/>
|
||||
<Fluent:Spinner Margin="5" DockPanel.Dock="Right" Width="60" Size="Small" Value="{Binding Margin}" Maximum="25" Minimum="0" Format="0 px" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Margin="5,5,50,5" Content="上传Logo" Command="{Binding UploadCommand}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
@@ -1,54 +0,0 @@
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using AIStudio.Wpf.ADiagram.Models;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
public class OutLineTextDesignerItemData : TitleBindableBase
|
||||
{
|
||||
public OutLineTextDesignerItemData()
|
||||
{
|
||||
|
||||
}
|
||||
public OutLineTextDesignerItemData(OutLineTextDesignerItemViewModel item)
|
||||
{
|
||||
this.Title = "矢量文本";
|
||||
this.Text = item.Text;
|
||||
this.FontViewModel = CopyHelper.Mapper<FontViewModel, IFontViewModel>(item.FontViewModel);
|
||||
}
|
||||
|
||||
private IFontViewModel _fontViewModel;
|
||||
public IFontViewModel FontViewModel
|
||||
{
|
||||
get
|
||||
{
|
||||
return _fontViewModel;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _fontViewModel, value);
|
||||
}
|
||||
}
|
||||
|
||||
private string _text;
|
||||
public string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
return _text;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _text, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
using AIStudio.Wpf.ADiagram.Services;
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows;
|
||||
using System.Globalization;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
public class OutLineTextDesignerItemViewModel : TextDesignerItemViewModel
|
||||
{
|
||||
private IUIVisualizerService visualiserService;
|
||||
|
||||
public OutLineTextDesignerItemViewModel(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public OutLineTextDesignerItemViewModel() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
|
||||
|
||||
FontViewModel.FontFamily = "Arial";
|
||||
FontViewModel.FontSize = 36;
|
||||
}
|
||||
|
||||
public void AutoSize()
|
||||
{
|
||||
var size = MeasureString();
|
||||
ItemWidth = size.Width;
|
||||
ItemHeight = size.Height;
|
||||
}
|
||||
|
||||
private Size MeasureString()
|
||||
{
|
||||
var formattedText = new FormattedText(
|
||||
Text,
|
||||
CultureInfo.CurrentUICulture,
|
||||
FlowDirection.LeftToRight,
|
||||
new Typeface(new FontFamily(FontViewModel.FontFamily), FontViewModel.FontStyle, FontViewModel.FontWeight, FontViewModel.FontStretch),
|
||||
FontViewModel.FontSize,
|
||||
Brushes.Black);
|
||||
|
||||
return new Size(formattedText.Width, formattedText.Height);
|
||||
}
|
||||
|
||||
protected override void ExecuteEditCommand(object parameter)
|
||||
{
|
||||
EditData();
|
||||
}
|
||||
|
||||
public override bool InitData()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
return EditData();
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool EditData()
|
||||
{
|
||||
if (IsReadOnly == true) return false;
|
||||
|
||||
OutLineTextDesignerItemData data = new OutLineTextDesignerItemData(this);
|
||||
if (visualiserService.ShowDialog(data) == true)
|
||||
{
|
||||
Text = data.Text;
|
||||
FontViewModel = CopyHelper.Mapper<FontViewModel, IFontViewModel>(data.FontViewModel);
|
||||
AutoSize();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Others"
|
||||
xmlns:gif="http://wpfanimatedgif.codeplex.com"
|
||||
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
|
||||
xmlns:dd="https://astudio.github.io/diagram"
|
||||
xmlns:Fluent="urn:fluent-ribbon"
|
||||
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
|
||||
|
||||
<converter:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
|
||||
<converter:DoubleToThickness x:Key="DoubleToThickness"/>
|
||||
<s:ColorBrushConverter x:Key="ColorBrushConverter"/>
|
||||
|
||||
<DataTemplate DataType="{x:Type model:OutLineTextDesignerItemViewModel}">
|
||||
<Viewbox Stretch="Fill" IsHitTestVisible="False">
|
||||
<controls:OutlineText StrokePosition="Outside"
|
||||
Text="{Binding Text}"
|
||||
FontSize="{Binding FontViewModel.FontSize}"
|
||||
FontFamily="{Binding FontViewModel.FontFamily}"
|
||||
FontWeight="{Binding FontViewModel.FontWeight}"
|
||||
FontStyle="{Binding FontViewModel.FontStyle}"
|
||||
FontStretch="{Binding FontViewModel.FontStretch}"
|
||||
TextDecorations="{Binding FontViewModel.TextDecorations}"
|
||||
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
StrokeThickness="{Binding ColorViewModel.LineWidth}"
|
||||
Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"/>
|
||||
</Viewbox>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- DataTemplate for Popup look and feel -->
|
||||
<DataTemplate DataType="{x:Type model:OutLineTextDesignerItemData}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Label Grid.Row="0"
|
||||
Content="添加文本"
|
||||
Margin="5" />
|
||||
<TextBox Grid.Row="1"
|
||||
Text="{Binding Text}"
|
||||
FontSize="{Binding ElementName=comboBoxFontSize,Path=SelectedItem}"
|
||||
FontFamily="{Binding ElementName=comboBoxFontName,Path=SelectedItem}"
|
||||
FontWeight="{Binding ElementName=buttonBold,Path=IsChecked,Converter={converter:ConverterBoolToValueMap Parameter='Regular'}, ConverterParameter='Bold'}"
|
||||
FontStyle="{Binding ElementName=buttonItalic,Path=IsChecked,Converter={converter:ConverterBoolToValueMap Parameter='Normal'}, ConverterParameter='Italic'}"
|
||||
TextDecorations="{Binding ElementName=buttonUnderline,Path=IsChecked,Converter={converter:ConverterBoolToValueMap Parameter='None'}, ConverterParameter='Underline'}"
|
||||
Height="100"
|
||||
Margin="5"
|
||||
TextWrapping="Wrap"/>
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal">
|
||||
<Fluent:ComboBox x:Name="comboBoxFontName"
|
||||
Margin="5"
|
||||
MinWidth="49"
|
||||
Height="22"
|
||||
BorderBrush="Gainsboro"
|
||||
IsTextSearchEnabled="True"
|
||||
ResizeMode="Vertical"
|
||||
KeyTip="FF"
|
||||
SizeDefinition="Small"
|
||||
ScrollViewer.CanContentScroll="False"
|
||||
ItemsSource="{x:Static dd:FontViewModel.FontFamilys}"
|
||||
SelectedItem="{Binding FontViewModel.FontFamily}">
|
||||
<Fluent:ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}"
|
||||
FontFamily="{Binding}" />
|
||||
</DataTemplate>
|
||||
</Fluent:ComboBox.ItemTemplate>
|
||||
</Fluent:ComboBox>
|
||||
<Fluent:ComboBox x:Name="comboBoxFontSize"
|
||||
Margin="5"
|
||||
Width="49"
|
||||
HorizontalAlignment="Left"
|
||||
Height="22"
|
||||
BorderBrush="Gainsboro"
|
||||
IsEditable="True"
|
||||
SizeDefinition="Small"
|
||||
ResizeMode="Vertical"
|
||||
KeyTip="FS"
|
||||
ItemsSource="{x:Static dd:FontViewModel.FontSizes}"
|
||||
SelectedItem="{Binding FontViewModel.FontSize}">
|
||||
<Fluent:ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding}"/>
|
||||
</DataTemplate>
|
||||
</Fluent:ComboBox.ItemTemplate>
|
||||
</Fluent:ComboBox>
|
||||
<Fluent:ToggleButton KeyTip="B"
|
||||
x:Name="buttonBold"
|
||||
Icon="pack://application:,,,/AIStudio.Wpf.ADiagram;component/Images/Bold.png"
|
||||
HorizontalAlignment="Left"
|
||||
SizeDefinition="Small"
|
||||
IsChecked="{Binding FontViewModel.FontWeight,Converter={converter:ConverterValueMapToBool Parameter='Regular'}, ConverterParameter='Bold'}"/>
|
||||
<Fluent:ToggleButton x:Name="buttonItalic"
|
||||
KeyTip="I"
|
||||
Icon="pack://application:,,,/AIStudio.Wpf.ADiagram;component/Images/Italic.png"
|
||||
HorizontalAlignment="Left"
|
||||
SizeDefinition="Small"
|
||||
IsChecked="{Binding FontViewModel.FontStyle,Converter={converter:ConverterValueMapToBool Parameter='Normal'}, ConverterParameter='Italic'}"/>
|
||||
<Fluent:ToggleButton x:Name="buttonUnderline"
|
||||
KeyTip="U"
|
||||
Icon="pack://application:,,,/AIStudio.Wpf.ADiagram;component/Images/Underline.png"
|
||||
HorizontalAlignment="Left"
|
||||
SizeDefinition="Small"
|
||||
IsChecked="{Binding FontViewModel.Underline}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
@@ -1,30 +0,0 @@
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
public class PathItemViewModel : DesignerItemViewModelBase
|
||||
{
|
||||
public PathItemViewModel() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PathItemViewModel(IDiagramViewModel parent, DesignerItemBase designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
this.ShowConnectors = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
|
||||
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Others"
|
||||
xmlns:convent="clr-namespace:AIStudio.Wpf.ADiagram.Converters">
|
||||
<convent:StringPathConverter x:Key="stringPathConverter"/>
|
||||
<s:ColorBrushConverter x:Key="ColorBrushConverter" />
|
||||
<Brush x:Key="ItemStroke">#FFD69436</Brush>
|
||||
<LinearGradientBrush x:Key="ItemBrush" StartPoint="0,0" EndPoint="0,1">
|
||||
<LinearGradientBrush.GradientStops>
|
||||
<GradientStop Color="#FAFBE9" Offset="0" />
|
||||
<GradientStop Color="Orange" Offset="1" />
|
||||
</LinearGradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
<Style x:Key="PathItemStyle" TargetType="Path">
|
||||
<!--<Setter Property="Fill" Value="{StaticResource ItemBrush}"/>
|
||||
<Setter Property="Stroke" Value="{StaticResource ItemStroke}"/>-->
|
||||
<Setter Property="Fill" Value="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"/>
|
||||
<Setter Property="Stroke" Value="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"/>
|
||||
<Setter Property="StrokeThickness" Value="1"/>
|
||||
<Setter Property="StrokeLineJoin" Value="Round"/>
|
||||
<Setter Property="Stretch" Value="Fill"/>
|
||||
<Setter Property="IsHitTestVisible" Value="True"/>
|
||||
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||
<Setter Property="Data" Value="{Binding Icon,Converter={StaticResource stringPathConverter}}"/>
|
||||
</Style>
|
||||
|
||||
<DataTemplate DataType="{x:Type model:PathItemViewModel}">
|
||||
<Grid>
|
||||
<Path Tag="Process" IsHitTestVisible="False" Style="{StaticResource PathItemStyle}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,39 +0,0 @@
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AIStudio.Wpf.ADiagram.Models;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
/// <summary>
|
||||
/// This is passed to the PopupWindow.xaml window, where a DataTemplate is used to provide the
|
||||
/// ContentControl with the look for this data. This class is also used to allow
|
||||
/// the popup to be cancelled without applying any changes to the calling ViewModel
|
||||
/// whos data will be updated if the PopupWindow.xaml window is closed successfully
|
||||
/// </summary>
|
||||
public class PersistDesignerItemData : TitleBindableBase
|
||||
{
|
||||
|
||||
|
||||
public PersistDesignerItemData(string currentHostUrl)
|
||||
{
|
||||
HostUrl = currentHostUrl;
|
||||
}
|
||||
|
||||
private string _hostUrl = "";
|
||||
public string HostUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hostUrl;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _hostUrl, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
using AIStudio.Wpf.ADiagram.Services;
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
public class PersistDesignerItemViewModel : DesignerItemViewModelBase
|
||||
{
|
||||
private IUIVisualizerService visualiserService;
|
||||
|
||||
public PersistDesignerItemViewModel(IDiagramViewModel parent, PersistDesignerItem designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PersistDesignerItemViewModel() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
|
||||
this.ShowConnectors = false;
|
||||
}
|
||||
|
||||
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
|
||||
{
|
||||
base.LoadDesignerItemViewModel(parent, designerbase);
|
||||
|
||||
PersistDesignerItem designer = designerbase as PersistDesignerItem;
|
||||
this.HostUrl = designer.HostUrl;
|
||||
}
|
||||
|
||||
|
||||
public string HostUrl { get; set; }
|
||||
|
||||
protected override void ExecuteEditCommand(object parameter)
|
||||
{
|
||||
PersistDesignerItemData data = new PersistDesignerItemData(HostUrl);
|
||||
if (visualiserService.ShowDialog(data) == true)
|
||||
{
|
||||
this.HostUrl = data.HostUrl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Others"
|
||||
xmlns:gif="http://wpfanimatedgif.codeplex.com"
|
||||
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
|
||||
xmlns:dd="https://astudio.github.io/diagram"
|
||||
xmlns:Fluent="urn:fluent-ribbon"
|
||||
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
|
||||
|
||||
<converter:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
|
||||
<converter:DoubleToThickness x:Key="DoubleToThickness"/>
|
||||
<s:ColorBrushConverter x:Key="ColorBrushConverter"/>
|
||||
|
||||
<ControlTemplate x:Key="infoButtonTemplate" TargetType="Button">
|
||||
<Grid x:Name="grid" Opacity="0.1">
|
||||
<Ellipse Width="16"
|
||||
Height="16"
|
||||
Stroke="Black"
|
||||
StrokeThickness="2"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Fill="White"/>
|
||||
<Label Content="i"
|
||||
FontWeight="Bold"
|
||||
FontStyle="Italic"
|
||||
HorizontalAlignment="Center"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="12" />
|
||||
</Grid>
|
||||
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver"
|
||||
Value="True">
|
||||
<Setter TargetName="grid"
|
||||
Property="Opacity"
|
||||
Value="1.0" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
|
||||
</ControlTemplate>
|
||||
|
||||
<!-- DataTemplate for DesignerCanvas look and feel -->
|
||||
<DataTemplate DataType="{x:Type model:PersistDesignerItemViewModel}">
|
||||
<Grid>
|
||||
<Image IsHitTestVisible="False"
|
||||
Stretch="Fill"
|
||||
Source="/AIStudio.Wpf.ADiagram;component/Images/Persist.png"
|
||||
Tag="setting" />
|
||||
<Button x:Name="btnSetting" HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
Margin="5"
|
||||
Template="{StaticResource infoButtonTemplate}"
|
||||
Command="{Binding EditCommand}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- DataTemplate for Popup look and feel -->
|
||||
<DataTemplate DataType="{x:Type model:PersistDesignerItemData}">
|
||||
<Grid Background="{DynamicResource Fluent.Ribbon.Brushes.AccentBaseColorBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0"
|
||||
Content="HostUrl"
|
||||
Margin="5" />
|
||||
<TextBox Grid.Row="1"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{Binding HostUrl}"
|
||||
Width="150"
|
||||
Margin="5" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,39 +0,0 @@
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AIStudio.Wpf.ADiagram.Models;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
/// <summary>
|
||||
/// This is passed to the PopupWindow.xaml window, where a DataTemplate is used to provide the
|
||||
/// ContentControl with the look for this data. This class is also used to allow
|
||||
/// the popup to be cancelled without applying any changes to the calling ViewModel
|
||||
/// whos data will be updated if the PopupWindow.xaml window is closed successfully
|
||||
/// </summary>
|
||||
public class SettingsDesignerItemData : TitleBindableBase
|
||||
{
|
||||
|
||||
|
||||
public SettingsDesignerItemData(string currentSetting1)
|
||||
{
|
||||
Setting1 = currentSetting1;
|
||||
}
|
||||
|
||||
private string _setting1 = "";
|
||||
public string Setting1
|
||||
{
|
||||
get
|
||||
{
|
||||
return _setting1;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _setting1, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using AIStudio.Wpf.ADiagram.Services;
|
||||
using Util.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
public class SettingsDesignerItemViewModel : DesignerItemViewModelBase
|
||||
{
|
||||
private IUIVisualizerService visualiserService;
|
||||
|
||||
public SettingsDesignerItemViewModel(IDiagramViewModel parent, SettingsDesignerItem designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SettingsDesignerItemViewModel() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
|
||||
this.ShowConnectors = false;
|
||||
}
|
||||
|
||||
protected override void LoadDesignerItemViewModel(IDiagramViewModel parent, SelectableDesignerItemBase designerbase)
|
||||
{
|
||||
base.LoadDesignerItemViewModel(parent, designerbase);
|
||||
|
||||
SettingsDesignerItem designer = designerbase as SettingsDesignerItem;
|
||||
this.Setting = designer.Setting;
|
||||
}
|
||||
|
||||
public String Setting{ get; set; }
|
||||
|
||||
protected override void ExecuteEditCommand(object parameter)
|
||||
{
|
||||
SettingsDesignerItemData data = new SettingsDesignerItemData(Setting);
|
||||
if (visualiserService.ShowDialog(data) == true)
|
||||
{
|
||||
this.Setting = data.Setting1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Others"
|
||||
xmlns:gif="http://wpfanimatedgif.codeplex.com"
|
||||
xmlns:converter="clr-namespace:AIStudio.Wpf.ADiagram.Converters"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.ADiagram.Controls"
|
||||
xmlns:dd="https://astudio.github.io/diagram"
|
||||
xmlns:Fluent="urn:fluent-ribbon"
|
||||
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
|
||||
|
||||
<converter:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
|
||||
<converter:DoubleToThickness x:Key="DoubleToThickness"/>
|
||||
<s:ColorBrushConverter x:Key="ColorBrushConverter"/>
|
||||
|
||||
<ControlTemplate x:Key="infoButtonTemplate" TargetType="Button">
|
||||
<Grid x:Name="grid" Opacity="0.1">
|
||||
<Ellipse Width="16"
|
||||
Height="16"
|
||||
Stroke="Black"
|
||||
StrokeThickness="2"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Fill="White"/>
|
||||
<Label Content="i"
|
||||
FontWeight="Bold"
|
||||
FontStyle="Italic"
|
||||
HorizontalAlignment="Center"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="12" />
|
||||
</Grid>
|
||||
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver"
|
||||
Value="True">
|
||||
<Setter TargetName="grid"
|
||||
Property="Opacity"
|
||||
Value="1.0" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
|
||||
</ControlTemplate>
|
||||
|
||||
<!-- DataTemplate for DesignerCanvas look and feel -->
|
||||
<DataTemplate DataType="{x:Type model:SettingsDesignerItemViewModel}">
|
||||
<Grid>
|
||||
<Image IsHitTestVisible="False"
|
||||
Stretch="Fill"
|
||||
Source="/AIStudio.Wpf.ADiagram;component/Images/Setting.png"
|
||||
Tag="setting" />
|
||||
<Button HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
Margin="5"
|
||||
Template="{StaticResource infoButtonTemplate}"
|
||||
Command="{Binding EditCommand}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- DataTemplate for Popup look and feel -->
|
||||
<DataTemplate DataType="{x:Type model:SettingsDesignerItemData}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0"
|
||||
Content="Setting1"
|
||||
Margin="5" />
|
||||
<TextBox Grid.Row="1"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{Binding Setting}"
|
||||
Width="150"
|
||||
Margin="5" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Util.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Demos.Others
|
||||
{
|
||||
public class SvgDesignerItemViewModel: MediaItemViewModel
|
||||
{
|
||||
protected override string Filter { get; set; } = "Svg|*.svg";
|
||||
|
||||
public SvgDesignerItemViewModel() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public SvgDesignerItemViewModel(IDiagramViewModel parent, MediaDesignerItem designer) : base(parent, designer)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:Util.DiagramDesigner;assembly=Util.DiagramDesigner"
|
||||
xmlns:model="clr-namespace:AIStudio.Wpf.ADiagram.Demos.Others"
|
||||
xmlns:svg="clr-namespace:Svg2XamlTestExtension;assembly=Svg2XamlTestExtension">
|
||||
<s:ColorBrushConverter x:Key="ColorBrushConverter" />
|
||||
|
||||
<DataTemplate DataType="{x:Type model:SvgDesignerItemViewModel}">
|
||||
<Grid IsHitTestVisible="False">
|
||||
<svg:PackSvg Width="Auto" Height="Auto" Path="{Binding Icon}" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
@@ -21,7 +21,7 @@
|
||||
"ItemWidth": 65.0,
|
||||
"ItemHeight": 65.0,
|
||||
"Icon": "M 0,0 H 60 V 40 C 30,30 30,50 0,40 Z",
|
||||
"ItemTypeName": "AIStudio.Wpf.ADiagram.Demos.Others.PathItemViewModel",
|
||||
"ItemTypeName": "AIStudio.Wpf.BaseDiagram.Extensions.ViewModels.PathItemViewModel",
|
||||
"Id": "da395032-ad9e-4dab-a035-f59bed5cb4c4",
|
||||
"ZIndex": 0,
|
||||
"IsGroup": false,
|
||||
@@ -93,76 +93,6 @@
|
||||
],
|
||||
"FlowNodeDesignerItems": [
|
||||
],
|
||||
"AllDesignerItems": [
|
||||
{
|
||||
"Left": 132.80000000000007,
|
||||
"Top": 101.26000022888184,
|
||||
"Margin": 0.0,
|
||||
"ItemWidth": 65.0,
|
||||
"ItemHeight": 65.0,
|
||||
"Icon": "M 0,0 H 60 V 40 C 30,30 30,50 0,40 Z",
|
||||
"ItemTypeName": "AIStudio.Wpf.ADiagram.Demos.Others.PathItemViewModel",
|
||||
"Id": "da395032-ad9e-4dab-a035-f59bed5cb4c4",
|
||||
"ZIndex": 0,
|
||||
"IsGroup": false,
|
||||
"ParentId": "00000000-0000-0000-0000-000000000000",
|
||||
"Text": "欢迎来到AIStudio画板",
|
||||
"ColorItem": {
|
||||
"LineColor": {
|
||||
"BrushType": 1,
|
||||
"Color": "#FF808080",
|
||||
"GradientStop": null,
|
||||
"Offset": null,
|
||||
"Image": null,
|
||||
"SubType": 0,
|
||||
"StartPoint": "0,0",
|
||||
"EndPoint": "0,0",
|
||||
"Opacity": 1.0,
|
||||
"LinearOrientation": 0,
|
||||
"RadialOrientation": 0,
|
||||
"Angle": 0
|
||||
},
|
||||
"FillColor": {
|
||||
"BrushType": 1,
|
||||
"Color": "#FFFFA500",
|
||||
"GradientStop": null,
|
||||
"Offset": null,
|
||||
"Image": null,
|
||||
"SubType": 0,
|
||||
"StartPoint": "0,0",
|
||||
"EndPoint": "0,0",
|
||||
"Opacity": 1.0,
|
||||
"LinearOrientation": 0,
|
||||
"RadialOrientation": 0,
|
||||
"Angle": 0
|
||||
},
|
||||
"ShadowColor": "#00FFFFFF",
|
||||
"LineWidth": 1.0,
|
||||
"LeftArrowPathStyle": 0,
|
||||
"RightArrowPathStyle": 1,
|
||||
"LeftArrowSizeStyle": 10,
|
||||
"RightArrowSizeStyle": 10
|
||||
},
|
||||
"FontItem": {
|
||||
"FontWeight": "Normal",
|
||||
"FontStyle": "Normal",
|
||||
"FontStretch": "Normal",
|
||||
"Underline": false,
|
||||
"Strikethrough": false,
|
||||
"OverLine": false,
|
||||
"FontColor": "#FF000000",
|
||||
"FontFamily": "Arial",
|
||||
"FontSize": 11.0,
|
||||
"FontObject": "Arial, 11pt",
|
||||
"TextEffectColor": "#00FFFFFF",
|
||||
"HighlightColor": "#00FFFFFF",
|
||||
"FontCase": 0,
|
||||
"HorizontalAlignment": 1,
|
||||
"VerticalAlignment": 1,
|
||||
"LineHeight": 0.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"ConnectionIds": [
|
||||
],
|
||||
"Connections": [
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Helpers
|
||||
{
|
||||
public class EnumHelper : DependencyObject
|
||||
{
|
||||
public static Type GetEnum(DependencyObject obj)
|
||||
{
|
||||
return (Type)obj.GetValue(EnumProperty);
|
||||
}
|
||||
|
||||
public static void SetEnum(DependencyObject obj, string value)
|
||||
{
|
||||
obj.SetValue(EnumProperty, value);
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Enum. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty EnumProperty =
|
||||
DependencyProperty.RegisterAttached("Enum", typeof(Type), typeof(EnumHelper), new PropertyMetadata(null, OnEnumChanged));
|
||||
|
||||
private static void OnEnumChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var control = sender as ItemsControl;
|
||||
|
||||
if (control != null)
|
||||
{
|
||||
if (e.NewValue != null)
|
||||
{
|
||||
var _enum = Enum.GetValues(e.NewValue as Type);
|
||||
control.ItemsSource = _enum;
|
||||
control.AlternationCount = _enum.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Helpers
|
||||
{
|
||||
public class NewNameHelper
|
||||
{
|
||||
public static string GetNewName(IEnumerable<string> names, string firstName = null)
|
||||
{
|
||||
string result = string.Empty;
|
||||
int i = 1;
|
||||
if (firstName == null)
|
||||
{
|
||||
firstName = "新建-";
|
||||
}
|
||||
|
||||
result = firstName + i;
|
||||
|
||||
while (names.Any(o => { return o == result; })) //存在同名则继续累加
|
||||
{
|
||||
result = firstName + ++i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
internal static class SafeNativeMethods
|
||||
{
|
||||
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int StrCmpLogicalW(string psz1, string psz2);
|
||||
}
|
||||
|
||||
public sealed class NaturalStringComparer : IComparer<string>
|
||||
{
|
||||
public int Compare(string a, string b)
|
||||
{
|
||||
return SafeNativeMethods.StrCmpLogicalW(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NaturalFileInfoNameComparer : IComparer<FileInfo>
|
||||
{
|
||||
public int Compare(FileInfo a, FileInfo b)
|
||||
{
|
||||
return SafeNativeMethods.StrCmpLogicalW(a.Name, b.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Helpers
|
||||
{
|
||||
public class TypeHelper
|
||||
{
|
||||
|
||||
public static Type GetType(string typeName)
|
||||
{
|
||||
|
||||
Type type = null;
|
||||
|
||||
Assembly[] assemblyArray = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
int assemblyArrayLength = assemblyArray.Length;
|
||||
|
||||
for (int i = 0; i < assemblyArrayLength; ++i)
|
||||
{
|
||||
|
||||
type = assemblyArray[i].GetType(typeName);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; (i < assemblyArrayLength); ++i)
|
||||
{
|
||||
Type[] typeArray = assemblyArray[i].GetTypes();
|
||||
int typeArrayLength = typeArray.Length;
|
||||
for (int j = 0; j < typeArrayLength; ++j)
|
||||
{
|
||||
if (typeArray[j].Name.Equals(typeName))
|
||||
{
|
||||
return typeArray[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Helpers
|
||||
{
|
||||
public class XmlSerializeHelper
|
||||
{
|
||||
public static string XmlSerialize<T>(T obj)
|
||||
{
|
||||
using (StringWriter sw = new StringWriter())
|
||||
{
|
||||
Type t = obj.GetType();
|
||||
XmlSerializer serializer = new XmlSerializer(obj.GetType());
|
||||
serializer.Serialize(sw, obj);
|
||||
sw.Close();
|
||||
return sw.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public static T DESerializer<T>(string strXML) where T : class
|
||||
{
|
||||
try
|
||||
{
|
||||
using (StringReader sr = new StringReader(strXML))
|
||||
{
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(T));
|
||||
return serializer.Deserialize(sr) as T;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Enums
|
||||
namespace AIStudio.Wpf.ADiagram.Models
|
||||
{
|
||||
public enum ColorType
|
||||
{
|
||||
@@ -7,9 +7,12 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using AIStudio.Wpf.ADiagram.Demos.Flowchart;
|
||||
using AIStudio.Wpf.ADiagram.Demos.Others;
|
||||
using AIStudio.Wpf.Flowchart;
|
||||
using AIStudio.Wpf.BaseDiagram.Extensions.ViewModels;
|
||||
using AIStudio.Wpf.BaseDiagram.Extensions.Models;
|
||||
using Newtonsoft.Json;
|
||||
using AIStudio.Wpf.Flowchart.Models;
|
||||
using AIStudio.Wpf.Flowchart.ViewModels;
|
||||
|
||||
namespace AIStudio.Wpf.ADiagram.Models
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user