From 0940f31b7eba1cf6b6a8c1fca72d97cf686e79f2 Mon Sep 17 00:00:00 2001
From: alielie <alielie@git.com>
Date: 星期五, 04 七月 2025 10:43:00 +0800
Subject: [PATCH] 优化插件,完善TreeListView

---
 Plugin.DataBoard/Plugin.DataBoard.csproj                    |   18 
 HMI.LogViewer/LogViewer.xaml                                |    8 
 Plugin.TestResult/DataTable.xaml                            |    5 
 HMI.DataViewer/DataViewer.xaml                              |    7 
 Plugin.SeqEditor/Util/Step2EPO.cs                           |    8 
 Plugin.TestResult/TestResultView.xaml.cs                    |    2 
 Plugin.TsExecution/Plugin.TsExecution.csproj                |    8 
 Plugin.SeqEditor/ViewModel/TreeListViewHandler.cs           |  119 ++
 HMI.MenuManage/RoleManage.xaml                              |    7 
 WPFProject/Lang/zh-CN/TestResult.json                       |    4 
 HMI.Core/Util/LangUtil.cs                                   |    5 
 HMI.ParameterManage/ParameterManage.xaml                    |    7 
 HMI.ParameterManage/TestItem.xaml                           |    7 
 Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs            |  373 +++++--
 WPFProject/Lang/zh-CN/SeqEditor.json                        |    1 
 HMI.UI/Controls/treegrid/Controls/TreeItemData.cs           |  280 +++-
 Plugin.SeqEditor/Entity/StepUI.cs                           |   41 
 OPCClient/OPCClient.csproj                                  |   18 
 Plugin.JarUI/Plugin.JarUI.csproj                            |   18 
 Plugin.TsExecution/ScannerManager.cs                        |  101 ++
 HMI.UI/Controls/treegrid/Themes/TreeItemContentControl.xaml |    8 
 HMI.UI/Controls/MultiCombox.xaml.cs                         |   26 
 Plugin.TsExecution/Scanner.xaml.cs                          |  209 ++++
 Plugin.TsExecution/TsExecution.xaml.cs                      |    2 
 HMI.UnitTest/MainWindow.xaml.cs                             |   29 
 Plugin.SeqEditor/Util/ItemData.cs                           |    4 
 WPFProject/App.xaml                                         |    2 
 HMI.UI/Controls/treegrid/Themes/TreeListView.xaml           |  140 ++
 Plugin.SeqEditor/ViewModel/StepDropHandler.cs               |  139 ++
 HMI.UI/Controls/treegrid/Controls/TreeDataGrid.cs           |   10 
 WPFProject/Lang/en-US/TestResult.json                       |    4 
 Plugin.SeqEditor/Entity/EditablePO/IEPO.cs                  |    2 
 Plugin.SeqEditor/SeqEditor.xaml.cs                          |   19 
 WPFProject/Lang/en-US/SeqEditor.json                        |    1 
 HMI.ParameterManage/ParameterSetting.xaml                   |    8 
 HMI.Core/HMI.Core.csproj                                    |    1 
 Plugin.TsExecution/Scanner.xaml                             |   77 +
 HMI.UI/Style/PanuonResource.xaml                            |   73 -
 HMI.UI/Controls/MultiCombox.xaml                            |   65 +
 Plugin.TsExecution/SingleControl.xaml                       |   84 +
 WPFProject/WPFProject.sln                                   |   32 
 Plugin.TsExecution/SingleControl.xaml.cs                    |   91 +
 SimpleUtil/HMI.LogUtil/HMI.LogUtil.csproj                   |   18 
 SimpleUtil/HMI.Util.Base/HMI.Util.Base.csproj               |   18 
 Plugin.SeqEditor/Entity/SeqUI.cs                            |   17 
 HMI.UI/Controls/treegrid/Controls/TreeListView.cs           |   86 +
 HMI.UI/Style/PanuonDataGrid.xaml                            |   88 +
 Plugin.SeqEditor/Plugin.SeqEditor.csproj                    |    1 
 HMI.MenuManage/MenuManage.xaml                              |    7 
 HMI.MenuManage/UserManage.xaml                              |    7 
 HMI.UI/Converter/IndentConverter.cs                         |   21 
 HMI.Core/Util/BindingProxy.cs                               |   22 
 Plugin.SeqEditor/SeqEditor.xaml                             |  375 ++++++-
 VisionBuilder.Run/VisionBuilder.Run.csproj                  |   18 
 Plugin.TestResult/DataTable.xaml.cs                         |   26 
 HMI.UI/HMI.UI.csproj                                        |   10 
 56 files changed, 2,344 insertions(+), 433 deletions(-)

diff --git a/HMI.Core/HMI.Core.csproj b/HMI.Core/HMI.Core.csproj
index bd6f331..600e655 100644
--- a/HMI.Core/HMI.Core.csproj
+++ b/HMI.Core/HMI.Core.csproj
@@ -110,6 +110,7 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Setting\SystemSetting.cs" />
     <Compile Include="Util\BeanUtil.cs" />
+    <Compile Include="Util\BindingProxy.cs" />
     <Compile Include="Util\DllHelper.cs" />
     <Compile Include="Util\HexUtil.cs" />
     <Compile Include="Util\JsonUtil.cs" />
diff --git a/HMI.Core/Util/BindingProxy.cs b/HMI.Core/Util/BindingProxy.cs
new file mode 100644
index 0000000..071e2a5
--- /dev/null
+++ b/HMI.Core/Util/BindingProxy.cs
@@ -0,0 +1,22 @@
+锘縰sing System.Windows;
+
+namespace HMI.Core.Util
+{
+    public class BindingProxy : Freezable
+    {
+        protected override Freezable CreateInstanceCore()
+        {
+            return new BindingProxy();
+        }
+
+        public object Data
+        {
+            get { return (object)GetValue(DataProperty); }
+            set { SetValue(DataProperty, value); }
+        }
+
+        public static readonly DependencyProperty DataProperty =
+            DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy),
+                                        new UIPropertyMetadata(null));
+    }
+}
diff --git a/HMI.Core/Util/LangUtil.cs b/HMI.Core/Util/LangUtil.cs
index abda81f..ce6f069 100644
--- a/HMI.Core/Util/LangUtil.cs
+++ b/HMI.Core/Util/LangUtil.cs
@@ -63,8 +63,9 @@
                 LoadAllDataByXaml();
                 LoadLang();
             }
-            finally { 
-                
+            finally
+            {
+
             }
         }
 
diff --git a/HMI.DataViewer/DataViewer.xaml b/HMI.DataViewer/DataViewer.xaml
index de10e6e..f5ef14b 100644
--- a/HMI.DataViewer/DataViewer.xaml
+++ b/HMI.DataViewer/DataViewer.xaml
@@ -13,6 +13,13 @@
              Background="{StaticResource WorkspaceBackground}"
              Loaded="PluginControl_Loaded"
              d:DesignHeight="450" d:DesignWidth="800">
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/HMI.UI;component/Style/PanuonDataGrid.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
     <Border Style="{StaticResource CardBoarder}">
         <Grid dp:GridHelper.Space="10">
             <Grid.RowDefinitions>
diff --git a/HMI.LogViewer/LogViewer.xaml b/HMI.LogViewer/LogViewer.xaml
index 8f9ea21..86632eb 100644
--- a/HMI.LogViewer/LogViewer.xaml
+++ b/HMI.LogViewer/LogViewer.xaml
@@ -13,7 +13,13 @@
              Loaded="UserControl_Loaded"
              Background="{StaticResource WorkspaceBackground}"
              d:DesignHeight="450" d:DesignWidth="800">
-
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/HMI.UI;component/Style/PanuonDataGrid.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
     <Border Style="{StaticResource CardBoarder}">
         <Grid dp:GridHelper.Space="10" Cursor="">
             <Grid.RowDefinitions>
diff --git a/HMI.MenuManage/MenuManage.xaml b/HMI.MenuManage/MenuManage.xaml
index 234de24..269e70e 100644
--- a/HMI.MenuManage/MenuManage.xaml
+++ b/HMI.MenuManage/MenuManage.xaml
@@ -15,6 +15,13 @@
              Loaded="DataGrid_Loaded"
              Background="{StaticResource WorkspaceBackground}"
              d:DesignHeight="450" d:DesignWidth="800">
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/HMI.UI;component/Style/PanuonDataGrid.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
     <Grid>
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="8*"/>
diff --git a/HMI.MenuManage/RoleManage.xaml b/HMI.MenuManage/RoleManage.xaml
index eda62eb..0f033c1 100644
--- a/HMI.MenuManage/RoleManage.xaml
+++ b/HMI.MenuManage/RoleManage.xaml
@@ -13,6 +13,13 @@
              Padding="10"
              Background="#f0f2f5"
              d:DesignHeight="450" d:DesignWidth="800">
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/HMI.UI;component/Style/PanuonDataGrid.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
     <Grid>
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="6*"/>
diff --git a/HMI.MenuManage/UserManage.xaml b/HMI.MenuManage/UserManage.xaml
index ace9978..d964dd7 100644
--- a/HMI.MenuManage/UserManage.xaml
+++ b/HMI.MenuManage/UserManage.xaml
@@ -12,6 +12,13 @@
              Background="{StaticResource WorkspaceBackground}"
              Padding="10"
              d:DesignHeight="450" d:DesignWidth="800">
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/HMI.UI;component/Style/PanuonDataGrid.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
     <Grid>
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="6*"/>
diff --git a/HMI.ParameterManage/ParameterManage.xaml b/HMI.ParameterManage/ParameterManage.xaml
index 3de79a9..838287d 100644
--- a/HMI.ParameterManage/ParameterManage.xaml
+++ b/HMI.ParameterManage/ParameterManage.xaml
@@ -15,6 +15,13 @@
              Loaded="UserControl_Loaded"
              Background="{StaticResource WorkspaceBackground}"
              d:DesignHeight="450" d:DesignWidth="800">
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/HMI.UI;component/Style/PanuonDataGrid.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
     <Grid>
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="3*"/>
diff --git a/HMI.ParameterManage/ParameterSetting.xaml b/HMI.ParameterManage/ParameterSetting.xaml
index 5a097b0..cc093dc 100644
--- a/HMI.ParameterManage/ParameterSetting.xaml
+++ b/HMI.ParameterManage/ParameterSetting.xaml
@@ -14,7 +14,13 @@
              Loaded="UserControl_Loaded"
              Background="{StaticResource WorkspaceBackground}"
              d:DesignHeight="450" d:DesignWidth="800">
-
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/HMI.UI;component/Style/PanuonDataGrid.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
     <Border Style="{StaticResource CardBoarder}">
         <Grid dp:GridHelper.Space="10" Cursor="">
             <Grid.RowDefinitions>
diff --git a/HMI.ParameterManage/TestItem.xaml b/HMI.ParameterManage/TestItem.xaml
index efa1607..a26e373 100644
--- a/HMI.ParameterManage/TestItem.xaml
+++ b/HMI.ParameterManage/TestItem.xaml
@@ -13,6 +13,13 @@
              Background="{StaticResource WorkspaceBackground}"
              Loaded="PluginControl_Loaded"
              d:DesignHeight="450" d:DesignWidth="800">
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/HMI.UI;component/Style/PanuonDataGrid.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
     <Border Style="{StaticResource CardBoarder}">
         <Grid dp:GridHelper.Space="10">
             <Grid.RowDefinitions>
diff --git a/HMI.UI/Controls/MultiCombox.xaml b/HMI.UI/Controls/MultiCombox.xaml
index c098596..abd39b2 100644
--- a/HMI.UI/Controls/MultiCombox.xaml
+++ b/HMI.UI/Controls/MultiCombox.xaml
@@ -1,10 +1,55 @@
-锘�<UserControl x:Class="HMI.UI.Controls.MultiCombox"
-             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
-             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
-             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
-             xmlns:local="clr-namespace:HMI.UI.Controls"
-             mc:Ignorable="d" 
-             d:DesignHeight="450" d:DesignWidth="800">
-    <ComboBox ></ComboBox>
-</UserControl>
+锘�<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+                    xmlns:local="clr-namespace:HMI.UI">
+    <Style TargetType="local:MultiComboBox" BasedOn="{StaticResource FormComboxStyle}">
+        <Setter Property="ItemTemplate">
+            <Setter.Value>
+                <DataTemplate DataType="util:ItemData">
+                    <StackPanel Orientation="Horizontal">
+                        <CheckBox IsChecked="{Binding IsChecked,UpdateSourceTrigger=PropertyChanged}">
+                            <!--<CheckBox.Style>
+                                <Style TargetType="CheckBox">
+                                    <Setter Property="Background" Value="White" />
+                                    <Setter Property="BorderBrush" Value="#FF262E34"/>
+                                    <Setter Property="Foreground" Value="#FF262E34"/>
+                                    <Setter Property="BorderThickness" Value="1"/>
+                                    <Setter Property="Template">
+                                        <Setter.Value>
+                                            <ControlTemplate TargetType="{x:Type CheckBox}">
+                                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" >
+                                                    <Border BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" Width="15" Height="15">
+                                                        --><!--                                   your color here --><!--
+                                                        <Path Stretch="Uniform" Width="15" Height="10" Fill="Black" Name="eliCheck" Data="F1 M 9.97498,1.22334L 4.6983,9.09834L 4.52164,9.09834L 0,5.19331L 1.27664,3.52165L 4.255,6.08833L 8.33331,1.52588e-005L 9.97498,1.22334 Z " Visibility="Collapsed"/>
+                                                    </Border>
+                                                    <TextBlock Margin="5,0,0,0"  VerticalAlignment="Center" Foreground="{TemplateBinding Foreground}" Text="{TemplateBinding Content}"></TextBlock>
+                                                </StackPanel>
+                                                <ControlTemplate.Triggers>
+                                                    <Trigger Property="IsMouseOver" Value="True">
+                                                        <Setter Property="Background" Value="LightGray" />
+                                                    </Trigger>
+                                                    <Trigger Property="IsPressed" Value="True">
+                                                        <Setter Property="Background" Value="#FF9C9E9F" />
+                                                    </Trigger>
+                                                    --><!--<Trigger Property="IsEnabled" Value="False">
+                                                        <Setter Property="Background" Value="LightGray" />
+                                                        <Setter Property="Foreground" Value="Gray" />
+                                                        <Setter Property="BorderBrush" Value="Gray"/>
+                                                        <Setter TargetName="eliCheck" Property="Opacity" Value="0.5" />
+                                                    </Trigger>--><!--
+                                                    <Trigger Property="IsChecked" Value="True">
+                                                        <Setter TargetName="eliCheck" Property="Visibility" Value="Visible"></Setter>
+                                                    </Trigger>
+                                                </ControlTemplate.Triggers>
+                                            </ControlTemplate>
+                                        </Setter.Value>
+                                    </Setter>
+                                </Style>
+                            </CheckBox.Style>-->
+                        </CheckBox>
+                        <TextBlock Text="{Binding DisplayName}" />
+                    </StackPanel>
+                </DataTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+</ResourceDictionary>
\ No newline at end of file
diff --git a/HMI.UI/Controls/MultiCombox.xaml.cs b/HMI.UI/Controls/MultiCombox.xaml.cs
index 85f5bcc..e688cd5 100644
--- a/HMI.UI/Controls/MultiCombox.xaml.cs
+++ b/HMI.UI/Controls/MultiCombox.xaml.cs
@@ -1,5 +1,4 @@
 锘縰sing System;
-using System.Collections;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Globalization;
@@ -53,6 +52,11 @@
 
         private void MultiComboBoxItem_PreviewMouseUp(object sender, MouseButtonEventArgs e)
         {
+            if (e.OriginalSource is CheckBox)
+            {
+                // 浠嶤heckBox鐐瑰嚮浼犺繃鏉ョ殑浜嬩欢瑕佹媺鍥炵劍鐐癸紝涓嶇劧浼氬崱鍦≒opup灞傚綋鍓嶇殑Item涓�
+                this.Focus();
+            }
             if (DataContext is MultiComboBoxData data)
             {
                 data.IsChecked = !data.IsChecked;
@@ -64,17 +68,17 @@
         {
             if (e.OldValue != null && e.OldValue is MultiComboBoxData oldData)
             {
-                oldData.IsCheckedChanged -= DataIsExpandedChange;
+                oldData.IsCheckedChanged -= DataIsCheckedChangedChange;
             }
             if (DataContext != null && DataContext is MultiComboBoxData newData)
             {
-                newData.IsCheckedChanged += DataIsExpandedChange;
+                newData.IsCheckedChanged += DataIsCheckedChangedChange;
             }
         }
 
-        private void DataIsExpandedChange(object sender, bool IsExpanded)
+        private void DataIsCheckedChangedChange(object sender, bool isChecked)
         {
-            parent.Item_IsCheckedChanged((MultiComboBoxData)sender, this, IsExpanded);
+            parent.Item_IsCheckedChanged((MultiComboBoxData)sender, this, isChecked);
         }
     }
 
@@ -151,6 +155,8 @@
     /// </summary>
     public partial class MultiComboBox : ComboBox
     {
+        public static readonly string[] splits = new string[] { ", " };
+
         protected override DependencyObject GetContainerForItemOverride()
         {
             var item = new MultiComboBoxItem(this);
@@ -182,8 +188,10 @@
         {
             var selectedValues = SelectedValues?.ToString() ?? "";
             var showNames = this.Text?.ToString() ?? "";
-            List<string> values = string.IsNullOrEmpty(selectedValues) ? new List<string>() : selectedValues.Split(',').ToList();
-            List<string> names = string.IsNullOrEmpty(showNames) ? new List<string>() : showNames.Split(',').ToList();
+            List<string> values = string.IsNullOrEmpty(selectedValues) ? new List<string>() :
+                selectedValues.Split(splits, StringSplitOptions.RemoveEmptyEntries).ToList();
+            List<string> names = string.IsNullOrEmpty(showNames) ? new List<string>() :
+                showNames.Split(splits, StringSplitOptions.RemoveEmptyEntries).ToList();
             if (isChecked)
             {
                 values.Add(data.DataValue);
@@ -194,8 +202,8 @@
                 values.Remove(data.DataValue);
                 names.Remove(data.DisplayName);
             }
-            Text = string.Join(",", names);
-            SelectedValues = string.Join(",", values);
+            Text = string.Join(", ", names);
+            SelectedValues = string.Join(", ", values);
         }
     }
 }
diff --git a/HMI.UI/Controls/treegrid/Controls/TreeDataGrid.cs b/HMI.UI/Controls/treegrid/Controls/TreeDataGrid.cs
index 8823656..8dc00d4 100644
--- a/HMI.UI/Controls/treegrid/Controls/TreeDataGrid.cs
+++ b/HMI.UI/Controls/treegrid/Controls/TreeDataGrid.cs
@@ -19,10 +19,10 @@
 
         static TreeDataGrid()
         {
-            //ScrollViewer.HorizontalScrollBarVisibilityProperty
-            //    .OverrideMetadata(typeof(TreeDataGrid), new FrameworkPropertyMetadata(ScrollBarVisibility.Disabled));
-            //ScrollViewer.VerticalScrollBarVisibilityProperty
-            //    .OverrideMetadata(typeof(TreeDataGrid), new FrameworkPropertyMetadata(ScrollBarVisibility.Disabled));
+            ScrollViewer.HorizontalScrollBarVisibilityProperty
+                .OverrideMetadata(typeof(TreeDataGrid), new FrameworkPropertyMetadata(ScrollBarVisibility.Disabled));
+            ScrollViewer.VerticalScrollBarVisibilityProperty
+                .OverrideMetadata(typeof(TreeDataGrid), new FrameworkPropertyMetadata(ScrollBarVisibility.Disabled));
         }
 
         protected override DependencyObject GetContainerForItemOverride()
@@ -50,10 +50,10 @@
             {
                 oldTreeData.IsExpandedChange -= DataIsExpandedChange;
                 oldTreeData.VisibleChange -= DataVisiableChange;
-
             }
             if (DataContext != null && DataContext is TreeItemData treeData)
             {
+                Visibility = treeData.IsVisible ? Visibility.Visible : Visibility.Collapsed;
                 treeData.IsExpandedChange += DataIsExpandedChange;
                 treeData.VisibleChange += DataVisiableChange;
             }
diff --git a/HMI.UI/Controls/treegrid/Controls/TreeItemData.cs b/HMI.UI/Controls/treegrid/Controls/TreeItemData.cs
index 46a045c..c49c447 100644
--- a/HMI.UI/Controls/treegrid/Controls/TreeItemData.cs
+++ b/HMI.UI/Controls/treegrid/Controls/TreeItemData.cs
@@ -4,8 +4,10 @@
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Collections.Specialized;
+using System.ComponentModel;
 using System.Globalization;
 using System.Linq;
+using System.Reflection;
 using System.Windows.Data;
 
 namespace HMI.UI
@@ -32,10 +34,10 @@
             get => _IsExpanded;
             set
             {
-                if (_IsExpanded == value)
-                {
-                    return;
-                }
+                //if (_IsExpanded == value)
+                //{
+                //    return;
+                //}
                 _IsExpanded = value;
                 Set("IsExpanded");
                 SetItemsVisible(value);
@@ -43,6 +45,84 @@
             }
         }
         #endregion
+
+        #region 灞炴�� IsVisible
+        private bool _IsVisible = true;
+
+        public bool IsVisible
+        {
+            get
+            {
+                return _IsVisible;
+            }
+            set
+            {
+                if (_IsVisible == value)
+                {
+                    return;
+                }
+                _IsVisible = value;
+                Set("IsVisible");
+                SetItemsVisible(value);
+                VisibleChange?.Invoke(this, value);
+            }
+        }
+
+        /// <summary>
+        /// 鐢ㄤ簬灞曞紑鐨勫彲瑙�
+        /// </summary>
+        /// <param name="visible"></param>
+        private void SetItemsVisible(bool visible)
+        {
+            if (IsExpanded == false || visible == false)
+            {
+                Items.ForEach(p => p.IsVisible = false);
+            }
+            else
+            {
+                Items.ForEach(p => p.IsVisible = true);
+            }
+        }
+
+        /// <summary>
+        /// 璁剧疆绛涢�夋槸鍚﹀彲瑙侊紝姣斿绛涢�塶ame1,鍒欏寘鍚玭ame1鐨勬暟鎹拰鍏剁埗鑺傜偣閮藉彲瑙�
+        /// </summary>
+        public bool SelectVisible
+        {
+            get
+            {
+                return _IsVisible;
+            }
+            set
+            {
+                if (_IsVisible == value)
+                {
+                    return;
+                }
+                _IsVisible = value;
+                Set("IsVisible");
+                SetItemsVisible(value);
+            }
+        }
+
+        /// <summary>
+        /// 鐢ㄤ簬绛涢�夌殑鍙
+        /// </summary>
+        /// <param name="visible"></param>
+        private void SetSelectVisible(bool visible)
+        {
+            if (visible)
+            {
+                ParentItem.SelectVisible = visible;
+            }
+            Items.ForEach(p => p.IsVisible = visible);
+        }
+        #endregion
+
+        public void NotifyUI()
+        {
+            IsExpanded = _IsExpanded;
+        }
 
         #region 灞炴�� Level
         private int _Level = 0;
@@ -107,6 +187,18 @@
             }
         }
         #endregion
+
+        /// <summary>
+        /// 鎵�鏈夊瓙椤规暟閲�
+        /// </summary>
+        private int allSubCount;
+
+        public int AllSubCount
+        {
+            get { return allSubCount; }
+            set { allSubCount = value; }
+        }
+
 
         #region 灞炴�� ParentItem
         private TreeItemData _ParentItem = null;
@@ -196,79 +288,6 @@
                 Set("IconType");
             }
         }
-        #endregion 
-
-        #region 灞炴�� IsVisible
-        private bool _IsVisible = true;
-
-        public bool IsVisible
-        {
-            get
-            {
-                return _IsVisible;
-            }
-            set
-            {
-                if (_IsVisible == value)
-                {
-                    return;
-                }
-                _IsVisible = value;
-                Set("IsVisible");
-                SetItemsVisible(value);
-                VisibleChange?.Invoke(this, value);
-            }
-        }
-
-        /// <summary>
-        /// 鐢ㄤ簬灞曞紑鐨勫彲瑙�
-        /// </summary>
-        /// <param name="visible"></param>
-        private void SetItemsVisible(bool visible)
-        {
-            if (IsExpanded == false || visible == false)
-            {
-                Items.ForEach(p => p.IsVisible = false);
-            }
-            else
-            {
-                Items.ForEach(p => p.IsVisible = true);
-            }
-        }
-
-        /// <summary>
-        /// 璁剧疆绛涢�夋槸鍚﹀彲瑙侊紝姣斿绛涢�塶ame1,鍒欏寘鍚玭ame1鐨勬暟鎹拰鍏剁埗鑺傜偣閮藉彲瑙�
-        /// </summary>
-        public bool SelectVisible
-        {
-            get
-            {
-                return _IsVisible;
-            }
-            set
-            {
-                if (_IsVisible == value)
-                {
-                    return;
-                }
-                _IsVisible = value;
-                Set("IsVisible");
-                SetItemsVisible(value);
-            }
-        }
-
-        /// <summary>
-        /// 鐢ㄤ簬绛涢�夌殑鍙
-        /// </summary>
-        /// <param name="visible"></param>
-        private void SetSelectVisible(bool visible)
-        {
-            if (visible)
-            {
-                ParentItem.SelectVisible = visible;
-            }
-            Items.ForEach(p => p.IsVisible = visible);
-        }
         #endregion
 
         int GetIconType()
@@ -310,6 +329,9 @@
         string _ItemsPath = "";
 
         List<TreeItemData> _RootItems = new List<TreeItemData>();
+        List<TreeItemData> levelOneItems = new List<TreeItemData>();
+
+        private PropertyInfo subDataProperty;
 
         #region 灞炴�� UseTree
         private bool _UseTree = true;
@@ -324,6 +346,12 @@
                 _UseTree = value;
             }
         }
+
+        public List<TreeItemData> RootItems
+        {
+            get => _RootItems;
+        }
+
         #endregion
 
         public TreeItemDataCollection()
@@ -341,15 +369,68 @@
             }
             UseTree = useTree;
             ResetItems();
+            //subDataProperty = typeof(T).GetProperty(itemsPath);
+        }
+
+        protected override void MoveItem(int oldIndex, int newIndex)
+        {
+            CheckReentrancy();
+            TreeItemData source = base[oldIndex];
+            TreeItemData target = base[newIndex];
+            newIndex += target.AllSubCount;
+            if (newIndex == oldIndex - 1)
+            {
+                return;
+            }
+            target = base[newIndex];
+            int times = source.AllSubCount;
+
+            if (oldIndex < newIndex)
+            {
+                base.RemoveItem(oldIndex);
+                base.InsertItem(newIndex, source);
+                OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
+                /// 浠庝笂寰�涓嬫媺
+                for (int i = 0; i < times; i++)
+                {
+                    CheckReentrancy();
+                    source = base[oldIndex];
+                    target = base[newIndex];
+                    base.RemoveItem(oldIndex);
+                    base.InsertItem(newIndex, source);
+                    OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
+                }
+            }
+            else if (oldIndex > newIndex)
+            {
+                /// 浠庝笅寰�涓婃媺
+                base.RemoveItem(oldIndex);
+                base.InsertItem(++newIndex, source);
+                OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
+                //MessageBox.Show($"source: {source.Data} {oldIndex}; target: {target.Data} {newIndex}");
+                for (int i = 0; i < times; i++)
+                {
+                    oldIndex++;
+                    newIndex++;
+                    CheckReentrancy();
+                    source = base[oldIndex];
+                    target = base[newIndex];
+                    //MessageBox.Show($"source: {source.Data} {oldIndex}; target: {target.Data} {newIndex}");
+                    base.RemoveItem(oldIndex);
+                    base.InsertItem(newIndex, source);
+                    OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
+                }
+            }
         }
 
         private void List_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
         {
-            ResetItems();
+            //ResetItems();
         }
 
-        private void ResetItems()
+        public void ResetItems()
         {
+            CheckReentrancy();
             if (_SourceItems is null)
             {
                 ClearAllItems();
@@ -359,7 +440,8 @@
             var items = new List<TreeItemData>();
             _RootItems.Clear();
 
-            var list = this.Items.ToDictionary(l => l.Data);
+            Dictionary<dynamic, TreeItemData> list = this.Items.
+                ToLookup(t => t.Data, t => t).ToDictionary(t => t.Key, t => t.First());
             foreach (var item in _SourceItems)
             {
                 if (list.TryGetValue(item, out var treeItem))
@@ -375,8 +457,9 @@
                 treeItem.Level = 0;
                 items.Add(treeItem);
                 _RootItems.Add(treeItem);
-
-                foreach (var sitem in GetSubItems(treeItem, _ItemsPath, list).ToList())
+                var subItems = GetSubItems(treeItem, _ItemsPath, list);
+                treeItem.AllSubCount = subItems.Count();
+                foreach (var sitem in subItems)
                 {
                     items.Add(sitem);
                 }
@@ -385,17 +468,20 @@
             ResetSubItems(_RootItems);
 
             this.Items.Clear();
-            if (UseTree)
-            {
-                _RootItems.ForEach(t => this.Items.Add(t));
-            }
-            else
-            {
-                items.ForEach(t => this.Items.Add(t));
-            }
+            items.ForEach(t => this.Items.Add(t));
+            //if (UseTree)
+            //{
+            //    _RootItems.ForEach(t => this.Items.Add(t));
+            //}
+            //else
+            //{
+            //    items.ForEach(t => this.Items.Add(t));
+            //}
+            OnPropertyChanged(new PropertyChangedEventArgs("Count"));
+            OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
         }
 
-        private void ResetSubItems(List<TreeItemData> items)
+        public static void ResetSubItems(IList<TreeItemData> items)
         {
             for (int i = 0; i < items.Count; i++)
             {
@@ -410,6 +496,13 @@
             var data = treeItem.Data;
             var p = data.GetType().GetProperty(itemsPath);
             var pvalue = p.GetValue(data, null);
+
+            if (pvalue is INotifyCollectionChanged inc)
+            {
+                //inc.CollectionChanged -= List_CollectionChanged;
+                //inc.CollectionChanged += List_CollectionChanged;
+            }
+
             treeItem.Items.Clear();
             if (pvalue is IEnumerable subItems)
             {
@@ -436,8 +529,9 @@
 
                     treeItem.Items.Add(subitem);
                     yield return subitem;
-
-                    foreach (var sitem in GetSubItems(subitem, itemsPath, list))
+                    var subSub = GetSubItems(subitem, itemsPath, list);
+                    subitem.AllSubCount = subSub.Count();
+                    foreach (var sitem in subSub)
                     {
                         yield return sitem;
                     }
diff --git a/HMI.UI/Controls/treegrid/Controls/TreeListView.cs b/HMI.UI/Controls/treegrid/Controls/TreeListView.cs
new file mode 100644
index 0000000..ab9e828
--- /dev/null
+++ b/HMI.UI/Controls/treegrid/Controls/TreeListView.cs
@@ -0,0 +1,86 @@
+锘縰sing System.Windows;
+using System.Windows.Controls;
+
+namespace HMI.UI
+{
+    public class TreeListView : TreeView
+    {
+        public static readonly DependencyProperty ColumnsProperty =
+            DependencyProperty.Register("Columns", typeof(GridViewColumnCollection), typeof(TreeListView),
+                new PropertyMetadata(new GridViewColumnCollection()));
+
+        public GridViewColumnCollection Columns
+        {
+            get { return (GridViewColumnCollection)GetValue(ColumnsProperty); }
+            set { SetValue(ColumnsProperty, value); }
+        }
+
+        public static readonly DependencyProperty ColumnHeaderContainerStyleProperty =
+            DependencyProperty.Register("ColumnHeaderContainerStyle", typeof(Style), typeof(TreeListView),
+                new PropertyMetadata(null));
+
+        public Style ColumnHeaderContainerStyle
+        {
+            get { return (Style)GetValue(ColumnHeaderContainerStyleProperty); }
+            set { SetValue(ColumnHeaderContainerStyleProperty, value); }
+        }
+
+        static TreeListView()
+        {
+            DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeListView),
+                new FrameworkPropertyMetadata(typeof(TreeListView)));
+        }
+
+        public TreeListView()
+        {
+            Columns = new GridViewColumnCollection();
+        }
+
+        protected override DependencyObject GetContainerForItemOverride()
+        {
+            return new TreeListViewItem(0, this);
+        }
+    }
+
+    public class TreeListViewItem : TreeViewItem
+    {
+        public static readonly DependencyProperty ColumnsProperty =
+            DependencyProperty.Register("Columns", typeof(GridViewColumnCollection), typeof(TreeListViewItem),
+                new PropertyMetadata(null));
+
+        public int level { get; private set; }
+        private TreeListView root;
+
+        public TreeListViewItem(int level, TreeListView root)
+        {
+            this.level = level;
+            this.root = root;
+            this.Loaded += TreeListViewItem_Loaded;
+        }
+
+        public GridViewColumnCollection Columns
+        {
+            get { return (GridViewColumnCollection)GetValue(ColumnsProperty); }
+            set { SetValue(ColumnsProperty, value); }
+        }
+
+        static TreeListViewItem()
+        {
+            DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeListViewItem),
+                new FrameworkPropertyMetadata(typeof(TreeListViewItem)));
+        }
+
+        private void TreeListViewItem_Loaded(object sender, RoutedEventArgs e)
+        {
+            if (root is TreeListView treeListView)
+            {
+                Columns = treeListView.Columns;
+            }
+        }
+
+        protected override DependencyObject GetContainerForItemOverride()
+        {
+            return new TreeListViewItem(level + 1, root);
+        }
+    }
+}
diff --git a/HMI.UI/Controls/treegrid/Themes/TreeItemContentControl.xaml b/HMI.UI/Controls/treegrid/Themes/TreeItemContentControl.xaml
index 7e13490..a597e4c 100644
--- a/HMI.UI/Controls/treegrid/Themes/TreeItemContentControl.xaml
+++ b/HMI.UI/Controls/treegrid/Themes/TreeItemContentControl.xaml
@@ -145,14 +145,8 @@
                                         <DataTemplate>
                                             <Grid x:Name="lineGrid" Width="15" Margin="0">
                                                 <Line x:Name="line" X1="7.5" Y1="0" X2="7.5" Y2="{Binding ElementName=lineGrid,Path=ActualHeight}" StrokeThickness="1"
-                                                      Stroke="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=DataGridRow},Path=Foreground}" StrokeDashArray="1,1"/>
+                  Stroke="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=local:TreeItemContentControl},Path=IconLineStroke}" StrokeDashArray="1,1"/>
                                             </Grid>
-                                             <!--杩欓噷鏀惧紑鏈変釜闂锛屼細璁╁彧鏈変竴涓牴鑺傜偣鐨勬爲鍒楄〃鏄剧ず閿欒--> 
-                                            <!--<DataTemplate.Triggers>
-                                                <DataTrigger Binding="{Binding IsLastItem}" Value="true">
-                                                    <Setter Property="Visibility" Value="Collapsed"/>
-                                                </DataTrigger>
-                                            </DataTemplate.Triggers>-->
                                         </DataTemplate>
                                     </ListBox.ItemTemplate>
                                 </ListBox>
diff --git a/HMI.UI/Controls/treegrid/Themes/TreeListView.xaml b/HMI.UI/Controls/treegrid/Themes/TreeListView.xaml
new file mode 100644
index 0000000..4a5891e
--- /dev/null
+++ b/HMI.UI/Controls/treegrid/Themes/TreeListView.xaml
@@ -0,0 +1,140 @@
+锘�<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
+                    xmlns:controls="clr-namespace:HMI.UI">
+
+    <Style TargetType="{x:Type controls:TreeListView}">
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="{x:Type controls:TreeListView}">
+                    <Border BorderBrush="{TemplateBinding BorderBrush}"
+                        BorderThickness="{TemplateBinding BorderThickness}"
+                        Background="{TemplateBinding Background}">
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="Auto"/>
+                                <RowDefinition/>
+                            </Grid.RowDefinitions>
+                            <GridViewHeaderRowPresenter Grid.Row="0" 
+                                                        Columns="{TemplateBinding Columns}"/>
+                            <ScrollViewer Grid.Row="1" Padding="{TemplateBinding Padding}" VerticalScrollBarVisibility="Auto">
+                                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
+                            </ScrollViewer>
+                        </Grid>
+                    </Border>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+
+    <!--<Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
+        <Setter Property="Width" Value="10"/>
+        <Setter Property="Height" Value="10"/>
+        <Setter Property="Margin" Value="0"/>
+        <Setter Property="Padding" Value="0"/>
+        <Setter Property="ToggleButton.RenderTransformOrigin" Value="0.5,0.5"/>
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="ToggleButton">
+                    <Path x:Name="ExpandPath" Margin="0" Fill="Black" Stroke="Black" 
+                      Data="M 4 0 L 10 5 L 4 10 Z"/>
+                    <ControlTemplate.Triggers>
+                        <Trigger Property="IsChecked" Value="True">
+                            <Setter Property="ToggleButton.RenderTransform">
+                                <Setter.Value>
+                                    <RotateTransform Angle="90"/>
+                                </Setter.Value>
+                            </Setter>
+                        </Trigger>
+                    </ControlTemplate.Triggers>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>-->
+
+    <Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
+        <Setter Property="Margin" Value="0"/>
+        <Setter Property="Padding" Value="0"/>
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="ToggleButton">
+                    <Border Background="Transparent" Cursor="Hand">
+                        <Grid x:Name="cross" Height="16"  Width="16" >
+                            <Path Data="M 0.5,0.5 l 15,0 l 0,15 l -15,0 L 0.5,0" Stroke="{TemplateBinding Foreground}" StrokeThickness="1"/>
+                            <Path x:Name="cross_h" Data="M 3,7.5 l 9,0" Stroke="{TemplateBinding Foreground}" StrokeThickness="1"/>
+                            <Path x:Name="cross_v" Data="M 7.5,3 l 0,9" Stroke="{TemplateBinding Foreground}" StrokeThickness="1"/>
+                        </Grid>
+                    </Border>
+                    <ControlTemplate.Triggers>
+                        <Trigger Property="IsChecked" Value="True">
+                            <Setter Property="Visibility" TargetName="cross_v" Value="Collapsed"/>
+                        </Trigger>
+                    </ControlTemplate.Triggers>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+
+    <ControlTemplate x:Key="tvi" TargetType="{x:Type controls:TreeListViewItem}">
+        <Grid>
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="Auto"/>
+                <ColumnDefinition Width="*"/>
+            </Grid.ColumnDefinitions>
+            <Grid.RowDefinitions>
+                <RowDefinition Height="Auto"/>
+                <RowDefinition/>
+            </Grid.RowDefinitions>
+
+            <Border x:Name="Bd"
+            Grid.Column="1"
+            Background="{TemplateBinding Background}"
+            BorderBrush="{TemplateBinding BorderBrush}"
+            BorderThickness="{TemplateBinding BorderThickness}"
+            Padding="{TemplateBinding Padding}">
+
+                <!--<GridViewRowPresenter x:Name="sb" Grid.Column="1" Columns="{TemplateBinding Columns}" 
+                                      Content="{Binding }"/>-->
+
+                <ContentPresenter Grid.Column="0" x:Name="cp"
+        Content="{TemplateBinding Header}"
+        ContentTemplate="{TemplateBinding HeaderTemplate}"
+        ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}"/>
+
+                <!--<Grid>
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="Auto"/>
+                    <ColumnDefinition Width="*"/>
+                </Grid.ColumnDefinitions>
+                
+                -->
+                <!--<GridViewRowPresenter Grid.Column="1" Columns="{TemplateBinding Columns}" 
+                                      Content="{Binding }"/>-->
+                <!--
+            </Grid>-->
+            </Border>
+
+            <ItemsPresenter x:Name="ItemsHost"
+                  Grid.Row="1"
+                  Grid.Column="1"/>
+        </Grid>
+        <ControlTemplate.Triggers>
+            <Trigger Property="IsExpanded" Value="False">
+                <Setter Property="Visibility" Value="Collapsed" TargetName="ItemsHost"/>
+            </Trigger>
+            <DataTrigger Binding="{Binding IsSelected,RelativeSource={RelativeSource Mode=Self}}" Value="True">
+                <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
+                <Setter Property="TextBlock.Foreground" TargetName="cp"  Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
+            </DataTrigger>
+            <!--<DataTrigger Binding="{Binding IsMouseOver,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=controls:TreeListViewItem,AncestorLevel=1}}" Value="True">
+            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
+            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
+        </DataTrigger>-->
+        </ControlTemplate.Triggers>
+    </ControlTemplate>
+
+    <Style TargetType="{x:Type controls:TreeListViewItem}">
+        <Setter Property="Margin" Value="0"/>
+        <Setter Property="Padding" Value="0"/>
+        <Setter Property="Template" Value="{StaticResource tvi}"/>
+    </Style>
+</ResourceDictionary>
\ No newline at end of file
diff --git a/HMI.UI/Converter/IndentConverter.cs b/HMI.UI/Converter/IndentConverter.cs
new file mode 100644
index 0000000..d31dc09
--- /dev/null
+++ b/HMI.UI/Converter/IndentConverter.cs
@@ -0,0 +1,21 @@
+锘縰sing System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+
+namespace HMI.UI.Converter
+{
+    public class IndentConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            int level = (int)value;
+            return new Thickness(level * 10, 0, 0, 0);
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return parameter;
+        }
+    }
+}
diff --git a/HMI.UI/HMI.UI.csproj b/HMI.UI/HMI.UI.csproj
index 9582666..a36b6f6 100644
--- a/HMI.UI/HMI.UI.csproj
+++ b/HMI.UI/HMI.UI.csproj
@@ -93,8 +93,10 @@
     <Compile Include="Controls\treegrid\Controls\TreeGrid.cs" />
     <Compile Include="Controls\treegrid\Controls\TreeItemContentControl.cs" />
     <Compile Include="Controls\treegrid\Controls\TreeItemData.cs" />
+    <Compile Include="Controls\treegrid\Controls\TreeListView.cs" />
     <Compile Include="Controls\treegrid\TreeItemConverter.cs" />
     <Compile Include="Controls\treegrid\TreeNodeExtend.cs" />
+    <Compile Include="Converter\IndentConverter.cs" />
     <Compile Include="Converter\VisibilityBoolConverter.cs" />
     <Compile Include="Converter\DataGridRowFlagConverter.cs" />
     <Compile Include="Converter\DataGridRowNumberConverter.cs" />
@@ -139,6 +141,10 @@
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
     </Page>
+    <Page Include="Controls\treegrid\Themes\TreeListView.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
     <Page Include="Controls\treegrid\Themes\TreeGrid.xaml">
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
@@ -159,6 +165,10 @@
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
+    <Page Include="Style\PanuonDataGrid.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
     <Page Include="Style\PanuonResource.xaml">
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
diff --git a/HMI.UI/Style/PanuonDataGrid.xaml b/HMI.UI/Style/PanuonDataGrid.xaml
new file mode 100644
index 0000000..4260135
--- /dev/null
+++ b/HMI.UI/Style/PanuonDataGrid.xaml
@@ -0,0 +1,88 @@
+锘�<ResourceDictionary 
+     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+                    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+                    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+                    mc:Ignorable="d"
+                    xmlns:ui="clr-namespace:HMI.UI"
+                    xmlns:sys="clr-namespace:System;assembly=mscorlib"
+                    xmlns:pw="https://opensource.panuon.com/wpf"
+                    xmlns:pu="https://opensource.panuon.com/wpf-ui"
+             xmlns:uic="clr-namespace:HMI.UI.Converter;assembly=HMI.UI"
+             xmlns:dp="clr-namespace:HMI.UI.DpUtil;assembly=HMI.UI">
+    <ResourceDictionary.MergedDictionaries>
+        <pu:StyleDictionary Includes="DataGrid" />
+        <ResourceDictionary Source="/HMI.UI;component/Style/Colors.xaml"/>
+        <ResourceDictionary Source="/HMI.UI;component/Resources/Font/Font.xaml"/>
+    </ResourceDictionary.MergedDictionaries>
+
+    <Style x:Key="DefaultDataGridRow" TargetType="DataGridRow" BasedOn="{StaticResource {x:Static pu:StyleKeys.DataGridRowStyle}}">
+        <Setter Property="Background" Value="White"/>
+        <Setter Property="DetailsVisibility" Value="Collapsed"/>
+        <Style.Triggers>
+            <Trigger Property="AlternationIndex" Value="1">
+                <Setter Property="Background" Value="#eeeeee"/>
+            </Trigger>
+        </Style.Triggers>
+    </Style>
+
+
+    <Style TargetType="DataGridCell" 
+       BasedOn="{StaticResource {x:Static pu:StyleKeys.DataGridCellStyle}}">
+        <Setter Property="Background" Value="Transparent"/>
+        <Setter Property="Padding" Value="5"/>
+        <Setter Property="Margin" Value="0"/>
+        <Setter Property="BorderThickness" Value="0"/>
+        <Setter Property="VerticalAlignment" Value="Stretch"/>
+    </Style>
+
+    <Style x:Key="DefaultDataGrid" TargetType="DataGrid" BasedOn="{StaticResource {x:Static pu:StyleKeys.DataGridStyle}}">
+        <Style.Resources>
+            <Style TargetType="DataGridColumnHeader" 
+       BasedOn="{StaticResource {x:Static pu:StyleKeys.DataGridColumnHeaderStyle}}">
+                <Setter Property="Padding" Value="10"/>
+                <Setter Property="BorderThickness" Value="0"/>
+            </Style>
+        </Style.Resources>
+
+        <Setter Property="RowHeight" Value="30"/>
+        <Setter Property="ColumnHeaderHeight" Value="36"/>
+
+        <Setter Property="pu:DataGridHelper.ColumnHeaderPadding" Value="0"/>
+        <Setter Property="ForceCursor" Value="True"/>
+        <Setter Property="SelectionMode" Value="Single"/>
+        <Setter Property="RowStyle" Value="{StaticResource DefaultDataGridRow}"/>
+        <Setter Property="AlternationCount" Value="2"></Setter>
+        <Setter Property="Foreground" Value="#3a3a3a"/>
+        <Setter Property="HorizontalGridLinesBrush" Value="{StaticResource TableBoarder}"/>
+        <Setter Property="VerticalGridLinesBrush" Value="{StaticResource TableBoarder}"/>
+        <Setter Property="BorderBrush" Value="{StaticResource TableBoarder}" />
+        <Setter Property="AutoGenerateColumns" Value="False"/>
+        <Setter Property="CanUserAddRows" Value="False"/>
+        <Setter Property="CanUserSortColumns" Value="False"/>
+        <Setter Property="CanUserDeleteRows" Value="False"/>
+        <Setter Property="RowHeaderWidth" Value="1"/>
+        <Setter Property="IsReadOnly" Value="True"/>
+        <Setter Property="GridLinesVisibility" Value="All"/>
+        <Setter Property="BorderThickness" Value="0"/>
+        <Setter Property="BorderBrush" Value="{StaticResource CommonBoarder}"/>
+        <Setter Property="FontSize" Value="{StaticResource ContentFontSize2}"/>
+        <Setter Property="pu:DataGridHelper.IsVerticalScrollBarCrossingColumnHeaderPanel" Value="True"/>
+        <Setter Property="pu:DataGridHelper.ColumnHeaderForeground" Value="White"/>
+        <Setter Property="pu:DataGridHelper.ColumnHeaderBackground" Value="{StaticResource TableHeader}"/>
+        <Setter Property="pu:DataGridHelper.ColumnHeaderHoverBackground" Value="{StaticResource TableHeader}"/>
+        <Setter Property="pu:DataGridHelper.ColumnHeaderSeparatorBrush" Value="{StaticResource TableBoarder}"/>
+        <Setter Property="pu:DataGridHelper.ColumnHeaderSeparatorVisibility" Value="Visible"/>
+        <Setter Property="pu:DataGridHelper.ColumnHeaderVerticalContentAlignment" Value="Center"/>
+        <Setter Property="pu:DataGridHelper.ColumnHeaderHorizontalContentAlignment" Value="Left"/>
+
+        <Setter Property="pu:DataGridHelper.RowHeaderSeparatorBrush" Value="{StaticResource CommonBoarder}"/>
+        <Setter Property="pu:DataGridHelper.RowHoverForeground" Value="{StaticResource SecondPrimaryColorContract}"/>
+        <Setter Property="pu:DataGridHelper.RowHoverBackground" Value="{StaticResource SecondPrimaryColor}"/>
+        <Setter Property="pu:DataGridHelper.RowSelectedBackground" Value="{StaticResource PrimaryColor}"/>
+        <Setter Property="pu:DataGridHelper.RowSelectedForeground" Value="White"/>
+        <Setter Property="pu:DataGridHelper.RowHeaderBorderThickness" Value="10,0,0,0"/>
+        <Setter Property="pu:DataGridHelper.ColumnHeaderBorderThickness" Value="0"/>
+        <Setter Property="pu:DataGridHelper.ColumnHeaderPadding" Value="0"/>
+    </Style>
+</ResourceDictionary>
\ No newline at end of file
diff --git a/HMI.UI/Style/PanuonResource.xaml b/HMI.UI/Style/PanuonResource.xaml
index 246d9d4..01cd250 100644
--- a/HMI.UI/Style/PanuonResource.xaml
+++ b/HMI.UI/Style/PanuonResource.xaml
@@ -11,8 +11,8 @@
              xmlns:uic="clr-namespace:HMI.UI.Converter;assembly=HMI.UI"
              xmlns:dp="clr-namespace:HMI.UI.DpUtil;assembly=HMI.UI">
     <ResourceDictionary.MergedDictionaries>
+        <pu:StyleDictionary Includes="PasswordBox,TextBox,ComboBox,Button,TreeView,Menu,ListBox,ContextMenu" />
         <ResourceDictionary Source="/HMI.UI;component/Style/Colors.xaml"/>
-        <pu:StyleDictionary Includes="PasswordBox,TextBox,ComboBox,Button,DataGrid,TreeView,Menu,ListBox,ContextMenu" />
         <ResourceDictionary Source="/HMI.UI;component/Resources/Font/Font.xaml"/>
     </ResourceDictionary.MergedDictionaries>
     <sys:Double x:Key="TitleFontSize">20</sys:Double>
@@ -55,7 +55,7 @@
         <Setter Property="pu:ButtonHelper.Icon" Value="&#xe643;"/>
         <Setter Property="Content" Value="{DynamicResource App.Edit}"/>
     </Style>
-    
+
     <Style x:Key="RfhBtn" TargetType="Button" BasedOn="{StaticResource PrimaryButton}">
         <Setter Property="pu:ButtonHelper.Icon" Value="&#xe631;"/>
         <Setter Property="Content" Value="{DynamicResource App.Refresh}"/>
@@ -161,80 +161,11 @@
         <Setter Property="Padding" Value="10"/>
     </Style>
 
-
-    <Style x:Key="DefaultDataGridRow" TargetType="DataGridRow" BasedOn="{StaticResource {x:Static pu:StyleKeys.DataGridRowStyle}}">
-        <Setter Property="Background" Value="White"/>
-        <Style.Triggers>
-            <Trigger Property="AlternationIndex" Value="1">
-                <Setter Property="Background" Value="#eeeeee"/>
-            </Trigger>
-        </Style.Triggers>
-    </Style>
-
     <Style x:Key="TableTextBlock" TargetType="TextBlock">
         <Setter Property="Padding" Value="0,2"/>
         <Setter Property="Margin" Value="0"/>
         <Setter Property="VerticalAlignment" Value="Center"/>
         <Setter Property="TextWrapping" Value="Wrap"/>
-    </Style>
-
-
-    <Style TargetType="DataGridCell" 
-       BasedOn="{StaticResource {x:Static pu:StyleKeys.DataGridCellStyle}}">
-        <Setter Property="Background" Value="Transparent"/>
-        <Setter Property="Padding" Value="5"/>
-        <Setter Property="Margin" Value="0"/>
-        <Setter Property="BorderThickness" Value="0"/>
-        <Setter Property="VerticalAlignment" Value="Stretch"/>
-    </Style>
-
-    <Style x:Key="DefaultDataGrid" TargetType="DataGrid" BasedOn="{StaticResource {x:Static pu:StyleKeys.DataGridStyle}}">
-        <Style.Resources>
-            <Style TargetType="DataGridColumnHeader" 
-       BasedOn="{StaticResource {x:Static pu:StyleKeys.DataGridColumnHeaderStyle}}">
-                <Setter Property="Padding" Value="10"/>
-                <Setter Property="BorderThickness" Value="0"/>
-            </Style>
-        </Style.Resources>
-
-        <Setter Property="RowHeight" Value="30"/>
-        <Setter Property="ColumnHeaderHeight" Value="36"/>
-        
-        <Setter Property="pu:DataGridHelper.ColumnHeaderPadding" Value="0"/>
-        <Setter Property="ForceCursor" Value="True"/>
-        <Setter Property="SelectionMode" Value="Single"/>
-        <Setter Property="RowStyle" Value="{StaticResource DefaultDataGridRow}"/>
-        <Setter Property="AlternationCount" Value="2"></Setter>
-        <Setter Property="Foreground" Value="#3a3a3a"/>
-        <Setter Property="HorizontalGridLinesBrush" Value="{StaticResource TableBoarder}"/>
-        <Setter Property="VerticalGridLinesBrush" Value="{StaticResource TableBoarder}"/>
-        <Setter Property="BorderBrush" Value="{StaticResource TableBoarder}" />
-        <Setter Property="AutoGenerateColumns" Value="False"/>
-        <Setter Property="CanUserAddRows" Value="False"/>
-        <Setter Property="CanUserSortColumns" Value="False"/>
-        <Setter Property="CanUserDeleteRows" Value="False"/>
-        <Setter Property="RowHeaderWidth" Value="1"/>
-        <Setter Property="IsReadOnly" Value="True"/>
-        <Setter Property="GridLinesVisibility" Value="All"/>
-        <Setter Property="BorderThickness" Value="0"/>
-        <Setter Property="BorderBrush" Value="{StaticResource CommonBoarder}"/>
-        <Setter Property="FontSize" Value="{StaticResource ContentFontSize2}"/>
-        <Setter Property="pu:DataGridHelper.ColumnHeaderForeground" Value="White"/>
-        <Setter Property="pu:DataGridHelper.ColumnHeaderBackground" Value="{StaticResource TableHeader}"/>
-        <Setter Property="pu:DataGridHelper.ColumnHeaderHoverBackground" Value="{StaticResource TableHeader}"/>
-        <Setter Property="pu:DataGridHelper.ColumnHeaderSeparatorBrush" Value="{StaticResource TableBoarder}"/>
-        <Setter Property="pu:DataGridHelper.ColumnHeaderSeparatorVisibility" Value="Visible"/>
-        <Setter Property="pu:DataGridHelper.ColumnHeaderVerticalContentAlignment" Value="Center"/>
-        <Setter Property="pu:DataGridHelper.ColumnHeaderHorizontalContentAlignment" Value="Left"/>
-
-        <Setter Property="pu:DataGridHelper.RowHeaderSeparatorBrush" Value="{StaticResource CommonBoarder}"/>
-        <Setter Property="pu:DataGridHelper.RowHoverForeground" Value="{StaticResource SecondPrimaryColorContract}"/>
-        <Setter Property="pu:DataGridHelper.RowHoverBackground" Value="{StaticResource SecondPrimaryColor}"/>
-        <Setter Property="pu:DataGridHelper.RowSelectedBackground" Value="{StaticResource PrimaryColor}"/>
-        <Setter Property="pu:DataGridHelper.RowSelectedForeground" Value="White"/>
-        <Setter Property="pu:DataGridHelper.RowHeaderBorderThickness" Value="10,0,0,0"/>
-        <Setter Property="pu:DataGridHelper.ColumnHeaderBorderThickness" Value="0"/>
-        <Setter Property="pu:DataGridHelper.ColumnHeaderPadding" Value="0"/>
     </Style>
 
     <Style x:Key="DefaultTreeView" TargetType="TreeView" BasedOn="{StaticResource {x:Static pu:StyleKeys.TreeViewStyle}}">
diff --git a/HMI.UnitTest/MainWindow.xaml.cs b/HMI.UnitTest/MainWindow.xaml.cs
index 11bfb1a..d367685 100644
--- a/HMI.UnitTest/MainWindow.xaml.cs
+++ b/HMI.UnitTest/MainWindow.xaml.cs
@@ -33,21 +33,22 @@
 
         private void Button_Click(object sender, RoutedEventArgs e)
         {
-            Task.Run(() =>
-            {
-                for (int j = 0; j < 1000; j++)
-                {
-                    string status = (j % 2 == 0) ? "Passed" : "Failed";
-                    string d = (j % 2 == 0) ? "9" : "9999999999999999999999999999999999999999999999999999999999999999995";
-                    tsExecution.AddTestData(0, $"ConnectivityCANRec,2,3,4,{d},6,{status}");
-                }
-            });
+            //Task.Run(() =>
+            //{
+            //    for (int j = 0; j < 1000; j++)
+            //    {
+            //        string status = (j % 2 == 0) ? "Passed" : "Failed";
+            //        string d = (j % 2 == 0) ? "9" : "9999999999999999999999999999999999999999999999999999999999999999995";
+            //        tsExecution.AddTestData(0, $"ConnectivityCANRec,2,3,4,{d},6,{status}");
+            //    }
+            //});
 
-            tsExecution.UpdatePositionStatus(0, "Passed");
-            tsExecution.UpdatePositionProcessValue(0, 12);
-            tsExecution.PausePosition(0);
-            tsExecution.SetPositionBarcode(0, "123456789");
-            tsExecution.SavePositionCSV(0);
+            //tsExecution.UpdatePositionStatus(0, "Passed");
+            tsExecution.UpdatePositionStatus(0, "Failed");
+            //tsExecution.UpdatePositionProcessValue(0, 12);
+            //tsExecution.PausePosition(0);
+            //tsExecution.SetPositionBarcode(0, "123456789");
+            //tsExecution.SavePositionCSV(0);
 
 
             //tsExecution.UpdatePositionStatus(1, "Failed");
diff --git a/OPCClient/OPCClient.csproj b/OPCClient/OPCClient.csproj
index 8f0a730..02bf99f 100644
--- a/OPCClient/OPCClient.csproj
+++ b/OPCClient/OPCClient.csproj
@@ -30,6 +30,24 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
       <HintPath>..\WPFProject\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
diff --git a/Plugin.DataBoard/Plugin.DataBoard.csproj b/Plugin.DataBoard/Plugin.DataBoard.csproj
index 48a30fc..9696880 100644
--- a/Plugin.DataBoard/Plugin.DataBoard.csproj
+++ b/Plugin.DataBoard/Plugin.DataBoard.csproj
@@ -33,6 +33,24 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="log4net, Version=3.0.4.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
       <HintPath>..\WPFProject\packages\log4net.3.0.4\lib\net462\log4net.dll</HintPath>
diff --git a/Plugin.JarUI/Plugin.JarUI.csproj b/Plugin.JarUI/Plugin.JarUI.csproj
index 6c998d7..18d9258 100644
--- a/Plugin.JarUI/Plugin.JarUI.csproj
+++ b/Plugin.JarUI/Plugin.JarUI.csproj
@@ -31,6 +31,24 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="log4net, Version=3.0.4.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
       <HintPath>..\WPFProject\packages\log4net.3.0.4\lib\net462\log4net.dll</HintPath>
diff --git a/Plugin.SeqEditor/Entity/EditablePO/IEPO.cs b/Plugin.SeqEditor/Entity/EditablePO/IEPO.cs
index dc06dfd..d495047 100644
--- a/Plugin.SeqEditor/Entity/EditablePO/IEPO.cs
+++ b/Plugin.SeqEditor/Entity/EditablePO/IEPO.cs
@@ -40,7 +40,7 @@
         public virtual void CustomPropertyChanged(string name)
         {
             OnPropertyChanged(name);
-            //StepUI?.UpdatePropertyChanged("Description");
+            StepUI?.UpdatePropertyChanged("Description");
         }
     }
 }
diff --git a/Plugin.SeqEditor/Entity/SeqUI.cs b/Plugin.SeqEditor/Entity/SeqUI.cs
index c008960..c6c2430 100644
--- a/Plugin.SeqEditor/Entity/SeqUI.cs
+++ b/Plugin.SeqEditor/Entity/SeqUI.cs
@@ -1,10 +1,19 @@
 锘縰sing CommunityToolkit.Mvvm.ComponentModel;
 using NationalInstruments.TestStand.Interop.API;
+using System.Runtime.InteropServices;
 
 namespace Plugin.SeqEditor.Entity
 {
     public partial class SeqUI : ObservableObject
     {
+        ~SeqUI()
+        {
+            if (sequence != null)
+            {
+                Marshal.ReleaseComObject(sequence);
+            }
+        }
+
         public Sequence sequence { get; private set; }
         public SeqUI(Sequence sequence)
         {
@@ -23,5 +32,13 @@
                 }
             }
         }
+
+        [ObservableProperty]
+        private bool isChanged;
+
+        public void OnStepSettingChanged(object sender, string propertyName)
+        {
+            IsChanged = true;
+        }
     }
 }
diff --git a/Plugin.SeqEditor/Entity/StepUI.cs b/Plugin.SeqEditor/Entity/StepUI.cs
index 79f71b0..91f5baf 100644
--- a/Plugin.SeqEditor/Entity/StepUI.cs
+++ b/Plugin.SeqEditor/Entity/StepUI.cs
@@ -1,21 +1,47 @@
 锘縰sing CommunityToolkit.Mvvm.ComponentModel;
 using NationalInstruments.TestStand.Interop.API;
 using System.Collections.ObjectModel;
+using System.Runtime.InteropServices;
 
 namespace Plugin.SeqEditor.Entity
 {
     public partial class StepUI : ObservableObject
     {
-        public Step step { get; private set; }
 
-        public StepUI(Step step)
+        ~StepUI()
+        {
+            if (step != null)
+            {
+                Marshal.ReleaseComObject(step);
+            }
+        }
+
+        public Step step { get; private set; }
+        public Sequence sequence { get; private set; }
+
+        public event EventHandler<string> SettingChanged;
+
+        public int IndexInSequence { 
+            get {
+                return sequence.GetStepIndex(Name, StepGroup);
+            } 
+        }
+
+        public StepUI(Step step, Sequence sequence)
         {
             this.step = step;
+            this.sequence = sequence;
         }
 
         public void UpdatePropertyChanged(string name)
         {
             OnPropertyChanged(name);
+        }
+
+        protected new void OnPropertyChanged(string name)
+        {
+            base.OnPropertyChanged(name);
+            SettingChanged?.Invoke(this, name);
         }
 
         public string Name
@@ -72,13 +98,11 @@
             }
         }
 
-
-
-        public StepGroups? StepGroup
+        public StepGroups StepGroup
         {
             get
             {
-                return step?.StepGroup;
+                return step.StepGroup;
             }
         }
 
@@ -87,5 +111,10 @@
 
         [ObservableProperty]
         public ObservableCollection<StepUI> children = new();
+
+        public override string ToString()
+        {
+            return Name;
+        }
     }
 }
diff --git a/Plugin.SeqEditor/Plugin.SeqEditor.csproj b/Plugin.SeqEditor/Plugin.SeqEditor.csproj
index 87fbf68..ce581ba 100644
--- a/Plugin.SeqEditor/Plugin.SeqEditor.csproj
+++ b/Plugin.SeqEditor/Plugin.SeqEditor.csproj
@@ -9,6 +9,7 @@
 	</PropertyGroup>
 	<ItemGroup>
 	  <PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
+	  <PackageReference Include="gong-wpf-dragdrop" Version="4.0.0" />
 	  <PackageReference Include="log4net" Version="3.0.4" />
 	  <PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" />
 	  <PackageReference Include="Panuon.WPF.UI" Version="1.3.0.2" />
diff --git a/Plugin.SeqEditor/SeqEditor.xaml b/Plugin.SeqEditor/SeqEditor.xaml
index 173f331..0867528 100644
--- a/Plugin.SeqEditor/SeqEditor.xaml
+++ b/Plugin.SeqEditor/SeqEditor.xaml
@@ -5,6 +5,7 @@
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:local="clr-namespace:Plugin.SeqEditor"
              mc:Ignorable="d" 
+             xmlns:hcu="clr-namespace:HMI.Core.Util;assembly=HMI.Core"
              xmlns:hb="clr-namespace:HMI.Base;assembly=HMI.Base"
              xmlns:uic="clr-namespace:HMI.UI.Converter;assembly=HMI.UI"
 xmlns:ui="clr-namespace:HMI.UI;assembly=HMI.UI"
@@ -12,6 +13,7 @@
 xmlns:pu="https://opensource.panuon.com/wpf-ui"
 xmlns:dp="clr-namespace:HMI.UI.DpUtil;assembly=HMI.UI"
 xmlns:util="clr-namespace:Plugin.SeqEditor.Util"
+        xmlns:dd="urn:gong-wpf-dragdrop"
         xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
              d:DesignHeight="450" d:DesignWidth="800">
     <i:Interaction.Triggers>
@@ -22,14 +24,29 @@
     <UserControl.Resources>
         <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/HMI.UI;component/Style/PanuonDataGrid.xaml"/>
+                <ResourceDictionary Source="/HMI.UI;component/Controls/MultiCombox.xaml"/>
+                <ResourceDictionary Source="/HMI.UI;component/Controls/TreeGrid/Themes/TreeListView.xaml"/>
                 <ResourceDictionary Source="/HMI.UI;component/Controls/TreeGrid/Themes/TreeItemContentControl.xaml"/>
                 <ResourceDictionary Source="/HMI.UI;component/Controls/TreeGrid/Themes/TreeGrid.xaml"/>
             </ResourceDictionary.MergedDictionaries>
+
+            <uic:IndentConverter x:Key="IndentConverter"/>
 
             <Style TargetType="pu:FormGroup">
                 <Setter Property="Padding" Value="0,10"/>
                 <Setter Property="HeaderFontSize" Value="14"/>
                 <Setter Property="HeaderFontWeight" Value="Bold"/>
+            </Style>
+
+            <Style x:Key="TreeTogg" TargetType="ToggleButton">
+                <Setter Property="Template">
+                    <Setter.Value>
+                        <ControlTemplate>
+                            <Border Width="0"/>
+                        </ControlTemplate>
+                    </Setter.Value>
+                </Setter>
             </Style>
 
             <!-- 鏍慓rid缁勪欢 -->
@@ -42,6 +59,92 @@
                 </CollectionViewSource.GroupDescriptions>
             </CollectionViewSource>
 
+            <hcu:BindingProxy x:Key="BindingProxy" Data="{Binding}"/>
+
+            <ContextMenu x:Key="stepContextMenu">
+                <ContextMenu.Resources>
+                    <Style TargetType="MenuItem">
+                        <Setter Property="DataContext" Value="{Binding Data,Source={StaticResource BindingProxy}}"/>
+                    </Style>
+                </ContextMenu.Resources>
+                <MenuItem Header="鎻掑叆Step">
+                    <MenuItem Header="Tests">
+                        <!--<MenuItem Header="Pass/Fail" Command="{Binding AddStepCommand}" 
+                              CommandParameter="Tests.PassFail"/>
+                        <MenuItem Header="MultiNumber" Command="{Binding AddStepCommand}"
+CommandParameter="Tests.NI_MultipleNumericLimitTest"/>-->
+                        <MenuItem Header="Number" Command="{Binding AddStepCommand}"
+CommandParameter="Tests.NumericLimitTest"/>
+                        <MenuItem Header="String" Command="{Binding AddStepCommand}"
+CommandParameter="Tests.StringValueTest"/>
+                    </MenuItem>
+
+                    <!--<MenuItem Header="Actions">
+                        <MenuItem Header="LabVIEW" Command="{Binding AddStepCommand}"
+CommandParameter="Actions.LabVIEW"/>
+                        <MenuItem Header="LabWindows/CVI" Command="{Binding AddStepCommand}"
+CommandParameter="Actions.LabWindows/CVI"/>
+                        <MenuItem Header="C/C++ DLL" Command="{Binding AddStepCommand}" 
+                              CommandParameter="Actions.C/C++ DLL"/>
+                        <MenuItem Header=".NET" Command="{Binding AddStepCommand}" 
+          CommandParameter="Actions..NET"/>
+
+                        <MenuItem Header="ActiveX/COM" Command="{Binding AddStepCommand}" 
+CommandParameter="Actions.ActiveX/COM"/>
+
+                        <MenuItem Header="None" Command="{Binding AddStepCommand}" 
+CommandParameter="Actions.None"/>
+
+                        <MenuItem Header="LabVIEW NXG" Command="{Binding AddStepCommand}"
+CommandParameter="Actions.LabVIEW NXG"/>
+                        <MenuItem Header="Python" Command="{Binding AddStepCommand}"
+CommandParameter="Actions.Python"/>
+                    </MenuItem>-->
+                </MenuItem>
+            </ContextMenu>
+
+            <Style x:Key="treeCell" TargetType="DataGridCell">
+                <Setter Property="Background" Value="Transparent"/>
+                <Setter Property="Padding" Value="5"/>
+                <Setter Property="Margin" Value="0"/>
+                <Setter Property="BorderThickness" Value="0"/>
+                <Setter Property="VerticalAlignment" Value="Stretch"/>
+                <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment,
+                    RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType=ui:TreeDataGrid}}"/>
+                <Setter Property="HorizontalContentAlignment" 
+                        Value="{Binding HorizontalContentAlignment,
+    RelativeSource={RelativeSource Mode=FindAncestor,AncestorLevel=1,AncestorType=ui:TreeDataGrid}}"/>
+            </Style>
+
+            <Style x:Key="stepRowStyle" TargetType="ui:TreeDataGridRow">
+                <Setter Property="ContextMenu" Value="{StaticResource stepContextMenu}"/>
+                <Setter Property="DetailsVisibility" Value="Collapsed"/>
+
+                <Style.Triggers>
+                    <Trigger Property="IsSelected" Value="True">
+                        <Setter Property="Background" Value="{StaticResource PrimaryColor}"/>
+                    </Trigger>
+                </Style.Triggers>
+            </Style>
+
+            <Style x:Key="sb" TargetType="ui:TreeDataGrid" BasedOn="{StaticResource DefaultDataGrid}">
+                <Setter Property="pu:DataGridHelper.RowHeaderSeparatorVisibility" Value="Visible"/>
+                <Setter Property="pu:DataGridHelper.RowHeaderSeparatorBrush" Value="#FFF"/>
+                <Setter Property="AreRowDetailsFrozen" Value="False"/>
+                <Setter Property="HeadersVisibility" Value="Column"/>
+                <Setter Property="DataGridCell.VerticalContentAlignment" Value="Center"/>
+                <Setter Property="DataGridCell.HorizontalContentAlignment" Value="Left"/>
+            </Style>
+
+            <Style x:Key="gvh" TargetType="GridViewColumnHeader">
+                <Setter Property="Background" Value="{DynamicResource VerBar}"/>
+            </Style>
+
+            <DataTemplate x:Key="gvht">
+                <Border Padding="6">
+                    <TextBlock Foreground="#FFF" Text="{Binding }"/>
+                </Border>
+            </DataTemplate>
         </ResourceDictionary>
     </UserControl.Resources>
     <Border Style="{StaticResource CardBoarder}" Padding="0">
@@ -64,7 +167,7 @@
                     <Button Style="{StaticResource SaveBtn}" Content="{DynamicResource se.save}" Command="{Binding SaveSeqFileCommand}"/>
                     <Button Style="{StaticResource SaveBtn}" pu:ButtonHelper.Icon="&#xe60b;"
                             Content="{DynamicResource se.saveTo}" 
-                            Command="{Binding SaveSeqFileCommand}"/>
+                            Command="{Binding SaveToFileCommand}" Cursor="Hand"/>
                     <Button Style="{StaticResource DelBtn}" Content="{DynamicResource se.close}"
                             pu:ButtonHelper.Icon="&#xe609;"
                             Command="{Binding CloseSeqFileCommand}"/>
@@ -75,7 +178,20 @@
 
                 <TextBlock DockPanel.Dock="Left" FontSize="{StaticResource ContentFontSize2}" 
                            Margin="20,0,0,0"
-VerticalAlignment="Bottom" LineHeight="{StaticResource TitleFontSize}" HorizontalAlignment="Left" Text="{Binding CurrentFileName}"/>
+VerticalAlignment="Bottom" LineHeight="{StaticResource TitleFontSize}" HorizontalAlignment="Left">
+                <Run Text="{Binding CurrentFileName}"/>
+                <Run DataContext="{Binding CurrentSeqUI}">
+                    <Run.Style>
+                        <Style TargetType="Run">
+                            <Style.Triggers>
+                                <DataTrigger Binding="{Binding IsChanged}" Value="True">
+                                    <Setter Property="Text" Value="*"/>    
+                                </DataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </Run.Style>
+                </Run>
+                </TextBlock>
             </DockPanel>
 
             <!--<pu:FormGroup Header="{DynamicResource se.seq}" Orientation="Vertical" Grid.Row="1" Grid.Column="0">
@@ -91,36 +207,11 @@
             </pu:FormGroup>-->
             <pu:FormGroup Grid.Row="1" Grid.Column="1" Header="姝ラ绫诲瀷" Style="{StaticResource InputFormGroupStyle}">
                 <StackPanel Orientation="Horizontal">
-
-                    <!--<ComboBox Text="{Binding TargetType}" 
-                              MinWidth="180" Margin="0,0,10,0" x:Name="CbFilter"
-                        SelectedValuePath="DataValue" IsEditable="True" >
-                        <ComboBox.ItemTemplate>
-                            <DataTemplate DataType="util:ItemData">
-                                <StackPanel Orientation="Horizontal">
-                                    <CheckBox IsChecked="{Binding IsChecked}" />
-                                    <TextBlock Text="{Binding DisplayName}" />
-                                </StackPanel>
-                            </DataTemplate>
-                        </ComboBox.ItemTemplate>
-                    </ComboBox>-->
-
                     <ui:MultiComboBox SelectedValues="{Binding TargetType}"
-                                      Style="{StaticResource FormComboxStyle}"
                                       pu:ComboBoxHelper.ClearButtonVisibility="Collapsed"
-                                      MinWidth="180" Margin="0,0,10,0" x:Name="CbFilter" IsEditable="True" IsReadOnly="True" >
-                        <ui:MultiComboBox.ItemTemplate>
-                            <DataTemplate DataType="util:ItemData">
-                                <StackPanel Orientation="Horizontal">
-                                    <CheckBox IsChecked="{Binding IsChecked,UpdateSourceTrigger=PropertyChanged}" />
-                                    <TextBlock Text="{Binding DisplayName}" />
-                                </StackPanel>
-                            </DataTemplate>
-                        </ui:MultiComboBox.ItemTemplate>
+                                      Width="450" Margin="0,0,10,0" x:Name="CbFilter" IsEditable="True" IsReadOnly="True" >
+
                     </ui:MultiComboBox>
-
-                    <!--<ComboBox Style="{StaticResource FormComboxStyle}" MinWidth="180" Margin="0,0,10,0" x:Name="CbFilter"/>-->
-
                     <Button Style="{StaticResource RfhBtn}" Command="{Binding RefreshCommand}"/>
                 </StackPanel>
             </pu:FormGroup>
@@ -190,43 +281,46 @@
                         </DataGridTemplateColumn>
                     </DataGrid.Columns>
                                  ItemsSource="{Binding AllSteps,Converter={StaticResource treeC}}"
+                                 PreviewMouseWheel="treeDataGrid_PreviewMouseWheel"
                 </DataGrid>-->
 
-                <ui:TreeDataGrid Grid.Row="1" x:Name="treeDataGrid"
-                                 VirtualizingPanel.IsContainerVirtualizable="True"
-                                VirtualizingPanel.IsVirtualizing="True"
-                                VirtualizingPanel.VirtualizationMode="Recycling"
-                                ScrollViewer.CanContentScroll="False"
-                                 VirtualizingPanel.IsVirtualizingWhenGrouping="True"
-                                EnableColumnVirtualization="True"
-                                EnableRowVirtualization="True"
-                                 PreviewMouseWheel="treeDataGrid_PreviewMouseWheel"
+                <!--<ui:TreeDataGrid Grid.Row="1" x:Name="treeDataGrid"
+                                          dd:DragDrop.IsDragSource="True"
+dd:DragDrop.IsDropTarget="True"
+dd:DragDrop.ShowAlwaysDropTargetAdorner="True"
+dd:DragDrop.UseDefaultDragAdorner="True"
+                                 dd:DragDrop.DropHandler="{Binding StepDropHandler}"
+                                 SelectionUnit="FullRow"
                                  AutoGenerateColumns="False"
-                                 IsReadOnly="True"
+                                 CanUserAddRows="False"
                                  Style="{StaticResource DefaultDataGrid}"
-                ItemsSource="{Binding Source={StaticResource TreeGridFilter}}"
+                                 ItemsSource="{Binding TreeCollection,IsAsync=True}"
                                  SelectedItem="{Binding TreeItemData}">
-
-                    <!--<DataGrid.GroupStyle>
+                    <DataGrid.GroupStyle>
                         <GroupStyle>
+                            <GroupStyle.Panel>
+                                <ItemsPanelTemplate>
+                                    <DataGridRowsPresenter/>
+                                </ItemsPanelTemplate>
+                            </GroupStyle.Panel>
                             <GroupStyle.ContainerStyle>
                                 <Style TargetType="{x:Type GroupItem}">
-                                    <Setter Property="Margin" Value="0,0,0,5" />
                                     <Setter Property="Template">
                                         <Setter.Value>
                                             <ControlTemplate TargetType="{x:Type GroupItem}">
-                                                <GroupBox Header="{Binding Name}">
+                                                <Expander BorderThickness="0" Background="DarkCyan" 
+                                                          Header="{Binding Name}" IsExpanded="True">
                                                     <ItemsPresenter />
-                                                </GroupBox>
+                                                </Expander>
                                             </ControlTemplate>
                                         </Setter.Value>
                                     </Setter>
                                 </Style>
                             </GroupStyle.ContainerStyle>
                         </GroupStyle>
-                    </DataGrid.GroupStyle>-->
+                    </DataGrid.GroupStyle>
 
-                    <ui:TreeDataGrid.Columns>
+                    <DataGrid.Columns>
                         <DataGridTemplateColumn IsReadOnly="True" Width="Auto">
                             <DataGridTemplateColumn.CellTemplate>
                                 <DataTemplate>
@@ -235,12 +329,187 @@
                             </DataGridTemplateColumn.CellTemplate>
                         </DataGridTemplateColumn>
 
-                        <DataGridTextColumn Header="鍚嶇О" Width="1*" Binding="{Binding Data.Name}"></DataGridTextColumn>
-                        <DataGridTextColumn Header="绫诲瀷" Width="1*" Binding="{Binding Data.Type}"></DataGridTextColumn>
-                        <DataGridTextColumn Header="鎻忚堪" Width="7*" Binding="{Binding  Data.Description}"></DataGridTextColumn>
-                        <DataGridTextColumn Header="RunMode" Width="*" Binding="{Binding Data.RunMode}"></DataGridTextColumn>
-                    </ui:TreeDataGrid.Columns>
-                </ui:TreeDataGrid>
+                        <DataGridTextColumn Width="1*" Binding="{Binding Data.Name}">
+                            <DataGridTextColumn.Header>
+                                <TextBlock Text="{DynamicResource se.name}"/>
+                            </DataGridTextColumn.Header>
+                        </DataGridTextColumn>
+
+                        <DataGridTextColumn Width="1*" Binding="{Binding Data.Type}">
+                            <DataGridTextColumn.Header>
+                                <TextBlock Text="{DynamicResource se.type}"/>
+                            </DataGridTextColumn.Header>
+                        </DataGridTextColumn>
+
+                        <DataGridTextColumn Width="6*" Binding="{Binding Data.Description}">
+                            <DataGridTextColumn.Header>
+                                <TextBlock Text="{DynamicResource se.description}"/>
+                            </DataGridTextColumn.Header>
+                        </DataGridTextColumn>
+
+                        <DataGridTemplateColumn Width="1*">
+                            <DataGridTemplateColumn.Header>
+                                <TextBlock Text="{DynamicResource se.runMode}"/>
+                            </DataGridTemplateColumn.Header>
+                            <DataGridTemplateColumn.CellTemplate>
+                                <DataTemplate>
+                                    <Grid x:Name="border" Margin="0">
+                                        <TextBlock x:Name="text" Margin="-1" Padding="0" VerticalAlignment="Center"/>
+                                    </Grid>
+                                    <DataTemplate.Triggers>
+                                        <DataTrigger Binding="{Binding Data.RunMode}" Value="Normal">
+                                            <Setter TargetName="text" Property="Text" Value="{DynamicResource se.normal}"/>
+                                        </DataTrigger>
+                                        <DataTrigger Binding="{Binding Data.RunMode}" Value="Skip">
+                                            <Setter TargetName="text" Property="Text" Value="{DynamicResource se.skip}"/>
+                                        </DataTrigger>
+                                        <DataTrigger Binding="{Binding Data.RunMode}" Value="Pass">
+                                            <Setter TargetName="text" Property="Text" Value="{DynamicResource se.pass}"/>
+                                        </DataTrigger>
+                                        <DataTrigger Binding="{Binding Data.RunMode}" Value="Fail">
+                                            <Setter TargetName="text" Property="Text" Value="{DynamicResource se.fail}"/>
+                                        </DataTrigger>
+                                    </DataTemplate.Triggers>
+                                </DataTemplate>
+                            </DataGridTemplateColumn.CellTemplate>
+                        </DataGridTemplateColumn>
+                    </DataGrid.Columns>
+                </ui:TreeDataGrid>-->
+
+
+                <ui:TreeListView Grid.Row="1" Grid.Column="1" ItemsSource="{Binding AllSteps}"
+                                 dd:DragDrop.IsDragSource="True"
+                                 dd:DragDrop.IsDropTarget="True"
+                                 dd:DragDrop.DropTargetAdornerBrush="Red"
+                                 dd:DragDrop.DropHandler="{Binding StepDropHandler}"
+                                 SizeChanged="TreeListView_SizeChanged">
+                    <i:Interaction.Triggers>
+                        <i:EventTrigger EventName="SelectedItemChanged">
+                            <i:InvokeCommandAction Command="{Binding SbCommand}" PassEventArgsToCommand="True"/>
+                        </i:EventTrigger>
+                        <i:EventTrigger EventName="PreviewMouseRightButtonDown">
+                            <i:InvokeCommandAction Command="{Binding Sb2Command}" PassEventArgsToCommand="True"/>
+                        </i:EventTrigger>
+                    </i:Interaction.Triggers>
+                    <ui:TreeListView.Resources>
+                        <Style x:Key="CellBorder" TargetType="Border">
+                            <Setter Property="Padding" Value="5"/>
+                            <Setter Property="BorderBrush" Value="{DynamicResource CommonBoarder}"/>
+                            <Setter Property="BorderThickness" Value="1,0,0,1"/>
+                            <Setter Property="Margin" Value="-6,0"/>
+                        </Style>
+                    </ui:TreeListView.Resources>
+
+                    <ui:TreeListView.Style>
+                        <Style TargetType="ui:TreeListView" BasedOn="{StaticResource DefaultTreeView}">
+                            <Setter Property="pu:TreeViewHelper.ToggleArrowToggleButtonStyle" Value="{StaticResource TreeTogg}"/>
+                            <Setter Property="pu:TreeViewHelper.ItemsPadding" Value="0"/>
+                            <Setter Property="Background" Value="#FFF"/>
+                            <Setter Property="ColumnHeaderContainerStyle" Value="{StaticResource gvh}"/>
+                            <Setter Property="Template">
+                                <Setter.Value>
+                                    <ControlTemplate TargetType="ui:TreeListView">
+                                        <Border BorderBrush="{TemplateBinding BorderBrush}"
+                BorderThickness="{TemplateBinding BorderThickness}"
+                Background="{TemplateBinding Background}">
+                                            <Grid>
+                                                <Grid.RowDefinitions>
+                                                    <RowDefinition Height="Auto"/>
+                                                    <RowDefinition/>
+                                                </Grid.RowDefinitions>
+                                                <GridViewHeaderRowPresenter
+                                                    Grid.Row="0" Columns="{TemplateBinding Columns}">
+                                                    <GridViewHeaderRowPresenter.ColumnHeaderContainerStyle>
+                                                        <Style TargetType="GridViewColumnHeader">
+                                                            <Setter Property="Background" Value="{DynamicResource VerBar}"/>
+                                                        </Style>
+                                                    </GridViewHeaderRowPresenter.ColumnHeaderContainerStyle>
+                                                </GridViewHeaderRowPresenter>
+                                                <ScrollViewer Grid.Row="1" Padding="{TemplateBinding Padding}" VerticalScrollBarVisibility="Auto">
+                                                    <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
+                                                </ScrollViewer>
+                                            </Grid>
+                                        </Border>
+                                    </ControlTemplate>
+                                </Setter.Value>
+                            </Setter>
+                        </Style>
+                    </ui:TreeListView.Style>
+
+                    <ui:TreeListView.Columns>
+                        <GridViewColumn Header="鍚嶇О" HeaderContainerStyle="{StaticResource gvh}"
+                                        HeaderTemplate="{StaticResource gvht}">
+                            <GridViewColumn.CellTemplate>
+                                <DataTemplate>
+                                    <Border Style="{StaticResource CellBorder}">
+                                        <StackPanel Orientation="Horizontal">
+                                            <ToggleButton x:Name="Expander"
+      Style="{StaticResource ExpandCollapseToggleStyle}"
+                                          Margin="{Binding level,Converter={StaticResource IndentConverter},RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ui:TreeListViewItem,AncestorLevel=1}}"
+      Grid.Column="0"
+IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ui:TreeListViewItem,AncestorLevel=1}}"
+ClickMode="Press"/>
+                                            <TextBlock Margin="5,0,0,0" Padding="6,0" Text="{Binding Name}"/>
+                                        </StackPanel>
+                                    </Border>
+
+                                    <DataTemplate.Triggers>
+                                        <DataTrigger Binding="{Binding HasItems, 
+RelativeSource={RelativeSource Mode=FindAncestor,
+AncestorType=ui:TreeListViewItem,AncestorLevel=1}}"
+         Value="False">
+                                            <Setter Property="Visibility" Value="Hidden" TargetName="Expander"/>
+                                        </DataTrigger>
+                                    </DataTemplate.Triggers>
+                                </DataTemplate>
+                            </GridViewColumn.CellTemplate>
+                        </GridViewColumn>
+
+                        <GridViewColumn Header="绫诲瀷" HeaderContainerStyle="{StaticResource gvh}" 
+                                        HeaderTemplate="{StaticResource gvht}">
+                            <GridViewColumn.CellTemplate>
+                                <DataTemplate>
+                                    <Border Style="{StaticResource CellBorder}">
+                                        <TextBlock Padding="6,0" Text="{Binding Type}"/>
+                                    </Border>
+                                </DataTemplate>
+                            </GridViewColumn.CellTemplate>
+                        </GridViewColumn>
+
+                        <GridViewColumn Header="鎻忚堪" HeaderContainerStyle="{StaticResource gvh}"
+                                        HeaderTemplate="{StaticResource gvht}">
+                            <GridViewColumn.CellTemplate>
+                                <DataTemplate>
+                                    <Border Style="{StaticResource CellBorder}">
+                                        <TextBlock Padding="6,0" Text="{Binding Description}"/>
+                                    </Border>
+                                </DataTemplate>
+                            </GridViewColumn.CellTemplate>
+                        </GridViewColumn>
+
+                        <GridViewColumn Header="{DynamicResource se.runMode}" 
+                                        Width="80"
+                                        HeaderContainerStyle="{StaticResource gvh}" 
+                                        HeaderTemplate="{StaticResource gvht}">
+                            <GridViewColumn.CellTemplate>
+                                <DataTemplate>
+                                    <Border Style="{StaticResource CellBorder}" BorderThickness="1,0,1,1">
+                                        <TextBlock Padding="6,0" Text="{Binding RunMode}"/>
+                                    </Border>
+                                </DataTemplate>
+                            </GridViewColumn.CellTemplate>
+                        </GridViewColumn>
+                    </ui:TreeListView.Columns>
+
+                    <TreeView.ItemTemplate>
+                        <HierarchicalDataTemplate ItemsSource="{Binding Children}">
+                            <GridViewRowPresenter
+                                ContextMenu="{StaticResource stepContextMenu}"
+                                          Columns="{Binding Columns, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ui:TreeListView,AncestorLevel=1}}" 
+                                          Content="{Binding }"/>
+                        </HierarchicalDataTemplate>
+                    </TreeView.ItemTemplate>
+                </ui:TreeListView>
 
             </pu:FormGroup>
 
diff --git a/Plugin.SeqEditor/SeqEditor.xaml.cs b/Plugin.SeqEditor/SeqEditor.xaml.cs
index 94f8f87..a6d4213 100644
--- a/Plugin.SeqEditor/SeqEditor.xaml.cs
+++ b/Plugin.SeqEditor/SeqEditor.xaml.cs
@@ -19,7 +19,7 @@
         InitializeComponent();
         CbFilter.ItemsSource = (IEnumerable<MultiComboBoxData>)
             new MultiComboBoxDataConverter().Convert(FilterTypeData.ItemSource,
-            null,null,null
+            null, null, null
             );
     }
 
@@ -66,5 +66,22 @@
     {
         e.Handled = false;
     }
+
+    private void Expander_PreviewMouseDown(object sender, MouseButtonEventArgs e)
+    {
+        e.Handled = false;
+    }
+
+    private void TreeListView_SizeChanged(object sender, SizeChangedEventArgs e)
+    {
+        var treeListView = sender as TreeListView;
+        var columns = treeListView.Columns;
+        var width = treeListView.ActualWidth;
+
+        columns[0].Width = columns[0].Width + (width - columns[0].Width - columns[1].Width - columns[2].Width - columns[3].Width);
+        //foreach (var col in columns) { 
+        //    col.Width = 
+        //}
+    }
 }
 
diff --git a/Plugin.SeqEditor/Util/ItemData.cs b/Plugin.SeqEditor/Util/ItemData.cs
index 3b81e9c..2ca8896 100644
--- a/Plugin.SeqEditor/Util/ItemData.cs
+++ b/Plugin.SeqEditor/Util/ItemData.cs
@@ -50,12 +50,12 @@
         public static readonly ItemData NumValTest =
             new(LangUtil.Get("Numeric Limit Test"), "NumericLimitTest");
 
-        public static readonly ItemData RECS =
+        public static readonly ItemData SequenceCall =
             new(LangUtil.Get("SequenceCall"), "SequenceCall");
 
         public static readonly List<ItemData> ItemSource =
             new List<ItemData> {
-                Wait,Action,StrValTest,//RECS,REIC
+                Wait,Action,StrValTest,NumValTest,//RECS,REIC
             };
     }
 
diff --git a/Plugin.SeqEditor/Util/Step2EPO.cs b/Plugin.SeqEditor/Util/Step2EPO.cs
index 7f3bff8..86f229a 100644
--- a/Plugin.SeqEditor/Util/Step2EPO.cs
+++ b/Plugin.SeqEditor/Util/Step2EPO.cs
@@ -34,10 +34,12 @@
                 case StepTypeStr.NumericLimitTest:
                     epo = new NumValTestEPO(step);
                     return new NumValTestPanel((NumValTestEPO)epo);
-                case StepTypeStr.Action:
-                    return new ActionPanel(step);
+                //case StepTypeStr.Action:
+                //    return new ActionPanel(step);
+                //case StepTypeStr.SequenceCall:
+                //    return new ActionPanel(step);
                 default:
-                    return null;
+                    return new ActionPanel(step);
             }
         }
     }
diff --git a/Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs b/Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs
index b369169..70fcd05 100644
--- a/Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs
+++ b/Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs
@@ -1,5 +1,6 @@
 锘縰sing CommunityToolkit.Mvvm.ComponentModel;
 using CommunityToolkit.Mvvm.Input;
+using GongSolutions.Wpf.DragDrop;
 using HMI.Core.Util;
 using HMI.UI;
 using HMI.UI.Util;
@@ -11,6 +12,11 @@
 using Plugin.SeqEditor.Util;
 using System.Collections.ObjectModel;
 using System.IO;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Input;
+using System.Windows.Media;
 
 namespace Plugin.SeqEditor.ViewModel
 {
@@ -44,8 +50,14 @@
         [ObservableProperty]
         private string targetType = null;
 
-
+        [ObservableProperty]
         private string currentFilePath;
+
+        [ObservableProperty]
+        private bool canDrop = true;
+
+        public IDropTarget StepDropHandler { get; set; }
+
         private Engine engine;
         private SequenceFile sequenceFile;
         private bool isLoaded;
@@ -54,15 +66,8 @@
 
         public List<ItemData> Types = FilterTypeData.ItemSource;
 
-        private HashSet<string> edits = new HashSet<string> {
-            StepTypeStr.PassFailTest,
-            StepTypeStr.NumericLimitTest,
-            StepTypeStr.NI_MultipleNumericLimitTest,
-            StepTypeStr.StringValueTest,
-            StepTypeStr.Action,
-            StepTypeStr.NI_Wait,
-            StepTypeStr.SequenceCall,
-        };
+        private HashSet<string> edits = new HashSet<string>();
+        public Dictionary<Sequence, ObservableCollection<StepUI>> sequenceCache { get; private set; } = new();
 
         public SeqEditorViewModel(SeqEditor control, ILog log)
         {
@@ -70,6 +75,8 @@
             this.control = control;
             engine = new Engine();
             engine.LoadTypePaletteFilesEx();
+            TargetType = string.Empty;
+            StepDropHandler = new TreeListViewHandler(this);
         }
 
         ~SeqEditorViewModel()
@@ -88,6 +95,10 @@
 
         private ObservableCollection<StepUI> LoadSteps(Sequence seq, string group = null)
         {
+            if (sequenceCache.ContainsKey(seq))
+            {
+                return sequenceCache[seq];
+            }
             //setupSteps.Clear();
             //var steps = new ObservableCollection<StepUI>();
             //int num = seq.GetNumSteps(StepGroups.StepGroup_Setup);
@@ -133,46 +144,51 @@
             //CurrentStepUI = null;
 
             var steps = new ObservableCollection<StepUI>();
+            StepGroups[] groups = new StepGroups[] { StepGroups.StepGroup_Setup, StepGroups.StepGroup_Main, StepGroups.StepGroup_Cleanup };
 
-            int num = seq.GetNumSteps(StepGroups.StepGroup_Setup);
-            for (int i = 0; i < num; i++)
+            foreach (var stepGroup in groups)
             {
-                Step step = seq.GetStep(i, StepGroups.StepGroup_Setup);
-                var ui = Convert2StepUI(step, group);
-                if (ui != null)
+                int num = seq.GetNumSteps(stepGroup);
+                for (int i = 0; i < num; i++)
                 {
-                    steps.Add(ui);
+                    Step step = seq.GetStep(i, stepGroup);
+                    var ui = Convert2StepUI(i, step, seq, group);
+                    if (ui != null)
+                    {
+                        steps.Add(ui);
+                    }
                 }
             }
 
-            num = seq.GetNumSteps(StepGroups.StepGroup_Main);
-            for (int i = 0; i < num; i++)
-            {
-                Step step = seq.GetStep(i, StepGroups.StepGroup_Main);
-                var ui = Convert2StepUI(step, group);
-                if (ui != null)
-                {
-                    steps.Add(ui);
-                }
-            }
+            //int num = seq.GetNumSteps(StepGroups.StepGroup_Main);
+            //for (int i = 0; i < num; i++)
+            //{
+            //    Step step = seq.GetStep(i, StepGroups.StepGroup_Main);
+            //    var ui = Convert2StepUI(step, seq, group);
+            //    if (ui != null)
+            //    {
+            //        steps.Add(ui);
+            //    }
+            //}
 
-            num = seq.GetNumSteps(StepGroups.StepGroup_Cleanup);
-            for (int i = 0; i < num; i++)
-            {
-                Step step = seq.GetStep(i, StepGroups.StepGroup_Cleanup);
-                var ui = Convert2StepUI(step, group);
-                if (ui != null)
-                {
-                    steps.Add(ui);
-                }
-            }
+            //num = seq.GetNumSteps(StepGroups.StepGroup_Cleanup);
+            //for (int i = 0; i < num; i++)
+            //{
+            //    Step step = seq.GetStep(i, StepGroups.StepGroup_Cleanup);
+            //    var ui = Convert2StepUI(step, seq, group);
+            //    if (ui != null)
+            //    {
+            //        steps.Add(ui);
+            //    }
+            //}
+            sequenceCache[seq] = steps;
             return steps;
         }
 
-        private StepUI Convert2StepUI(Step step, string group)
+        private StepUI Convert2StepUI(int index, Step step, Sequence sequence, string group)
         {
-            var ui = new StepUI(step);
-            if (!edits.Contains(ui.Type))
+            var ui = new StepUI(step, sequence);
+            if (edits != null && edits.Count > 0 && !edits.Contains(ui.Type))
             {
                 return null;
             }
@@ -202,16 +218,21 @@
             {
                 var po = step.Module.AsPropertyObject();
                 bool useCurFile = po.GetValBoolean("UseCurFile", 0);
-                if (useCurFile)
+                string sfPath = po.GetValString("SFPath", 0);
+                if (useCurFile || Path.GetFileName(currentFilePath).Equals(sfPath, StringComparison.CurrentCultureIgnoreCase))
                 {
                     string seqName = po.GetValString("SeqName", 0);
-                    Sequence sequence = sequenceFile.GetSequenceByName(seqName);
-                    if (sequence == null)
+                    Sequence sunSequence = sequenceFile.GetSequenceByName(seqName);
+                    if (sunSequence == null)
                     {
                         return ui;
                     }
-                    ui.Children = LoadSteps(sequence, group);
+                    ui.Children = LoadSteps(sunSequence, group);
                 }
+            }
+            if (CurrentSeqUI != null)
+            {
+                ui.SettingChanged += CurrentSeqUI.OnStepSettingChanged;
             }
             return ui;
         }
@@ -232,20 +253,19 @@
             {
                 Filter = $"{LangUtil.Get("se.seq")}|*.seq;"
             };
-            if (ofd.ShowDialog() == true)
+            if (ofd.ShowDialog() == true && DoClose())
             {
                 control.BackgroundAction(() =>
                 {
                     try
                     {
                         var start = DateTime.Now;
-                        currentFilePath = ofd.FileName;
-                        CurrentFileName = $"{LangUtil.Get("se.currentFile")}{Path.GetFileName(currentFilePath)}";
+                        CurrentFilePath = ofd.FileName;
                         if (sequenceFile != null)
                         {
                             engine.ReleaseSequenceFileEx(sequenceFile);
                         }
-                        sequenceFile = engine.GetSequenceFileEx(currentFilePath);
+                        sequenceFile = engine.GetSequenceFileEx(CurrentFilePath);
                         Sequence main = sequenceFile.GetSequenceByName("MainSequence");
                         CurrentSeqUI = new SeqUI(main);
 
@@ -257,15 +277,19 @@
                         //}
                         //Sequences = seqs;
 
-                        if (Sequences != null && Sequences.Count > 0)
-                        {
-                            CurrentSeqUI = Sequences[0];
-                        }
-                        log.Info($"Open File [{currentFilePath}] In {(DateTime.Now - start).TotalMilliseconds}ms");
+                        //if (Sequences != null && Sequences.Count > 0)
+                        //{
+                        //    CurrentSeqUI = Sequences[0];
+                        //}
+                        log.Info($"Open File [{CurrentFilePath}] In {(DateTime.Now - start).TotalMilliseconds}ms");
                     }
                     catch (Exception ex)
                     {
-
+                        log.Error($"Open Sequence Failed.", ex);
+                        control.Dispatcher.Invoke(() =>
+                        {
+                            MsgBoxHelper2.Error(ex.Message);
+                        });
                     }
                 }, LangUtil.Get("se.seqIsLoading"));
             }
@@ -274,54 +298,92 @@
         [RelayCommand]
         private void SaveSeqFile()
         {
-            sequenceFile?.Save(currentFilePath);
+            if (sequenceFile == null) return;
+            try
+            {
+                sequenceFile?.Save(CurrentFilePath);
+                CurrentSeqUI.IsChanged = false;
+                ToastHelper.Success(LangUtil.Get("App.SaveSuccess"));
+            }
+            catch (Exception ex)
+            {
+                log.Error("Save Sequence File Error.", ex);
+                ToastHelper.Error($"{LangUtil.Get("App.SaveFailed")}: {ex.Message}");
+            }
+        }
+
+        [RelayCommand]
+        private void SaveToFile()
+        {
+            if (sequenceFile == null) return;
+            try
+            {
+                SaveFileDialog sfd = new SaveFileDialog()
+                {
+                    Filter = $"{LangUtil.Get("se.seq")}|*.seq;"
+                };
+                if (sfd.ShowDialog() == true)
+                {
+                    sequenceFile.Save(sfd.FileName);
+                    CurrentFilePath = sfd.FileName;
+                    ToastHelper.Success(LangUtil.Get("App.SaveSuccess"));
+                    CurrentSeqUI.IsChanged = false;
+                }
+            }
+            catch (Exception ex)
+            {
+                log.Error("Save Sequence File Error.", ex);
+                ToastHelper.Error($"{LangUtil.Get("App.SaveFailed")}: {ex.Message}");
+            }
         }
 
         [RelayCommand]
         private void Refresh()
         {
             if (CurrentSeqUI == null) return;
-            if (string.IsNullOrEmpty(TargetType))
-            {
-                edits = new HashSet<string> {
-                    StepTypeStr.PassFailTest,
-                    StepTypeStr.NumericLimitTest,
-                    StepTypeStr.NI_MultipleNumericLimitTest,
-                    StepTypeStr.StringValueTest,
-                    StepTypeStr.Action,
-                    StepTypeStr.NI_Wait,
-                    StepTypeStr.SequenceCall,
-                };
-            }
-            else
-            {
-                edits = new HashSet<string>(TargetType.Split(','))
-                {
-                    StepTypeStr.SequenceCall
-                };
-            }
-            AllSteps = LoadSteps(CurrentSeqUI.sequence);
+            RefreshData();
         }
 
-        [RelayCommand]
-        private void CloseSeqFile()
+        private bool DoClose()
         {
-            //AllSteps = new ObservableCollection<StepUI>();
+            if (CurrentSeqUI?.IsChanged == true)
+            {
+                if (MsgBoxHelper2.WarnChoose(LangUtil.Get("se.makeSureClose"))
+                    == System.Windows.MessageBoxResult.OK)
+                {
+                    goto DoClose;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+
+        DoClose:
             if (engine != null && sequenceFile != null)
             {
                 engine.ReleaseSequenceFileEx(sequenceFile);
                 sequenceFile = null;
             }
+
             setupSteps.Clear();
             mainSteps.Clear();
             cleanupSteps.Clear();
             AllSteps = new();
             Sequences.Clear();
-            currentFilePath = string.Empty;
+            CurrentFilePath = string.Empty;
             CurrentFileName = string.Empty;
             CurrentSeqUI = null;
             CurrentStepUI = null;
             CurrentSeqTitle = LangUtil.Get("se.steps");
+            sequenceCache.Clear();
+            return true;
+        }
+
+        [RelayCommand]
+        private void CloseSeqFile()
+        {
+            DoClose();
         }
 
         [RelayCommand]
@@ -330,21 +392,22 @@
             try
             {
                 var group = CurrentStepUI.step.StepGroup;
+                var targetSequence = CurrentStepUI.sequence;
 
-                ObservableCollection<StepUI> source;
-                if (group == StepGroups.StepGroup_Setup)
-                {
-                    source = setupSteps;
-                }
-                else if (group == StepGroups.StepGroup_Main)
-                {
-                    source = mainSteps;
-                }
-                else
-                {
-                    source = cleanupSteps;
-                }
-                int index = source.IndexOf(CurrentStepUI);
+                ObservableCollection<StepUI> source = sequenceCache[targetSequence];
+                //if (group == StepGroups.StepGroup_Setup)
+                //{
+                //    source = setupSteps;
+                //}
+                //else if (group == StepGroups.StepGroup_Main)
+                //{
+                //    source = mainSteps;
+                //}
+                //else
+                //{
+                //    source = cleanupSteps;
+                //}
+                int index = CurrentStepUI.IndexInSequence;
                 if (index < 0)
                 {
                     return;
@@ -355,14 +418,6 @@
                     case "Tests.PassFail":
                         newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.PassFailTest);
                         newStep.Name = DefaultStepName.PassFailTest;
-                        var p = newStep.AsPropertyObject();
-                        string name = p.Name;
-                        var ps = p.GetSubProperties("", 0);
-                        foreach (var pp in ps)
-                        {
-                            string sname = pp.Name;
-                        }
-
                         break;
                     case "Tests.NumericLimitTest":
                         newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.NumericLimitTest);
@@ -408,12 +463,37 @@
                         newStep = engine.NewStep(AdapterKeyNames.PythonAdapterKeyName, StepTypeStr.Action);
                         newStep.Name = DefaultStepName.Action;
                         break;
-
                     default:
                         return;
                 }
-                CurrentSeqUI.sequence.InsertStep(newStep, index + 1, group);
-                AllSteps = LoadSteps(CurrentSeqUI.sequence);
+                var newUI = new StepUI(newStep, targetSequence);
+
+                
+                targetSequence.InsertStep(newStep, index + 1, group);
+                ObservableCollection<StepUI> datasource = sequenceCache[targetSequence];
+                int uiIndex = datasource.IndexOf(CurrentStepUI);
+                datasource.Insert(uiIndex + 1, newUI);
+
+
+                //var newItem = new TreeItemData
+                //{
+                //    Level = TreeItemData.Level,
+                //    ParentItem = TreeItemData.ParentItem,
+                //    ParentItems = TreeItemData.ParentItems,
+                //    Data = newUI
+                //};
+                //var parentItem = TreeItemData.ParentItem;
+                //if (parentItem != null)
+                //{
+                //    var items = parentItem.Items;
+                //    int innerIndex = items.IndexOf(TreeItemData);
+
+                    
+                //    items.Insert(innerIndex + 1, newItem);
+                //    TreeItemDataCollection.ResetSubItems(items);
+                //}
+                //int itemIndex = TreeCollection.IndexOf(TreeItemData);
+                //TreeCollection.Insert(itemIndex + TreeItemData.AllSubCount + 1, newItem);
             }
             catch (Exception ex)
             {
@@ -422,12 +502,96 @@
             }
         }
 
+        [RelayCommand]
+        private void Sb(RoutedPropertyChangedEventArgs<object> e)
+        {
+            CurrentStepUI = e.NewValue as StepUI;
+        }
+
+        static TreeListViewItem VisualUpwardSearch(DependencyObject source)
+        {
+            while (source != null && !(source is TreeViewItem))
+                source = VisualTreeHelper.GetParent(source);
+
+            return source as TreeListViewItem;
+        }
+
+        [RelayCommand]
+        private void Sb2(MouseButtonEventArgs e)
+        {
+            var item = VisualUpwardSearch(e.OriginalSource as DependencyObject);
+            if (item != null)
+            {
+                item.Focus();
+                e.Handled = true;
+            }
+        }
+
         [ObservableProperty]
         private TreeItemData treeItemData;
+
+        public void RefreshView()
+        {
+            CollectionViewSource cvs = control.Resources["TreeGridFilter"] as CollectionViewSource;
+            control.Dispatcher.Invoke(() =>
+            {
+                cvs.View.Refresh();
+            });
+        }
+
+        [ObservableProperty]
+        private TreeItemDataCollection treeCollection = new TreeItemDataCollection();
+
+        public void RefreshData()
+        {
+            sequenceCache.Clear();
+            AllSteps = LoadSteps(CurrentSeqUI.sequence);
+        }
+
+        partial void OnAllStepsChanged(ObservableCollection<StepUI> data)
+        {
+            TreeCollection = new TreeItemDataCollection(AllSteps, "Children", true);
+        }
 
         partial void OnTreeItemDataChanged(TreeItemData data)
         {
             CurrentStepUI = data?.Data as StepUI;
+        }
+
+        partial void OnTargetTypeChanged(string value)
+        {
+            if (string.IsNullOrEmpty(value))
+            {
+                edits = new HashSet<string>
+                {
+                    //StepTypeStr.PassFailTest,
+                    //StepTypeStr.NumericLimitTest,
+                    //StepTypeStr.NI_MultipleNumericLimitTest,
+                    //StepTypeStr.StringValueTest,
+                    //StepTypeStr.Action,
+                    //StepTypeStr.NI_Wait,
+                    //StepTypeStr.SequenceCall,
+                };
+            }
+            else
+            {
+                edits = new HashSet<string>(value.Split(MultiComboBox.splits, StringSplitOptions.RemoveEmptyEntries))
+                {
+                    StepTypeStr.SequenceCall
+                };
+            }
+        }
+
+        partial void OnCurrentFilePathChanged(string value)
+        {
+            if (string.IsNullOrEmpty(value))
+            {
+                CurrentFileName = string.Empty;
+            }
+            else
+            {
+                CurrentFileName = $"{LangUtil.Get("se.currentFile")}{Path.GetFileName(value)}";
+            }
         }
 
         partial void OnCurrentStepUIChanged(StepUI stepUI)
@@ -436,7 +600,6 @@
             control.editPanelContainer.Child = panel;
             if (stepUI != null)
             {
-
                 //window.commonP.RefreshStep(stepUI);
             }
         }
@@ -446,7 +609,7 @@
             if (seqUI != null)
             {
                 CurrentStepUI = null;
-                AllSteps = LoadSteps(seqUI.sequence);
+                RefreshData();
             }
             CurrentSeqTitle = $"{seqUI?.Name} {LangUtil.Get("se.steps")}";
         }
diff --git a/Plugin.SeqEditor/ViewModel/StepDropHandler.cs b/Plugin.SeqEditor/ViewModel/StepDropHandler.cs
new file mode 100644
index 0000000..6c39449
--- /dev/null
+++ b/Plugin.SeqEditor/ViewModel/StepDropHandler.cs
@@ -0,0 +1,139 @@
+锘縰sing GongSolutions.Wpf.DragDrop;
+using HMI.UI;
+using NationalInstruments.TestStand.Interop.API;
+using Plugin.SeqEditor.Entity;
+using System.Windows;
+
+namespace Plugin.SeqEditor.ViewModel
+{
+    public class StepDropHandler : DefaultDropHandler
+    {
+        private SeqEditorViewModel model;
+        public StepDropHandler(SeqEditorViewModel model)
+        {
+            this.model = model;
+        }
+
+        public bool CanConvert(IDropInfo dropInfo)
+        {
+            if (!(dropInfo.TargetItem is TreeItemData targetItem))
+            {
+                return false;
+            }
+
+            if (!(targetItem.Data is StepUI target))
+            {
+                return false;
+            }
+
+            if (!(dropInfo.Data is TreeItemData sourceItem))
+            {
+                return false;
+            }
+
+            if (!(sourceItem.Data is StepUI source))
+            {
+                return false;
+            }
+
+            if (targetItem.ParentItem != sourceItem.ParentItem)
+            {
+                return false;
+            }
+
+            if (source == target)
+            {
+                return false;
+            }
+
+            if (source.sequence != target.sequence)
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        public override void DragOver(IDropInfo dropInfo)
+        {
+            if (CanConvert(dropInfo))
+            {
+                dropInfo.Effects = DragDropEffects.Move;
+                dropInfo.DropTargetHintState = DropHintState.Active;
+            }
+            else
+            {
+                dropInfo.DropTargetHintState = DropHintState.None;
+            }
+        }
+
+        public override void Drop(IDropInfo dropInfo)
+        {
+            if (!CanConvert(dropInfo))
+            {
+                return;
+            }
+            var sourceItem = (TreeItemData)dropInfo.Data;
+            var targetItem = (TreeItemData)dropInfo.TargetItem;
+
+            var source = sourceItem.Data as StepUI;
+            var target = targetItem.Data as StepUI;
+            int sourceIndex = source.IndexInSequence;
+            int targetIndex = target.IndexInSequence;
+
+            TreeItemDataCollection collection = model.TreeCollection;
+
+            List<TreeItemData> datasource;
+
+            if (sourceItem.ParentItem == null)
+            {
+                datasource = collection.RootItems;
+            }
+            else
+            {
+                datasource = sourceItem.ParentItem.Items;
+            }
+
+            //ObservableCollection<TreeItemData> datasource =
+            //   (ObservableCollection<TreeItemData>)dropInfo.TargetCollection.TryGetList();
+
+            int uiSourceIndex = collection.IndexOf(sourceItem);
+            int uiTargetIndex = collection.IndexOf(targetItem);
+
+            if (uiSourceIndex == uiTargetIndex + 1)
+            {
+                return;
+            }
+
+            StepGroups group = target.StepGroup;
+            if (sourceIndex == targetIndex) {
+                return;
+            }
+
+            if (sourceIndex < targetIndex)
+            {
+                source.sequence.DeleteStep(sourceIndex, source.StepGroup);
+                target.sequence.InsertStep(source.step, targetIndex, group);
+
+                collection.Move(uiSourceIndex, uiTargetIndex);
+
+                //datasource.RemoveAt(uiSourceIndex);
+                //datasource.Insert(uiTargetIndex, sourceItem);
+            }
+            else if (sourceIndex > targetIndex)
+            {
+                source.sequence.DeleteStep(sourceIndex, source.StepGroup);
+                target.sequence.InsertStep(source.step, targetIndex + 1, group);
+
+                collection.Move(uiSourceIndex, uiTargetIndex);
+            }
+            model.CurrentSeqUI.IsChanged = true;
+            //var task = Task.Run(() =>
+            //{
+            //    collection.ResetItems();
+            //    model.TreeItemData = sourceItem;
+            //});
+            //task.Wait();
+        }
+    }
+}
diff --git a/Plugin.SeqEditor/ViewModel/TreeListViewHandler.cs b/Plugin.SeqEditor/ViewModel/TreeListViewHandler.cs
new file mode 100644
index 0000000..b68f3fc
--- /dev/null
+++ b/Plugin.SeqEditor/ViewModel/TreeListViewHandler.cs
@@ -0,0 +1,119 @@
+锘縰sing GongSolutions.Wpf.DragDrop;
+using NationalInstruments.TestStand.Interop.API;
+using Plugin.SeqEditor.Entity;
+using System.Collections.ObjectModel;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace Plugin.SeqEditor.ViewModel
+{
+    public class TreeListViewHandler : DefaultDropHandler
+    {
+        private SeqEditorViewModel model;
+        public TreeListViewHandler(SeqEditorViewModel model)
+        {
+            this.model = model;
+        }
+
+        public bool CanConvert(IDropInfo dropInfo)
+        {
+            if (!(dropInfo.TargetItem is StepUI target))
+            {
+                return false;
+            }
+
+            if (!(dropInfo.Data is StepUI source))
+            {
+                return false;
+            }
+
+            if (source == target)
+            {
+                return false;
+            }
+
+            if (target.sequence != source.sequence)
+            {
+                return false;
+            }
+            return true;
+        }
+
+        public override void DragOver(IDropInfo dropInfo)
+        {
+            if (CanConvert(dropInfo))
+            {
+                dropInfo.Effects = DragDropEffects.Move;
+
+                if (dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.TargetItemCenter))
+                {
+                    dropInfo.DropTargetAdorner = null;
+                }
+                else
+                {
+                    dropInfo.DropTargetAdorner = DropTargetAdorners.Insert;
+                }
+
+                //if (dropInfo.DropTargetAdorner == DropTargetAdorners.Highlight) { 
+
+                //}
+                //dropInfo.DropTargetAdorner = DropTargetAdorners.Insert;
+                dropInfo.DropTargetHintState = DropHintState.Active;
+                dropInfo.DropTargetHintAdorner = DropTargetAdorners.Hint;
+            }
+            else
+            {
+                dropInfo.Effects = DragDropEffects.None;
+                dropInfo.DropTargetHintAdorner = DropTargetAdorners.Hint;
+                dropInfo.DropTargetHintState = DropHintState.Error;
+            }
+        }
+
+        public override void Drop(IDropInfo dropInfo)
+        {
+            if (!CanConvert(dropInfo))
+            {
+                return;
+            }
+            //var sourceItem = (TreeItemData)dropInfo.Data;
+            //var targetItem = (TreeItemData)dropInfo.TargetItem;
+
+            var source = dropInfo.Data as StepUI;
+            var target = dropInfo.TargetItem as StepUI;
+
+            int sourceIndex = source.IndexInSequence;
+            int targetIndex = target.IndexInSequence;
+
+
+            if (sourceIndex == targetIndex)
+            {
+                return;
+            }
+
+            bool insertBefore = dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.BeforeTargetItem);
+
+            if (!insertBefore && (sourceIndex == targetIndex + 1)) {
+                return;
+            }
+
+            ObservableCollection<StepUI> datasource = model.sequenceCache[source.sequence];
+            int uiSourceIndex = datasource.IndexOf(source);
+            int uiTargetIndex = datasource.IndexOf(target);
+
+            StepGroups group = target.StepGroup;
+
+            if (sourceIndex < targetIndex)
+            {
+                source.sequence.DeleteStep(sourceIndex, source.StepGroup);
+                target.sequence.InsertStep(source.step, targetIndex, group);
+                datasource.Move(uiSourceIndex, uiTargetIndex);
+            }
+            else if (sourceIndex > targetIndex)
+            {
+                source.sequence.DeleteStep(sourceIndex, source.StepGroup);
+                target.sequence.InsertStep(source.step, targetIndex, group);
+                datasource.Move(uiSourceIndex, uiTargetIndex);
+            }
+        }
+    }
+}
diff --git a/Plugin.TestResult/DataTable.xaml b/Plugin.TestResult/DataTable.xaml
index 30ee9be..473cac1 100644
--- a/Plugin.TestResult/DataTable.xaml
+++ b/Plugin.TestResult/DataTable.xaml
@@ -112,10 +112,13 @@
             <Grid.ColumnDefinitions>
                 <ColumnDefinition/>
                 <ColumnDefinition/>
+                <ColumnDefinition/>
             </Grid.ColumnDefinitions>
             <Button Click="ScanWindow_Click" Style="{StaticResource PrimaryButton}"
         Content="{DynamicResource Tr.Scan}"/>
-            <Button Grid.Column="1" Click="SetStationGlobal_Click" Style="{StaticResource SuccessButton}"
+            <Button Grid.Column="1" Click="ClearAllSnr_Click" Style="{StaticResource DangerButton}"
+Content="{DynamicResource Tr.ClearAllSNR}"/>
+            <Button Grid.Column="2" Click="SetStationGlobal_Click" Style="{StaticResource SuccessButton}"
         Content="{DynamicResource App.Start}"/>
         </Grid>
         
diff --git a/Plugin.TestResult/DataTable.xaml.cs b/Plugin.TestResult/DataTable.xaml.cs
index 200341f..54364f4 100644
--- a/Plugin.TestResult/DataTable.xaml.cs
+++ b/Plugin.TestResult/DataTable.xaml.cs
@@ -1,4 +1,5 @@
 锘縰sing HMI.Core.Util;
+using HMI.UI.Util;
 using HMI.Util;
 using Plugin.TestResult;
 using Plugin.TestResult_WPF.Model;
@@ -257,6 +258,7 @@
             dutNo = this.index * this.cellCount + dutNo;
 
             string LookupStr = $"StationState.SN[{dutNo}]";
+            ViewControl.Logger.Info($"PositionCode: [{e.positionCode}], SNR: [{e.snrCode}], LookUpStr: [{LookupStr}]");
 
             parent.engine.Globals.SetValString(LookupStr, 0, snrCode);
             parent.engine.CommitGlobalsToDisk(promptOnSaveConflicts: false);
@@ -369,6 +371,7 @@
         private void TcpServer_NewRequestReceived(TcpSession session, StringRequestInfo requestInfo)
         {
             string msg = requestInfo.Body;
+            ViewControl.Logger.Info($"TCP Data From {session.RemoteEndPoint}: {msg}.");
             string[] datas_10015 = msg.Split(';');
             int cellIndex = int.Parse(datas_10015[1]);
 
@@ -518,5 +521,28 @@
             };
             setting.Open(true, this.title);
         }
+
+        private void ClearAllSnr_Click(object sender, RoutedEventArgs e)
+        {
+            if (MsgBoxHelper.WarnMessage(Window.GetWindow(this), LangUtil.Get("Tr.MakeSureClearAllSNR")) == MessageBoxResult.OK)
+            {
+                try
+                {
+                    for (int i = 0; i < this.cellCount; i++)
+                    {
+                        int dutNo = this.index * this.cellCount + i;
+                        string LookupStr = $"StationState.SN[{dutNo}]";
+                        parent.engine.Globals.SetValString(LookupStr, 0, "");
+                        GetSingleCell(i).SetStatus("waiting");
+                    }
+                    ToastHelper.Success(LangUtil.Get("App.DeleteSuccess"));
+                }
+                catch (Exception ex)
+                {
+                    ViewControl.Logger.Error("ClearAllSnr_Click Error.", ex);
+                    MsgBoxHelper.Error(Window.GetWindow(this), ex.Message);
+                }
+            }
+        }
     }
 }
diff --git a/Plugin.TestResult/TestResultView.xaml.cs b/Plugin.TestResult/TestResultView.xaml.cs
index 5f56462..4f73cfe 100644
--- a/Plugin.TestResult/TestResultView.xaml.cs
+++ b/Plugin.TestResult/TestResultView.xaml.cs
@@ -1,6 +1,5 @@
 锘縰sing HMI.Core.Util;
 using HMI.UI.Util;
-using NationalInstruments.TestStand.Interop.AdapterAPI;
 using NationalInstruments.TestStand.Interop.API;
 using NationalInstruments.TestStand.Interop.UI.Ax;
 using NationalInstruments.TestStand.Utility;
@@ -173,7 +172,6 @@
                 this.testApp.LoginOnStart = false;
                 this.testApp.Start();
                 this.modeSeq = this.engine.GetSequenceFileEx(@"C:\Program Files\National Instruments\TestStand 2020\Components\Models\TestStandModels\ParallelModel.seq");
-
             }
             catch (Exception ex)
             {
diff --git a/Plugin.TsExecution/Plugin.TsExecution.csproj b/Plugin.TsExecution/Plugin.TsExecution.csproj
index 33bec6a..cc21afc 100644
--- a/Plugin.TsExecution/Plugin.TsExecution.csproj
+++ b/Plugin.TsExecution/Plugin.TsExecution.csproj
@@ -136,6 +136,10 @@
     <Reference Include="WindowsFormsIntegration" />
   </ItemGroup>
   <ItemGroup>
+    <Page Include="Scanner.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
     <Page Include="SingleControl.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
@@ -145,6 +149,10 @@
       <SubType>Designer</SubType>
     </Page>
     <Compile Include="Entity\TestStep.cs" />
+    <Compile Include="Scanner.xaml.cs">
+      <DependentUpon>Scanner.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="ScannerManager.cs" />
     <Compile Include="Setting\TsSetting.cs" />
     <Compile Include="SingleControl.xaml.cs">
       <DependentUpon>SingleControl.xaml</DependentUpon>
diff --git a/Plugin.TsExecution/Scanner.xaml b/Plugin.TsExecution/Scanner.xaml
new file mode 100644
index 0000000..cbb817a
--- /dev/null
+++ b/Plugin.TsExecution/Scanner.xaml
@@ -0,0 +1,77 @@
+锘�<pu:WindowX x:Class="Plugin.TsExecution.Scanner"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:Plugin.TsExecution"
+        WindowStartupLocation="CenterScreen"
+        Closing="Window_Closing"
+        FontSize="20"
+        mc:Ignorable="d"
+        Style="{StaticResource ModalWindow}"
+        xmlns:hb="clr-namespace:HMI.Base;assembly=HMI.Base"
+        xmlns:uic="clr-namespace:HMI.UI.Converter;assembly=HMI.UI"
+        xmlns:pw="https://opensource.panuon.com/wpf"
+        xmlns:pu="https://opensource.panuon.com/wpf-ui"
+        xmlns:dp="clr-namespace:HMI.UI.DpUtil;assembly=HMI.UI"
+        xmlns:cc="clr-namespace:HMI.Core;assembly=HMI.Core"
+        InteropOwnersMask="False"
+        SizeToContent="Height"
+        pu:WindowXModalDialog.Buttons="{x:Null}"
+        Title="{Binding title}" Width="600">
+    <Window.Resources>
+        <Style TargetType="Label">
+            <Setter Property="HorizontalAlignment" Value="Right"/>
+            <Setter Property="FontSize" Value="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType=Window}, 
+Converter={StaticResource fc}, ConverterParameter='80,1920'}" />
+        </Style>
+        <Style TargetType="TextBox">
+            <Setter Property="FontSize" Value="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType=Window}, 
+Converter={StaticResource fc}, ConverterParameter='100,1920'}" />
+        </Style>
+        <Style TargetType="Button" BasedOn="{StaticResource PrimaryButton}">
+            <Setter Property="FontSize" Value="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType=Window}, 
+Converter={StaticResource fc}, ConverterParameter='20,1920'}" />
+        </Style>
+    </Window.Resources>
+
+    <Grid Margin="10">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto"/>
+            <RowDefinition Height="Auto"/>
+            <RowDefinition Height="Auto"/>
+        </Grid.RowDefinitions>
+
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition/>
+            <ColumnDefinition/>
+        </Grid.ColumnDefinitions>
+
+        <!--<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" Padding="0"
+               Content="{DynamicResource Tr.PleaseScanSnr}"
+               Margin="0,0,0,20"
+               />-->
+        <GroupBox Grid.Row="1" Header="{DynamicResource Tr.PleaseScanSnr}" Padding="0,0,0,10" Grid.ColumnSpan="2" >
+            <StackPanel>
+                <pu:FormGroup 
+         Header="{DynamicResource Tr.PositionSnr}"
+         dp:FormGroupHelper.IsRequired="True"
+         Style="{StaticResource InputFormGroupStyle}">
+                    <TextBox Style="{StaticResource EditorTextBoxStyle}" x:Name="positionText" TextWrapping="NoWrap"/>
+                </pu:FormGroup>
+
+                <pu:FormGroup 
+         Header="{DynamicResource Tr.ProductSnr}"
+         dp:FormGroupHelper.IsRequired="True" Style="{StaticResource InputFormGroupStyle}">
+                    <TextBox Style="{StaticResource EditorTextBoxStyle}" x:Name="snrText" TextWrapping="NoWrap"/>
+                </pu:FormGroup>
+            </StackPanel>
+
+        </GroupBox>
+
+        <Button Grid.Row="2" Click="Con_Click" Style="{StaticResource PrimaryButton}"
+        Content="{DynamicResource Tr.ContinueScan}"/>
+        <Button Grid.Row="2" Grid.Column="1" Click="Ok_Click" Style="{StaticResource SuccessButton}"
+        Content="{DynamicResource Tr.FinishScan}"/>
+    </Grid>
+</pu:WindowX>
diff --git a/Plugin.TsExecution/Scanner.xaml.cs b/Plugin.TsExecution/Scanner.xaml.cs
new file mode 100644
index 0000000..f2ee750
--- /dev/null
+++ b/Plugin.TsExecution/Scanner.xaml.cs
@@ -0,0 +1,209 @@
+锘縰sing HMI.Core.Util;
+using HMI.UI.Entity;
+using HMI.UI.Util;
+using HMI.Util;
+using Panuon.WPF.UI;
+using System;
+using System.ComponentModel;
+using System.IO.Ports;
+using System.Windows;
+
+namespace Plugin.TsExecution
+{
+    public class BarcodeEventArg
+    {
+        public string name { get; private set; }
+        public string positionCode { get; private set; }
+        public string snrCode { get; private set; }
+
+        public BarcodeEventArg(string name, string positionCode, string snrCode)
+        {
+            this.name = name;
+            this.positionCode = positionCode;
+            this.snrCode = snrCode;
+        }
+    }
+
+    /// <summary>
+    /// Scanner.xaml 鐨勪氦浜掗�昏緫
+    /// </summary>
+    public partial class Scanner : WindowX
+    {
+        private string _title;
+
+        public string title
+        {
+            get { return _title; }
+            set => Set(ref _title, value);
+        }
+
+        public event EventHandler<BarcodeEventArg> FinishBarcode;
+        SerialPort serialPort;
+        public Scanner(string title)
+        {
+            this.title = title;
+            this.DataContext = this;
+            InitializeComponent();
+            Loaded += Scanner_Loaded;
+        }
+
+        private void Scanner_Loaded(object sender, RoutedEventArgs e)
+        {
+            InitScanner();
+            Loaded -= Scanner_Loaded;
+        }
+
+        /// <summary>
+        /// 璁剧疆鎵爜鏋�
+        /// </summary>
+        private void InitScanner()
+        {
+            string comStr = "";
+            if (serialPort != null) return;
+
+            string section = this.Tag.ToString();
+            ScannerConfig common = ScannerConfig.ReadFromIni("", "Config");
+
+            string portName = IniFileHelper.ReadIniData(section, "PortName", "","");
+            if (string.IsNullOrEmpty(portName))
+            {
+                if (section.StartsWith("A"))
+                {
+                    portName = "COM1";
+                }
+                else
+                {
+                    portName = "COM2";
+                }
+            }
+            common.PortName = portName;
+
+
+            // 閰嶇疆涓插彛
+            serialPort = new SerialPort
+            {
+                PortName = common.PortName,
+                BaudRate = common.BaudRate,
+                Parity = Parity.None,
+                DataBits = common.DataBits,
+                StopBits = common.StopBits,
+                Handshake = Handshake.None,
+                DtrEnable = common.DtrEnable,
+                RtsEnable = common.RtsEnable
+                //ReadTimeout = 500,
+                //WriteTimeout = 500,
+                //ReciveBufferSize=4096
+            };
+
+            try
+            {
+                // 鎵撳紑涓插彛
+                serialPort.Open();
+                // 娉ㄥ唽鎺ユ敹鏁版嵁浜嬩欢
+                serialPort.DataReceived += SerialPort_DataReceived;
+            }
+            catch (Exception ex)
+            {
+                MsgBoxHelper.Error(this, $"{this.lang("Tr.InitGunFailed")}: {ex.StackTrace}");
+            }
+        }
+
+        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
+        {
+            try
+            {
+                SerialPort sp = (SerialPort)sender;
+                string barcode = ReadDataFrom(sp);
+
+                //string barcode = 
+                Dispatcher.Invoke(() =>
+                {
+                    if (snrText.IsFocused)
+                    {
+                        snrText.Text = barcode;
+                        Con_Click(null, null);
+                    }
+                    else
+                    {
+                        positionText.Text = barcode;
+                        //positionText.Focus();
+                        //snrText.Text = "";
+                        snrText.Focus();
+                    }
+                });
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show($"{this.lang("Tr.GetGunData")}: {ex.StackTrace}");
+            }
+        }
+
+        private void Con_Click(object sender, RoutedEventArgs e)
+        {
+            Dispatcher.Invoke(() =>
+            {
+                string position = positionText.Text, snr = snrText.Text;
+                if (string.IsNullOrEmpty(position) || string.IsNullOrEmpty(snr))
+                {
+                    ToastHelper.Warning(this, this.lang("Tr.PleaseInputSnrs"));
+                    return;
+                }
+                try
+                {
+                    FinishBarcode.Invoke(this, new BarcodeEventArg(Tag.ToString(), position, snr));
+                    //positionText.Text = "";
+                    //snrText.Text = "";
+                    positionText.Focus();
+                }
+                catch (Exception ex)
+                {
+                    ToastHelper.Warning(this, ex.Message);
+                }
+            });
+        }
+
+        private void Ok_Click(object sender, RoutedEventArgs e)
+        {
+            string position = positionText.Text, snr = snrText.Text;
+            if (string.IsNullOrEmpty(position) || string.IsNullOrEmpty(snr))
+            {
+                ToastHelper.Warning(this, this.lang("Tr.PleaseInputSnrs"));
+                return;
+            }
+            try
+            {
+                FinishBarcode.Invoke(this, new BarcodeEventArg(Tag.ToString(), position, snr));
+                this.Close();
+            }
+            catch (Exception ex)
+            {
+                ToastHelper.Warning(this, ex.Message);
+            }
+        }
+
+        private string ReadDataFrom(SerialPort sp)
+        {
+            string barcode = "";
+            while (sp.BytesToRead > 0)
+            {
+                byte[] buffer = new byte[sp.BytesToRead];
+                sp.Read(buffer, 0, buffer.Length);
+                barcode += System.Text.Encoding.UTF8.GetString(buffer);
+                System.Threading.Thread.Sleep(50);
+            }
+            return barcode;
+        }
+
+        private void Window_Closing(object sender, CancelEventArgs e)
+        {
+            try
+            {
+                serialPort.Close();
+                serialPort = null;
+            }
+            catch (Exception ex)
+            {
+            }
+        }
+    }
+}
diff --git a/Plugin.TsExecution/ScannerManager.cs b/Plugin.TsExecution/ScannerManager.cs
new file mode 100644
index 0000000..00ac8c1
--- /dev/null
+++ b/Plugin.TsExecution/ScannerManager.cs
@@ -0,0 +1,101 @@
+锘縰sing HMI.UI.Entity;
+using System;
+using System.Collections.Generic;
+using System.IO.Ports;
+using System.Windows.Controls;
+
+namespace Plugin.TsExecution
+{
+    public class ScannerManager
+    {
+        public static Dictionary<string, SerialPort> map = new Dictionary<string, SerialPort>();
+        public static Dictionary<SerialPort, Queue<TextBox>> controlMap = new Dictionary<SerialPort, Queue<TextBox>>();
+
+        public static Dictionary<SerialPort, TextBox> focusMap = new Dictionary<SerialPort, TextBox>();
+        public static Dictionary<TextBox, SerialPort> reverseMap = new Dictionary<TextBox, SerialPort>();
+
+
+        public static void RegisterCom(ScannerConfig setting, TextBox tb)
+        {
+            if (!map.ContainsKey(setting.PortName))
+            {
+                // 閰嶇疆涓插彛
+                var serialPort = new SerialPort
+                {
+                    PortName = setting.PortName,
+                    BaudRate = setting.BaudRate,
+                    Parity = Parity.None,
+                    DataBits = setting.DataBits,
+                    StopBits = setting.StopBits,
+                    Handshake = Handshake.None,
+                    DtrEnable = setting.DtrEnable,
+                    RtsEnable = setting.RtsEnable
+                    //ReadTimeout = 500,
+                    //WriteTimeout = 500,
+                    //ReciveBufferSize=4096
+                };
+
+                try
+                {
+                    // 鎵撳紑涓插彛
+                    serialPort.Open();
+                    map[setting.PortName] = serialPort;
+                    controlMap[serialPort] = new Queue<TextBox>();
+                    reverseMap[tb] = serialPort;
+                    tb.GotFocus += Tb_GotFocus;
+                    controlMap[serialPort].Enqueue(tb);
+
+                    // 娉ㄥ唽鎺ユ敹鏁版嵁浜嬩欢
+                    serialPort.DataReceived += SerialPort_DataReceived; ;
+                }
+                catch (Exception ex)
+                {
+
+                }
+            }
+            else { 
+                
+            }
+        }
+
+        private static string ReadDataFrom(SerialPort sp)
+        {
+            string barcode = "";
+            while (sp.BytesToRead > 0)
+            {
+                byte[] buffer = new byte[sp.BytesToRead];
+                sp.Read(buffer, 0, buffer.Length);
+                barcode += System.Text.Encoding.UTF8.GetString(buffer);
+                System.Threading.Thread.Sleep(50);
+            }
+            return barcode;
+        }
+
+        private static void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
+        {
+            var sp = sender as SerialPort;
+            string barcode = ReadDataFrom(sp);
+            TextBox tb;
+            if (focusMap.ContainsKey(sp))
+            {
+                tb = focusMap[sp];
+            }
+            else
+            {
+                tb = controlMap[sp].Dequeue();
+            }
+            //string barcode = 
+            tb.Dispatcher.Invoke(() =>
+                {
+                    tb.Text = barcode;
+                });
+        }
+
+        private static void Tb_GotFocus(object sender, System.Windows.RoutedEventArgs e)
+        {
+            var tb = sender as TextBox;
+            SerialPort sp = reverseMap[tb];
+            focusMap[sp] = tb;
+        }
+    }
+}
diff --git a/Plugin.TsExecution/SingleControl.xaml b/Plugin.TsExecution/SingleControl.xaml
index 5cfe37e..6d87ceb 100644
--- a/Plugin.TsExecution/SingleControl.xaml
+++ b/Plugin.TsExecution/SingleControl.xaml
@@ -16,23 +16,28 @@
              x:Name="control"
              d:DesignHeight="450" d:DesignWidth="800">
     <UserControl.Resources>
-        <sys:Double x:Key="nanD">NaN</sys:Double>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/HMI.UI;component/Style/PanuonDataGrid.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+            <sys:Double x:Key="nanD">NaN</sys:Double>
 
-        <Style TargetType="Label" x:Key="baseLabel">
-            <Setter Property="HorizontalContentAlignment" Value="Left"/>
-            <Setter Property="VerticalContentAlignment" Value="Center"/>
-            <Setter Property="Padding" Value="5"/>
-            <Setter Property="FontSize" Value="{Binding ActualWidth,ElementName=control,
+            <Style TargetType="Label" x:Key="baseLabel">
+                <Setter Property="HorizontalContentAlignment" Value="Left"/>
+                <Setter Property="VerticalContentAlignment" Value="Center"/>
+                <Setter Property="Padding" Value="5"/>
+                <Setter Property="FontSize" Value="{Binding ActualWidth,ElementName=control,
 Converter={StaticResource fc}, ConverterParameter='20,1093,20'}"/>
-        </Style>
-        <Style TargetType="TextBlock" x:Key="baseText">
-            <Setter Property="HorizontalAlignment" Value="Left"/>
-            <Setter Property="VerticalAlignment" Value="Center"/>
-            <Setter Property="Padding" Value="0,0,2,0"/>
-            <Setter Property="FontSize" Value="{Binding ActualWidth,ElementName=control,
+            </Style>
+            <Style TargetType="TextBlock" x:Key="baseText">
+                <Setter Property="HorizontalAlignment" Value="Left"/>
+                <Setter Property="VerticalAlignment" Value="Center"/>
+                <Setter Property="Padding" Value="0,0,2,0"/>
+                <Setter Property="FontSize" Value="{Binding ActualWidth,ElementName=control,
 Converter={StaticResource fc}, ConverterParameter='20,1093,20'}"/>
-        </Style>
-        <Brush x:Key="passedColor">#beed00</Brush>
+            </Style>
+            <Brush x:Key="passedColor">#beed00</Brush>
+        </ResourceDictionary>
     </UserControl.Resources>
 
     <Grid>
@@ -312,6 +317,19 @@
                     <Label Padding="0" FontSize="12" VerticalContentAlignment="Center" Content="{Binding CurrentStep}"/>
 
                     <StackPanel DockPanel.Dock="Right" Orientation="Horizontal" Margin="0,0,5,0">
+                        <!--<Button FontSize="12" x:Name="scannerSetting" 
+                                Margin="0,0,10,0" Click="Button_Click" Content="鎵爜鏋缃�">
+                            <Button.Style>
+                                <Style TargetType="Button" BasedOn="{StaticResource LinkButton}">
+                                    <Style.Triggers>
+                                        <DataTrigger Binding="{Binding IsAutoMode}" Value="True">
+                                            <Setter Property="Visibility" Value="Collapsed"/>
+                                        </DataTrigger>
+                                    </Style.Triggers>
+                                </Style>
+                            </Button.Style>
+                        </Button>-->
+
                         <Label Padding="0" FontSize="12" 
 VerticalAlignment="Center"
 VerticalContentAlignment="Center" Content="{DynamicResource Ts.ProbeCount}"/>
@@ -381,6 +399,44 @@
             </Border>
         </Canvas>
 
+        <Canvas Grid.Row="0" Grid.RowSpan="5" Visibility="Collapsed"
+        Background="#AAFFFFFF" x:Name="scannerPanel" SizeChanged="pausePanel_Loaded">
+            <Border BorderBrush="#000" Background="#FFF" BorderThickness="0.5" CornerRadius="5" x:Name="scannerVisualModal">
+                <Grid>
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="Auto"/>
+                        <RowDefinition Height="Auto"/>
+                        <RowDefinition Height="Auto"/>
+                    </Grid.RowDefinitions>
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="Auto"/>
+                        <ColumnDefinition />
+                    </Grid.ColumnDefinitions>
+                    <Border Padding="10,5,0,5" Grid.ColumnSpan="2" Background="{StaticResource PrimaryColor}"
+                   CornerRadius="5,5,0,0">
+                        <Label Padding="0" Margin="0" Foreground="#FFF" Content="璇锋壂鐮�"/>
+                    </Border>
+
+                    <pu:FormGroup Margin="20,20,20,0" Grid.Row="1" Grid.ColumnSpan="2"
+                       FontSize="{Binding ActualWidth,ElementName=control,
+Converter={StaticResource fc}, ConverterParameter='20,1093,20'}" Orientation="Horizontal" Header="SNR">
+                        <TextBox Width="{Binding ActualWidth,ElementName=control,
+Converter={StaticResource fc}, ConverterParameter='180,1093'}" 
+                                 FontSize="{Binding ActualWidth,ElementName=control,
+Converter={StaticResource fc}, ConverterParameter='15,1093,15'}"
+                                 x:Name="TbManualSnr" Style="{StaticResource EditorTextBoxStyle}"/>
+                    </pu:FormGroup>
+                    <StackPanel Margin="10" Grid.Row="2" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Right">
+                        <Button Style="{StaticResource ModalButton}" 
+                        x:Name="scannerOkBtn"
+                        Click="Button_Click"
+                        Background="{DynamicResource PrimaryColor}"
+                        Tag="OK" Content="{DynamicResource App.Continue}"/>
+                    </StackPanel>
+                </Grid>
+            </Border>
+        </Canvas>
+
 
         <!--<DockPanel Grid.Row="4">
             <StatusBar>
diff --git a/Plugin.TsExecution/SingleControl.xaml.cs b/Plugin.TsExecution/SingleControl.xaml.cs
index c82ecb6..33afb58 100644
--- a/Plugin.TsExecution/SingleControl.xaml.cs
+++ b/Plugin.TsExecution/SingleControl.xaml.cs
@@ -1,4 +1,7 @@
-锘縰sing HMI.Core.Util;
+锘縰sing HMI.Core.Manager;
+using HMI.Core.Util;
+using HMI.UI;
+using HMI.UI.Util;
 using HMI.Util;
 using NationalInstruments.TestStand.Interop.API;
 using Plugin.TsExecution.Entity;
@@ -7,6 +10,7 @@
 using System.ComponentModel;
 using System.IO;
 using System.Runtime.CompilerServices;
+using System.Threading;
 using System.Timers;
 using System.Windows;
 using System.Windows.Controls;
@@ -58,15 +62,15 @@
             }
         }
 
-        private double passNum;
-        public double PassNum
+        private int passNum;
+        public int PassNum
         {
             get => passNum;
             private set { Set(ref passNum, value); }
         }
 
-        private double failNum;
-        public double FailNum
+        private int failNum;
+        public int FailNum
         {
             get => failNum;
             private set { Set(ref failNum, value); }
@@ -135,7 +139,7 @@
         private DateTime TimeNow = new DateTime();
         private TimeSpan TimeCount = new TimeSpan();
 
-        private Timer refreshTimer;
+        private System.Timers.Timer refreshTimer;
 
         private string currentStep = "绛夊緟鎵爜";
         public string CurrentStep
@@ -198,6 +202,16 @@
 
         public int ProbeWarn { get; private set; }
 
+        private bool isAutoMode;
+        public bool IsAutoMode
+        {
+            get => isAutoMode;
+            set
+            {
+                Set(ref isAutoMode, value);
+            }
+        }
+
         public SingleControl(int Index, string CountIniPath, int probeWarn)
         {
             this.CountIniPath = CountIniPath;
@@ -205,7 +219,7 @@
             this.index = Index;
             ProbeWarn = probeWarn;
 
-            refreshTimer = new Timer()
+            refreshTimer = new System.Timers.Timer()
             {
                 Interval = 100
             };
@@ -213,6 +227,15 @@
             ReadProbeCount();
             ReadCounter();
             InitializeComponent();
+            try
+            {
+                var value = ParameterManager.GetCommonParameterByName("AutoTestMode");
+                IsAutoMode = bool.Parse(value.Value);
+            }
+            catch
+            {
+                IsAutoMode = true;
+            }
             //if (ProbeWarn > 0)
             //{
             //    probeWarnPanel.Visibility = Visibility.Visible;
@@ -328,16 +351,20 @@
             if (result == true)
             {
                 PassNum += 1;
+                //Interlocked.Increment(ref passNum);
+                //Set("PassNum");
             }
             else if (result == false)
             {
                 FailNum += 1;
+                //Interlocked.Increment(ref failNum);
+                //Set("FailNum");
             }
 
             TotalNum = PassNum + FailNum;
             if (TotalNum != 0)
             {
-                PassRate = (PassNum / TotalNum);
+                PassRate = ((double)PassNum / TotalNum);
             }
             else
             {
@@ -462,17 +489,57 @@
                     SequenceFileContext?.StationGlobals.SetValBoolean($"StationState.IsContinue_{index}", 1, true);
                     pausePanel.Visibility = Visibility.Collapsed;
                     break;
+                case "scannerSetting":
+                    //ScannerSetting setting = new ScannerSetting()
+                    //{
+                    //    Owner = Window.GetWindow(this)
+                    //};
+                    //setting.Open(true, $"Socket{index}", CountIniPath);
+                    ShowScannerPanel();
+                    break;
+                case "scannerOkBtn":
+                    SendSnr2Ts();
+                    break;
                 default:
                     break;
+            }
+        }
+        public void ShowScannerPanel()
+        {
+            scannerPanel.Visibility = Visibility.Visible;
+        }
+
+        private void SendSnr2Ts()
+        {
+            try
+            {
+                string snr = TbManualSnr.Text;
+                SequenceFileContext?.StationGlobals.SetValString($"StationState.SN[{index}]", 1, snr);
+                scannerPanel.Visibility = Visibility.Collapsed;
+                TbManualSnr.Text = string.Empty;
+            }
+            catch (Exception ex)
+            {
+                ToastHelper.Error(ex.Message);
             }
         }
 
         private void pausePanel_Loaded(object sender, RoutedEventArgs e)
         {
-            var can = pausePanel;
-            var modal = visualModal;
-            Canvas.SetLeft(modal, (pausePanel.ActualWidth - visualModal.ActualWidth) / 2);
-            Canvas.SetTop(modal, (pausePanel.ActualHeight - visualModal.ActualHeight) / 2);
+            if (sender == pausePanel)
+            {
+                var can = pausePanel;
+                var modal = visualModal;
+                Canvas.SetLeft(modal, (pausePanel.ActualWidth - visualModal.ActualWidth) / 2);
+                Canvas.SetTop(modal, (pausePanel.ActualHeight - visualModal.ActualHeight) / 2);
+            }
+            else
+            {
+                var can = scannerPanel;
+                var modal = scannerVisualModal;
+                Canvas.SetLeft(modal, (scannerPanel.ActualWidth - scannerVisualModal.ActualWidth) / 2);
+                Canvas.SetTop(modal, (scannerPanel.ActualHeight - scannerVisualModal.ActualHeight) / 2);
+            }
         }
     }
 }
diff --git a/Plugin.TsExecution/TsExecution.xaml.cs b/Plugin.TsExecution/TsExecution.xaml.cs
index 528df03..89c3ac3 100644
--- a/Plugin.TsExecution/TsExecution.xaml.cs
+++ b/Plugin.TsExecution/TsExecution.xaml.cs
@@ -18,12 +18,10 @@
 using System.ComponentModel;
 using System.IO;
 using System.Linq;
-using System.Reflection;
 using System.Timers;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Forms.DataVisualization.Charting;
-using System.Xml.Linq;
 
 namespace Plugin.TsExecution
 {
diff --git a/SimpleUtil/HMI.LogUtil/HMI.LogUtil.csproj b/SimpleUtil/HMI.LogUtil/HMI.LogUtil.csproj
index 7f76962..3407e37 100644
--- a/SimpleUtil/HMI.LogUtil/HMI.LogUtil.csproj
+++ b/SimpleUtil/HMI.LogUtil/HMI.LogUtil.csproj
@@ -30,6 +30,24 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.Core" />
diff --git a/SimpleUtil/HMI.Util.Base/HMI.Util.Base.csproj b/SimpleUtil/HMI.Util.Base/HMI.Util.Base.csproj
index eeaf7ca..4404d58 100644
--- a/SimpleUtil/HMI.Util.Base/HMI.Util.Base.csproj
+++ b/SimpleUtil/HMI.Util.Base/HMI.Util.Base.csproj
@@ -30,6 +30,24 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.Core" />
diff --git a/VisionBuilder.Run/VisionBuilder.Run.csproj b/VisionBuilder.Run/VisionBuilder.Run.csproj
index 023d44e..454f928 100644
--- a/VisionBuilder.Run/VisionBuilder.Run.csproj
+++ b/VisionBuilder.Run/VisionBuilder.Run.csproj
@@ -31,6 +31,24 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.Data" />
diff --git a/WPFProject/App.xaml b/WPFProject/App.xaml
index 0368538..e68ae7c 100644
--- a/WPFProject/App.xaml
+++ b/WPFProject/App.xaml
@@ -7,6 +7,7 @@
              xmlns:uic="clr-namespace:HMI.UI.Converter;assembly=HMI.UI"
              xmlns:hc="clr-namespace:HMI.Core;assembly=HMI.Core"
              ShutdownMode="OnExplicitShutdown"
+             xmlns:sys="clr-namespace:System;assembly=mscorlib"
              Startup="Application_Startup">
     <Application.Resources>
         <ResourceDictionary>
@@ -18,6 +19,7 @@
                 <ResourceDictionary Source="/HMI.UI;component/Style/PanuonResource.xaml"/>
                 <ResourceDictionary Source="/HMI.UI;component/Style/MsgBoxStyle.xaml"/>
             </ResourceDictionary.MergedDictionaries>
+            <sys:Double x:Key="nanD">NaN</sys:Double>
             <Style TargetType="{x:Type pu:FormGroup}" BasedOn="{StaticResource InputFormGroupStyle}"></Style>
             <uic:PathImageConverter x:Key="path2Image"/>
             <uic:DataGridRowNumberConverter x:Key="rowNumber"/>
diff --git a/WPFProject/Lang/en-US/SeqEditor.json b/WPFProject/Lang/en-US/SeqEditor.json
index e2643bf..730b66a 100644
--- a/WPFProject/Lang/en-US/SeqEditor.json
+++ b/WPFProject/Lang/en-US/SeqEditor.json
@@ -24,6 +24,7 @@
   "se.seqIsLoading": "Sequence is loading",
   "se.compType": "Comparison Type",
   "se.targetVal": "Target Val",
+  "se.makeSureClose": "Current sequence is not saved锛宮ake sure you want to close.",
 
   "se.data.none": "None",
   "se.strComp.SCCS": "String Comparsion - Case Sensitive",
diff --git a/WPFProject/Lang/en-US/TestResult.json b/WPFProject/Lang/en-US/TestResult.json
index e1b6a67..fa126a2 100644
--- a/WPFProject/Lang/en-US/TestResult.json
+++ b/WPFProject/Lang/en-US/TestResult.json
@@ -36,5 +36,7 @@
   "Tr.DtrEnable": "DtrEnable",
   "Tr.RtsEnable": "RtsEnable",
   "Tr.CommonSetting": "Common Setting",
-  "Tr.ScannerSetting": " Scanner Setting"
+  "Tr.ScannerSetting": " Scanner Setting",
+  "Tr.ClearAllSNR": "Clear All SNR",
+  "Tr.MakeSureClearAllSNR": "Are you sure you want to clear all SNR?"
 }
\ No newline at end of file
diff --git a/WPFProject/Lang/zh-CN/SeqEditor.json b/WPFProject/Lang/zh-CN/SeqEditor.json
index 018e449..2dc442f 100644
--- a/WPFProject/Lang/zh-CN/SeqEditor.json
+++ b/WPFProject/Lang/zh-CN/SeqEditor.json
@@ -24,6 +24,7 @@
   "se.seqIsLoading": "姝e湪鍔犺浇娴嬭瘯搴忓垪",
   "se.compType": "姣旇緝鏂瑰紡",
   "se.targetVal": "鏈熸湜鍊�",
+  "se.makeSureClose": "褰撳墠鏂囦欢鏈繚瀛橈紝纭瑕佸叧闂悧锛�",
 
   "se.data.none": "鏃�",
   "se.strComp.SCCS": "姣旇緝瀛楃涓�-澶у皬鍐欐晱鎰�",
diff --git a/WPFProject/Lang/zh-CN/TestResult.json b/WPFProject/Lang/zh-CN/TestResult.json
index b0046eb..6dd00fd 100644
--- a/WPFProject/Lang/zh-CN/TestResult.json
+++ b/WPFProject/Lang/zh-CN/TestResult.json
@@ -36,5 +36,7 @@
   "Tr.DtrEnable": "鍚敤DTR",
   "Tr.RtsEnable": "鍚敤RTS",
   "Tr.CommonSetting": "閫氱敤璁剧疆",
-  "Tr.ScannerSetting": "鎵爜鏋缃�"
+  "Tr.ScannerSetting": "鎵爜鏋缃�",
+  "Tr.ClearAllSNR": "娓呯┖鏉$爜",
+  "Tr.MakeSureClearAllSNR": "纭畾瑕佹竻绌烘潯鐮佸悧锛�"
 }
\ No newline at end of file
diff --git a/WPFProject/WPFProject.sln b/WPFProject/WPFProject.sln
index ded9cb2..1e074b0 100644
--- a/WPFProject/WPFProject.sln
+++ b/WPFProject/WPFProject.sln
@@ -123,8 +123,8 @@
 		{DE4205C6-5923-46FD-A4B9-65169BF61C75}.Release|x64.Build.0 = Release|Any CPU
 		{7C299AED-88CC-437E-A68B-1550AA72E6B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{7C299AED-88CC-437E-A68B-1550AA72E6B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{7C299AED-88CC-437E-A68B-1550AA72E6B0}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{7C299AED-88CC-437E-A68B-1550AA72E6B0}.Debug|x64.Build.0 = Debug|Any CPU
+		{7C299AED-88CC-437E-A68B-1550AA72E6B0}.Debug|x64.ActiveCfg = Debug|x64
+		{7C299AED-88CC-437E-A68B-1550AA72E6B0}.Debug|x64.Build.0 = Debug|x64
 		{7C299AED-88CC-437E-A68B-1550AA72E6B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{7C299AED-88CC-437E-A68B-1550AA72E6B0}.Release|Any CPU.Build.0 = Release|Any CPU
 		{7C299AED-88CC-437E-A68B-1550AA72E6B0}.Release|x64.ActiveCfg = Release|Any CPU
@@ -235,16 +235,16 @@
 		{306A83DC-A7DB-4057-BAA7-477D8756F5D9}.Release|x64.Build.0 = Release|Any CPU
 		{D0806FA6-3F6D-4304-81B8-EAD9DA7CB5B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{D0806FA6-3F6D-4304-81B8-EAD9DA7CB5B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{D0806FA6-3F6D-4304-81B8-EAD9DA7CB5B2}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{D0806FA6-3F6D-4304-81B8-EAD9DA7CB5B2}.Debug|x64.Build.0 = Debug|Any CPU
+		{D0806FA6-3F6D-4304-81B8-EAD9DA7CB5B2}.Debug|x64.ActiveCfg = Debug|x64
+		{D0806FA6-3F6D-4304-81B8-EAD9DA7CB5B2}.Debug|x64.Build.0 = Debug|x64
 		{D0806FA6-3F6D-4304-81B8-EAD9DA7CB5B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{D0806FA6-3F6D-4304-81B8-EAD9DA7CB5B2}.Release|Any CPU.Build.0 = Release|Any CPU
 		{D0806FA6-3F6D-4304-81B8-EAD9DA7CB5B2}.Release|x64.ActiveCfg = Release|Any CPU
 		{D0806FA6-3F6D-4304-81B8-EAD9DA7CB5B2}.Release|x64.Build.0 = Release|Any CPU
 		{E5740BB5-9FC6-4A20-B7C2-CC90C281ED05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{E5740BB5-9FC6-4A20-B7C2-CC90C281ED05}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{E5740BB5-9FC6-4A20-B7C2-CC90C281ED05}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{E5740BB5-9FC6-4A20-B7C2-CC90C281ED05}.Debug|x64.Build.0 = Debug|Any CPU
+		{E5740BB5-9FC6-4A20-B7C2-CC90C281ED05}.Debug|x64.ActiveCfg = Debug|x64
+		{E5740BB5-9FC6-4A20-B7C2-CC90C281ED05}.Debug|x64.Build.0 = Debug|x64
 		{E5740BB5-9FC6-4A20-B7C2-CC90C281ED05}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{E5740BB5-9FC6-4A20-B7C2-CC90C281ED05}.Release|Any CPU.Build.0 = Release|Any CPU
 		{E5740BB5-9FC6-4A20-B7C2-CC90C281ED05}.Release|x64.ActiveCfg = Release|Any CPU
@@ -259,8 +259,8 @@
 		{30201EC1-9A82-48DB-94B9-BD5C1190228B}.Release|x64.Build.0 = Release|Any CPU
 		{BE42AB26-3270-43E1-84B8-6929D862FF8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{BE42AB26-3270-43E1-84B8-6929D862FF8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{BE42AB26-3270-43E1-84B8-6929D862FF8D}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{BE42AB26-3270-43E1-84B8-6929D862FF8D}.Debug|x64.Build.0 = Debug|Any CPU
+		{BE42AB26-3270-43E1-84B8-6929D862FF8D}.Debug|x64.ActiveCfg = Debug|x64
+		{BE42AB26-3270-43E1-84B8-6929D862FF8D}.Debug|x64.Build.0 = Debug|x64
 		{BE42AB26-3270-43E1-84B8-6929D862FF8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{BE42AB26-3270-43E1-84B8-6929D862FF8D}.Release|Any CPU.Build.0 = Release|Any CPU
 		{BE42AB26-3270-43E1-84B8-6929D862FF8D}.Release|x64.ActiveCfg = Release|Any CPU
@@ -283,24 +283,24 @@
 		{6735FDB8-B471-41C3-93CB-E8ADBD0989F0}.Release|x64.Build.0 = Release|Any CPU
 		{6D0AAB08-0F3E-48CE-B755-9D29BC8F1225}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{6D0AAB08-0F3E-48CE-B755-9D29BC8F1225}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6D0AAB08-0F3E-48CE-B755-9D29BC8F1225}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{6D0AAB08-0F3E-48CE-B755-9D29BC8F1225}.Debug|x64.Build.0 = Debug|Any CPU
+		{6D0AAB08-0F3E-48CE-B755-9D29BC8F1225}.Debug|x64.ActiveCfg = Debug|x64
+		{6D0AAB08-0F3E-48CE-B755-9D29BC8F1225}.Debug|x64.Build.0 = Debug|x64
 		{6D0AAB08-0F3E-48CE-B755-9D29BC8F1225}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{6D0AAB08-0F3E-48CE-B755-9D29BC8F1225}.Release|Any CPU.Build.0 = Release|Any CPU
 		{6D0AAB08-0F3E-48CE-B755-9D29BC8F1225}.Release|x64.ActiveCfg = Release|Any CPU
 		{6D0AAB08-0F3E-48CE-B755-9D29BC8F1225}.Release|x64.Build.0 = Release|Any CPU
 		{D59E25D1-9B27-46A1-8438-92661DD23FAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{D59E25D1-9B27-46A1-8438-92661DD23FAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{D59E25D1-9B27-46A1-8438-92661DD23FAE}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{D59E25D1-9B27-46A1-8438-92661DD23FAE}.Debug|x64.Build.0 = Debug|Any CPU
+		{D59E25D1-9B27-46A1-8438-92661DD23FAE}.Debug|x64.ActiveCfg = Debug|x64
+		{D59E25D1-9B27-46A1-8438-92661DD23FAE}.Debug|x64.Build.0 = Debug|x64
 		{D59E25D1-9B27-46A1-8438-92661DD23FAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{D59E25D1-9B27-46A1-8438-92661DD23FAE}.Release|Any CPU.Build.0 = Release|Any CPU
 		{D59E25D1-9B27-46A1-8438-92661DD23FAE}.Release|x64.ActiveCfg = Release|Any CPU
 		{D59E25D1-9B27-46A1-8438-92661DD23FAE}.Release|x64.Build.0 = Release|Any CPU
 		{968FE602-22D6-42BD-981C-601AD518A896}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{968FE602-22D6-42BD-981C-601AD518A896}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{968FE602-22D6-42BD-981C-601AD518A896}.Debug|x64.ActiveCfg = Debug|Any CPU
-		{968FE602-22D6-42BD-981C-601AD518A896}.Debug|x64.Build.0 = Debug|Any CPU
+		{968FE602-22D6-42BD-981C-601AD518A896}.Debug|x64.ActiveCfg = Debug|x64
+		{968FE602-22D6-42BD-981C-601AD518A896}.Debug|x64.Build.0 = Debug|x64
 		{968FE602-22D6-42BD-981C-601AD518A896}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{968FE602-22D6-42BD-981C-601AD518A896}.Release|Any CPU.Build.0 = Release|Any CPU
 		{968FE602-22D6-42BD-981C-601AD518A896}.Release|x64.ActiveCfg = Release|Any CPU
@@ -311,8 +311,8 @@
 		{717FD815-FF95-4F30-B4D9-9CEA978CA40E}.Debug|x64.Build.0 = Debug|x64
 		{717FD815-FF95-4F30-B4D9-9CEA978CA40E}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{717FD815-FF95-4F30-B4D9-9CEA978CA40E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{717FD815-FF95-4F30-B4D9-9CEA978CA40E}.Release|x64.ActiveCfg = Release|Any CPU
-		{717FD815-FF95-4F30-B4D9-9CEA978CA40E}.Release|x64.Build.0 = Release|Any CPU
+		{717FD815-FF95-4F30-B4D9-9CEA978CA40E}.Release|x64.ActiveCfg = Release|x64
+		{717FD815-FF95-4F30-B4D9-9CEA978CA40E}.Release|x64.Build.0 = Release|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

--
Gitblit v1.9.1