mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-02 07:06:37 +08:00
整理整理
This commit is contained in:
BIN
AIStudio.Wpf.DiagramDesigner.Additionals/A.ico
Normal file
BIN
AIStudio.Wpf.DiagramDesigner.Additionals/A.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
AIStudio.Wpf.DiagramDesigner.Additionals/A.png
Normal file
BIN
AIStudio.Wpf.DiagramDesigner.Additionals/A.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,40 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<Company>AIStudio.Wpf.Controls</Company>
|
||||
<Authors>akwkevin</Authors>
|
||||
<PackageProjectUrl>https://gitee.com/akwkevin</PackageProjectUrl>
|
||||
<PackageIcon>A.png</PackageIcon>
|
||||
<PackageIconUrl />
|
||||
<NeutralLanguage />
|
||||
<Version>1.0.1</Version>
|
||||
<Description>一个Wpf的Diagram控件帮助库</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Fluent.Ribbon" Version="8.0.3" />
|
||||
<PackageReference Include="MahApps.Metro.IconPacks" Version="4.8.0" />
|
||||
<PackageReference Include="AIStudio.Wpf.Svg2XamlExtension" Version="1.2.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AIStudio.Wpf.DiagramDesigner\AIStudio.Wpf.DiagramDesigner.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="A.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="zxing.core">
|
||||
<HintPath>DLL\zxing.core.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,905 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
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.DiagramDesigner.Additionals.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
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.DiagramDesigner.Additionals.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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
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.DiagramDesigner.Additionals.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<UserControl x:Class="AIStudio.Wpf.DiagramDesigner.Additionals.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.DiagramDesigner.Additionals.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>
|
||||
@@ -0,0 +1,129 @@
|
||||
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.DiagramDesigner.Additionals.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<UserControl x:Class="AIStudio.Wpf.DiagramDesigner.Additionals.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.DiagramDesigner.Additionals.Controls"
|
||||
xmlns:Fluent="urn:fluent-ribbon"
|
||||
xmlns:converter="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Converters"
|
||||
xmlns:helper="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals"
|
||||
xmlns:dd="https://gitee.com/akwkevin/aistudio.-wpf.-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>
|
||||
@@ -0,0 +1,46 @@
|
||||
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 AIStudio.Wpf.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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 AIStudio.Wpf.DiagramDesigner.GradientStop target)
|
||||
{
|
||||
ColorObject.SelectedGradientStop = target;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:options="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
||||
mc:Ignorable="options d">
|
||||
<!-- Matadata -->
|
||||
<system:String x:Key="Theme.Name">Light.Blue</system:String>
|
||||
<system:String x:Key="Theme.Origin">Fluent.Ribbon</system:String>
|
||||
<system:String x:Key="Theme.DisplayName">Blue (Light)</system:String>
|
||||
<system:String x:Key="Theme.BaseColorScheme">Light</system:String>
|
||||
<system:String x:Key="Theme.ColorScheme">Blue</system:String>
|
||||
<system:String x:Key="Theme.AlternativeColorScheme">Blue</system:String>
|
||||
|
||||
<Color x:Key="Theme.PrimaryAccentColor">#FF0078D7</Color>
|
||||
<SolidColorBrush x:Key="Theme.ShowcaseBrush" Color="#FF0078D7" options:Freeze="True" />
|
||||
<system:Boolean x:Key="Theme.IsHighContrast">False</system:Boolean>
|
||||
|
||||
<!-- COLORS -->
|
||||
|
||||
<!-- Accent colors -->
|
||||
<Color x:Key="Fluent.Ribbon.Colors.AccentBaseColor">#FF0078D7</Color>
|
||||
<!--80%-->
|
||||
<Color x:Key="Fluent.Ribbon.Colors.AccentColor80">#CC0078D7</Color>
|
||||
<!--60%-->
|
||||
<Color x:Key="Fluent.Ribbon.Colors.AccentColor60">#990078D7</Color>
|
||||
<!--40%-->
|
||||
<Color x:Key="Fluent.Ribbon.Colors.AccentColor40">#660078D7</Color>
|
||||
<!--20%-->
|
||||
<Color x:Key="Fluent.Ribbon.Colors.AccentColor20">#330078D7</Color>
|
||||
|
||||
<Color x:Key="Fluent.Ribbon.Colors.HighlightColor">#FF086F9E</Color>
|
||||
|
||||
<!-- Base colors -->
|
||||
<Color x:Key="BlackColor">#FF000000</Color>
|
||||
<Color x:Key="BlackColor20">#51000000</Color>
|
||||
<Color x:Key="WhiteColor">#FFFFFFFF</Color>
|
||||
<Color x:Key="WhiteColor20">#51FFFFFF</Color>
|
||||
<Color x:Key="Gray1">#FF333333</Color>
|
||||
<Color x:Key="Gray2">#FF7F7F7F</Color>
|
||||
<Color x:Key="Gray3">#FF9D9D9D</Color>
|
||||
<Color x:Key="Gray4">#FFA59F93</Color>
|
||||
<Color x:Key="Gray5">#FFB9B9B9</Color>
|
||||
<Color x:Key="Gray6">#FFCCCCCC</Color>
|
||||
<Color x:Key="Gray7">#FFD8D8D9</Color>
|
||||
<Color x:Key="Gray8">#FFE0E0E0</Color>
|
||||
<Color x:Key="Gray9">#5EC9C9C9</Color>
|
||||
<Color x:Key="Gray10">#FFF7F7F7</Color>
|
||||
|
||||
<Color x:Key="TransparentWhiteColor">#00FFFFFF</Color>
|
||||
<Color x:Key="Fluent.Ribbon.Colors.HighTransparentWhiteColor">#17FFFFFF</Color>
|
||||
|
||||
<!-- Foreground -->
|
||||
<Color x:Key="Fluent.Ribbon.Colors.IdealForegroundColor">White</Color>
|
||||
<Color x:Key="Fluent.Ribbon.Colors.DarkIdealForegroundDisabledColor">#ADADAD</Color>
|
||||
|
||||
<!-- Misc colors -->
|
||||
<Color x:Key="Fluent.Ribbon.Colors.ExtremeHighlightColor">#FFFFD232</Color>
|
||||
<Color x:Key="Fluent.Ribbon.Colors.DarkExtremeHighlightColor">#FFF29536</Color>
|
||||
|
||||
<!-- END COLORS -->
|
||||
|
||||
<!-- BRUSHES -->
|
||||
|
||||
<!-- Accent brushes -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.AccentBaseColorBrush" Color="{StaticResource Fluent.Ribbon.Colors.AccentBaseColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.AccentColorBrush80" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor80}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.AccentColorBrush60" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor60}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.AccentColorBrush40" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor40}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.AccentColorBrush20" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor20}" options:Freeze="True" />
|
||||
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.HighlightBrush" Color="{StaticResource Fluent.Ribbon.Colors.HighlightColor}" options:Freeze="True" />
|
||||
|
||||
<!-- Misc brushes -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ExtremeHighlightBrush" Color="{StaticResource Fluent.Ribbon.Colors.ExtremeHighlightColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.DarkExtremeHighlightBrush" Color="{StaticResource Fluent.Ribbon.Colors.DarkExtremeHighlightColor}" options:Freeze="True" />
|
||||
|
||||
<!-- Base brushes -->
|
||||
<SolidColorBrush x:Key="WhiteBrush" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="WhiteBrush20" Color="{StaticResource WhiteColor20}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="BlackBrush" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="BlackBrush20" Color="{StaticResource BlackColor20}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="GrayBrush1" Color="{StaticResource Gray1}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="GrayBrush2" Color="{StaticResource Gray2}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="GrayBrush3" Color="{StaticResource Gray3}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="GrayBrush4" Color="{StaticResource Gray4}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="GrayBrush5" Color="{StaticResource Gray5}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="GrayBrush6" Color="{StaticResource Gray6}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="GrayBrush7" Color="{StaticResource Gray7}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="GrayBrush8" Color="{StaticResource Gray8}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="GrayBrush9" Color="{StaticResource Gray9}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="GrayBrush10" Color="{StaticResource Gray10}" options:Freeze="True" />
|
||||
|
||||
<SolidColorBrush x:Key="TransparentWhiteBrush" Color="{StaticResource TransparentWhiteColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="HighTransparentWhiteBrush" Color="{StaticResource Fluent.Ribbon.Colors.HighTransparentWhiteColor}" options:Freeze="True" />
|
||||
|
||||
<!-- Foreground -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.IdealForegroundColorBrush" Color="{StaticResource Fluent.Ribbon.Colors.IdealForegroundColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.IdealForegroundDisabledBrush" Color="{StaticResource Fluent.Ribbon.Colors.IdealForegroundColor}" Opacity="0.4" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.DarkIdealForegroundDisabledBrush" Color="{StaticResource Fluent.Ribbon.Colors.DarkIdealForegroundDisabledColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.LabelTextBrush" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
|
||||
<!-- Generic control brushes -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Control.BorderBrush" Color="{StaticResource Gray6}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Control.Disabled.BorderBrush" Color="{StaticResource Gray5}" options:Freeze="True" />
|
||||
|
||||
<!-- Backstage -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Backstage.Background" Color="{StaticResource Fluent.Ribbon.Colors.AccentBaseColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Backstage.Foreground" Color="{StaticResource Fluent.Ribbon.Colors.IdealForegroundColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Backstage.BackButton.Background" Color="Transparent" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Backstage.BackButton.Foreground" Color="{StaticResource Fluent.Ribbon.Colors.IdealForegroundColor}" options:Freeze="True" />
|
||||
|
||||
<!-- BackstageTabControl -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.BackstageTabControl.Button.MouseOver.Background" Color="{StaticResource BlackColor20}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.BackstageTabControl.ItemsPanelBackground" Color="{StaticResource Fluent.Ribbon.Colors.AccentBaseColor}" options:Freeze="True" />
|
||||
|
||||
<!-- BackstageTabItem -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.BackstageTabItem.Header.Foreground" Color="{StaticResource Fluent.Ribbon.Colors.IdealForegroundColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.BackstageTabItem.MouseOver.Background" Color="{StaticResource BlackColor20}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.BackstageTabItem.Selected.Background" Color="{StaticResource WhiteColor20}" options:Freeze="True" />
|
||||
|
||||
<!-- Button -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Button.MouseOver.BorderBrush" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor40}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Button.MouseOver.Background" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor20}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Button.Pressed.BorderBrush" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor60}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Button.Pressed.Background" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor40}" options:Freeze="True" />
|
||||
|
||||
<!-- ToggleButton -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ToggleButton.Checked.Background" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor20}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ToggleButton.Checked.BorderBrush" Color="{StaticResource Fluent.Ribbon.Colors.HighlightColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ToggleButton.CheckedMouseOver.Background" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor20}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ToggleButton.CheckedMouseOver.BorderBrush" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor60}" options:Freeze="True" />
|
||||
|
||||
<!-- CheckBox -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.CheckBox.BorderBrush" Color="{StaticResource Gray3}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.CheckBox.Background" Color="{StaticResource Gray10}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.CheckBox.MouseOver.Stroke" Color="{StaticResource Gray1}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.CheckBox.Pressed.Stroke" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
|
||||
<!-- ColorGallery -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ColorGallery.Background" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ColorGallery.Item.BorderBrush" Color="{StaticResource Gray8}" options:Freeze="True" />
|
||||
|
||||
<!-- DropDown -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.DropDown.BackgroundBrush" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.DropDown.BorderBrush" Color="{StaticResource Gray5}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.DropDown.Resize.BorderBrush" Color="{StaticResource Gray7}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.DropDown.Resize.BackgroundBrush" Color="{StaticResource Gray8}" options:Freeze="True" />
|
||||
|
||||
<!-- Gallery -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Gallery.Header.Background" Color="{StaticResource Gray3}" options:Freeze="True" />
|
||||
|
||||
<!-- GalleryGroupContainer -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.GalleryGroupContainer.Header.Background" Color="{StaticResource Gray8}" options:Freeze="True" />
|
||||
|
||||
<!-- GalleryItem -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.GalleryItem.MouseOver" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor20}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.GalleryItem.Selected" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor40}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.GalleryItem.Pressed" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor60}" options:Freeze="True" />
|
||||
|
||||
<!-- Images -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Images.QuickAccessToolbarDropDown" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Images.QuickAccessToolbarDropDown.BelowRibbon" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Images.QuickAccessToolbarExtender" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Images.QuickAccessToolbarExtender.BelowRibbon" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Images.RibbonCollapse" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Images.RibbonExpand" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Images.RibbonPin" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
|
||||
<!-- KeyTip -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.KeyTip.Background" Color="{StaticResource Gray1}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.KeyTip.BorderBrush" Color="{StaticResource Gray2}" options:Freeze="True" />
|
||||
|
||||
<!-- MenuItem -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.MenuItem.Background" Color="Transparent" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ApplicationMenuItem.CheckBox.Background" Color="#FFFCF1C2" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ApplicationMenuItem.CheckBox.BorderBrush" Color="#FFF29536" options:Freeze="True" />
|
||||
|
||||
<LinearGradientBrush x:Key="Fluent.Ribbon.MenuItem.SubMenu.Arrow.Fill" EndPoint="0.945,0.872" StartPoint="0.055,0.128" options:Freeze="True">
|
||||
<GradientStop Color="{StaticResource Gray2}" Offset="1" />
|
||||
<GradientStop Color="{StaticResource Gray3}" />
|
||||
</LinearGradientBrush>
|
||||
|
||||
<!-- Ribbon -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Ribbon.Background" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
|
||||
<!-- RibbonContextualTabGroup -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonContextualTabGroup.Background.OpacityMask" Color="#14000000" options:Freeze="True" />
|
||||
|
||||
<!-- RibbonGroupBox -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonGroupBox.Collapsed.BorderBrush" Color="{StaticResource Gray6}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonGroupBox.Collapsed.MouseOver.Background" Color="{StaticResource Gray10}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonGroupBox.DropDownOpen.Background" Color="{StaticResource Gray8}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonGroupBox.Header.Foreground" Color="{StaticResource Gray2}" options:Freeze="True" />
|
||||
|
||||
<!-- RibbonTabControl -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabControl.Background" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabControl.Foreground" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabControl.Content.Background" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabControl.Content.BorderBrush" Color="Transparent" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabControl.Content.Foreground" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabControl.TabsGrid.Background" Color="Transparent" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabControl.TabsGrid.Foreground" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
|
||||
<!-- RibbonContextualTabGroup -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonContextualTabGroup.TabItemSelectedForeground" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonContextualTabGroup.TabItemMouseOverForeground" Color="{StaticResource Fluent.Ribbon.Colors.HighlightColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonContextualTabGroup.TabItemSelectedMouseOverForeground" Color="{StaticResource Fluent.Ribbon.Colors.HighlightColor}" options:Freeze="True" />
|
||||
|
||||
<!-- RibbonTabItem -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabItem.Foreground" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabItem.BorderBrush" Color="{StaticResource Gray8}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabItem.Active.Background" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabItem.MouseOver.Background" Color="Transparent" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabItem.MouseOver.Foreground" Color="{StaticResource Fluent.Ribbon.Colors.HighlightColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabItem.Selected.Foreground" Color="{StaticResource Gray1}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabItem.Selected.MouseOver.Foreground" Color="{StaticResource Fluent.Ribbon.Colors.HighlightColor}" options:Freeze="True" />
|
||||
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonTabItem.Contextual.Background.OpacityMask" Color="#14000000" options:Freeze="True" />
|
||||
|
||||
<!-- RibbonWindow -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonWindow.TitleBackground" Color="Transparent" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.RibbonWindow.TitleForeground" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
|
||||
<!-- Separator -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Separator.BorderBrush" Color="{StaticResource Gray8}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.Separator.Background" Color="{StaticResource Gray8}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.GroupSeparator.Background" Color="{StaticResource Gray8}" options:Freeze="True" />
|
||||
|
||||
<!-- ScreenTip -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ScreenTip.BorderBrush" Color="{StaticResource Gray7}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ScreenTip.Background" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
|
||||
<!-- Scroll-Buttons -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ScrollButton.Default.BorderBrush" Color="{StaticResource Gray4}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ScrollButton.Default.Background" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
|
||||
<!-- ScrollBar -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ScrollBar.Background" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ScrollThumb.Default.BorderBrush" Color="{StaticResource Gray4}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ScrollThumb.Default.Background" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
|
||||
<!-- ScrollViewer -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ScrollViewer.Button.BorderBrush" Color="{StaticResource Gray2}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.ScrollViewer.Button.Background" Color="{StaticResource Gray8}" options:Freeze="True" />
|
||||
|
||||
<!-- TextBox -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.TextBox.BorderBrush" Color="{StaticResource Gray6}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.TextBox.Background" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.TextBox.CaretBrush" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.TextBox.SelectionBrush" Color="{x:Static SystemColors.HighlightColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.TextBox.MouseOver.Background" Color="{StaticResource WhiteColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.TextBox.MouseOver.BorderBrush" Color="{StaticResource Gray5}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.TextBox.Disabled.Background" Color="{StaticResource Gray10}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.TextBox.Disabled.BorderBrush" Color="{StaticResource Gray8}" options:Freeze="True" />
|
||||
|
||||
<!-- WindowCommands -->
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.WindowCommands.CaptionButton.Foreground" Color="{StaticResource BlackColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.WindowCommands.CaptionButton.Background" Color="{StaticResource TransparentWhiteColor}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.WindowCommands.CaptionButton.MouseOver.Background" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor20}" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.WindowCommands.CaptionButton.Pressed.Background" Color="{StaticResource Fluent.Ribbon.Colors.AccentColor40}" options:Freeze="True" />
|
||||
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.WindowCommands.CloseButton.MouseOver.Background" Color="#E81123" options:Freeze="True" />
|
||||
<SolidColorBrush x:Key="Fluent.Ribbon.Brushes.WindowCommands.CloseButton.Pressed.Background" Color="#A92831" options:Freeze="True" />
|
||||
|
||||
<!-- END BRUSHES -->
|
||||
</ResourceDictionary>
|
||||
309
AIStudio.Wpf.DiagramDesigner.Additionals/Controls/OutlineText.cs
Normal file
309
AIStudio.Wpf.DiagramDesigner.Additionals/Controls/OutlineText.cs
Normal file
@@ -0,0 +1,309 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<UserControl x:Class="AIStudio.Wpf.DiagramDesigner.Additionals.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.DiagramDesigner.Additionals.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>
|
||||
@@ -0,0 +1,140 @@
|
||||
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.DiagramDesigner.Additionals.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); //计算出旋转角度
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
618
AIStudio.Wpf.DiagramDesigner.Additionals/Controls/WPFRuler.cs
Normal file
618
AIStudio.Wpf.DiagramDesigner.Additionals/Controls/WPFRuler.cs
Normal file
@@ -0,0 +1,618 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using AIStudio.Wpf.DiagramDesigner.Additionals.Controls;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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 AIStudio.Wpf.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**************************************************************************************
|
||||
|
||||
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.DiagramDesigner.Additionals.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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
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.DiagramDesigner.Additionals.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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using AIStudio.Wpf.DiagramDesigner.Additionals.Controls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
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.DiagramDesigner.Additionals.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
AIStudio.Wpf.DiagramDesigner.Additionals/DLL/zxing.core.dll
Normal file
BIN
AIStudio.Wpf.DiagramDesigner.Additionals/DLL/zxing.core.dll
Normal file
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.Models
|
||||
{
|
||||
public class PathDesignerItem : DesignerItemBase
|
||||
{
|
||||
public PathDesignerItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PathDesignerItem(DesignerItemViewModelBase item) : base(item) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Xml.Serialization;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.Models
|
||||
{
|
||||
public class PersistDesignerItem : DesignerItemBase
|
||||
{
|
||||
public PersistDesignerItem()
|
||||
{
|
||||
|
||||
}
|
||||
public PersistDesignerItem(PersistDesignerItemViewModel item) : base(item)
|
||||
{
|
||||
this.HostUrl = item.HostUrl;
|
||||
}
|
||||
|
||||
[XmlAttribute]
|
||||
public string HostUrl { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.Models
|
||||
{
|
||||
public class SettingsDesignerItem : DesignerItemBase
|
||||
{
|
||||
public SettingsDesignerItem()
|
||||
{
|
||||
|
||||
}
|
||||
public SettingsDesignerItem(SettingsDesignerItemViewModel item) : base(item)
|
||||
{
|
||||
this.Setting = item.Setting;
|
||||
}
|
||||
|
||||
public string Setting { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using AIStudio.Wpf.DiagramDesigner.Additionals.Commands;
|
||||
using AIStudio.Wpf.DiagramDesigner.Additionals.Models;
|
||||
using System.Windows.Input;
|
||||
using ZXing;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Models;
|
||||
using AIStudio.Wpf.DiagramDesigner.Services;
|
||||
using ZXing;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels
|
||||
{
|
||||
public class BarcodeDesignerItemViewModel : DesignerItemViewModelBase
|
||||
{
|
||||
private IUIVisualizerService visualiserService;
|
||||
|
||||
public BarcodeDesignerItemViewModel() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public BarcodeDesignerItemViewModel(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public BarcodeDesignerItemViewModel(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
|
||||
{
|
||||
}
|
||||
|
||||
public override SelectableItemBase GetSerializableObject()
|
||||
{
|
||||
return new DesignerItemBase(this, Format.ToString());
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
base.Init();
|
||||
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
|
||||
|
||||
}
|
||||
|
||||
protected override void LoadDesignerItemViewModel(IDiagramViewModel root, SelectableItemBase designerbase)
|
||||
{
|
||||
base.LoadDesignerItemViewModel(root, designerbase);
|
||||
|
||||
if (designerbase is DesignerItemBase designer)
|
||||
{
|
||||
Format = (BarcodeFormat)Enum.Parse(typeof(BarcodeFormat), designer.Reserve.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
private bool _showText;
|
||||
public override bool ShowText
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _showText, value);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
Icon = data.Icon;
|
||||
Margin = data.Margin;
|
||||
if (needauto)
|
||||
{
|
||||
AutoSize();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:viewmodel="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels"
|
||||
xmlns:gif="http://wpfanimatedgif.codeplex.com"
|
||||
xmlns:converter="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Converters"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Controls"
|
||||
xmlns:dd="https://gitee.com/akwkevin/aistudio.-wpf.-diagram"
|
||||
xmlns:Fluent="urn:fluent-ribbon"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
|
||||
|
||||
<dd:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
|
||||
<converter:DoubleToThickness x:Key="DoubleToThickness"/>
|
||||
<dd:ColorBrushConverter x:Key="ColorBrushConverter"/>
|
||||
|
||||
|
||||
<DataTemplate DataType="{x:Type viewmodel: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 viewmodel: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>
|
||||
@@ -0,0 +1,48 @@
|
||||
using AIStudio.Wpf.DiagramDesigner.Additionals.Models;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Models;
|
||||
using AIStudio.Wpf.DiagramDesigner.Services;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels
|
||||
{
|
||||
public class OutLineTextDesignerItemViewModel : TextDesignerItemViewModel
|
||||
{
|
||||
private IUIVisualizerService visualiserService;
|
||||
public OutLineTextDesignerItemViewModel() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public OutLineTextDesignerItemViewModel(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public OutLineTextDesignerItemViewModel(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override SelectableItemBase GetSerializableObject()
|
||||
{
|
||||
return new TextDesignerItem(this);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:viewmodel="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels"
|
||||
xmlns:gif="http://wpfanimatedgif.codeplex.com"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Controls"
|
||||
xmlns:dd="https://gitee.com/akwkevin/aistudio.-wpf.-diagram"
|
||||
xmlns:Fluent="urn:fluent-ribbon"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
|
||||
|
||||
<dd:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
|
||||
<dd:DoubleToThickness x:Key="DoubleToThickness"/>
|
||||
<dd:ColorBrushConverter x:Key="ColorBrushConverter"/>
|
||||
|
||||
<DataTemplate DataType="{x:Type viewmodel: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 viewmodel: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={dd:ConverterBoolToValueMap Parameter='Regular'}, ConverterParameter='Bold'}"
|
||||
FontStyle="{Binding ElementName=buttonItalic,Path=IsChecked,Converter={dd:ConverterBoolToValueMap Parameter='Normal'}, ConverterParameter='Italic'}"
|
||||
TextDecorations="{Binding ElementName=buttonUnderline,Path=IsChecked,Converter={dd: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.DiagramDesigner.Additionals;component/Images/Bold.png"
|
||||
HorizontalAlignment="Left"
|
||||
SizeDefinition="Small"
|
||||
IsChecked="{Binding FontViewModel.FontWeight,Converter={dd:ConverterValueMapToBool Parameter='Regular'}, ConverterParameter='Bold'}"/>
|
||||
<Fluent:ToggleButton x:Name="buttonItalic"
|
||||
KeyTip="I"
|
||||
Icon="pack://application:,,,/AIStudio.Wpf.DiagramDesigner.Additionals;component/Images/Italic.png"
|
||||
HorizontalAlignment="Left"
|
||||
SizeDefinition="Small"
|
||||
IsChecked="{Binding FontViewModel.FontStyle,Converter={dd:ConverterValueMapToBool Parameter='Normal'}, ConverterParameter='Italic'}"/>
|
||||
<Fluent:ToggleButton x:Name="buttonUnderline"
|
||||
KeyTip="U"
|
||||
Icon="pack://application:,,,/AIStudio.Wpf.DiagramDesigner.Additionals;component/Images/Underline.png"
|
||||
HorizontalAlignment="Left"
|
||||
SizeDefinition="Small"
|
||||
IsChecked="{Binding FontViewModel.Underline}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Models;
|
||||
using AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.Models;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels
|
||||
{
|
||||
public class PathItemViewModel : DesignerItemViewModelBase
|
||||
{
|
||||
public PathItemViewModel() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PathItemViewModel(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public PathItemViewModel(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override SelectableItemBase GetSerializableObject()
|
||||
{
|
||||
return new PathDesignerItem(this);
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
this.ShowConnectors = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:AIStudio.Wpf.DiagramDesigner;assembly=AIStudio.Wpf.DiagramDesigner"
|
||||
xmlns:viewmodel="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels"
|
||||
xmlns:convent="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.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 viewmodel:PathItemViewModel}">
|
||||
<Grid>
|
||||
<Path Tag="Process" IsHitTestVisible="False" Style="{StaticResource PathItemStyle}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,33 @@
|
||||
using AIStudio.Wpf.DiagramDesigner.Additionals.Models;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels
|
||||
{
|
||||
/// <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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Models;
|
||||
using AIStudio.Wpf.DiagramDesigner.Services;
|
||||
using AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.Models;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels
|
||||
{
|
||||
public class PersistDesignerItemViewModel : DesignerItemViewModelBase
|
||||
{
|
||||
private IUIVisualizerService visualiserService;
|
||||
|
||||
public PersistDesignerItemViewModel() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PersistDesignerItemViewModel(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PersistDesignerItemViewModel(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override SelectableItemBase GetSerializableObject()
|
||||
{
|
||||
return new PersistDesignerItem(this);
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
|
||||
this.ShowConnectors = false;
|
||||
}
|
||||
|
||||
protected override void LoadDesignerItemViewModel(IDiagramViewModel root, SelectableItemBase designerbase)
|
||||
{
|
||||
base.LoadDesignerItemViewModel(root, designerbase);
|
||||
|
||||
if (designerbase is PersistDesignerItem designer)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:viewmodel="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels"
|
||||
xmlns:gif="http://wpfanimatedgif.codeplex.com"
|
||||
xmlns:converter="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Converters"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Controls"
|
||||
xmlns:dd="https://gitee.com/akwkevin/aistudio.-wpf.-diagram"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
|
||||
|
||||
<dd:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
|
||||
<dd:DoubleToThickness x:Key="DoubleToThickness"/>
|
||||
<dd: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 viewmodel:PersistDesignerItemViewModel}">
|
||||
<Grid>
|
||||
<Image IsHitTestVisible="False"
|
||||
Stretch="Fill"
|
||||
Source="/AIStudio.Wpf.DiagramApp;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 viewmodel: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>
|
||||
@@ -0,0 +1,33 @@
|
||||
using AIStudio.Wpf.DiagramDesigner.Additionals.Models;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels
|
||||
{
|
||||
/// <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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Models;
|
||||
using AIStudio.Wpf.DiagramDesigner.Services;
|
||||
using AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.Models;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels
|
||||
{
|
||||
public class SettingsDesignerItemViewModel : DesignerItemViewModelBase
|
||||
{
|
||||
private IUIVisualizerService visualiserService;
|
||||
|
||||
public SettingsDesignerItemViewModel() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SettingsDesignerItemViewModel(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SettingsDesignerItemViewModel(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override SelectableItemBase GetSerializableObject()
|
||||
{
|
||||
return new SettingsDesignerItem(this);
|
||||
}
|
||||
|
||||
protected override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
visualiserService = ApplicationServicesProvider.Instance.Provider.VisualizerService;
|
||||
this.ShowConnectors = false;
|
||||
}
|
||||
|
||||
protected override void LoadDesignerItemViewModel(IDiagramViewModel root, SelectableItemBase designerbase)
|
||||
{
|
||||
base.LoadDesignerItemViewModel(root, designerbase);
|
||||
|
||||
if (designerbase is SettingsDesignerItem designer)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:viewmodel="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels"
|
||||
xmlns:gif="http://wpfanimatedgif.codeplex.com"
|
||||
xmlns:converter="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Converters"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Controls"
|
||||
xmlns:dd="https://gitee.com/akwkevin/aistudio.-wpf.-diagram"
|
||||
xmlns:Fluent="urn:fluent-ribbon"
|
||||
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
|
||||
|
||||
<dd:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
|
||||
<converter:DoubleToThickness x:Key="DoubleToThickness"/>
|
||||
<dd: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 viewmodel:SettingsDesignerItemViewModel}">
|
||||
<Grid>
|
||||
<Image IsHitTestVisible="False"
|
||||
Stretch="Fill"
|
||||
Source="/AIStudio.Wpf.DiagramApp;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 viewmodel: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>
|
||||
@@ -0,0 +1,29 @@
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Models;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels
|
||||
{
|
||||
public class SvgDesignerItemViewModel: MediaItemViewModel
|
||||
{
|
||||
protected override string Filter { get; set; } = "Svg|*.svg";
|
||||
|
||||
public SvgDesignerItemViewModel() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public SvgDesignerItemViewModel(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SvgDesignerItemViewModel(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override SelectableItemBase GetSerializableObject()
|
||||
{
|
||||
return new MediaDesignerItem(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:AIStudio.Wpf.DiagramDesigner;assembly=AIStudio.Wpf.DiagramDesigner"
|
||||
xmlns:viewmodel="clr-namespace:AIStudio.Wpf.DiagramDesigner.Additionals.Extensions.ViewModels"
|
||||
xmlns:svg="https://gitee.com/akwkevin/aistudio.-wpf.-test/tree/master/Controls/AIStudio.Wpf.Svg2XamlExtension">
|
||||
<s:ColorBrushConverter x:Key="ColorBrushConverter" />
|
||||
|
||||
<DataTemplate DataType="{x:Type viewmodel:SvgDesignerItemViewModel}">
|
||||
<Grid IsHitTestVisible="False">
|
||||
<svg:PackSvg Width="Auto" Height="Auto" Path="{Binding Icon}" Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals
|
||||
{
|
||||
public class EnumHelper : DependencyObject
|
||||
{
|
||||
public static Type GetEnum(DependencyObject obj)
|
||||
{
|
||||
return (Type)obj.GetValue(EnumProperty);
|
||||
}
|
||||
|
||||
public static void SetEnum(DependencyObject obj, Type 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)
|
||||
{
|
||||
if (DesignerHelper.IsInDesignMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
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.DiagramDesigner.Additionals
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Additionals.Models
|
||||
{
|
||||
public class TitleBindableBase : BindableBase
|
||||
{
|
||||
private string _title;
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return _title;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetProperty(ref _title, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
|
||||
[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)
|
||||
)]
|
||||
|
||||
[assembly: XmlnsDefinition("https://gitee.com/akwkevin/aistudio.-wpf.-diagram", "AIStudio.Wpf.DiagramDesigner.Additionals")]
|
||||
[assembly: XmlnsDefinition("https://gitee.com/akwkevin/aistudio.-wpf.-diagram", "AIStudio.Wpf.DiagramDesigner.Additionals.Controls")]
|
||||
|
||||
[assembly: XmlnsPrefix("https://gitee.com/akwkevin/aistudio.-wpf.-diagram", "dd")]
|
||||
Reference in New Issue
Block a user