Parcourir la source

合并代码 使track数据的模拟、解析与真实通讯数据一致

zhouhr il y a 1 an
Parent
commit
1b4b48cc7b

+ 599 - 2
Venus/Venus_MainPages/ViewModels/WaferHistoryDBViewModel.cs

@@ -1,17 +1,614 @@
 using Prism.Mvvm;
 using System;
+using Prism.Commands;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Venus_MainPages.Views;
+using MECF.Framework.Common.CommonData;
+using System.Collections.ObjectModel;
+using Xceed.Wpf.Toolkit.Primitives;
+using Venus_MainPages.Unity;
+using System.Windows;
+using MECF.Framework.Common.DataCenter;
+using System.Data;
+using System.ComponentModel;
+using OpenSEMI.Ctrlib.Controls;
+using Venus_Core;
+using RecipeStep = MECF.Framework.Common.CommonData.RecipeStep;
 
 namespace Venus_MainPages.ViewModels
 {
-    internal class WaferHistoryDBViewModel:BindableBase
+    public class WaferHistoryDBViewModel:BindableBase
     {
+        private ObservableCollection<WaferHistoryMovement> _movements = new ObservableCollection<WaferHistoryMovement>();
+        public ObservableCollection<WaferHistoryMovement> Movements
+        {
+            get { return _movements; }
+            set { SetProperty(ref _movements, value); }
+        }
+        private WaferHistoryItem _selectedItem;
+        public WaferHistoryItem SelectedItem
+        {
+            get { return _selectedItem; }
+            set { SetProperty(ref _selectedItem, value); }
+        }
+        private DateTime _searchBeginTime;
+        public DateTime SearchBeginTime
+        {
+            get { return _searchBeginTime; }
+            set { SetProperty(ref _searchBeginTime, value); }
+        }
+        private ObservableCollection<WaferHistoryLot> _lots = new ObservableCollection<WaferHistoryLot>();
+        public ObservableCollection<WaferHistoryLot> Lots
+        {
+            get { return _lots; }
+            set { SetProperty(ref _lots, value); }
+        }
+        public ObservableCollection<WaferHistoryRecipe> _recipes = new ObservableCollection<WaferHistoryRecipe>();
+        public ObservableCollection<WaferHistoryRecipe> Recipes
+        {
+            get { return _recipes; }
+            set { SetProperty(ref _recipes, value); }
+        }
+        private WaferHistoryRecipe _recipe;
+        public WaferHistoryRecipe Recipe
+        {
+            get { return _recipe; }
+            set { SetProperty(ref _recipe, value); }
+        }
+        private ObservableCollection<LazyTreeItem<WaferHistoryItem>> _historyData;
+        public ObservableCollection<LazyTreeItem<WaferHistoryItem>> HistoryData
+        {
+            get { return _historyData; }
+            set { SetProperty(ref _historyData, value); }
+        }
+        private ObservableCollection<WaferHistoryWafer> _wafers = new ObservableCollection<WaferHistoryWafer>();
+        public ObservableCollection<WaferHistoryWafer> Wafers
+        {
+            get { return _wafers; }
+            set { SetProperty(ref _wafers, value); }
+        }
+        private DateTime _searchEndTime;
+        public DateTime SearchEndTime
+        {
+            get { return _searchEndTime; }
+            set { SetProperty(ref _searchEndTime, value); }
+        }
+        private string keyWord;
+        public string KeyWord
+        {
+            get { return keyWord; }
+            set { SetProperty(ref keyWord, value); }
+        }
+        private WaferHistoryDBView view;
+        public DateTime StartDateTime { get; set; }
+        public DateTime EndDateTime { get; set; }
+
+        private DelegateCommand<object> _QueryCommand;
+        public DelegateCommand<object> QueryCommand =>
+            _QueryCommand ?? (_QueryCommand = new DelegateCommand<object>(QueryLots));
+
+        private DelegateCommand<WaferHistoryItem> _SelectionChangedCommand;
+        public DelegateCommand<WaferHistoryItem> SelectionChangedCommand =>
+            _SelectionChangedCommand ?? (_SelectionChangedCommand = new DelegateCommand<WaferHistoryItem>(SelectionChanged));
+
+
+        private DelegateCommand<object> _LoadCommandPD;
+        public DelegateCommand<object> LoadCommandPD =>
+            _LoadCommandPD ?? (_LoadCommandPD = new DelegateCommand<object>(OnLoadPd));
+
         public WaferHistoryDBViewModel()
         {
-        
+            HistoryData = new ObservableCollection<LazyTreeItem<WaferHistoryItem>>();
+        }
+        void QueryLots(object e)
+        {
+            this.SearchBeginTime = this.view.wfTimeFrom.Value;
+            this.SearchEndTime = this.view.wfTimeTo.Value;
+
+            if (SearchBeginTime > SearchEndTime)
+            {
+                MessageBox.Show("Time range invalid, start time should be early than end time");
+                return;
+            }
+
+            Lots = new ObservableCollection<WaferHistoryLot>(QueryLot(SearchBeginTime, SearchEndTime, KeyWord));//.OrderByDescending(lot => lot.StartTime).ToArray();
+            HistoryData.Clear();
+            var lotsItem = new WaferHistoryItem() { Name = "Lots", };
+            var root = new LazyTreeItem<WaferHistoryItem>(lotsItem, x => LoadSubItem(x));
+            root.SubItems = new ObservableCollection<LazyTreeItem<WaferHistoryItem>>(Lots.Select(x => new LazyTreeItem<WaferHistoryItem>(new WaferHistoryItem() { ID = x.ID, Name = x.Name, StartTime = x.StartTime, EndTime = x.EndTime, Type = WaferHistoryItemType.Lot }, LoadSubItem)));
+            root.IsExpanded = true;
+            HistoryData.Add(root);
+            SelectedItem = lotsItem;
+        }
+        private Dictionary<string, object> _mapGasNameValue = new Dictionary<string, object>();
+
+        private Dictionary<string, string> _mapGasNameKey = new Dictionary<string, string>()
+        {
+            {"PMA.MfcGas1.GasName", "PMA.IoMfc.MfcGas1"},
+            {"PMA.MfcGas2.GasName", "PMA.IoMfc.MfcGas2"},
+            {"PMA.MfcGas3.GasName", "PMA.IoMfc.MfcGas3"},
+            {"PMA.MfcGas4.GasName", "PMA.IoMfc.MfcGas4"},
+            {"PMA.MfcGas5.GasName", "PMA.IoMfc.MfcGas5"},
+
+            {"PMB.MfcGas1.GasName", "PMB.IoMfc.MfcGas1"},
+            {"PMB.MfcGas2.GasName", "PMB.IoMfc.MfcGas2"},
+            {"PMB.MfcGas3.GasName", "PMB.IoMfc.MfcGas3"},
+            {"PMB.MfcGas4.GasName", "PMB.IoMfc.MfcGas4"},
+            {"PMB.MfcGas5.GasName", "PMB.IoMfc.MfcGas5"},
+        };
+
+        //protected override void OnActivate()
+        //{
+        //    base.OnActivate();
+
+        //    _mapGasNameValue = QueryDataClient.Instance.Service.PollConfig(_mapGasNameKey.Keys);
+        //}
+        private void SelectionChanged(WaferHistoryItem item)
+        {
+            switch (item.Type)
+            {
+                case WaferHistoryItemType.Lot:
+
+                    QueryLotWafer(item);
+
+                    break;
+                case WaferHistoryItemType.Wafer:
+                    QueryWaferRecipe(item);
+                    QueryWaferMovement(item);
+
+                    break;
+                case WaferHistoryItemType.Recipe:
+
+                    QueryRecipe(item);
+
+                    break;
+                default:
+                    break;
+            }
+            SelectedItem = item;
+        }
+        public WaferHistoryRecipe QueryRecipe(WaferHistoryItem whItem)
+        {
+            WaferHistoryRecipe result = new WaferHistoryRecipe();
+
+            string sql = $"SELECT * FROM \"process_data\" where \"guid\" = '{whItem.ID}'and  \"process_begin_time\" >= '{whItem.StartTime:yyyy/MM/dd HH:mm:ss.fff}' and \"process_begin_time\" <= '{whItem.EndTime:yyyy/MM/dd HH:mm:ss.fff}';";
+
+
+            //Application.Current.Dispatcher.BeginInvoke(new Action(() =>
+            //{
+            DataTable dbData = QueryDataClient.Instance.Service.QueryData(sql);
+
+            if (dbData != null && dbData.Rows.Count > 0)
+            {
+                for (int i = 0; i < dbData.Rows.Count; i++)
+                {
+                    WaferHistoryRecipe item = new WaferHistoryRecipe();
+
+                    item.ID = dbData.Rows[i]["guid"].ToString();
+                    var itemName = dbData.Rows[i]["recipe_name"].ToString();
+
+                    if (!dbData.Rows[i]["process_begin_time"].Equals(DBNull.Value))
+                        item.StartTime = (DateTime)dbData.Rows[i]["process_begin_time"];
+
+                    if (!dbData.Rows[i]["process_end_time"].Equals(DBNull.Value))
+                        item.EndTime = (DateTime)dbData.Rows[i]["process_end_time"];
+
+                    if (dbData.Rows[i].Table.Columns.Contains("recipe_setting_time") && !dbData.Rows[i]["recipe_setting_time"].Equals(DBNull.Value))
+                        item.SettingTime = dbData.Rows[i]["recipe_setting_time"].ToString();
+
+                    item.ActualTime = item.Duration;
+
+                    item.Recipe = itemName;
+
+                    item.Chamber = dbData.Rows[i]["process_in"].ToString();
+
+                    item.Name = itemName;
+
+                    item.Type = WaferHistoryItemType.Recipe;
+
+                    result = item;
+
+
+                }
+            }
+
+
+            sql = $"SELECT * FROM \"recipe_step_data\" where \"process_data_guid\" = '{whItem.ID}' and  \"step_begin_time\" >= '{whItem.StartTime:yyyy/MM/dd HH:mm:ss.fff}' and \"step_begin_time\" <= '{whItem.EndTime:yyyy/MM/dd HH:mm:ss.fff}' order by step_number ASC;";
+            dbData = QueryDataClient.Instance.Service.QueryData(sql);
+
+            List<RecipeStep> steps = new List<RecipeStep>();
+            if (dbData != null && dbData.Rows.Count > 0)
+            {
+                for (int i = 0; i < dbData.Rows.Count; i++)
+                {
+                    RecipeStep item = new RecipeStep();
+
+                    item.No = int.Parse(dbData.Rows[i]["step_number"].ToString());
+                    item.Name = dbData.Rows[i]["step_name"].ToString();
+
+                    if (!dbData.Rows[i]["step_begin_time"].Equals(DBNull.Value))
+                        item.StartTime = (DateTime)dbData.Rows[i]["step_begin_time"];
+
+                    if (!dbData.Rows[i]["step_end_time"].Equals(DBNull.Value))
+                        item.EndTime = (DateTime)dbData.Rows[i]["step_end_time"];
+
+                    item.ActualTime = item.EndTime.CompareTo(item.StartTime) <= 0 ? "" : item.EndTime.Subtract(item.StartTime).TotalSeconds.ToString();
+
+                    item.SettingTime = dbData.Rows[i]["step_time"].ToString();
+
+                    steps.Add(item);
+                }
+            }
+
+
+            sql = $"SELECT * FROM \"step_fdc_data\" where \"process_data_guid\" = '{whItem.ID}' and  \"create_time\" >= '{whItem.StartTime:yyyy/MM/dd HH:mm:ss.fff}' and \"create_time\" <= '{whItem.EndTime:yyyy/MM/dd HH:mm:ss.fff}'order by step_number ASC;";
+            dbData = QueryDataClient.Instance.Service.QueryData(sql);
+
+            List<RecipeStepFdcData> fdcs = new List<RecipeStepFdcData>();
+            if (dbData != null && dbData.Rows.Count > 0)
+            {
+                for (int i = 0; i < dbData.Rows.Count; i++)
+                {
+                    RecipeStepFdcData item = new RecipeStepFdcData();
+
+                    item.StepNumber = int.Parse(dbData.Rows[i]["step_number"].ToString());
+                    item.Name = dbData.Rows[i]["parameter_name"].ToString();
+
+                    foreach (var name in _mapGasNameKey)
+                    {
+                        if (item.Name.Contains(name.Value) && _mapGasNameValue.ContainsKey(name.Key))
+                            item.Name = item.Name.Replace(name.Value, (string)_mapGasNameValue[name.Key]);
+                    }
+
+
+                    if (!dbData.Rows[i]["sample_count"].Equals(DBNull.Value))
+                        item.SampleCount = (int)dbData.Rows[i]["sample_count"];
+
+                    if (!dbData.Rows[i]["setpoint"].Equals(DBNull.Value))
+                        item.SetPoint = (float)dbData.Rows[i]["setpoint"];
+
+                    if (!dbData.Rows[i]["min_value"].Equals(DBNull.Value))
+                        item.MinValue = (float)dbData.Rows[i]["min_value"];
+
+                    if (!dbData.Rows[i]["max_value"].Equals(DBNull.Value))
+                        item.MaxValue = (float)dbData.Rows[i]["max_value"];
+
+                    if (!dbData.Rows[i]["std_value"].Equals(DBNull.Value))
+                        item.StdValue = (float)dbData.Rows[i]["std_value"];
+
+                    if (!dbData.Rows[i]["mean_value"].Equals(DBNull.Value))
+                        item.MeanValue = (float)dbData.Rows[i]["mean_value"];
+
+
+                    fdcs.Add(item);
+                }
+            }
+
+            result.Steps = steps;
+            result.Fdcs = fdcs;
+
+            Recipe = result;
+
+            return result;
+        }
+        public List<WaferHistoryMovement> QueryWaferMovement(WaferHistoryItem whItem)
+        {
+            List<WaferHistoryMovement> result = new List<WaferHistoryMovement>();
+
+            string sql = $"SELECT * FROM \"wafer_move_history\" where \"wafer_data_guid\" = '{whItem.ID}'and  \"arrive_time\" >= '{whItem.StartTime:yyyy/MM/dd HH:mm:ss.fff}' and \"arrive_time\" <= '{whItem.EndTime:yyyy/MM/dd HH:mm:ss.fff}' order by \"arrive_time\" ASC limit 1000;";
+
+            Movements.Clear();
+            //Application.Current.Dispatcher.BeginInvoke(new Action(() =>
+            //{
+            DataTable dbData = QueryDataClient.Instance.Service.QueryData(sql);
+
+            if (dbData != null && dbData.Rows.Count > 0)
+            {
+                for (int i = 0; i < dbData.Rows.Count - 1; i++)
+                {
+                    WaferHistoryMovement item = new WaferHistoryMovement();
+
+                    item.Source = $"station : {dbData.Rows[i]["station"]} slot : {dbData.Rows[i]["slot"]}";
+                    item.Destination = $"station : {dbData.Rows[i + 1]["station"]} slot : {dbData.Rows[i + 1]["slot"]}";
+                    item.InTime = dbData.Rows[i]["arrive_time"].ToString();
+
+                    result.Add(item);
+
+                    Movements.Add(item);
+
+                }
+            }
+
+
+            //}));
+
+            return result;
+        }
+        public List<WaferHistoryWafer> QueryLotWafer(WaferHistoryItem whItem)
+        {
+            List<WaferHistoryWafer> result = new List<WaferHistoryWafer>();
+
+            //string sql = $"select data.*,process_data.process_status from (SELECT * FROM wafer_data,lot_wafer_data where lot_wafer_data.lot_data_guid = '{lotGuid}' and lot_wafer_data.wafer_data_guid = wafer_data.guid order by wafer_data.create_time ASC; as data )" +
+            //    $" LEFT JOIN process_data ON process_data.wafer_data_guid=data.wafer_id";
+            string sql = $"SELECT wafer_data.*,lot_wafer_data.*,process_data.process_status as status FROM wafer_data LEFT JOIN lot_wafer_data ON lot_wafer_data.wafer_data_guid = wafer_data.guid " +
+                        $"LEFT JOIN process_data ON process_data.wafer_data_guid = wafer_data.guid where lot_wafer_data.lot_data_guid = '{whItem.ID}' order by wafer_data.create_time ASC";
+            Wafers.Clear();
+            //Application.Current.Dispatcher.BeginInvoke(new Action(() =>
+            //{
+            DataTable dbData = QueryDataClient.Instance.Service.QueryData(sql);
+
+            Dictionary<string, int> itemPtr = new Dictionary<string, int>();
+            List<string> itemNameList = new List<string>();
+
+            if (dbData != null && dbData.Rows.Count > 0)
+            {
+                for (int i = 0; i < dbData.Rows.Count; i++)
+                {
+                    WaferHistoryWafer item = new WaferHistoryWafer();
+
+                    item.ID = dbData.Rows[i]["guid"].ToString();
+                    if (!itemPtr.ContainsKey(item.ID))
+                    {
+                        itemPtr.Add(item.ID, 0);
+                    }
+
+                    var itemLoadPort = dbData.Rows[i]["create_station"].ToString();
+                    var itemSlot = dbData.Rows[i]["create_slot"].ToString();
+
+                    //item.CarrierID = dbData.Rows[i]["rfid"].ToString();
+
+                    item.LotID = dbData.Rows[i]["lot_id"].ToString();
+                    item.SlotID = dbData.Rows[i]["create_slot"].ToString();
+                    var itemWaferID = dbData.Rows[i]["wafer_id"].ToString();
+
+                    item.Sequence = dbData.Rows[i]["sequence_name"].ToString();
+
+                    item.Status = dbData.Rows[i]["status"].ToString();
+
+                    sql = $"SELECT * FROM \"wafer_move_history\" where \"wafer_data_guid\" = '{item.ID}' and  \"arrive_time\" >= '{whItem.StartTime:yyyy/MM/dd HH:mm:ss.fff}' and \"arrive_time\" <= '{whItem.EndTime:yyyy/MM/dd HH:mm:ss.fff}' order by \"arrive_time\" ASC limit 1000;";
+                    DataTable dbDataMovement = QueryDataClient.Instance.Service.QueryData(sql);
+
+                    if (dbDataMovement != null && dbDataMovement.Rows.Count >= 2 && dbDataMovement.Rows.Count > itemPtr[item.ID])
+                    {
+                        item.StartTime = (DateTime)dbDataMovement.Rows[itemPtr[item.ID]]["arrive_time"];
+                        for (int j = itemPtr[item.ID]; j < dbDataMovement.Rows.Count; j++)
+                        {
+                            if (dbDataMovement.Rows[j]["station"].ToString().StartsWith("LP"))
+                            {
+                                item.EndTime = (DateTime)dbDataMovement.Rows[j]["arrive_time"];
+                                itemPtr[item.ID] = j + 1;
+                                break;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        if (!dbData.Rows[i]["create_time"].Equals(DBNull.Value))
+                        {
+                            item.StartTime = ((DateTime)dbData.Rows[i]["create_time"]);
+                        }
+
+                        if (!dbData.Rows[i]["delete_time"].Equals(DBNull.Value))
+                            item.EndTime = ((DateTime)dbData.Rows[i]["delete_time"]);
+                    }
+
+                    item.Name = $"{itemLoadPort} - {itemSlot} - {itemWaferID}";
+
+                    item.Type = WaferHistoryItemType.Wafer;
+
+                    if (!itemNameList.Contains(item.Name))
+                    {
+                        Wafers.Add(item);
+                        result.Add(item);
+                        itemNameList.Add(item.Name);
+                    }
+                }
+            }
+
+
+            //}));
+
+            return result;
+        }
+
+
+        public List<WaferHistoryRecipe> QueryWaferRecipe(WaferHistoryItem whItem)
+        {
+            List<WaferHistoryRecipe> result = new List<WaferHistoryRecipe>();
+
+            string sql = $"SELECT * FROM \"process_data\" where \"wafer_data_guid\" = '{whItem.ID}'and  \"process_begin_time\" >= '{whItem.StartTime:yyyy/MM/dd HH:mm:ss.fff}' and \"process_begin_time\" <= '{whItem.EndTime:yyyy/MM/dd HH:mm:ss.fff}' order by \"process_begin_time\" ASC;";
+
+            Recipes.Clear();
+            //Application.Current.Dispatcher.BeginInvoke(new Action(() =>
+            //{
+            DataTable dbData = QueryDataClient.Instance.Service.QueryData(sql);
+
+            if (dbData != null && dbData.Rows.Count > 0)
+            {
+                for (int i = 0; i < dbData.Rows.Count; i++)
+                {
+                    WaferHistoryRecipe item = new WaferHistoryRecipe();
+
+                    item.ID = dbData.Rows[i]["guid"].ToString();
+                    var itemName = dbData.Rows[i]["recipe_name"].ToString();
+
+                    if (!dbData.Rows[i]["process_begin_time"].Equals(DBNull.Value))
+                        item.StartTime = (DateTime)dbData.Rows[i]["process_begin_time"];
+
+                    if (dbData.Rows[i].Table.Columns.Contains("process_end_time") && !dbData.Rows[i]["process_end_time"].Equals(DBNull.Value))
+                        item.EndTime = (DateTime)dbData.Rows[i]["process_end_time"];
+
+                    if (dbData.Rows[i].Table.Columns.Contains("recipe_setting_time") && !dbData.Rows[i]["recipe_setting_time"].Equals(DBNull.Value))
+                        item.SettingTime = dbData.Rows[i]["recipe_setting_time"].ToString();
+
+                    item.ActualTime = item.Duration;
+
+                    item.Recipe = itemName;
+
+                    item.Chamber = dbData.Rows[i]["process_in"].ToString();
+
+                    item.Name = itemName;
+
+                    item.Type = WaferHistoryItemType.Recipe;
+
+                    Recipes.Add(item);
+
+                    result.Add(item);
+                }
+            }
+
+
+            //}));
+
+            return result;
+        }
+        public List<WaferHistoryLot> QueryLot(DateTime from, DateTime to, string key)
+        {
+            List<WaferHistoryLot> result = new List<WaferHistoryLot>();
+
+            string sql = $"SELECT * FROM \"lot_data\" where \"start_time\" >= '{from:yyyy/MM/dd HH:mm:ss.fff}' and \"start_time\" <= '{to:yyyy/MM/dd HH:mm:ss.fff}' ";
+
+            if (!string.IsNullOrWhiteSpace(key))
+                sql += $" and lower(\"name\") like '%{key.ToLower()}%'";
+
+            sql += "order by \"start_time\" ASC;";
+
+            //Application.Current.Dispatcher.BeginInvoke(new Action(() =>
+            //{
+            DataTable dbData = QueryDataClient.Instance.Service.QueryData(sql);
+
+            if (dbData != null && dbData.Rows.Count > 0)
+            {
+                for (int i = 0; i < dbData.Rows.Count; i++)
+                {
+                    WaferHistoryLot item = new WaferHistoryLot();
+                    string name = dbData.Rows[i]["name"].ToString();
+                    string time = "";
+                    item.WaferCount = (int)dbData.Rows[i]["total_wafer_count"];
+                    item.ID = dbData.Rows[i]["guid"].ToString();
+
+                    if (!dbData.Rows[i]["start_time"].Equals(DBNull.Value))
+                    {
+                        item.StartTime = ((DateTime)dbData.Rows[i]["start_time"]);
+                        time = item.StartTime.ToString("yyyy-MM-dd HH:mm:ss");
+                    }
+
+                    if (!dbData.Rows[i]["end_time"].Equals(DBNull.Value))
+                    {
+                        item.EndTime = ((DateTime)dbData.Rows[i]["end_time"]);
+                    }
+                    item.InputPort = dbData.Rows[i]["input_port"].ToString();
+                    item.Name = $"{name}-{time}";
+                    item.LotID = $"{name}";
+                    result.Add(item);
+                }
+            }
+
+            return result;
+        }
+        private void OnLoadPd(Object eventView)
+        {
+            this.view = (WaferHistoryDBView)eventView;
+            this.view.wfTimeFrom.Value = DateTime.Today;
+            this.view.wfTimeTo.Value = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 23, 59, 59, 999);
+        }
+        protected List<LazyTreeItem<WaferHistoryItem>> LoadSubItem(WaferHistoryItem item)
+        {
+            switch (item.Type)
+            {
+                case WaferHistoryItemType.Lot:
+                    var wafers = QueryLotWafer(item);
+                    return wafers.Select(x => new LazyTreeItem<WaferHistoryItem>(x, y => LoadSubItem(y))).OrderBy(s => s.Data.StartTime).ToList();
+                case WaferHistoryItemType.Wafer:
+                    var recipes = QueryWaferRecipe(item);
+                    return recipes.Select(x => new LazyTreeItem<WaferHistoryItem>(x, y => LoadSubItem(y))).OrderBy(s => s.Data.StartTime).ToList();
+                default:
+                    break;
+            }
+            return new List<LazyTreeItem<WaferHistoryItem>> { };
         }
     }
+
+
+    public class LazyTreeItem<T> : INotifyPropertyChanged where T : ITreeItem<T>, new()
+    {
+        private LazyTreeItem<T> dummyChild;
+        private T data;
+        private Func<T, List<LazyTreeItem<T>>> loader;
+
+
+        private LazyTreeItem()
+        {
+            data = new T();
+            data.ID = Guid.NewGuid().ToString();
+        }
+
+        public LazyTreeItem(T data, Func<T, List<LazyTreeItem<T>>> loader)
+        {
+            this.data = data;
+            this.loader = loader;
+
+            dummyChild = new LazyTreeItem<T>();
+
+            SubItems = new ObservableCollection<LazyTreeItem<T>>();
+            SubItems.Add(dummyChild);
+        }
+
+        public T Data
+        {
+            get
+            {
+                return data;
+            }
+        }
+        public ObservableCollection<LazyTreeItem<T>> SubItems
+        {
+            get; set;
+        }
+
+        private bool isExpanded;
+
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        private void OnPropertyChanged(string name)
+        {
+            if (PropertyChanged != null)
+            {
+                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(name));
+            }
+        }
+
+        public bool HasDummyChild
+        {
+            get { return SubItems.Count == 1 && SubItems.First().data.ID == dummyChild.data.ID; }
+        }
+
+        public bool IsExpanded
+        {
+            get { return isExpanded; }
+            set
+            {
+                if (value != isExpanded)
+                {
+                    isExpanded = value;
+                    OnPropertyChanged("IsExpanded");
+                }
+
+                if (HasDummyChild)
+                {
+                    SubItems.Remove(dummyChild);
+                    var items = loader(data);
+                    foreach (var item in items)
+                    {
+                        SubItems.Add(item);
+                    }
+                    //items.ForEachDo(x => SubItems.Add(x));
+                }
+            }
+        }
+    }
+
 }

+ 277 - 3
Venus/Venus_MainPages/Views/WaferHistoryDBView.xaml

@@ -4,11 +4,285 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:local="clr-namespace:Venus_MainPages.Views"
+             xmlns:wfi ="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration" 
+             xmlns:wf ="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
+             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
              xmlns:prism="http://prismlibrary.com/" 
+             xmlns:waferHistory="clr-namespace:Venus_MainPages.Views"
              prism:ViewModelLocator.AutoWireViewModel="True"
              mc:Ignorable="d" 
-             d:DesignHeight="450" d:DesignWidth="800">
-    <Grid>
-            
+             d:DesignHeight="450" d:DesignWidth="1800"
+             x:Name="WaferDataView">
+    <i:Interaction.Triggers>
+        <i:EventTrigger EventName="Loaded">
+            <i:InvokeCommandAction Command="{Binding LoadCommandPD}" CommandParameter="{Binding ElementName=WaferDataView}"/>
+        </i:EventTrigger>
+    </i:Interaction.Triggers>
+    <Grid x:Name="root">
+        <Grid.Resources>
+            <waferHistory:HideMinTimeConverters x:Key="HideMinTimeConvert"/>
+            <waferHistory:MinTime2BoolConverters x:Key="MinTime2BoolConverter"/>
+            <waferHistory:RecipeStepNull2Empty x:Key="RecipeStepNull2Empty"/>
+            <Grid x:Key="LotLayout">
+                <DataGrid ItemsSource="{Binding Lots}" IsReadOnly="True" AutoGenerateColumns="False" RowHeight="25" 
+                          CanUserAddRows="False" CanUserResizeRows="False" CanUserResizeColumns="True" FontFamily="Arial" FontSize="14">
+                    <DataGrid.Columns>
+                        <DataGridTextColumn Header="Lot ID" Width="180*" Binding="{Binding LotID}" />
+                        <DataGridTextColumn Header="LP Position" Width="100*" Binding="{Binding InputPort}" />
+                        <DataGridTextColumn Header="Start Time" Width="150*" Binding="{Binding StartTime,Converter={StaticResource HideMinTimeConvert}}" />
+                        <DataGridTextColumn Header="End Time" Width="150*" Binding="{Binding EndTime,Converter={StaticResource HideMinTimeConvert}}" />
+                        <DataGridTextColumn Header="Duration" Width="75*" Binding="{Binding Duration}" />
+                        <DataGridTextColumn Header="Wafer Count" Width="100*" Binding="{Binding WaferCount}" />
+                        <DataGridTextColumn Header="Fault Wafer Count" Width="150*" Binding="{Binding FaultWaferCount}" />
+                        <DataGridTemplateColumn Header="Lots Data" Width="100*">
+                            <DataGridTemplateColumn.CellTemplate>
+                                <DataTemplate>
+                                    <Button Content="To Slot" Margin="0" Height="22" VerticalContentAlignment="Center" FontSize="12">
+                                        <i:Interaction.Triggers>
+                                            <i:EventTrigger EventName="Click">
+                                                <i:InvokeCommandAction Command="{Binding DataContext.ToChartCommand,ElementName=root}" CommandParameter="{Binding }" />
+                                            </i:EventTrigger>
+                                        </i:Interaction.Triggers>
+                                    </Button>
+                                </DataTemplate>
+                            </DataGridTemplateColumn.CellTemplate>
+                        </DataGridTemplateColumn>
+                    </DataGrid.Columns>
+                </DataGrid>
+            </Grid>
+
+            <Grid x:Key="WaferLayout">
+                <DataGrid ItemsSource="{Binding Wafers}"   IsReadOnly="True"  AutoGenerateColumns="False" RowHeight="25" 
+                          CanUserAddRows="False" CanUserResizeRows="False" CanUserResizeColumns="True" FontFamily="Arial" FontSize="14" >
+                    <DataGrid.Columns>
+                        <DataGridTextColumn Header="Lot ID" Width="100*" Binding="{Binding LotID}" />
+                        <DataGridTextColumn Header="Slot ID" Width="100*" Binding="{Binding SlotID}" />
+                        <DataGridTextColumn Header="Arrive Time" Width="150*" Binding="{Binding StartTime,Converter={StaticResource HideMinTimeConvert}}" />
+                        <DataGridTextColumn Header="Remove Time" Width="150*" Binding="{Binding EndTime,Converter={StaticResource HideMinTimeConvert}}" />
+                        <DataGridTextColumn Header="Duration" Width="75*" Binding="{Binding Duration}" />
+                        <DataGridTextColumn Header="Sequence" Width="200*" Binding="{Binding Sequence}" />
+                        <DataGridTextColumn Header="Status" Width="200*" Binding="{Binding Status}" />
+                        <DataGridTemplateColumn Header="Chart" Width="100*">
+                            <DataGridTemplateColumn.CellTemplate>
+                                <DataTemplate>
+                                    <Button Content="To Chart" IsEnabled="{Binding EndTime,Converter={StaticResource MinTime2BoolConverter }}" Margin="0" Height="22" VerticalContentAlignment="Center" FontSize="12">
+                                        <i:Interaction.Triggers>
+                                            <i:EventTrigger EventName="Click">
+                                                <i:InvokeCommandAction Command="{Binding DataContext.ToChartCommand,ElementName=root}" CommandParameter="{Binding }" />
+                                            </i:EventTrigger>
+                                        </i:Interaction.Triggers>
+                                    </Button>
+                                </DataTemplate>
+                            </DataGridTemplateColumn.CellTemplate>
+                        </DataGridTemplateColumn>
+                    </DataGrid.Columns>
+                </DataGrid>
+            </Grid>
+
+            <Grid x:Key="MovementLayout">
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="20*"/>
+                    <RowDefinition Height="50*"/>
+                </Grid.RowDefinitions>
+                <DataGrid  ItemsSource="{Binding Recipes}" IsReadOnly="True" AutoGenerateColumns="False"  RowHeight="25" 
+                               CanUserAddRows="False" CanUserResizeRows="False" CanUserResizeColumns="True" FontFamily="Arial" FontSize="14" >
+                    <DataGrid.Columns>
+                        <DataGridTextColumn Header="Name"  Width="200*"  Binding="{Binding Recipe}" />
+                        <DataGridTextColumn Header="StartTime"   Width="150*" Binding="{Binding StartTime,Converter={StaticResource HideMinTimeConvert}}" />
+                        <DataGridTextColumn Header="EndTime"  Width="150*"  Binding="{Binding EndTime,Converter={StaticResource HideMinTimeConvert}}" />
+                        <DataGridTextColumn Header="Chamber"  Width="100*"  Binding="{Binding Chamber}" />
+                        <DataGridTextColumn Header="SettingTime"  Width="150*"  Binding="{Binding SettingTime}" />
+                        <DataGridTextColumn Header="ActualTime"  Width="150*"  Binding="{Binding ActualTime}" />
+                        <DataGridTemplateColumn Header="Chart" Width="100*">
+                            <DataGridTemplateColumn.CellTemplate>
+                                <DataTemplate>
+                                    <Button Content="To Chart" Margin="0" Height="22" VerticalContentAlignment="Center" FontSize="12">
+                                        <i:Interaction.Triggers>
+                                            <i:EventTrigger EventName="Click">
+                                                <i:InvokeCommandAction Command="{Binding DataContext.ToChartCommand,ElementName=root}" CommandParameter="{Binding StartTime}" />
+                                            </i:EventTrigger>
+                                        </i:Interaction.Triggers>
+                                    </Button>
+                                </DataTemplate>
+                            </DataGridTemplateColumn.CellTemplate>
+                        </DataGridTemplateColumn>
+                    </DataGrid.Columns>
+                </DataGrid>
+
+                <TabControl Grid.Row="1">
+                    <TabItem Header="Movements">
+                        <DataGrid  ItemsSource="{Binding Movements}" IsReadOnly="True" AutoGenerateColumns="False"  RowHeight="25" 
+                                   CanUserAddRows="False" CanUserResizeRows="False" CanUserResizeColumns="True" FontFamily="Arial" FontSize="14">
+                            <DataGrid.Columns>
+                                <DataGridTextColumn Header="Source" Width="200*" Binding="{Binding Source}" />
+                                <DataGridTextColumn Header="Destination" Width="200*" Binding="{Binding Destination}" />
+                                <DataGridTextColumn Header="Time" Width="200*" Binding="{Binding InTime,Converter={StaticResource HideMinTimeConvert}}" />
+                            </DataGrid.Columns>
+                        </DataGrid>
+                    </TabItem>
+                </TabControl>
+            </Grid>
+
+            <Grid x:Key="RecipeLayout">
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="20*" />
+                    <RowDefinition Height="80*" />
+                </Grid.RowDefinitions>
+
+                <Border BorderBrush="{DynamicResource Tab_BD}" BorderThickness="1" Background="{DynamicResource Tab_BG}">
+                    <Grid  DataContext="{Binding Recipe}"  Background="{DynamicResource DataGrid_BG_First}">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="10*"/>
+                            <ColumnDefinition Width="10*"/>
+                            <ColumnDefinition Width="10*"/>
+                            <ColumnDefinition Width="10*"/>
+                            <ColumnDefinition Width="10*"/>
+                            <ColumnDefinition Width="10*"/>
+                        </Grid.ColumnDefinitions>
+
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="30"/>
+                            <RowDefinition Height="30"/>
+                        </Grid.RowDefinitions>
+                        <Border BorderBrush="{DynamicResource Table_BD}" BorderThickness="0,0,1,1" Grid.Column="0" Background="{DynamicResource Table_BG_Title}" Grid.Row="0" Padding="5,1">
+                            <TextBlock Text="Name" TextWrapping="Wrap" Foreground="{DynamicResource FG_Black}" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+                        </Border>
+                        <Border BorderBrush="{DynamicResource Table_BD}" BorderThickness="0,0,1,1" Grid.Column="1" Background="{DynamicResource Table_BG_Title}" Grid.Row="0" Padding="5,1">
+                            <TextBlock Text="StartTime" TextWrapping="Wrap" Foreground="{DynamicResource FG_Black}" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+                        </Border>
+                        <Border BorderBrush="{DynamicResource Table_BD}" BorderThickness="0,0,1,1" Grid.Column="2" Background="{DynamicResource Table_BG_Title}" Grid.Row="0" Padding="5,1">
+                            <TextBlock Text="EndTime" TextWrapping="Wrap" Foreground="{DynamicResource FG_Black}" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+                        </Border>
+                        <Border BorderBrush="{DynamicResource Table_BD}" BorderThickness="0,0,1,1" Grid.Column="3" Background="{DynamicResource Table_BG_Title}" Grid.Row="0" Padding="5,1">
+                            <TextBlock Text="Chamber" TextWrapping="Wrap" Foreground="{DynamicResource FG_Black}" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+                        </Border>
+                        <Border BorderBrush="{DynamicResource Table_BD}" BorderThickness="0,0,1,1" Grid.Column="4" Background="{DynamicResource Table_BG_Title}" Grid.Row="0" Padding="5,1">
+                            <TextBlock Text="SettingTime" TextWrapping="Wrap" Foreground="{DynamicResource FG_Black}" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+                        </Border>
+                        <Border BorderBrush="{DynamicResource Table_BD}" BorderThickness="0,0,0,1" Grid.Column="5" Background="{DynamicResource Table_BG_Title}" Grid.Row="0" Padding="5,1">
+                            <TextBlock Text="ActualTime" TextWrapping="Wrap" Foreground="{DynamicResource FG_Black}" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+                        </Border>
+
+                        <Border BorderBrush="{DynamicResource Table_BD}" BorderThickness="0,0,1,1" Background="{DynamicResource Table_BG_Content}" Grid.Column="0" Grid.Row="1" Padding="5,1">
+                            <TextBlock Text="{Binding Recipe}" TextWrapping="Wrap" Foreground="{DynamicResource FG_Black}" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+                        </Border>
+                        <Border BorderBrush="{DynamicResource Table_BD}" BorderThickness="0,0,1,1" Background="{DynamicResource Table_BG_Content}" Grid.Column="1" Grid.Row="1" Padding="5,1">
+                            <TextBlock Text="{Binding StartTime,Converter={StaticResource HideMinTimeConvert}}" TextWrapping="Wrap" Foreground="{DynamicResource FG_Black}" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+                        </Border>
+                        <Border BorderBrush="{DynamicResource Table_BD}" BorderThickness="0,0,1,1" Background="{DynamicResource Table_BG_Content}" Grid.Column="2" Grid.Row="1" Padding="5,1">
+                            <TextBlock Text="{Binding EndTime,Converter={StaticResource HideMinTimeConvert}}" TextWrapping="Wrap" Foreground="{DynamicResource FG_Black}" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+                        </Border>
+                        <Border BorderBrush="{DynamicResource Table_BD}" BorderThickness="0,0,1,1" Background="{DynamicResource Table_BG_Content}" Grid.Column="3" Grid.Row="1" Padding="5,1">
+                            <TextBlock Text="{Binding Chamber}" TextWrapping="Wrap" Foreground="{DynamicResource FG_Black}" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+                        </Border>
+                        <Border BorderBrush="{DynamicResource Table_BD}" BorderThickness="0,0,1,1" Background="{DynamicResource Table_BG_Content}" Grid.Column="4" Grid.Row="1" Padding="5,1">
+                            <TextBlock Text="{Binding SettingTime}" TextWrapping="Wrap" Foreground="{DynamicResource FG_Black}" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+                        </Border>
+                        <Border BorderBrush="{DynamicResource Table_BD}" BorderThickness="0,0,0,1" Background="{DynamicResource Table_BG_Content}" Grid.Column="5" Grid.Row="1" Padding="5,1">
+                            <TextBlock Text="{Binding ActualTime}" TextWrapping="Wrap" Foreground="{DynamicResource FG_Black}" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+                        </Border>
+
+                    </Grid>
+                </Border>
+
+                <TabControl Grid.Row="1"  >
+                    <TabItem Header="Steps">
+                        <DataGrid  ItemsSource="{Binding Recipe.Steps, Converter={StaticResource RecipeStepNull2Empty}}"  IsReadOnly="True"  AutoGenerateColumns="False" 
+                                   CanUserAddRows="False" CanUserResizeRows="False" CanUserResizeColumns="True" FontFamily="Arial" FontSize="14" >
+                            <DataGrid.Columns>
+                                <DataGridTextColumn Header="#"  Binding="{Binding No}" />
+                                <DataGridTextColumn Header="Name" Width="200*"  Binding="{Binding Name}" />
+                                <DataGridTextColumn Header="Start Time" Width="200*" Binding="{Binding StartTime,Converter={StaticResource HideMinTimeConvert}}" />
+                                <DataGridTextColumn Header="End Time" Width="200*" Binding="{Binding EndTime,Converter={StaticResource HideMinTimeConvert}}" />
+                                <DataGridTextColumn Header="Actual Time" Width="100*" Binding="{Binding ActualTime}" />
+                                <DataGridTextColumn Header="Setting Time" Width="100*" Binding="{Binding SettingTime}" />
+                            </DataGrid.Columns>
+                        </DataGrid>
+                    </TabItem>
+
+                    <TabItem Header="FDC">
+                        <DataGrid  ItemsSource="{Binding Recipe.Fdcs}"  IsReadOnly="True"  AutoGenerateColumns="False" 
+                                   CanUserAddRows="False" CanUserResizeRows="False" CanUserResizeColumns="True" FontFamily="Arial" FontSize="14" >
+                            <DataGrid.Columns>
+                                <DataGridTextColumn Header="#"  Binding="{Binding StepNumber}" />
+                                <DataGridTextColumn Header="Name" Width="200"  Binding="{Binding Name}" />
+                                <DataGridTextColumn Header="SetPoint" Width="100"  Binding="{Binding SetPoint}" />
+                                <DataGridTextColumn Header="Count" Width="50"  Binding="{Binding SampleCount}" />
+                                <DataGridTextColumn Header="Min" Width="100" Binding="{Binding MinValue}" />
+                                <DataGridTextColumn Header="Max" Width="100" Binding="{Binding MaxValue}" />
+                                <DataGridTextColumn Header="Mean" Width="100" Binding="{Binding MeanValue}" />
+                                <DataGridTextColumn Header="Std" Width="100" Binding="{Binding StdValue}" />
+                            </DataGrid.Columns>
+                        </DataGrid>
+                    </TabItem>
+                </TabControl>
+
+            </Grid>
+
+            <waferHistory:HistoryLayoutSelectorConverter x:Key="HistoryLayoutSelectorConverter" WaferLayout="{StaticResource WaferLayout}"
+												  MovementLayout="{StaticResource MovementLayout}"
+												  RecipeLayout="{StaticResource RecipeLayout}"
+												  LotsLayout="{StaticResource LotLayout}"/>
+        </Grid.Resources>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="40"></RowDefinition>
+            <RowDefinition Height="700"></RowDefinition>
+        </Grid.RowDefinitions>
+        <StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal" Margin="2,10,2,2">
+            <Label Content="Start_Time:"/>
+            <wfi:WindowsFormsHost Margin="5,0,0,0" FontSize="14" FontFamily="Arial" Width="170" Height="22" VerticalAlignment="Center">
+                <wf:DateTimePicker x:Name="wfTimeFrom" Value="2011-8-1" CustomFormat="yyyy/MM/dd HH:mm:ss" Format="Custom"></wf:DateTimePicker>
+            </wfi:WindowsFormsHost>
+            <Label Content="End_Time:"/>
+            <wfi:WindowsFormsHost Margin="5,0,0,0" FontSize="14" FontFamily="Arial" Width="170" Height="22" VerticalAlignment="Center">
+                <wf:DateTimePicker x:Name="wfTimeTo" Value="2011-8-1" CustomFormat="yyyy/MM/dd HH:mm:ss" Format="Custom"></wf:DateTimePicker>
+            </wfi:WindowsFormsHost>
+            <Label Content="LotName:" />
+            <TextBox Width="200" Text="{Binding KeyWord}" />
+            <Button Content="Query" Width="120" Margin="4,2,4,2" Command="{Binding QueryCommand}"/>
+        </StackPanel>
+        <Grid Grid.Row="1" Grid.Column="0" >
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="350" />
+            <ColumnDefinition Width="*" />
+        </Grid.ColumnDefinitions>
+            <Border Grid.Row="0" Margin="0,5,13,0" BorderBrush="{DynamicResource Tab_BD}" BorderThickness="1" Background="{DynamicResource Table_BG_Content}" >
+                <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
+                    <TreeView ItemsSource="{Binding HistoryData}" SelectedValuePath="Data">
+                        <TreeView.ItemContainerStyle>
+                            <Style TargetType="{x:Type TreeViewItem}">
+                                <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
+                                <Setter Property="FontWeight" Value="Normal" />
+                                <Setter Property="IsSelected" Value="{Binding this.IsSelected}"/>
+                                <Style.Triggers>
+                                    <Trigger Property="IsSelected" Value="True">
+                                        <Setter Property="FontWeight" Value="Bold"/>
+                                    </Trigger>
+                                </Style.Triggers>
+                            </Style>
+                        </TreeView.ItemContainerStyle>
+
+                        <TreeView.ItemTemplate>
+                            <HierarchicalDataTemplate ItemsSource="{Binding SubItems}">
+                                <TextBlock Text="{Binding Data.ItemInfo}">
+
+                                    <i:Interaction.Triggers>
+                                        <i:EventTrigger EventName="MouseLeftButtonDown">
+                                            <i:InvokeCommandAction Command="{Binding DataContext.SelectionChangedCommand,ElementName=root,UpdateSourceTrigger=PropertyChanged}" CommandParameter="{Binding Data}" />
+                                        </i:EventTrigger>
+                                    </i:Interaction.Triggers>
+                                </TextBlock>
+                            </HierarchicalDataTemplate>
+                        </TreeView.ItemTemplate>
+                    </TreeView>
+                </ScrollViewer>
+            </Border>
+
+            <GridSplitter Grid.Column="0" Width="10" HorizontalAlignment="Right"  Background="Transparent"  VerticalAlignment="Stretch" Style="{DynamicResource VerticalGridSplitterStyle}">
+            </GridSplitter>
+            <Grid Grid.Row="0" Grid.Column="1">
+                <ContentControl  Content="{Binding SelectedItem,UpdateSourceTrigger=PropertyChanged, Converter={StaticResource HistoryLayoutSelectorConverter}}"/>
+            </Grid>
+        </Grid>
     </Grid>
 </UserControl>

+ 92 - 1
Venus/Venus_MainPages/Views/WaferHistoryDBView.xaml.cs

@@ -1,5 +1,7 @@
-using System;
+using MECF.Framework.Common.CommonData;
+using System;
 using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -25,4 +27,93 @@ namespace Venus_MainPages.Views
             InitializeComponent();
         }
     }
+    public class HistoryLayoutSelectorConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            if (value != null)
+            {
+                var type = ((WaferHistoryItem)value).Type;
+                switch (type)
+                {
+                    case WaferHistoryItemType.None:
+                        return LotsLayout;
+                    case WaferHistoryItemType.Lot:
+                        return WaferLayout;
+                    case WaferHistoryItemType.Wafer:
+                        return MovementLayout;
+                    case WaferHistoryItemType.Recipe:
+                        return RecipeLayout;
+                    default:
+                        break;
+                }
+            }
+            return null;
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return null;
+        }
+
+        public object WaferLayout { get; set; }
+        public object MovementLayout { get; set; }
+        public object RecipeLayout { get; set; }
+        public object LotsLayout { get; set; }
+    }
+    public class HideMinTimeConverters : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            if (value is DateTime)
+                return (DateTime)value == DateTime.MinValue ? "" : ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
+
+            if (DateTime.TryParse((string)value, out DateTime dateTime))
+                return dateTime == DateTime.MinValue ? "" : dateTime.ToString("yyyy-MM-dd HH:mm:ss");
+
+            return "";
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            return null;
+        }
+    }
+
+    public class MinTime2BoolConverters : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            if (value is DateTime)
+                return (DateTime)value != DateTime.MinValue;
+
+            if (DateTime.TryParse((string)value, out DateTime dateTime))
+                return dateTime != DateTime.MinValue;
+
+            return false;
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            return null;
+        }
+    }
+
+    public class RecipeStepNull2Empty : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            if (value != null && (value is List<RecipeStep>) && ((List<RecipeStep>)value).Count > 0)
+            {
+                return value;
+            }
+
+            return new List<RecipeStep>() { new RecipeStep() { Name = "", StartTime = DateTime.MinValue, EndTime = DateTime.MinValue, ActualTime = "", SettingTime = "" } };
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            return null;
+        }
+    }
 }