mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-27 03:33:25 +08:00
Mind Editoe
This commit is contained in:
171
AIStudio.Wpf.Mind/Controls/DropDownButton.xaml
Normal file
171
AIStudio.Wpf.Mind/Controls/DropDownButton.xaml
Normal file
@@ -0,0 +1,171 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.Mind.Controls">
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/AIStudio.Wpf.Mind;component/Styles/Button.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/AIStudio.Wpf.Mind;component/Styles/ContextMenu.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Style x:Key="AIStudio.Styles.DropDownButton" TargetType="{x:Type controls:DropDownButton}">
|
||||
<Setter Property="ArrowBrush" Value="Black" />
|
||||
<Setter Property="ArrowMouseOverBrush"
|
||||
Value="{Binding Foreground, RelativeSource={RelativeSource Mode=Self},
|
||||
Converter={StaticResource BrushOpacityConverter}, ConverterParameter=0.16}" />
|
||||
<Setter Property="ArrowPressedBrush" Value="Black" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="ButtonStyle" Value="{StaticResource FlatButtonStyle}" />
|
||||
<Setter Property="Focusable" Value="False" />
|
||||
<Setter Property="Foreground" Value="Black" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||
<Setter Property="MenuStyle" Value="{StaticResource ContextMenuStyle}" />
|
||||
<Setter Property="MinHeight" Value="26" />
|
||||
<Setter Property="Padding" Value="3" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type controls:DropDownButton}">
|
||||
<Grid>
|
||||
<Border x:Name="PART_Border"
|
||||
Background="Transparent"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="3"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
|
||||
UseLayoutRounding="True">
|
||||
<Button x:Name="PART_Button"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
FocusVisualStyle="{TemplateBinding FocusVisualStyle}"
|
||||
Foreground="{TemplateBinding Foreground}"
|
||||
RenderOptions.ClearTypeHint="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(RenderOptions.ClearTypeHint), Mode=OneWay}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
|
||||
Style="{TemplateBinding ButtonStyle}">
|
||||
<DockPanel x:Name="PART_Content"
|
||||
Focusable="False"
|
||||
LastChildFill="True">
|
||||
<!-- Material - ChevronDown -->
|
||||
<Path x:Name="PART_Arrow"
|
||||
Width="9"
|
||||
Height="6"
|
||||
Margin="0 0 3 0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z"
|
||||
DockPanel.Dock="Right"
|
||||
Stretch="Fill"
|
||||
Fill="{TemplateBinding ArrowBrush}"
|
||||
Visibility="{TemplateBinding ArrowVisibility}" />
|
||||
<StackPanel x:Name="PART_ContentOrientation"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Focusable="False"
|
||||
Orientation="Horizontal">
|
||||
<ContentPresenter HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding Icon}"
|
||||
ContentTemplate="{TemplateBinding IconTemplate}"
|
||||
Focusable="False"
|
||||
RecognizesAccessKey="True"
|
||||
UseLayoutRounding="False" />
|
||||
<ContentControl x:Name="PART_ButtonContent"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{Binding Content, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
ContentStringFormat="{TemplateBinding ContentStringFormat}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
|
||||
UseLayoutRounding="False" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu x:Name="PART_Menu"
|
||||
MinWidth="{TemplateBinding ActualWidth}"
|
||||
DisplayMemberPath="{TemplateBinding DisplayMemberPath}"
|
||||
GroupStyleSelector="{TemplateBinding GroupStyleSelector}"
|
||||
IsOpen="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
ItemContainerStyle="{TemplateBinding ItemContainerStyle}"
|
||||
ItemContainerStyleSelector="{TemplateBinding ItemContainerStyleSelector}"
|
||||
ItemStringFormat="{TemplateBinding ItemStringFormat}"
|
||||
ItemTemplate="{TemplateBinding ItemTemplate}"
|
||||
ItemTemplateSelector="{TemplateBinding ItemTemplateSelector}"
|
||||
ItemsPanel="{TemplateBinding ItemsPanel}"
|
||||
ItemsSource="{TemplateBinding ItemsSource}"
|
||||
Placement="Bottom"
|
||||
StaysOpen="False"
|
||||
Style="{TemplateBinding MenuStyle}"
|
||||
UseLayoutRounding="False" />
|
||||
</Button.ContextMenu>
|
||||
</Button>
|
||||
|
||||
</Border>
|
||||
<!--<Popup x:Name="PART_Popup"
|
||||
Placement="Bottom"
|
||||
IsOpen="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
AllowsTransparency="True"
|
||||
Margin="0,0,-4,0">
|
||||
<Border>
|
||||
<ScrollViewer x:Name="PART_ScrollViewer"
|
||||
IsTabStop="False"
|
||||
Margin="1"
|
||||
SnapsToDevicePixels="True"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Hidden">
|
||||
<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Local" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Popup>-->
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="Content" Value="{x:Null}">
|
||||
<Setter TargetName="PART_ButtonContent" Property="Margin" Value="0" />
|
||||
</Trigger>
|
||||
<Trigger Property="Orientation" Value="Vertical">
|
||||
<Setter TargetName="PART_Arrow" Property="DockPanel.Dock" Value="Bottom" />
|
||||
<Setter TargetName="PART_Arrow" Property="Margin" Value="0 0 0 3" />
|
||||
<Setter TargetName="PART_ContentOrientation" Property="Orientation" Value="Vertical" />
|
||||
</Trigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsMouseOver" Value="True" />
|
||||
<Condition SourceName="PART_Button" Property="IsEnabled" Value="True" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter TargetName="PART_Arrow" Property="Fill" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ArrowMouseOverBrush, Mode=OneWay}" />
|
||||
</MultiTrigger>
|
||||
<Trigger SourceName="PART_Button" Property="IsPressed" Value="True">
|
||||
<Setter TargetName="PART_Arrow" Property="Fill" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ArrowPressedBrush, Mode=OneWay}" />
|
||||
</Trigger>
|
||||
<Trigger SourceName="PART_Button" Property="IsEnabled" Value="False">
|
||||
<Setter Property="Opacity" Value=".55" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsFocused" Value="True">
|
||||
<Setter Property="BorderBrush" Value="LightGray" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsKeyboardFocusWithin" Value="True">
|
||||
<Setter Property="BorderBrush" Value="LightGray" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Opacity" Value=".55" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="{x:Type controls:DropDownButton}" BasedOn="{StaticResource AIStudio.Styles.DropDownButton}" />
|
||||
|
||||
</ResourceDictionary>
|
||||
685
AIStudio.Wpf.Mind/Controls/DropDownButton.xaml.cs
Normal file
685
AIStudio.Wpf.Mind/Controls/DropDownButton.xaml.cs
Normal file
@@ -0,0 +1,685 @@
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.Mind.Controls
|
||||
{
|
||||
[ContentProperty(nameof(ItemsSource))]
|
||||
[TemplatePart(Name = "PART_Button", Type = typeof(Button))]
|
||||
[TemplatePart(Name = "PART_ButtonContent", Type = typeof(ContentControl))]
|
||||
[TemplatePart(Name = "PART_Menu", Type = typeof(ContextMenu))]
|
||||
[StyleTypedProperty(Property = nameof(ButtonStyle), StyleTargetType = typeof(Button))]
|
||||
[StyleTypedProperty(Property = nameof(MenuStyle), StyleTargetType = typeof(ContextMenu))]
|
||||
public class DropDownButton : ItemsControl, ICommandSource
|
||||
{
|
||||
public static readonly RoutedEvent ClickEvent
|
||||
= EventManager.RegisterRoutedEvent(nameof(Click),
|
||||
RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler),
|
||||
typeof(DropDownButton));
|
||||
|
||||
public event RoutedEventHandler Click
|
||||
{
|
||||
add => this.AddHandler(ClickEvent, value);
|
||||
remove => this.RemoveHandler(ClickEvent, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="IsExpanded"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty IsExpandedProperty
|
||||
= DependencyProperty.Register(nameof(IsExpanded),
|
||||
typeof(bool),
|
||||
typeof(DropDownButton),
|
||||
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsExpandedPropertyChangedCallback));
|
||||
|
||||
private static void OnIsExpandedPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
||||
{
|
||||
if (dependencyObject is DropDownButton dropDownButton
|
||||
&& !(dropDownButton.contextMenu == null))
|
||||
{
|
||||
dropDownButton.SetContextMenuPlacementTarget(dropDownButton.contextMenu);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void SetContextMenuPlacementTarget(ContextMenu contextMenu)
|
||||
{
|
||||
if (this.button != null)
|
||||
{
|
||||
contextMenu.PlacementTarget = this.button;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the "popup" menu for this control is currently open
|
||||
/// </summary>
|
||||
public bool IsExpanded
|
||||
{
|
||||
get => (bool)this.GetValue(IsExpandedProperty);
|
||||
set => this.SetValue(IsExpandedProperty, (bool)value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="ExtraTag"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty ExtraTagProperty
|
||||
= DependencyProperty.Register(nameof(ExtraTag),
|
||||
typeof(object),
|
||||
typeof(DropDownButton));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an extra tag.
|
||||
/// </summary>
|
||||
public object ExtraTag
|
||||
{
|
||||
get => this.GetValue(ExtraTagProperty);
|
||||
set => this.SetValue(ExtraTagProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="Orientation"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty OrientationProperty
|
||||
= DependencyProperty.Register(nameof(Orientation),
|
||||
typeof(Orientation),
|
||||
typeof(DropDownButton),
|
||||
new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the orientation of children stacking.
|
||||
/// </summary>
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => (Orientation)this.GetValue(OrientationProperty);
|
||||
set => this.SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="Icon"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty IconProperty
|
||||
= DependencyProperty.Register(nameof(Icon),
|
||||
typeof(object),
|
||||
typeof(DropDownButton));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content for the icon part.
|
||||
/// </summary>
|
||||
[Bindable(true)]
|
||||
public object Icon
|
||||
{
|
||||
get => this.GetValue(IconProperty);
|
||||
set => this.SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="IconTemplate"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty IconTemplateProperty
|
||||
= DependencyProperty.Register(nameof(IconTemplate),
|
||||
typeof(DataTemplate),
|
||||
typeof(DropDownButton));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the DataTemplate for the icon part.
|
||||
/// </summary>
|
||||
[Bindable(true)]
|
||||
public DataTemplate IconTemplate
|
||||
{
|
||||
get => (DataTemplate)this.GetValue(IconTemplateProperty);
|
||||
set => this.SetValue(IconTemplateProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="Command"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty CommandProperty
|
||||
= DependencyProperty.Register(nameof(Command),
|
||||
typeof(ICommand),
|
||||
typeof(DropDownButton),
|
||||
new PropertyMetadata(null, OnCommandPropertyChangedCallback));
|
||||
|
||||
private static void OnCommandPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
(dependencyObject as DropDownButton).OnCommandChanged((ICommand)e.OldValue, (ICommand)e.NewValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the command to invoke when the content button is pressed.
|
||||
/// </summary>
|
||||
public ICommand Command
|
||||
{
|
||||
get => (ICommand)this.GetValue(CommandProperty);
|
||||
set => this.SetValue(CommandProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="CommandTarget"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty CommandTargetProperty
|
||||
= DependencyProperty.Register(nameof(CommandTarget),
|
||||
typeof(IInputElement),
|
||||
typeof(DropDownButton),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the element on which to raise the specified command.
|
||||
/// </summary>
|
||||
public IInputElement CommandTarget
|
||||
{
|
||||
get => (IInputElement)this.GetValue(CommandTargetProperty);
|
||||
set => this.SetValue(CommandTargetProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="CommandParameter"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty CommandParameterProperty
|
||||
= DependencyProperty.Register(nameof(CommandParameter),
|
||||
typeof(object),
|
||||
typeof(DropDownButton),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the parameter to pass to the command property.
|
||||
/// </summary>
|
||||
public object CommandParameter
|
||||
{
|
||||
get => (object)this.GetValue(CommandParameterProperty);
|
||||
set => this.SetValue(CommandParameterProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="Content"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty ContentProperty
|
||||
= DependencyProperty.Register(nameof(Content),
|
||||
typeof(object),
|
||||
typeof(DropDownButton));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content of this control.
|
||||
/// </summary>
|
||||
public object Content
|
||||
{
|
||||
get => (object)this.GetValue(ContentProperty);
|
||||
set => this.SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="ContentTemplate"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty ContentTemplateProperty
|
||||
= DependencyProperty.Register(nameof(ContentTemplate),
|
||||
typeof(DataTemplate),
|
||||
typeof(DropDownButton),
|
||||
new FrameworkPropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the data template used to display the content of the DropDownButton.
|
||||
/// </summary>
|
||||
[Bindable(true)]
|
||||
public DataTemplate ContentTemplate
|
||||
{
|
||||
get => (DataTemplate)this.GetValue(ContentTemplateProperty);
|
||||
set => this.SetValue(ContentTemplateProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="ContentTemplateSelector"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty ContentTemplateSelectorProperty
|
||||
= DependencyProperty.Register(nameof(ContentTemplateSelector),
|
||||
typeof(DataTemplateSelector),
|
||||
typeof(DropDownButton),
|
||||
new FrameworkPropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a template selector that enables an application writer to provide custom template-selection logic.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property is ignored if <seealso cref="ContentTemplate"/> is set.
|
||||
/// </remarks>
|
||||
[Bindable(true)]
|
||||
public DataTemplateSelector ContentTemplateSelector
|
||||
{
|
||||
get => (DataTemplateSelector)this.GetValue(ContentTemplateSelectorProperty);
|
||||
set => this.SetValue(ContentTemplateSelectorProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="ContentStringFormat"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty ContentStringFormatProperty
|
||||
= DependencyProperty.Register(nameof(ContentStringFormat),
|
||||
typeof(string),
|
||||
typeof(DropDownButton),
|
||||
new FrameworkPropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a composite string that specifies how to format the content property if it is displayed as a string.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property is ignored if <seealso cref="ContentTemplate"/> is set.
|
||||
/// </remarks>
|
||||
[Bindable(true)]
|
||||
public string ContentStringFormat
|
||||
{
|
||||
get => (string)this.GetValue(ContentStringFormatProperty);
|
||||
set => this.SetValue(ContentStringFormatProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="ButtonStyle"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty ButtonStyleProperty
|
||||
= DependencyProperty.Register(nameof(ButtonStyle),
|
||||
typeof(Style),
|
||||
typeof(DropDownButton),
|
||||
new FrameworkPropertyMetadata(default(Style), FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the button content style.
|
||||
/// </summary>
|
||||
public Style ButtonStyle
|
||||
{
|
||||
get => (Style)this.GetValue(ButtonStyleProperty);
|
||||
set => this.SetValue(ButtonStyleProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="MenuStyle"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty MenuStyleProperty
|
||||
= DependencyProperty.Register(nameof(MenuStyle),
|
||||
typeof(Style),
|
||||
typeof(DropDownButton),
|
||||
new FrameworkPropertyMetadata(default(Style), FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the "popup" menu style.
|
||||
/// </summary>
|
||||
public Style MenuStyle
|
||||
{
|
||||
get => (Style)this.GetValue(MenuStyleProperty);
|
||||
set => this.SetValue(MenuStyleProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="ArrowBrush"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty ArrowBrushProperty
|
||||
= DependencyProperty.Register(nameof(ArrowBrush),
|
||||
typeof(Brush),
|
||||
typeof(DropDownButton),
|
||||
new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the foreground brush for the button arrow icon.
|
||||
/// </summary>
|
||||
public Brush ArrowBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(ArrowBrushProperty);
|
||||
set => this.SetValue(ArrowBrushProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="ArrowMouseOverBrush"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty ArrowMouseOverBrushProperty
|
||||
= DependencyProperty.Register(nameof(ArrowMouseOverBrush),
|
||||
typeof(Brush),
|
||||
typeof(DropDownButton),
|
||||
new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the foreground brush of the button arrow icon if the mouse is over the drop down button.
|
||||
/// </summary>
|
||||
public Brush ArrowMouseOverBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(ArrowMouseOverBrushProperty);
|
||||
set => this.SetValue(ArrowMouseOverBrushProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="ArrowPressedBrush"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty ArrowPressedBrushProperty
|
||||
= DependencyProperty.Register(nameof(ArrowPressedBrush),
|
||||
typeof(Brush),
|
||||
typeof(DropDownButton),
|
||||
new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the foreground brush of the button arrow icon if the arrow button is pressed.
|
||||
/// </summary>
|
||||
public Brush ArrowPressedBrush
|
||||
{
|
||||
get => (Brush)this.GetValue(ArrowPressedBrushProperty);
|
||||
set => this.SetValue(ArrowPressedBrushProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>Identifies the <see cref="ArrowVisibility"/> dependency property.</summary>
|
||||
public static readonly DependencyProperty ArrowVisibilityProperty
|
||||
= DependencyProperty.Register(nameof(ArrowVisibility),
|
||||
typeof(Visibility),
|
||||
typeof(DropDownButton),
|
||||
new FrameworkPropertyMetadata(Visibility.Visible, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the visibility of the button arrow icon.
|
||||
/// </summary>
|
||||
public Visibility ArrowVisibility
|
||||
{
|
||||
get => (Visibility)this.GetValue(ArrowVisibilityProperty);
|
||||
set => this.SetValue(ArrowVisibilityProperty, value);
|
||||
}
|
||||
|
||||
static DropDownButton()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(DropDownButton), new FrameworkPropertyMetadata(typeof(DropDownButton)));
|
||||
}
|
||||
|
||||
private void OnCommandChanged(ICommand oldCommand, ICommand newCommand)
|
||||
{
|
||||
if (oldCommand != null)
|
||||
{
|
||||
this.UnhookCommand(oldCommand);
|
||||
}
|
||||
|
||||
if (newCommand != null)
|
||||
{
|
||||
this.HookCommand(newCommand);
|
||||
}
|
||||
}
|
||||
|
||||
private void UnhookCommand(ICommand command)
|
||||
{
|
||||
CanExecuteChangedEventManager.RemoveHandler(command, this.OnCanExecuteChanged);
|
||||
this.UpdateCanExecute();
|
||||
}
|
||||
|
||||
private void HookCommand(ICommand command)
|
||||
{
|
||||
CanExecuteChangedEventManager.AddHandler(command, this.OnCanExecuteChanged);
|
||||
this.UpdateCanExecute();
|
||||
}
|
||||
|
||||
private void OnCanExecuteChanged(object sender, EventArgs e)
|
||||
{
|
||||
this.UpdateCanExecute();
|
||||
}
|
||||
|
||||
private void UpdateCanExecute()
|
||||
{
|
||||
this.CanExecute = this.Command == null || CommandHelpers.CanExecuteCommandSource(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool IsEnabledCore => base.IsEnabledCore && this.CanExecute;
|
||||
|
||||
private bool canExecute = true;
|
||||
|
||||
private bool CanExecute
|
||||
{
|
||||
get => this.canExecute;
|
||||
set
|
||||
{
|
||||
if (value == this.canExecute)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.canExecute = value;
|
||||
this.CoerceValue(IsEnabledProperty);
|
||||
}
|
||||
}
|
||||
|
||||
private void ButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CommandHelpers.ExecuteCommandSource(this);
|
||||
|
||||
if (this.contextMenu?.HasItems == true)
|
||||
{
|
||||
this.SetCurrentValue(IsExpandedProperty, true);
|
||||
}
|
||||
|
||||
e.RoutedEvent = ClickEvent;
|
||||
this.RaiseEvent(e);
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
if (this.button != null)
|
||||
{
|
||||
this.button.Click -= this.ButtonClick;
|
||||
}
|
||||
|
||||
this.button = this.GetTemplateChild("PART_Button") as Button;
|
||||
if (this.button != null)
|
||||
{
|
||||
this.button.Click += this.ButtonClick;
|
||||
}
|
||||
|
||||
this.GroupStyle.CollectionChanged -= this.OnGroupStyleCollectionChanged;
|
||||
|
||||
this.contextMenu = this.GetTemplateChild("PART_Menu") as ContextMenu;
|
||||
if (this.contextMenu != null)
|
||||
{
|
||||
foreach (var groupStyle in this.GroupStyle)
|
||||
{
|
||||
this.contextMenu.GroupStyle.Add(groupStyle);
|
||||
}
|
||||
|
||||
this.GroupStyle.CollectionChanged += this.OnGroupStyleCollectionChanged;
|
||||
|
||||
if (this.Items != null && this.ItemsSource == null)
|
||||
{
|
||||
foreach (var newItem in this.Items)
|
||||
{
|
||||
this.TryRemoveVisualFromOldTree(newItem);
|
||||
this.contextMenu.Items.Add(newItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
private void OnGroupStyleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
#else
|
||||
private void OnGroupStyleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
#endif
|
||||
{
|
||||
if (e.OldItems != null)
|
||||
{
|
||||
foreach (var groupStyle in e.OldItems.OfType<GroupStyle>())
|
||||
{
|
||||
this.contextMenu?.GroupStyle.Remove(groupStyle);
|
||||
}
|
||||
}
|
||||
|
||||
if (e.NewItems != null)
|
||||
{
|
||||
foreach (var groupStyle in e.NewItems.OfType<GroupStyle>())
|
||||
{
|
||||
this.contextMenu?.GroupStyle.Add(groupStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnMouseRightButtonUp(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseRightButtonUp(e);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void TryRemoveVisualFromOldTree(object item)
|
||||
{
|
||||
if (item is Visual visual)
|
||||
{
|
||||
var parent = LogicalTreeHelper.GetParent(visual) as FrameworkElement ?? VisualTreeHelper.GetParent(visual) as FrameworkElement;
|
||||
if (Equals(this, parent))
|
||||
{
|
||||
this.RemoveLogicalChild(visual);
|
||||
this.RemoveVisualChild(visual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Invoked when the <see cref="P:System.Windows.Controls.ItemsControl.Items" /> property changes.</summary>
|
||||
/// <param name="e">Information about the change.</param>
|
||||
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
base.OnItemsChanged(e);
|
||||
if (this.contextMenu == null || this.ItemsSource != null || this.contextMenu.ItemsSource != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.Action)
|
||||
{
|
||||
case NotifyCollectionChangedAction.Add:
|
||||
if (e.NewItems != null)
|
||||
{
|
||||
foreach (var newItem in e.NewItems)
|
||||
{
|
||||
this.TryRemoveVisualFromOldTree(newItem);
|
||||
this.contextMenu.Items.Add(newItem);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Remove:
|
||||
if (e.OldItems != null)
|
||||
{
|
||||
foreach (var oldItem in e.OldItems)
|
||||
{
|
||||
this.contextMenu.Items.Remove(oldItem);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Move:
|
||||
case NotifyCollectionChangedAction.Replace:
|
||||
if (e.OldItems != null)
|
||||
{
|
||||
foreach (var oldItem in e.OldItems)
|
||||
{
|
||||
this.contextMenu.Items.Remove(oldItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (e.NewItems != null)
|
||||
{
|
||||
foreach (var newItem in e.NewItems)
|
||||
{
|
||||
this.TryRemoveVisualFromOldTree(newItem);
|
||||
this.contextMenu.Items.Add(newItem);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case NotifyCollectionChangedAction.Reset:
|
||||
if (this.Items != null)
|
||||
{
|
||||
this.contextMenu.Items.Clear();
|
||||
foreach (var newItem in this.Items)
|
||||
{
|
||||
this.TryRemoveVisualFromOldTree(newItem);
|
||||
this.contextMenu.Items.Add(newItem);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private Button button;
|
||||
private ContextMenu contextMenu;
|
||||
}
|
||||
|
||||
internal static class CommandHelpers
|
||||
{
|
||||
internal static bool CanExecuteCommandSource(ICommandSource commandSource)
|
||||
{
|
||||
var command = commandSource.Command;
|
||||
if (command == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var commandParameter = commandSource.CommandParameter ?? commandSource;
|
||||
if (command is RoutedCommand routedCommand)
|
||||
{
|
||||
var target = commandSource.CommandTarget ?? commandSource as IInputElement;
|
||||
return routedCommand.CanExecute(commandParameter, target);
|
||||
}
|
||||
|
||||
return command.CanExecute(commandParameter);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SecuritySafeCritical]
|
||||
internal static void ExecuteCommandSource(ICommandSource commandSource)
|
||||
{
|
||||
CriticalExecuteCommandSource(commandSource);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
internal static void CriticalExecuteCommandSource(ICommandSource commandSource)
|
||||
{
|
||||
var command = commandSource.Command;
|
||||
if (command == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var commandParameter = commandSource.CommandParameter ?? commandSource;
|
||||
if (command is RoutedCommand routedCommand)
|
||||
{
|
||||
var target = commandSource.CommandTarget ?? commandSource as IInputElement;
|
||||
if (routedCommand.CanExecute(commandParameter, target))
|
||||
{
|
||||
routedCommand.Execute(commandParameter, target);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (command.CanExecute(commandParameter))
|
||||
{
|
||||
command.Execute(commandParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool CanExecuteCommandSource(ICommandSource commandSource, ICommand theCommand)
|
||||
{
|
||||
var command = theCommand;
|
||||
if (command == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var commandParameter = commandSource.CommandParameter ?? commandSource;
|
||||
if (command is RoutedCommand routedCommand)
|
||||
{
|
||||
var target = commandSource.CommandTarget ?? commandSource as IInputElement;
|
||||
return routedCommand.CanExecute(commandParameter, target);
|
||||
}
|
||||
|
||||
return command.CanExecute(commandParameter);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SecuritySafeCritical]
|
||||
internal static void ExecuteCommandSource(ICommandSource commandSource, ICommand theCommand)
|
||||
{
|
||||
CriticalExecuteCommandSource(commandSource, theCommand);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
internal static void CriticalExecuteCommandSource(ICommandSource commandSource, ICommand theCommand)
|
||||
{
|
||||
var command = theCommand;
|
||||
if (command == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var commandParameter = commandSource.CommandParameter ?? commandSource;
|
||||
if (command is RoutedCommand routedCommand)
|
||||
{
|
||||
var target = commandSource.CommandTarget ?? commandSource as IInputElement;
|
||||
if (routedCommand.CanExecute(commandParameter, target))
|
||||
{
|
||||
routedCommand.Execute(commandParameter, target);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (command.CanExecute(commandParameter))
|
||||
{
|
||||
command.Execute(commandParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
<!-- ToolBox Control -->
|
||||
<ContentControl Template="{Binding ToolBox,RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"/>
|
||||
|
||||
<ScrollViewer Grid.Column="1">
|
||||
<ScrollViewer Grid.Row="1">
|
||||
<!-- Diagram Control -->
|
||||
<dd:DiagramControl x:Name="PART_DiagramControl" MinWidth="1000" MinHeight="1000" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
|
||||
</ScrollViewer>
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Windows;
|
||||
using System.Xml.Linq;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
using AIStudio.Wpf.Mind.ViewModels;
|
||||
|
||||
namespace AIStudio.Wpf.Mind.Controls
|
||||
{
|
||||
@@ -22,7 +23,7 @@ namespace AIStudio.Wpf.Mind.Controls
|
||||
public const string PART_DiagramControl = "PART_DiagramControl";
|
||||
private DiagramControl _diagramControl;
|
||||
|
||||
private IDiagramViewModel _diagramViewModel;
|
||||
private MindDiagramViewModel _diagramViewModel;
|
||||
|
||||
static MindEditor()
|
||||
{
|
||||
@@ -31,16 +32,10 @@ namespace AIStudio.Wpf.Mind.Controls
|
||||
|
||||
public MindEditor()
|
||||
{
|
||||
_diagramViewModel = new DiagramViewModel();
|
||||
_diagramViewModel.ShowGrid = true;
|
||||
_diagramViewModel.GridCellSize = new SizeBase(125 / ScreenHelper.ScreenScale, 125 / ScreenHelper.ScreenScale);
|
||||
_diagramViewModel = new MindDiagramViewModel();
|
||||
_diagramViewModel.GridMarginSize = new Size(0, 0);
|
||||
_diagramViewModel.CellHorizontalAlignment = CellHorizontalAlignment.Center;
|
||||
_diagramViewModel.CellVerticalAlignment = CellVerticalAlignment.Center;
|
||||
_diagramViewModel.PageSizeType = PageSizeType.Custom;
|
||||
_diagramViewModel.PageSize = new SizeBase(double.NaN, double.NaN);
|
||||
_diagramViewModel.ColorViewModel = new ColorViewModel() { LineWidth = 2 };
|
||||
_diagramViewModel.DrawModeViewModel = new DrawModeViewModel() { LineDrawMode = DrawMode.ConnectingLineSmooth };
|
||||
|
||||
_diagramViewModel.PropertyChanged += DiagramViewModel_PropertyChanged;
|
||||
}
|
||||
@@ -52,7 +47,7 @@ namespace AIStudio.Wpf.Mind.Controls
|
||||
_diagramControl = GetTemplateChild(PART_DiagramControl) as DiagramControl;
|
||||
_diagramControl.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
_diagramControl.VerticalAlignment = VerticalAlignment.Stretch;
|
||||
_diagramControl.DataContext = _diagramViewModel;
|
||||
this.DataContext = _diagramViewModel;
|
||||
|
||||
GetDataFunc = GetData;
|
||||
}
|
||||
@@ -97,7 +92,11 @@ namespace AIStudio.Wpf.Mind.Controls
|
||||
{
|
||||
_diagramViewModel.IsLoading = true;
|
||||
_diagramViewModel.Items.Clear();
|
||||
//_diagramViewModel.ToObject(json);
|
||||
MindNode level1node = new MindNode(_diagramViewModel, Mind.NodeLevel.Level1, _diagramViewModel.MindType) { Text = "思维导图" };
|
||||
_diagramViewModel.DirectAddItemCommand.Execute(level1node);
|
||||
level1node.Left = 200;
|
||||
level1node.Top = 200;
|
||||
_diagramViewModel.DoCommandManager.Init();
|
||||
_diagramViewModel.IsLoading = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,18 @@
|
||||
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.Mind.Controls"
|
||||
xmlns:dd="https://gitee.com/akwkevin/aistudio.-wpf.-diagram"
|
||||
xmlns:controls="clr-namespace:AIStudio.Wpf.Mind.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800" >
|
||||
<Grid Height="60">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/AIStudio.Wpf.Mind;component/Styles/Button.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Height="70">
|
||||
<TabControl>
|
||||
<TabItem Header="思路">
|
||||
<Grid>
|
||||
@@ -14,6 +22,112 @@
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Style="{StaticResource FlatButtonStyle}" Grid.Row="0" Grid.Column="0" Command="{Binding UndoCommand}">
|
||||
<Path Width="12" Height="12" Stretch="Uniform" Fill="Black" Data="M255.545 8c-66.269.119-126.438 26.233-170.86 68.685L48.971 40.971C33.851 25.851 8 36.559 8 57.941V192c0 13.255 10.745 24 24 24h134.059c21.382 0 32.09-25.851 16.971-40.971l-41.75-41.75c30.864-28.899 70.801-44.907 113.23-45.273 92.398-.798 170.283 73.977 169.484 169.442C423.236 348.009 349.816 424 256 424c-41.127 0-79.997-14.678-110.63-41.556-4.743-4.161-11.906-3.908-16.368.553L89.34 422.659c-4.872 4.872-4.631 12.815.482 17.433C133.798 479.813 192.074 504 256 504c136.966 0 247.999-111.033 248-247.998C504.001 119.193 392.354 7.755 255.545 8z"></Path>
|
||||
</Button>
|
||||
<Button Style="{StaticResource FlatButtonStyle}" Grid.Row="1" Grid.Column="0" Command="{Binding RedoCommand}">
|
||||
<Path Width="12" Height="12" Stretch="Uniform" Fill="Black" Data="M256.455 8c66.269.119 126.437 26.233 170.859 68.685l35.715-35.715C478.149 25.851 504 36.559 504 57.941V192c0 13.255-10.745 24-24 24H345.941c-21.382 0-32.09-25.851-16.971-40.971l41.75-41.75c-30.864-28.899-70.801-44.907-113.23-45.273-92.398-.798-170.283 73.977-169.484 169.442C88.764 348.009 162.184 424 256 424c41.127 0 79.997-14.678 110.629-41.556 4.743-4.161 11.906-3.908 16.368.553l39.662 39.662c4.872 4.872 4.631 12.815-.482 17.433C378.202 479.813 319.926 504 256 504 119.034 504 8.001 392.967 8 256.002 7.999 119.193 119.646 7.755 256.455 8z"></Path>
|
||||
</Button>
|
||||
|
||||
<Button Style="{StaticResource FlatButtonStyle}" Grid.Row="0" Grid.Column="1" Command="{Binding AddChildCommand}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Stretch="Uniform" Fill="Black" Data="M992.9 500.1H355c-19.3 0-35 15.7-35 35V660H182V340.8h427.8c32 0 58-26 58-58V58c0-32-25.9-58-58-58H58C26 0 0 26 0 58v224.8c0 32 26 58 58 58h54V689c0 13.3 7.4 24.8 18.2 30.7 6.3 6.3 15.1 10.3 24.8 10.3h165v145.9c0 19.3 15.7 35 35 35h226c19.3 0 35-15.7 35-35s-15.7-35-35-35H390V570.1h567.9V611c0 19.3 15.7 35 35 35s35-15.7 35-35v-75.9c0-19.3-15.7-35-35-35zM70 70h527.8v200.8H70V70zM989 830h-89v-89c0-19.3-15.7-35-35-35s-35 15.7-35 35v89h-89c-19.3 0-35 15.7-35 35s15.7 35 35 35h89v89c0 19.3 15.7 35 35 35s35-15.7 35-35v-89h89c19.3 0 35-15.7 35-35s-15.7-35-35-35z"></Path>
|
||||
<TextBlock>插入下级主题</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Style="{StaticResource FlatButtonStyle}" Grid.Row="1" Grid.Column="1" Command="{Binding AddPeerCommand}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Stretch="Uniform" Fill="Black" Data="M651.8 775.5h-20.3v-527h178V305c0 19.3 15.7 35 35 35s35-15.7 35-35v-91.5c0-19.3-15.7-35-35-35h-248c-19.3 0-35 15.7-35 35V477H340.8V236.1c0-32-26-58-58-58H58c-32 0-58 26-58 58v551.8c0 32 26 58 58 58h224.8c32 0 58-26 58-58V547h220.7v263.5c0 19.3 15.7 35 35 35h55.3c19.3 0 35-15.7 35-35s-15.7-35-35-35z m-381 0.4H70V248.1h200.8v527.8zM990 651.5h-89v-89c0-19.3-15.7-35-35-35s-35 15.7-35 35v89h-89c-19.3 0-35 15.7-35 35s15.7 35 35 35h89v89c0 19.3 15.7 35 35 35s35-15.7 35-35v-89h89c19.3 0 35-15.7 35-35s-15.7-35-35-35z"></Path>
|
||||
<TextBlock>插入同级主题</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Style="{StaticResource FlatButtonStyle}" Grid.Row="0" Grid.Column="2" Command="{Binding AddParentCommand}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Stretch="Uniform" Fill="Black" RenderTransformOrigin="0.5,0.5" Data="M992.9 500.1H355c-19.3 0-35 15.7-35 35V660H182V340.8h427.8c32 0 58-26 58-58V58c0-32-25.9-58-58-58H58C26 0 0 26 0 58v224.8c0 32 26 58 58 58h54V689c0 13.3 7.4 24.8 18.2 30.7 6.3 6.3 15.1 10.3 24.8 10.3h165v145.9c0 19.3 15.7 35 35 35h226c19.3 0 35-15.7 35-35s-15.7-35-35-35H390V570.1h567.9V611c0 19.3 15.7 35 35 35s35-15.7 35-35v-75.9c0-19.3-15.7-35-35-35zM70 70h527.8v200.8H70V70zM989 830h-89v-89c0-19.3-15.7-35-35-35s-35 15.7-35 35v89h-89c-19.3 0-35 15.7-35 35s15.7 35 35 35h89v89c0 19.3 15.7 35 35 35s35-15.7 35-35v-89h89c19.3 0 35-15.7 35-35s-15.7-35-35-35z">
|
||||
<Path.RenderTransform>
|
||||
<ScaleTransform ScaleX="-1" ScaleY="-1"/>
|
||||
</Path.RenderTransform>
|
||||
</Path>
|
||||
<TextBlock>插入上级主题</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<Button Style="{StaticResource FlatButtonStyle}" Grid.Row="0" Grid.Column="3" Command="{Binding MoveForwardCommand}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Stretch="Uniform" Fill="Black" Data="M62.5 500L312.5 500L312.5 937.5L687.5 937.5L687.5 500L937.5 500L500 62.5Z"></Path>
|
||||
<TextBlock>上移</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Style="{StaticResource FlatButtonStyle}" Grid.Row="1" Grid.Column="3" Command="{Binding MoveBackCommand}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Stretch="Uniform" Fill="Black" Data="M687.5 62.5L312.5 62.5L312.5 500L62.5 500L500 937.5L937.4 500L687.5 500Z"></Path>
|
||||
<TextBlock>下移</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Style="{StaticResource FlatButtonStyle}" Grid.Row="0" Grid.Column="4" Command="{Binding EditCommand}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Stretch="Uniform" Fill="Black" Data="M8,12H16V14H8V12M10,20H6V4H13V9H18V12.1L20,10.1V8L14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H10V20M8,18H12.1L13,17.1V16H8V18M20.2,13C20.3,13 20.5,13.1 20.6,13.2L21.9,14.5C22.1,14.7 22.1,15.1 21.9,15.3L20.9,16.3L18.8,14.2L19.8,13.2C19.9,13.1 20,13 20.2,13M20.2,16.9L14.1,23H12V20.9L18.1,14.8L20.2,16.9Z"></Path>
|
||||
<TextBlock>编辑</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Style="{StaticResource FlatButtonStyle}" Grid.Column="4" Command="{Binding DeleteSelfCommand}" Height="22" Grid.RowSpan="2" VerticalAlignment="Bottom">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Path Width="12" Height="12" Stretch="Uniform" Fill="Black" Data="M 25.3333,23.75L 50.6667,23.75C 51.5411,23.75 51.8541,27.3125 51.8541,27.3125L 24.1458,27.3125C 24.1458,27.3125 24.4589,23.75 25.3333,23.75 Z M 35.625,19.7917L 40.375,19.7917C 40.8122,19.7917 41.9583,20.9378 41.9583,21.375C 41.9583,21.8122 40.8122,22.9584 40.375,22.9584L 35.625,22.9584C 35.1878,22.9584 34.0416,21.8122 34.0416,21.375C 34.0416,20.9378 35.1878,19.7917 35.625,19.7917 Z M 27.7083,28.5L 48.2916,28.5C 49.1661,28.5 49.875,29.2089 49.875,30.0834L 48.2916,53.8334C 48.2916,54.7078 47.5828,55.4167 46.7083,55.4167L 29.2917,55.4167C 28.4172,55.4167 27.7083,54.7078 27.7083,53.8334L 26.125,30.0834C 26.125,29.2089 26.8339,28.5 27.7083,28.5 Z M 30.0833,31.6667L 30.4792,52.25L 33.25,52.25L 32.8542,31.6667L 30.0833,31.6667 Z M 36.4167,31.6667L 36.4167,52.25L 39.5833,52.25L 39.5833,31.6667L 36.4167,31.6667 Z M 43.1458,31.6667L 42.75,52.25L 45.5208,52.25L 45.9167,31.6667L 43.1458,31.6667 Z "></Path>
|
||||
<TextBlock>删除</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<controls:DropDownButton Grid.RowSpan="2" Grid.Column="5" >
|
||||
<controls:DropDownButton.Content>
|
||||
<StackPanel>
|
||||
<Path Width="18" Height="18" Stretch="Uniform" Fill="Black" Data="M 23.4963,46.1288L 25.0796,48.8712L 29.4053,50.0303L 33.519,47.6553L 34.8902,46.8636L 37.6326,45.2803L 38.4242,46.6515L 37.2652,50.9772L 30.4091,54.9356L 21.7577,52.6174L 18.591,47.1326L 20.9091,38.4811L 27.7652,34.5227L 32.0909,35.6818L 32.8826,37.053L 30.1402,38.6364L 28.769,39.428L 24.6553,41.803L 23.4963,46.1288 Z M 38.7348,28.1895L 45.5908,24.2311L 54.2423,26.5493L 57.409,32.0341L 55.0908,40.6856L 48.2348,44.6439L 43.9091,43.4848L 43.1174,42.1136L 45.8598,40.5303L 47.231,39.7386L 51.3446,37.3636L 52.5037,33.0379L 50.9204,30.2955L 46.5946,29.1364L 42.481,31.5114L 41.1098,32.3031L 38.3674,33.8864L 37.5757,32.5152L 38.7348,28.1895 Z M 33.9006,45.1496L 31.7377,44.5701L 30.5502,42.5133L 31.1298,40.3504L 42.0994,34.0171L 44.2623,34.5966L 45.4498,36.6534L 44.8702,38.8163L 33.9006,45.1496 Z "></Path>
|
||||
<TextBlock>链接</TextBlock>
|
||||
</StackPanel>
|
||||
</controls:DropDownButton.Content>
|
||||
<controls:DropDownButton.Items>
|
||||
<MenuItem Header="插入链接"></MenuItem>
|
||||
<MenuItem Header="移除已有链接"></MenuItem>
|
||||
</controls:DropDownButton.Items>
|
||||
</controls:DropDownButton>
|
||||
<controls:DropDownButton Grid.RowSpan="2" Grid.Column="6" >
|
||||
<controls:DropDownButton.Content>
|
||||
<StackPanel>
|
||||
<Path Width="18" Height="18" Stretch="Uniform" Fill="Black" Data="M250 645L350 745L625 470L800 645L950 495V950H250V645zM250 503.55V250H405L554.3000000000001 399.25L350 603.55L250 503.55zM546.45 250H950V353.5500000000001L800 503.5500000000001L546.45 250zM200 1050H1000A50 50 0 0 0 1050 1000V200A50 50 0 0 0 1000 150H200A50 50 0 0 0 150 200V1000A50 50 0 0 0 200 1050zM775 700A75 75 0 1 0 775 850A75 75 0 0 0 775 700z"></Path>
|
||||
<TextBlock>图片</TextBlock>
|
||||
</StackPanel>
|
||||
</controls:DropDownButton.Content>
|
||||
<controls:DropDownButton.Items>
|
||||
<MenuItem Header="插入图片"></MenuItem>
|
||||
<MenuItem Header="移除已有图片"></MenuItem>
|
||||
</controls:DropDownButton.Items>
|
||||
</controls:DropDownButton>
|
||||
<controls:DropDownButton Grid.RowSpan="2" Grid.Column="7" >
|
||||
<controls:DropDownButton.Content>
|
||||
<StackPanel>
|
||||
<Path Width="18" Height="18" Stretch="Uniform" Fill="Black" Data="M5,3C3.89,3 3,3.89 3,5V19C3,20.11 3.89,21 5,21H19C20.11,21 21,20.11 21,19V5C21,3.89 20.11,3 19,3H5M5,5H19V19H5V5M7,7V9H17V7H7M7,11V13H17V11H7M7,15V17H14V15H7Z"></Path>
|
||||
<TextBlock>备注</TextBlock>
|
||||
</StackPanel>
|
||||
</controls:DropDownButton.Content>
|
||||
<controls:DropDownButton.Items>
|
||||
<MenuItem Header="插入备注"></MenuItem>
|
||||
<MenuItem Header="移除已有备注"></MenuItem>
|
||||
</controls:DropDownButton.Items>
|
||||
</controls:DropDownButton>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="外观">
|
||||
@@ -22,6 +136,36 @@
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<controls:DropDownButton Grid.RowSpan="2" Grid.Column="7">
|
||||
<controls:DropDownButton.Content>
|
||||
<StackPanel>
|
||||
<Path Width="18" Height="18" Stretch="Uniform" Fill="Black" Data="M5,3C3.89,3 3,3.89 3,5V19C3,20.11 3.89,21 5,21H19C20.11,21 21,20.11 21,19V5C21,3.89 20.11,3 19,3H5M5,5H19V19H5V5M7,7V9H17V7H7M7,11V13H17V11H7M7,15V17H14V15H7Z"></Path>
|
||||
<TextBlock>类型</TextBlock>
|
||||
</StackPanel>
|
||||
</controls:DropDownButton.Content>
|
||||
<controls:DropDownButton.Items>
|
||||
<MenuItem Header="思维导图" IsCheckable="True" IsChecked="{Binding MindType,Converter={dd:ConverterValueMapToBool Parameter='Mind'}, ConverterParameter='Mind'}" />
|
||||
<MenuItem Header="目录组织图" IsCheckable="True" IsChecked="{Binding MindType,Converter={dd:ConverterValueMapToBool Parameter='Directory'}, ConverterParameter='Directory'}" />
|
||||
<MenuItem Header="鱼骨头图" IsCheckable="True" IsChecked="{Binding MindType,Converter={dd:ConverterValueMapToBool Parameter='FishBone'}, ConverterParameter='FishBone'}" />
|
||||
<MenuItem Header="逻辑结构图" IsCheckable="True" IsChecked="{Binding MindType,Converter={dd:ConverterValueMapToBool Parameter='Logical'}, ConverterParameter='Logical'}" />
|
||||
<MenuItem Header="组织结构图" IsCheckable="True" IsChecked="{Binding MindType,Converter={dd:ConverterValueMapToBool Parameter='Organizational'}, ConverterParameter='Organizational'}" />
|
||||
<MenuItem Header="天盘图" IsCheckable="True" IsChecked="{Binding MindType,Converter={dd:ConverterValueMapToBool Parameter='Celestial'}, ConverterParameter='Celestial'}" />
|
||||
</controls:DropDownButton.Items>
|
||||
</controls:DropDownButton>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="视图">
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Windows.Media;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Algorithms;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
using AIStudio.Wpf.DiagramDesigner.Helpers;
|
||||
using AIStudio.Wpf.Mind.ViewModels;
|
||||
|
||||
namespace AIStudio.Wpf.Mind.Helpers
|
||||
@@ -34,6 +35,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
|
||||
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
|
||||
|
||||
mindNode.ConnectorOrientation = ConnectorOrientation.None;
|
||||
break;
|
||||
}
|
||||
case NodeLevel.Level2:
|
||||
@@ -109,12 +111,12 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
if (mindNode.NodeLevel == NodeLevel.Level1)
|
||||
{
|
||||
var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
|
||||
sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, childrensizes.Sum(p => p.Width)), sizewithSpacing.Height + childrensizes.Max(p => p.Height));
|
||||
sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, childrensizes.SumOrDefault(p => p.Width)), sizewithSpacing.Height + childrensizes.MaxOrDefault(p => p.Height));
|
||||
}
|
||||
else
|
||||
{
|
||||
var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
|
||||
sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, sizewithSpacing.Width * 0.5 + childrensizes.Max(p => p.Width)), sizewithSpacing.Height + childrensizes.Sum(p => p.Height));
|
||||
sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, sizewithSpacing.Width * 0.5 + childrensizes.MaxOrDefault(p => p.Width)), sizewithSpacing.Height + childrensizes.SumOrDefault(p => p.Height));
|
||||
}
|
||||
}
|
||||
mindNode.DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
|
||||
@@ -127,7 +129,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
{
|
||||
if (mindNode.NodeLevel == NodeLevel.Level1)
|
||||
{
|
||||
double left = mindNode.MiddlePosition.X - Math.Max(mindNode.DesiredSize.Width, mindNode.Children.Sum(p => p.DesiredSize.Width)) / 2;
|
||||
double left = mindNode.MiddlePosition.X - Math.Max(mindNode.DesiredSize.Width, mindNode.Children.SumOrDefault(p => p.DesiredSize.Width)) / 2;
|
||||
double top = mindNode.MiddlePosition.Y + mindNode.ItemHeight / 2 + mindNode.Spacing.Height;
|
||||
if (mindNode.Children?.Count > 0)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Windows.Media;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Algorithms;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
using AIStudio.Wpf.DiagramDesigner.Helpers;
|
||||
using AIStudio.Wpf.Mind.ViewModels;
|
||||
|
||||
namespace AIStudio.Wpf.Mind.Helpers
|
||||
@@ -39,6 +40,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
|
||||
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
|
||||
|
||||
mindNode.ConnectorOrientation = ConnectorOrientation.None;
|
||||
break;
|
||||
}
|
||||
case NodeLevel.Level2:
|
||||
@@ -144,18 +146,18 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
var bottoms = mindNode.Children.Where((p, index) => index % 2 == 1).ToList();
|
||||
bottoms.ForEach(p => p.ConnectorOrientation = ConnectorOrientation.TopLeft);
|
||||
var bottomsizes = bottoms.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
|
||||
sizewithSpacing = new SizeBase(sizewithSpacing.Width + bottomoffset + Math.Max(topsizes.Sum(p => p.Width), bottomsizes.Sum(p => p.Width)), sizewithSpacing.Height + topsizes.Max(p => p.Height) + bottomsizes.Max(p => p.Height));
|
||||
sizewithSpacing = new SizeBase(sizewithSpacing.Width + bottomoffset + Math.Max(topsizes.SumOrDefault(p => p.Width), bottomsizes.SumOrDefault(p => p.Width)), sizewithSpacing.Height + topsizes.MaxOrDefault(p => p.Height) + bottomsizes.MaxOrDefault(p => p.Height));
|
||||
}
|
||||
else if (mindNode.NodeLevel == NodeLevel.Level2)
|
||||
{
|
||||
var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
|
||||
var lastchildsize = childrensizes.LastOrDefault();
|
||||
sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, sizewithSpacing.Height + childrensizes.Sum(p => p.Height) - lastchildsize.Height / 2 + lastchildsize.Width), sizewithSpacing.Height + childrensizes.Sum(p => p.Height));
|
||||
sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, sizewithSpacing.Height + childrensizes.SumOrDefault(p => p.Height) - lastchildsize.Height / 2 + lastchildsize.Width), sizewithSpacing.Height + childrensizes.SumOrDefault(p => p.Height));
|
||||
}
|
||||
else if (mindNode.NodeLevel == NodeLevel.Level3)
|
||||
{
|
||||
var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
|
||||
sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, sizewithSpacing.Width * 0.5 + childrensizes.Max(p => p.Width)), sizewithSpacing.Height + childrensizes.Sum(p => p.Height));
|
||||
sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, sizewithSpacing.Width * 0.5 + childrensizes.MaxOrDefault(p => p.Width)), sizewithSpacing.Height + childrensizes.SumOrDefault(p => p.Height));
|
||||
}
|
||||
}
|
||||
mindNode.DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Windows.Media;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Algorithms;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
using AIStudio.Wpf.DiagramDesigner.Helpers;
|
||||
using AIStudio.Wpf.Mind.ViewModels;
|
||||
|
||||
namespace AIStudio.Wpf.Mind.Helpers
|
||||
@@ -35,6 +36,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.Circle;
|
||||
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
|
||||
|
||||
mindNode.ConnectorOrientation = ConnectorOrientation.None;
|
||||
break;
|
||||
}
|
||||
case NodeLevel.Level2:
|
||||
@@ -106,7 +108,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
if (mindNode.Children?.Count > 0)
|
||||
{
|
||||
var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
|
||||
sizewithSpacing = new SizeBase(sizewithSpacing.Width + childrensizes.Max(p => p.Width), Math.Max(sizewithSpacing.Height, childrensizes.Sum(p => p.Height)));
|
||||
sizewithSpacing = new SizeBase(sizewithSpacing.Width + childrensizes.MaxOrDefault(p => p.Width), Math.Max(sizewithSpacing.Height, childrensizes.SumOrDefault(p => p.Height)));
|
||||
}
|
||||
mindNode.DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
|
||||
mindNode.Visible = isExpanded;
|
||||
@@ -117,7 +119,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
public void ArrangeOverride(MindNode mindNode)
|
||||
{
|
||||
double left = mindNode.MiddlePosition.X + mindNode.ItemWidth / 2 + mindNode.Spacing.Width;
|
||||
double top = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, mindNode.Children.Sum(p => p.DesiredSize.Height)) / 2;
|
||||
double top = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, mindNode.Children.SumOrDefault(p => p.DesiredSize.Height)) / 2;
|
||||
if (mindNode.Children?.Count > 0)
|
||||
{
|
||||
foreach (var child in mindNode.Children)
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Windows.Media;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Algorithms;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
using AIStudio.Wpf.DiagramDesigner.Helpers;
|
||||
using AIStudio.Wpf.Mind.ViewModels;
|
||||
|
||||
namespace AIStudio.Wpf.Mind.Helpers
|
||||
@@ -35,6 +36,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.Circle;
|
||||
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
|
||||
|
||||
mindNode.ConnectorOrientation = ConnectorOrientation.None;
|
||||
break;
|
||||
}
|
||||
case NodeLevel.Level2:
|
||||
@@ -114,12 +116,12 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
var lefts = mindNode.Children.Where((p, index) => index % 2 == 1).ToList();
|
||||
lefts.ForEach(p => p.ConnectorOrientation = ConnectorOrientation.Right);
|
||||
var leftsizes = lefts.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
|
||||
sizewithSpacing = new SizeBase(sizewithSpacing.Width + rightsizes.Max(p => p.Width) + +leftsizes.Max(p => p.Width), Math.Max(sizewithSpacing.Height, Math.Max(rightsizes.Sum(p => p.Height), leftsizes.Sum(p => p.Height))));
|
||||
sizewithSpacing = new SizeBase(sizewithSpacing.Width + rightsizes.MaxOrDefault(p => p.Width) + +leftsizes.MaxOrDefault(p => p.Width), Math.Max(sizewithSpacing.Height, Math.Max(rightsizes.SumOrDefault(p => p.Height), leftsizes.SumOrDefault(p => p.Height))));
|
||||
}
|
||||
else
|
||||
{
|
||||
var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
|
||||
sizewithSpacing = new SizeBase(sizewithSpacing.Width + childrensizes.Max(p => p.Width), Math.Max(sizewithSpacing.Height, childrensizes.Sum(p => p.Height)));
|
||||
sizewithSpacing = new SizeBase(sizewithSpacing.Width + childrensizes.MaxOrDefault(p => p.Width), Math.Max(sizewithSpacing.Height, childrensizes.SumOrDefault(p => p.Height)));
|
||||
}
|
||||
}
|
||||
mindNode.DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
|
||||
@@ -136,7 +138,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
{
|
||||
var rights = mindNode.Children.Where(p => p.ConnectorOrientation == ConnectorOrientation.Left).ToList();
|
||||
double left = mindNode.MiddlePosition.X + mindNode.ItemWidth / 2 + mindNode.Spacing.Width;
|
||||
double lefttop = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, rights.Sum(p => p.DesiredSize.Height)) / 2;
|
||||
double lefttop = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, rights.SumOrDefault(p => p.DesiredSize.Height)) / 2;
|
||||
foreach (var child in rights)
|
||||
{
|
||||
child.Left = left + child.Spacing.Width + child.Offset.X;
|
||||
@@ -154,7 +156,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
|
||||
var lefts = mindNode.Children.Where(p => p.ConnectorOrientation == ConnectorOrientation.Right).ToList();
|
||||
double right = mindNode.MiddlePosition.X - mindNode.ItemWidth / 2 - mindNode.Spacing.Width;
|
||||
double righttop = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, lefts.Sum(p => p.DesiredSize.Height)) / 2;
|
||||
double righttop = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, lefts.SumOrDefault(p => p.DesiredSize.Height)) / 2;
|
||||
foreach (var child in lefts)
|
||||
{
|
||||
child.Left = right - child.Spacing.Width - child.ItemWidth + child.Offset.X;
|
||||
@@ -176,7 +178,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
if (mindNode.GetLevel2Node().ConnectorOrientation == ConnectorOrientation.Left)
|
||||
{
|
||||
double left = mindNode.MiddlePosition.X + mindNode.ItemWidth / 2 + mindNode.Spacing.Width;
|
||||
double top = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, mindNode.Children.Sum(p => p.DesiredSize.Height)) / 2;
|
||||
double top = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, mindNode.Children.SumOrDefault(p => p.DesiredSize.Height)) / 2;
|
||||
if (mindNode.Children?.Count > 0)
|
||||
{
|
||||
foreach (var child in mindNode.Children)
|
||||
@@ -198,7 +200,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
else
|
||||
{
|
||||
double right = mindNode.MiddlePosition.X - mindNode.ItemWidth / 2 - mindNode.Spacing.Width;
|
||||
double top = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, mindNode.Children.Sum(p => p.DesiredSize.Height)) / 2;
|
||||
double top = mindNode.MiddlePosition.Y - Math.Min(mindNode.DesiredSize.Height, mindNode.Children.SumOrDefault(p => p.DesiredSize.Height)) / 2;
|
||||
if (mindNode.Children?.Count > 0)
|
||||
{
|
||||
foreach (var child in mindNode.Children)
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Windows.Media;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using AIStudio.Wpf.DiagramDesigner.Algorithms;
|
||||
using AIStudio.Wpf.DiagramDesigner.Geometrys;
|
||||
using AIStudio.Wpf.DiagramDesigner.Helpers;
|
||||
using AIStudio.Wpf.Mind.ViewModels;
|
||||
|
||||
namespace AIStudio.Wpf.Mind.Helpers
|
||||
@@ -33,6 +34,8 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
mindNode.FontViewModel.FontSize = 15;
|
||||
mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
|
||||
mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
|
||||
|
||||
mindNode.ConnectorOrientation = ConnectorOrientation.None;
|
||||
break;
|
||||
}
|
||||
case NodeLevel.Level2:
|
||||
@@ -107,7 +110,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
if (mindNode.Children?.Count > 0)
|
||||
{
|
||||
var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
|
||||
sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, childrensizes.Sum(p => p.Width)), sizewithSpacing.Height + childrensizes.Max(p => p.Height));
|
||||
sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, childrensizes.SumOrDefault(p => p.Width)), sizewithSpacing.Height + childrensizes.MaxOrDefault(p => p.Height));
|
||||
}
|
||||
mindNode.DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
|
||||
mindNode.Visible = isExpanded;
|
||||
@@ -117,7 +120,7 @@ namespace AIStudio.Wpf.Mind.Helpers
|
||||
|
||||
public void ArrangeOverride(MindNode mindNode)
|
||||
{
|
||||
double left = mindNode.MiddlePosition.X - Math.Max(mindNode.DesiredSize.Width, mindNode.Children.Sum(p => p.DesiredSize.Width)) / 2;
|
||||
double left = mindNode.MiddlePosition.X - Math.Max(mindNode.DesiredSize.Width, mindNode.Children.SumOrDefault(p => p.DesiredSize.Width)) / 2;
|
||||
double top = mindNode.MiddlePosition.Y + mindNode.ItemHeight / 2 + mindNode.Spacing.Height;
|
||||
if (mindNode.Children?.Count > 0)
|
||||
{
|
||||
|
||||
48
AIStudio.Wpf.Mind/Styles/Button.xaml
Normal file
48
AIStudio.Wpf.Mind/Styles/Button.xaml
Normal file
@@ -0,0 +1,48 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:dd="https://gitee.com/akwkevin/aistudio.-wpf.-diagram">
|
||||
|
||||
<dd:BrushOpacityConverter x:Key="BrushOpacityConverter"/>
|
||||
|
||||
<Style x:Key="FlatButtonStyle" TargetType="{x:Type ButtonBase}">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Foreground" Value="Black" />
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="3" />
|
||||
<Setter Property="MinHeight" Value="22" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ButtonBase}">
|
||||
<Grid>
|
||||
<Border x:Name="border"
|
||||
Background="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Background}"
|
||||
CornerRadius="3"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}">
|
||||
|
||||
<ContentPresenter x:Name="content" RecognizesAccessKey="True"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
<!--触发器-->
|
||||
<ControlTemplate.Triggers>
|
||||
<!--设置鼠标进入时的背景、前景样式-->
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Background" TargetName="border" Value="{Binding Foreground,
|
||||
RelativeSource={RelativeSource Mode=TemplatedParent},
|
||||
Converter={StaticResource BrushOpacityConverter},
|
||||
ConverterParameter=0.16}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="Opacity" Value="0.5"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
61
AIStudio.Wpf.Mind/Styles/ContextMenu.xaml
Normal file
61
AIStudio.Wpf.Mind/Styles/ContextMenu.xaml
Normal file
@@ -0,0 +1,61 @@
|
||||
<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">
|
||||
|
||||
<DropShadowEffect x:Key="DropShadowEffectStyle"
|
||||
x:Shared="False"
|
||||
BlurRadius="4"
|
||||
Direction="315"
|
||||
Opacity="0.3"
|
||||
ShadowDepth="2"
|
||||
Color="Black"
|
||||
options:Freeze="True" />
|
||||
|
||||
<Style x:Key="ContextMenuStyle" TargetType="{x:Type ContextMenu}">
|
||||
<Setter Property="Background" Value="White" />
|
||||
<Setter Property="Block.TextAlignment" Value="Left" />
|
||||
<Setter Property="BorderBrush" Value="LightGray" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="Foreground" Value="Black" />
|
||||
<Setter Property="Grid.IsSharedSizeScope" Value="True" />
|
||||
<Setter Property="HasDropShadow" Value="True" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ContextMenu}">
|
||||
<Border x:Name="Border"
|
||||
Width="{TemplateBinding Width}"
|
||||
Height="{TemplateBinding Height}"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="3"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
|
||||
|
||||
<ScrollViewer x:Name="SubMenuScrollViewer"
|
||||
CanContentScroll="True">
|
||||
<ItemsPresenter x:Name="ItemsPresenter"
|
||||
Margin="0"
|
||||
Grid.IsSharedSizeScope="True"
|
||||
KeyboardNavigation.DirectionalNavigation="Cycle"
|
||||
KeyboardNavigation.TabNavigation="Cycle"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="HasDropShadow" Value="True">
|
||||
<Setter TargetName="Border" Property="Effect" Value="{StaticResource DropShadowEffectStyle}" />
|
||||
<Setter TargetName="Border" Property="Margin" Value="0 0 6 6" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="TextOptions.TextFormattingMode" Value="Ideal" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -2,6 +2,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/AIStudio.Wpf.Mind;component/Controls/DropDownButton.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/AIStudio.Wpf.Mind;component/Controls/MindEditor.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
|
||||
@@ -37,6 +37,48 @@
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<ControlTemplate x:Key="MindNodeLevelStyle" TargetType="{x:Type ContentControl}">
|
||||
<Grid>
|
||||
<Grid.ContextMenu>
|
||||
<ContextMenu ItemsSource="{Binding MenuOptions}">
|
||||
<ContextMenu.ItemContainerStyle>
|
||||
<Style TargetType="MenuItem">
|
||||
<Setter Property="MenuItem.Header" Value="{Binding Text}" />
|
||||
<Setter Property="MenuItem.ItemsSource" Value="{Binding Children}" />
|
||||
<Setter Property="MenuItem.Command" Value="{Binding Command}" />
|
||||
<Setter Property="MenuItem.Icon" Value="{Binding Icon}" />
|
||||
<Setter Property="CommandParameter" Value="{Binding CommandParameter}" />
|
||||
<Setter Property="MenuItem.IsCheckable" Value="{Binding IsCheckable}" />
|
||||
<Setter Property="MenuItem.IsChecked" Value="{Binding IsChecked}" />
|
||||
</Style>
|
||||
</ContextMenu.ItemContainerStyle>
|
||||
</ContextMenu>
|
||||
</Grid.ContextMenu>
|
||||
<Grid IsHitTestVisible="False">
|
||||
<Border BorderThickness="{Binding BorderThickness}"
|
||||
BorderBrush="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
CornerRadius="{Binding CornerRadius}">
|
||||
</Border>
|
||||
</Grid>
|
||||
<ToggleButton x:Name="toggle" IsChecked="{Binding IsExpanded}" Style="{StaticResource ExpandCollapseToggleStyle}" HorizontalAlignment="Left" Margin="-15,0,0,0" Visibility="{Binding Children.Count,Converter={StaticResource IntToVisibilityConverter}}"/>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding ConnectorOrientation}" Value="None">
|
||||
<Setter TargetName="toggle" Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ConnectorOrientation}" Value="Right">
|
||||
<Setter TargetName="toggle" Property="HorizontalAlignment" Value="Right"/>
|
||||
<Setter TargetName="toggle" Property="Margin" Value="0,0,-15,0"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ConnectorOrientation}" Value="Top">
|
||||
<Setter TargetName="toggle" Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter TargetName="toggle" Property="VerticalAlignment" Value="Top"/>
|
||||
<Setter TargetName="toggle" Property="Margin" Value="0,-15,0,0"/>
|
||||
</DataTrigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="MindLevel1NodeStyle" TargetType="{x:Type ContentControl}">
|
||||
<Grid >
|
||||
<Grid.ContextMenu>
|
||||
@@ -143,8 +185,8 @@
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="MindNodeStyle" TargetType="{x:Type ContentControl}">
|
||||
<Setter Property="Template" Value="{StaticResource MindLevel1NodeStyle}" />
|
||||
<Style.Triggers>
|
||||
<Setter Property="Template" Value="{StaticResource MindNodeLevelStyle}" />
|
||||
<!--<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding NodeLevel}" Value="Level1">
|
||||
<Setter Property="Template" Value="{StaticResource MindLevel1NodeStyle}" />
|
||||
</DataTrigger>
|
||||
@@ -154,7 +196,7 @@
|
||||
<DataTrigger Binding="{Binding NodeLevel}" Value="Level3">
|
||||
<Setter Property="Template" Value="{StaticResource MindLevel3NodeStyle}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style.Triggers>-->
|
||||
</Style>
|
||||
|
||||
<DataTemplate DataType="{x:Type viewmodel:MindNode}">
|
||||
|
||||
57
AIStudio.Wpf.Mind/ViewModels/IMindDiagramViewModel.cs
Normal file
57
AIStudio.Wpf.Mind/ViewModels/IMindDiagramViewModel.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.Mind.ViewModels
|
||||
{
|
||||
public interface IMindDiagramViewModel : IDiagramViewModel
|
||||
{
|
||||
MindType MindType
|
||||
{
|
||||
get;set;
|
||||
}
|
||||
|
||||
SimpleCommand AddParentCommand
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
SimpleCommand AddChildCommand
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
SimpleCommand AddPeerCommand
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
SimpleCommand DeleteSelfCommand
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
SimpleCommand MoveForwardCommand
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
SimpleCommand MoveBackCommand
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
SimpleCommand ChangeMindTypeCommand
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
SimpleCommand ChangeMindThemeCommand
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
}
|
||||
382
AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs
Normal file
382
AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs
Normal file
@@ -0,0 +1,382 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
|
||||
namespace AIStudio.Wpf.Mind.ViewModels
|
||||
{
|
||||
public class MindDiagramViewModel : DiagramViewModel, IMindDiagramViewModel
|
||||
{
|
||||
#region
|
||||
private MindType _mindType = Mind.MindType.Mind;
|
||||
public MindType MindType
|
||||
{
|
||||
get
|
||||
{
|
||||
return _mindType;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _mindType, value))
|
||||
{
|
||||
ExecutedChangeMindTypeCommand(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
public SimpleCommand AddParentCommand
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand AddChildCommand
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand AddPeerCommand
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand DeleteSelfCommand
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand MoveForwardCommand
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand MoveBackCommand
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
private SimpleCommand _changeMindTypeCommand;
|
||||
public SimpleCommand ChangeMindTypeCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._changeMindTypeCommand ?? (this._changeMindTypeCommand = new SimpleCommand(MindExecuteEnable, this.ExecutedChangeMindTypeCommand));
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleCommand ChangeMindThemeCommand
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand ResetLayout
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand Expand2Level1
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand Expand2Level2
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand Expand2Level3
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand Expand2Level4
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand Expand2Level5
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand Expand2Level6
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public MindDiagramViewModel()
|
||||
{
|
||||
AddChildCommand = new SimpleCommand(MindExecuteEnable, ExecuteAddChildCommand);
|
||||
AddParentCommand = new SimpleCommand(MindLevelEnable, ExecuteAddParentCommand);
|
||||
AddPeerCommand = new SimpleCommand(MindLevelEnable, ExecuteAddPeerCommand);
|
||||
DeleteSelfCommand = new SimpleCommand(MindLevelEnable, ExecuteDeleteSelfCommand);
|
||||
MoveForwardCommand = new SimpleCommand(MindExecuteEnable, ExecuteMoveForwardCommand);
|
||||
MoveBackCommand = new SimpleCommand(MindExecuteEnable, ExecuteMoveBackCommand);
|
||||
}
|
||||
|
||||
public bool MindExecuteEnable(object para)
|
||||
{
|
||||
if (ExecuteEnable(para) == false) return false;
|
||||
|
||||
if (SelectedItem is MindNode) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool MindLevelEnable(object obj)
|
||||
{
|
||||
if (MindExecuteEnable(obj) == false) return false;
|
||||
|
||||
return (SelectedItem as MindNode).NodeLevel != NodeLevel.Level1;
|
||||
}
|
||||
|
||||
#region 操作
|
||||
private void ExecutedChangeMindTypeCommand(object obj)
|
||||
{
|
||||
if (obj is MindType mindType)
|
||||
{
|
||||
Items.OfType<MindNode>().ToList().ForEach(item => { item.MindType = mindType; });
|
||||
|
||||
Items.OfType<MindNode>().FirstOrDefault()?.LayoutUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteAddChildCommand(object parameter)
|
||||
{
|
||||
List<MindNode> items = new List<MindNode>();
|
||||
if (parameter is MindNode parent)
|
||||
{
|
||||
|
||||
}
|
||||
else if (parameter is IEnumerable<MindNode> para)
|
||||
{
|
||||
parent = para.FirstOrDefault();//第一个固定为父节点
|
||||
items = para.Skip(1).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
parent = SelectedItem as MindNode;
|
||||
}
|
||||
|
||||
if (items?.Count == 0)
|
||||
{
|
||||
var node = new MindNode(this, (NodeLevel)Math.Min((int)parent.NodeLevel + 1, (int)NodeLevel.Level3), this.MindType) { Text = "分支主题" };
|
||||
items.Add(node);
|
||||
}
|
||||
|
||||
DoCommandManager.DoNewCommand(this.ToString(),
|
||||
() => {
|
||||
foreach (var item in items)
|
||||
{
|
||||
parent.AddChild(item);
|
||||
}
|
||||
parent.LayoutUpdated();
|
||||
},
|
||||
() => {
|
||||
foreach (var item in items)
|
||||
{
|
||||
parent.RemoveChild(item);
|
||||
}
|
||||
parent.LayoutUpdated();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void ExecuteAddParentCommand(object parameter)
|
||||
{
|
||||
List<MindNode> items = new List<MindNode>();
|
||||
if (parameter is MindNode node)
|
||||
{
|
||||
|
||||
}
|
||||
else if (parameter is IEnumerable<MindNode> para)
|
||||
{
|
||||
node = para.FirstOrDefault();//第一个固定为父节点
|
||||
items = para.Skip(1).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
node = SelectedItem as MindNode;
|
||||
}
|
||||
if (items?.Count == 0)
|
||||
{
|
||||
items.Add(new MindNode(this, node.NodeLevel, this.MindType) { Text = "分支主题" });
|
||||
}
|
||||
|
||||
if (node.Parent is MindNode parent)
|
||||
{
|
||||
DoCommandManager.DoNewCommand(this.ToString(),
|
||||
() => {
|
||||
int index = parent.Children.IndexOf(node);
|
||||
|
||||
parent.AddChild(items[0], index + 1);
|
||||
parent.RemoveChild(node);
|
||||
items[0].AddChild(node);
|
||||
|
||||
parent.LayoutUpdated();
|
||||
},
|
||||
() => {
|
||||
int index = parent.Children.IndexOf(items[0]);
|
||||
items[0].RemoveChild(node);
|
||||
parent.AddChild(node, index + 1);
|
||||
|
||||
parent.LayoutUpdated();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteAddPeerCommand(object parameter)
|
||||
{
|
||||
List<MindNode> items = new List<MindNode>();
|
||||
if (parameter is MindNode pear)
|
||||
{
|
||||
|
||||
}
|
||||
else if (parameter is IEnumerable<MindNode> para)
|
||||
{
|
||||
pear = para.FirstOrDefault();//第一个固定为同级节点
|
||||
items = para.Skip(1).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
pear = SelectedItem as MindNode;
|
||||
}
|
||||
|
||||
if (items?.Count == 0)
|
||||
{
|
||||
var node = new MindNode(this, pear.NodeLevel, this.MindType) { Text = "分支主题" };
|
||||
items.Add(node);
|
||||
}
|
||||
|
||||
|
||||
if (pear.Parent is MindNode parent)
|
||||
{
|
||||
DoCommandManager.DoNewCommand(this.ToString(),
|
||||
() => {
|
||||
int index = parent.Children.IndexOf(pear);
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
parent.AddChild(items[i], index + i + 1);
|
||||
}
|
||||
|
||||
parent.LayoutUpdated();
|
||||
},
|
||||
() => {
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
parent.RemoveChild(items[i]);
|
||||
}
|
||||
parent.LayoutUpdated();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void ExecuteMoveBackCommand(object parameter)
|
||||
{
|
||||
if (parameter is MindNode node)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
node = SelectedItem as MindNode;
|
||||
}
|
||||
|
||||
if (node.Parent is MindNode parent)
|
||||
{
|
||||
DoCommandManager.DoNewCommand(this.ToString(),
|
||||
() => {
|
||||
int index = parent.Children.IndexOf(node);
|
||||
if (index < parent.Children.Count - 1)
|
||||
{
|
||||
parent.RemoveChild(node);
|
||||
parent.AddChild(node, index + 1);
|
||||
parent.LayoutUpdated();
|
||||
}
|
||||
},
|
||||
() => {
|
||||
int index = parent.Children.IndexOf(node);
|
||||
if (index > 0)
|
||||
{
|
||||
parent.RemoveChild(node);
|
||||
parent.AddChild(node, index - 1);
|
||||
parent.LayoutUpdated();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void ExecuteMoveForwardCommand(object parameter)
|
||||
{
|
||||
if (parameter is MindNode node)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
node = SelectedItem as MindNode;
|
||||
}
|
||||
|
||||
if (node.Parent is MindNode parent)
|
||||
{
|
||||
DoCommandManager.DoNewCommand(this.ToString(),
|
||||
() => {
|
||||
int index = parent.Children.IndexOf(node);
|
||||
if (index > 0)
|
||||
{
|
||||
parent.RemoveChild(node);
|
||||
parent.AddChild(node, index - 1);
|
||||
parent.LayoutUpdated();
|
||||
}
|
||||
},
|
||||
() => {
|
||||
int index = parent.Children.IndexOf(node);
|
||||
if (index < parent.Children.Count - 1)
|
||||
{
|
||||
parent.RemoveChild(node);
|
||||
parent.AddChild(node, index + 1);
|
||||
parent.LayoutUpdated();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void ExecuteDeleteSelfCommand(object parameter)
|
||||
{
|
||||
if (parameter is MindNode node)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
node = SelectedItem as MindNode;
|
||||
}
|
||||
|
||||
if (node.Parent is MindNode parent)
|
||||
{
|
||||
int index = parent.Children.IndexOf(node);
|
||||
DoCommandManager.DoNewCommand(this.ToString(),
|
||||
() => {
|
||||
parent.RemoveChild(node, true);
|
||||
parent.LayoutUpdated();
|
||||
},
|
||||
() => {
|
||||
parent.AddChild(node, index);
|
||||
parent.LayoutUpdated();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ using AIStudio.Wpf.Flowchart.Models;
|
||||
using AIStudio.Wpf.Mind.Helpers;
|
||||
using AIStudio.Wpf.Mind.Models;
|
||||
|
||||
|
||||
namespace AIStudio.Wpf.Mind.ViewModels
|
||||
{
|
||||
public class MindNode : DiagramItemViewModel
|
||||
@@ -31,20 +32,19 @@ namespace AIStudio.Wpf.Mind.ViewModels
|
||||
public MindNode(IDiagramViewModel root, NodeLevel nodeLevel, MindType mindType = MindType.Mind) : base(root)
|
||||
{
|
||||
NodeLevel = nodeLevel;
|
||||
MindType = mindType;
|
||||
MindType = mindType;
|
||||
|
||||
InitLayout();
|
||||
MindLayout.Appearance(this);
|
||||
InitLayout(true);
|
||||
}
|
||||
|
||||
public MindNode(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer)
|
||||
{
|
||||
InitLayout();
|
||||
InitLayout(false);
|
||||
}
|
||||
|
||||
public MindNode(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
|
||||
{
|
||||
InitLayout();
|
||||
InitLayout(false);
|
||||
}
|
||||
|
||||
public override SelectableItemBase GetSerializableObject()
|
||||
@@ -58,21 +58,25 @@ namespace AIStudio.Wpf.Mind.ViewModels
|
||||
|
||||
EnabledForConnection = false;
|
||||
|
||||
AddChildCommand = new SimpleCommand(Command_Enable, ExecuteAddChildCommand);
|
||||
AddParentCommand = new SimpleCommand(Level_Enable, ExecuteAddParentCommand);
|
||||
AddPeerCommand = new SimpleCommand(Level_Enable, ExecuteAddPeerCommand);
|
||||
DeleteCommand = new SimpleCommand(Level_Enable, ExecuteDeleteCommand);
|
||||
MoveForwardCommand = new SimpleCommand(Command_Enable, ExecuteMoveForwardCommand);
|
||||
MoveBackCommand = new SimpleCommand(Command_Enable, ExecuteMoveBackCommand);
|
||||
AddChildCommand = (Root as IMindDiagramViewModel)?.AddChildCommand;
|
||||
AddParentCommand = (Root as IMindDiagramViewModel)?.AddParentCommand;
|
||||
AddPeerCommand = (Root as IMindDiagramViewModel)?.AddPeerCommand;
|
||||
DeleteSelfCommand = (Root as IMindDiagramViewModel)?.DeleteSelfCommand;
|
||||
MoveForwardCommand = (Root as IMindDiagramViewModel)?.MoveForwardCommand;
|
||||
MoveBackCommand = (Root as IMindDiagramViewModel)?.MoveBackCommand;
|
||||
BuildMenuOptions();
|
||||
|
||||
this.PropertyChanged += this.Item_PropertyChanged;
|
||||
}
|
||||
|
||||
protected void InitLayout()
|
||||
protected void InitLayout(bool initAppearance)
|
||||
{
|
||||
var layout = GlobalType.AllTypes.Where(p => typeof(IMindLayout).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == MindType.ToString() + "Layout");
|
||||
MindLayout = layout != null ? (System.Activator.CreateInstance(layout) as IMindLayout) : new MindLayout();
|
||||
|
||||
if (initAppearance)
|
||||
{
|
||||
MindLayout.Appearance(this);
|
||||
}
|
||||
this.PropertyChanged += this.Item_PropertyChanged;
|
||||
}
|
||||
|
||||
protected override void LoadDesignerItemViewModel(SelectableItemBase designerbase)
|
||||
@@ -103,8 +107,6 @@ namespace AIStudio.Wpf.Mind.ViewModels
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private bool Level_Enable(object obj)
|
||||
{
|
||||
if (Command_Enable(obj) == false) return false;
|
||||
@@ -115,7 +117,7 @@ namespace AIStudio.Wpf.Mind.ViewModels
|
||||
#region 属性
|
||||
public IMindLayout MindLayout
|
||||
{
|
||||
get;set;
|
||||
get; set;
|
||||
}
|
||||
[Browsable(false)]
|
||||
private NodeLevel _nodeLevel;
|
||||
@@ -130,6 +132,29 @@ namespace AIStudio.Wpf.Mind.ViewModels
|
||||
SetProperty(ref _nodeLevel, value);
|
||||
}
|
||||
}
|
||||
//public MindNode ParentNode
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// return Parent as MindNode;
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
//public int NodeLevel
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// if (ParentNode == null)
|
||||
// {
|
||||
// return 0;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return ParentNode.NodeLevel + 1;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
private MindType _mindType;
|
||||
public MindType MindType
|
||||
@@ -142,7 +167,7 @@ namespace AIStudio.Wpf.Mind.ViewModels
|
||||
{
|
||||
SetProperty(ref _mindType, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isExpanded = true;
|
||||
public bool IsExpanded
|
||||
@@ -214,7 +239,7 @@ namespace AIStudio.Wpf.Mind.ViewModels
|
||||
|
||||
public bool LayoutUpdating
|
||||
{
|
||||
get;set;
|
||||
get; set;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -314,7 +339,7 @@ namespace AIStudio.Wpf.Mind.ViewModels
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SimpleCommand DeleteCommand
|
||||
public SimpleCommand DeleteSelfCommand
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
@@ -337,136 +362,37 @@ namespace AIStudio.Wpf.Mind.ViewModels
|
||||
CinchMenuItem menuItem = new CinchMenuItem();
|
||||
menuItem.Text = "下级";
|
||||
menuItem.Command = AddChildCommand;
|
||||
menuItem.CommandParameter = this;
|
||||
menuOptions.Add(menuItem);
|
||||
menuItem = new CinchMenuItem();
|
||||
menuItem.Text = "同级";
|
||||
menuItem.Command = AddPeerCommand;
|
||||
menuItem.CommandParameter = this;
|
||||
menuOptions.Add(menuItem);
|
||||
menuItem = new CinchMenuItem();
|
||||
menuItem.Text = "上级";
|
||||
menuItem.Command = AddParentCommand;
|
||||
menuItem.CommandParameter = this;
|
||||
menuOptions.Add(menuItem);
|
||||
menuItem = new CinchMenuItem();
|
||||
menuItem.Text = "前移";
|
||||
menuItem.Command = MoveForwardCommand;
|
||||
menuItem.CommandParameter = this;
|
||||
menuOptions.Add(menuItem);
|
||||
menuItem = new CinchMenuItem();
|
||||
menuItem.Text = "后移";
|
||||
menuItem.Command = MoveBackCommand;
|
||||
menuItem.CommandParameter = this;
|
||||
menuOptions.Add(menuItem);
|
||||
menuItem = new CinchMenuItem();
|
||||
menuItem.Text = "删除";
|
||||
menuItem.Command = DeleteCommand;
|
||||
menuItem.Command = DeleteSelfCommand;
|
||||
menuItem.CommandParameter = this;
|
||||
menuOptions.Add(menuItem);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 操作
|
||||
public void ExecuteAddChildCommand(object obj)
|
||||
{
|
||||
if (obj is MindNode node)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
node = new MindNode(Root, (NodeLevel)Math.Min((int)NodeLevel + 1, (int)NodeLevel.Level3), this.MindType) { Text = "分支主题" };
|
||||
}
|
||||
AddChild(node);
|
||||
|
||||
LayoutUpdated();
|
||||
}
|
||||
|
||||
public void ExecuteAddParentCommand(object obj)
|
||||
{
|
||||
if (Parent is MindNode parent)
|
||||
{
|
||||
if (obj is MindNode node)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NodeLevel == NodeLevel.Level1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (NodeLevel == NodeLevel.Level2)
|
||||
node = new MindNode(Root, NodeLevel.Level2, this.MindType) { Text = "分支主题" };
|
||||
else
|
||||
node = new MindNode(Root, NodeLevel.Level3, this.MindType) { Text = "分支主题" };
|
||||
}
|
||||
|
||||
parent.RemoveChild(this);
|
||||
int index = parent.Children.IndexOf(this);
|
||||
parent.AddChild(node, index + 1);
|
||||
|
||||
node.AddChild(this);
|
||||
|
||||
LayoutUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteAddPeerCommand(object obj)
|
||||
{
|
||||
if (Parent is MindNode parent)
|
||||
{
|
||||
if (obj is MindNode node)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NodeLevel == NodeLevel.Level1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (NodeLevel == NodeLevel.Level2)
|
||||
node = new MindNode(Root, NodeLevel.Level2, this.MindType) { Text = "分支主题" };
|
||||
else
|
||||
node = new MindNode(Root, NodeLevel.Level3, this.MindType) { Text = "分支主题" };
|
||||
}
|
||||
int index = parent.Children.IndexOf(this);
|
||||
parent.AddChild(node, index + 1);
|
||||
|
||||
LayoutUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteMoveBackCommand(object obj)
|
||||
{
|
||||
if (Parent is MindNode parent)
|
||||
{
|
||||
int index = parent.Children.IndexOf(this);
|
||||
if (index < parent.Children.Count - 1)
|
||||
{
|
||||
parent.RemoveChild(this);
|
||||
parent.AddChild(this, index + 1);
|
||||
LayoutUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteMoveForwardCommand(object obj)
|
||||
{
|
||||
if (Parent is MindNode parent)
|
||||
{
|
||||
int index = parent.Children.IndexOf(this);
|
||||
if (index > 0)
|
||||
{
|
||||
parent.RemoveChild(this);
|
||||
parent.AddChild(this, index - 1);
|
||||
LayoutUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteDeleteCommand(object obj)
|
||||
{
|
||||
if (Parent is MindNode parent)
|
||||
{
|
||||
parent.RemoveChild(this, true);
|
||||
LayoutUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
#region 操作
|
||||
public void AddChild(MindNode item, int index = -1)
|
||||
{
|
||||
if (this.NodeLevel == NodeLevel.Level1)
|
||||
@@ -486,13 +412,10 @@ namespace AIStudio.Wpf.Mind.ViewModels
|
||||
this.Children.Add(item);
|
||||
}
|
||||
item.Parent = this;
|
||||
Root?.DirectAddItemCommand.Execute(item);
|
||||
|
||||
ConnectionViewModel connector = MindLayout?.GetConnectionViewModel(this, item);
|
||||
Root?.DirectAddItemCommand.Execute(connector);
|
||||
Root?.ClearSelectedItemsCommand.Execute(new SelectableDesignerItemViewModelBase[] { connector });
|
||||
|
||||
Root?.BringForwardCommand.Execute(new DesignerItemViewModelBase[] { item });
|
||||
Root?.DirectAddItemCommand.Execute(new SelectableDesignerItemViewModelBase[] { item, connector });
|
||||
connector.ZIndex = -1;
|
||||
this.IsSelected = true;
|
||||
}
|
||||
|
||||
public void RemoveChild(MindNode item, bool removeall = false)
|
||||
@@ -535,17 +458,9 @@ namespace AIStudio.Wpf.Mind.ViewModels
|
||||
case nameof(NodeLevel):
|
||||
MindLayout?.Appearance(this);
|
||||
break;
|
||||
//case nameof(MindType):
|
||||
// if (NodeLevel == NodeLevel.Level1)
|
||||
// {
|
||||
// MindLayout?.Appearance(this);
|
||||
// LayoutUpdated();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// GetLevel1Node().MindType = MindType;
|
||||
// }
|
||||
// break;
|
||||
case nameof(MindType):
|
||||
InitLayout(true);
|
||||
break;
|
||||
case nameof(Left):
|
||||
{
|
||||
if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs)
|
||||
@@ -625,7 +540,7 @@ namespace AIStudio.Wpf.Mind.ViewModels
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
public class LinkInfo : BindableBase
|
||||
{
|
||||
private string _url;
|
||||
|
||||
Reference in New Issue
Block a user