using DeskRedis.Enums; using DeskRedis.Model; using DeskRedis.Model.Configs; using DeskRedis.MyControl.CustomControl; using DeskRedis.Util; using ServiceStack.Redis; using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace DeskRedis { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { #region 私有变量 /// <summary> /// 当前选中的节点。 /// </summary> private TreeViewItemWithOperator currentSelectedTreeViewItem; #endregion #region 构造方法 public MainWindow() { this.InitializeComponent(); this.WindowStartupLocation = WindowStartupLocation.CenterScreen; this.Loaded += this.MainWindow_Loaded; this.Closing += this.MainWindow_Closing; string pathConnections = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "connections.json"); if (!File.Exists(pathConnections)) { File.Create(pathConnections).Close(); File.WriteAllText(pathConnections, "[]"); } string pathConfig = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "app.ini"); if (!File.Exists(pathConfig)) { File.Create(pathConfig).Close(); IniUtil.WriteINI(pathConfig, "Window", "WindowState", WindowState.Normal.ToString()); IniUtil.WriteINI(pathConfig, "Window", "Width", "1200"); IniUtil.WriteINI(pathConfig, "Window", "Height", "680"); } string state = IniUtil.ReadINI(pathConfig, "Window", "WindowState", WindowState.Normal.ToString()); Enum.TryParse(state, out WindowState eState); if (eState == WindowState.Normal) { string sWidth = IniUtil.ReadINI(pathConfig, "Window", "Width", "1200"); string sHeigth = IniUtil.ReadINI(pathConfig, "Window", "Heigth", "680"); this.Width = double.Parse(sWidth); this.Height = double.Parse(sHeigth); } else { this.WindowState = eState; } } #endregion #region 私有方法 /// <summary> /// 初始化连接信息树。 /// </summary> private void InitTree() { List<ConnectionConfig> configs = GlobalBusiness.GetAllConnectionConfig(); foreach (ConnectionConfig config in configs) { TreeView tree = this.CreateRootNode(config); this.gridRedisList.Children.Add(tree); } } /// <summary> /// 创建根节点。 /// </summary> /// <param name="config"></param> /// <returns></returns> private TreeView CreateRootNode(ConnectionConfig config) { TreeView tree = new TreeView(); VirtualizingPanel.SetIsVirtualizing(tree, true); VirtualizingPanel.SetVirtualizationMode(tree, VirtualizationMode.Recycling); tree.Tag = config.Id; tree.Margin = new Thickness(2); tree.FontSize = 14; tree.FontFamily = new FontFamily("courier new;microsoft yahei ui;宋体"); TreeViewItemWithOperator root = new TreeViewItemWithOperator(); NodeInfo nodeInfo = new NodeInfo() { NodeTyp = NodeType.Connection, ConfigId = config.Id, Header = config.Name }; root.Name = "root_" + config.Id; root.Header = config.Name; root.NodeInfo = nodeInfo; root.Margin = new Thickness(0, 2, 0, 2); root.FontWeight = FontWeights.Bold; root.UseOperation(new OperateType[] { OperateType.REFRESH, OperateType.DELETE }); root.MouseUp += Node_MouseUp; root.MouseDoubleClick += Root_MouseDoubleClick; root.OnRefresh += TreeViewItem_Refresh; root.OnDelete += TreeViewItem_Delete; root.ContextMenu = this.CreateRootContextMenu(nodeInfo); tree.Items.Add(root); return tree; } /// <summary> /// 创建DB列表节点 /// </summary> /// <param name="parent"></param> private void CreateDBNode(TreeViewItemWithOperator parent) { NodeInfo nodeInfo = parent.NodeInfo; ConnectionConfig config = GlobalBusiness.DictConnectionConfig[nodeInfo.ConfigId]; Task.Run(() => { try { this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Visible; }); this.SetLog(this.tbLog, $"正在打开连接 {config.Name}({config.IP}:{config.Port}) ..."); string result = GlobalBusiness.RedisCaches[config.Id].ConnectTest(); if ("SUCCESS".Equals(result)) { int count = GlobalBusiness.RedisCaches[config.Id].GetDataBaseCount(); for (int i = 0; i < count; i++) { int dbIndex = i; this.Dispatcher.Invoke(() => { TreeViewItemWithOperator item = new TreeViewItemWithOperator(); NodeInfo info = new NodeInfo() { NodeTyp = NodeType.DataBase, ConfigId = config.Id, DbIndex = dbIndex, Header = "db" + dbIndex }; item.Name = parent.Name + "_" + dbIndex; item.Header = "db" + dbIndex; item.NodeInfo = info; item.Margin = new Thickness(0, 2, 0, 2); item.FontWeight = FontWeights.Normal; item.UseOperation(new OperateType[] { OperateType.ADD, OperateType.REFRESH, OperateType.FLUSH }); item.Foreground = new SolidColorBrush(Colors.DarkBlue); item.ContextMenu = this.CreateDBContextMenu(info); item.MouseDoubleClick += DB_MouseDoubleClick; item.OnClear += TreeViewItem_Clear; item.OnRefresh += TreeViewItem_Refresh; item.OnAddKeyValue += Item_OnAddKeyValue; parent.Items.Add(item); }); } this.SetLog(this.tbLog, $"成功打开连接 {config.Name}({config.IP}:{config.Port})。"); } else { MessageBox.Show(result); this.SetLog(this.tbLog, $"打开连接 {config.Name}({config.IP}:{config.Port})失败。"); } this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Collapsed; }); } catch (Exception ex) { this.SetLog(this.tbLog, $"打开连接错误:{ex.Message}"); this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Collapsed; }); } }); } /// <summary> /// 创建键节点 /// </summary> /// <param name="parent">父节点。</param> /// <param name="keys">键集合。</param> private void CreateKeyNode(TreeViewItemWithOperator parent, List<string> keys) { NodeInfo nodeInfo = parent.NodeInfo; List<KeyInfo> keyInfos = this.ParseKeys(keys); foreach (KeyInfo info in keyInfos) { if (info.IsKey) //键节点 { TreeViewItemWithOperator keyItem = new TreeViewItemWithOperator(); NodeInfo keyNodeInfo = new NodeInfo() { NodeTyp = NodeType.Key, ConfigId = nodeInfo.ConfigId, Header = info.Header, DbIndex = nodeInfo.DbIndex, Key = info.Key }; keyItem.Header = info.Header; keyItem.NodeInfo = keyNodeInfo; keyItem.Margin = new Thickness(0, 2, 0, 2); keyItem.FontWeight = FontWeights.Normal; keyItem.UseOperation(new OperateType[] { OperateType.DELETE, OperateType.REFRESH }); keyItem.ContextMenu = this.CreateKeyContextMenu(keyNodeInfo); keyItem.MouseLeftButtonUp += KeyItem_MouseLeftButtonUp; keyItem.OnDelete += TreeViewItem_Delete; keyItem.OnRefresh += TreeViewItem_Refresh; parent.Items.Add(keyItem); } else //键文件夹节点 { TreeViewItemWithOperator item = new TreeViewItemWithOperator(); NodeInfo itemNodeInfo = new NodeInfo() { NodeTyp = NodeType.Folder, ConfigId = nodeInfo.ConfigId, Header = info.Header, DbIndex = nodeInfo.DbIndex, Key = info.Header }; item.Header = info.Header; item.NodeInfo = itemNodeInfo; item.Margin = new Thickness(0, 2, 0, 2); item.ContextMenu?.Items.Clear(); item.FontWeight = FontWeights.Normal; item.Foreground = new SolidColorBrush(Colors.Orange); item.UseOperation(new OperateType[] { OperateType.FLUSH, OperateType.REFRESH }); item.OnRefresh += TreeViewItem_Refresh; item.OnClear += TreeViewItem_Clear; item.ContextMenu = this.CreateKeyFolderContextMenu(itemNodeInfo); if (info.Keys != null && info.Keys.Count > 0) { foreach (KeyInfo key in info.Keys) { TreeViewItemWithOperator keyItem = new TreeViewItemWithOperator(); NodeInfo keyNodeInfo = new NodeInfo() { NodeTyp = NodeType.Key, ConfigId = nodeInfo.ConfigId, Header = key.Header, DbIndex = nodeInfo.DbIndex, Key = key.Key }; keyItem.Header = key.Header; keyItem.NodeInfo = keyNodeInfo; keyItem.Margin = new Thickness(0, 2, 0, 2); keyItem.FontWeight = FontWeights.Normal; keyItem.UseOperation(new OperateType[] { OperateType.DELETE, OperateType.REFRESH }); keyItem.ContextMenu = this.CreateKeyContextMenu(keyNodeInfo); keyItem.MouseLeftButtonUp += KeyItem_MouseLeftButtonUp; keyItem.OnRefresh += TreeViewItem_Refresh; keyItem.OnDelete += TreeViewItem_Clear; item.Items.Add(keyItem); } } parent.Items.Add(item); } } } /// <summary> /// 创建根节点右键菜单。 /// </summary> /// <param name="nodeInfo">节点信息。</param> /// <returns></returns> private ContextMenu CreateRootContextMenu(NodeInfo nodeInfo) { ContextMenu menu = new ContextMenu(); MenuItem itemOpen = new MenuItem(); itemOpen.Name = "MenuItem_Root_Open_" + nodeInfo.ConfigId; itemOpen.Tag = new NodeInfo() { ConfigId = nodeInfo.ConfigId, DbIndex = nodeInfo.DbIndex, Header = nodeInfo.Header, Key = nodeInfo.Key, OperateTyp = OperateType.OPEN }; itemOpen.Header = "打开"; itemOpen.Click += MenuItem_Root_Click; menu.Items.Add(itemOpen); MenuItem itemRefresh = new MenuItem(); itemRefresh.Name = "MenuItem_Root_Refresh_" + nodeInfo.ConfigId; itemRefresh.Tag = new NodeInfo() { ConfigId = nodeInfo.ConfigId, DbIndex = nodeInfo.DbIndex, Header = nodeInfo.Header, Key = nodeInfo.Key, OperateTyp = OperateType.REFRESH }; itemRefresh.Header = "刷新"; itemRefresh.Click += MenuItem_Root_Click; menu.Items.Add(itemRefresh); Separator separator1 = new Separator(); menu.Items.Add(separator1); MenuItem itemEdit = new MenuItem(); itemEdit.Name = "MenuItem_Root_Edit_" + nodeInfo.ConfigId; itemEdit.Tag = new NodeInfo() { ConfigId = nodeInfo.ConfigId, DbIndex = nodeInfo.DbIndex, Header = nodeInfo.Header, Key = nodeInfo.Key, OperateTyp = OperateType.EDIT }; itemEdit.Header = "编辑"; itemEdit.Click += MenuItem_Root_Click; menu.Items.Add(itemEdit); MenuItem itemDelete = new MenuItem(); itemDelete.Name = "MenuItem_Root_Delete_" + nodeInfo.ConfigId; itemDelete.Tag = new NodeInfo() { ConfigId = nodeInfo.ConfigId, DbIndex = nodeInfo.DbIndex, Header = nodeInfo.Header, Key = nodeInfo.Key, OperateTyp = OperateType.DELETE }; itemDelete.Header = "删除"; itemDelete.Click += MenuItem_Root_Click; menu.Items.Add(itemDelete); Separator separator2 = new Separator(); menu.Items.Add(separator2); MenuItem itemClose = new MenuItem(); itemClose.Name = "MenuItem_Root_Close_" + nodeInfo.ConfigId; itemClose.Tag = new NodeInfo() { ConfigId = nodeInfo.ConfigId, DbIndex = nodeInfo.DbIndex, Header = nodeInfo.Header, Key = nodeInfo.Key, OperateTyp = OperateType.CLOSE }; itemClose.Header = "关闭"; itemClose.Click += MenuItem_Root_Click; menu.Items.Add(itemClose); return menu; } /// <summary> /// 创建db(二级列表)的右键菜单。 /// </summary> /// <param name="nodeInfo">节点信息。</param> /// <returns></returns> private ContextMenu CreateDBContextMenu(NodeInfo nodeInfo) { ContextMenu menu = new ContextMenu(); MenuItem itemOpen = new MenuItem(); itemOpen.Name = "MenuItem_DB_Open_" + nodeInfo.ConfigId + "_" + nodeInfo.DbIndex; itemOpen.Tag = new NodeInfo() { ConfigId = nodeInfo.ConfigId, DbIndex = nodeInfo.DbIndex, Header = nodeInfo.Header, Key = nodeInfo.Key, OperateTyp = OperateType.OPEN }; itemOpen.Header = "打开"; itemOpen.Click += MenuItem_DB_Click; menu.Items.Add(itemOpen); MenuItem itemRefresh = new MenuItem(); itemRefresh.Name = "MenuItem_DB_Refresh_" + nodeInfo.ConfigId + "_" + nodeInfo.DbIndex; itemRefresh.Tag = new NodeInfo() { ConfigId = nodeInfo.ConfigId, DbIndex = nodeInfo.DbIndex, Header = nodeInfo.Header, Key = nodeInfo.Key, OperateTyp = OperateType.REFRESH }; itemRefresh.Header = "刷新"; itemRefresh.Click += MenuItem_DB_Click; menu.Items.Add(itemRefresh); MenuItem itemSearch = new MenuItem(); itemSearch.Name = "MenuItem_DB_Search_" + nodeInfo.ConfigId + "_" + nodeInfo.DbIndex; itemSearch.Tag = new NodeInfo() { ConfigId = nodeInfo.ConfigId, DbIndex = nodeInfo.DbIndex, Header = nodeInfo.Header, Key = nodeInfo.Key, OperateTyp = OperateType.SEARCH }; itemSearch.Header = "搜索"; itemSearch.Click += MenuItem_DB_Click; menu.Items.Add(itemSearch); Separator separator = new Separator(); menu.Items.Add(separator); MenuItem itemClose = new MenuItem(); itemClose.Name = "MenuItem_DB_Close_" + nodeInfo.ConfigId + "_" + nodeInfo.DbIndex; itemClose.Tag = new NodeInfo() { ConfigId = nodeInfo.ConfigId, DbIndex = nodeInfo.DbIndex, Header = nodeInfo.Header, Key = nodeInfo.Key, OperateTyp = OperateType.CLOSE }; itemClose.Header = "关闭"; itemClose.Click += MenuItem_DB_Click; menu.Items.Add(itemClose); separator = new Separator(); menu.Items.Add(separator); MenuItem itemDelete = new MenuItem(); itemDelete.Name = "MenuItem_DB_Flush_" + nodeInfo.ConfigId + "_" + nodeInfo.DbIndex; itemDelete.Tag = new NodeInfo() { ConfigId = nodeInfo.ConfigId, DbIndex = nodeInfo.DbIndex, Header = nodeInfo.Header, Key = nodeInfo.Key, OperateTyp = OperateType.FLUSH }; itemDelete.Header = "清空"; itemDelete.Click += MenuItem_DB_Click; menu.Items.Add(itemDelete); return menu; } /// <summary> /// 创建键文件夹的右键菜单。 /// </summary> /// <param name="nodeInfo">节点信息。</param> /// <returns></returns> private ContextMenu CreateKeyFolderContextMenu(NodeInfo nodeInfo) { ContextMenu menu = new ContextMenu(); MenuItem itemOpen = new MenuItem(); itemOpen.Name = "MenuItem_Key_Folder_Delete_" + nodeInfo.ConfigId; itemOpen.Tag = new NodeInfo() { ConfigId = nodeInfo.ConfigId, DbIndex = nodeInfo.DbIndex, Header = nodeInfo.Header, Key = nodeInfo.Key, OperateTyp = OperateType.DELETE }; itemOpen.Header = "删除"; itemOpen.Click += MenuItem_KeyFolder_Click; menu.Items.Add(itemOpen); return menu; } /// <summary> /// 创建键的右键菜单。 /// </summary> /// <param name="nodeInfo">节点信息</param> /// <returns></returns> private ContextMenu CreateKeyContextMenu(NodeInfo nodeInfo) { ContextMenu menu = new ContextMenu(); MenuItem itemOpen = new MenuItem(); itemOpen.Name = "MenuItem_Key_Delete_" + nodeInfo.ConfigId; itemOpen.Tag = new NodeInfo() { ConfigId = nodeInfo.ConfigId, DbIndex = nodeInfo.DbIndex, Header = nodeInfo.Header, Key = nodeInfo.Key, OperateTyp = OperateType.DELETE }; itemOpen.Header = "删除"; itemOpen.Click += MenuItem_Key_Click; menu.Items.Add(itemOpen); return menu; } /// <summary> /// 打开数据库节点。 /// </summary> /// <param name="nodeInfo"></param> /// <param name="item">子节点</param> private void OpenDB(NodeInfo nodeInfo, TreeViewItemWithOperator item) { Task.Factory.StartNew(() => { this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Visible; }); this.SetLog(this.tbLog, $"正在打开 {nodeInfo.Header} 数据库..."); List<string> keys = GlobalBusiness.RedisCaches[nodeInfo.ConfigId].GetAllKeys(nodeInfo.DbIndex); if (keys == null || keys.Count <= 0) { this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Collapsed; MessageBox.Show("该库没有任何数据!"); }); return; } this.Dispatcher.Invoke(() => { this.CreateKeyNode(item, keys); }); this.SetLog(this.tbLog, $"完成打开 {nodeInfo.Header} 数据库。"); this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Collapsed; }); }); } /// <summary> /// 解析键信息。 /// </summary> /// <param name="keys"></param> /// <returns></returns> private List<KeyInfo> ParseKeys(List<string> keys) { List<KeyInfo> keyInfos = new List<KeyInfo>(); foreach (string key in keys) { if (key.Contains(":")) { string[] strs = key.Split(':'); if (strs.Length > 1) { KeyInfo info = keyInfos.Find(p => p.Header.Equals(strs[0])); if (info == null) { info = new KeyInfo() { IsKey = false, Header = strs[0], Keys = new List<KeyInfo>() }; keyInfos.Add(info); } info.Keys.Add(new KeyInfo() { IsKey = true, Key = key, Header = key }); } } else { keyInfos.Add(new KeyInfo() { IsKey = true, Key = key, Header = key }); } } return keyInfos; } /// <summary> /// 设置日志内容。 /// </summary> /// <param name="tb">文本框控件。</param> /// <param name="log">日志内容。</param> private void SetLog(TextBox tb, string log) { tb.Dispatcher.Invoke(() => { tb.AppendText("[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "] " + log + Environment.NewLine); }); } /// <summary> /// 删除指定的键。 /// </summary> /// <param name="configId">配置id</param> /// <param name="dbIndex">redis的数据库索引</param> /// <param name="key">键</param> private void DeleteKey(string configId, int dbIndex, string key) { if (MessageBox.Show($"确定要删除 {key} 吗?", "删除提示", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { if (GlobalBusiness.RedisCaches[configId].Remove(key, dbIndex)) { TreeViewItemWithOperator parent = this.currentSelectedTreeViewItem.Parent as TreeViewItemWithOperator; parent.Items.Remove(this.currentSelectedTreeViewItem); this.tbKey.Clear(); this.ucRedisValue4String.Clear(); } } } /// <summary> /// 读取值。 /// </summary> /// <param name="nodeInfo"></param> private void ReadValue(NodeInfo nodeInfo) { Task.Factory.StartNew(() => { try { this.SetLog(this.tbLog, $"正在读取 {nodeInfo.Key} 的值..."); this.Dispatcher.Invoke(() => { this.ucRedisValue4String.Clear(); this.gridLoading.Visibility = Visibility.Visible; this.tbKey.Text = nodeInfo.Key; }); RedisValue redisValue = GlobalBusiness.RedisCaches[nodeInfo.ConfigId] .Get(nodeInfo.Key, nodeInfo.DbIndex); redisValue.ConfigId = nodeInfo.ConfigId; this.Dispatcher.Invoke(() => { this.tblockTTL.Text = redisValue.TTL.ToString(); switch (redisValue.Type) { case RedisKeyType.None: case RedisKeyType.String: { this.ucRedisValue4String.Visibility = Visibility.Visible; this.ucRedisValue4List.Visibility = Visibility.Collapsed; this.ucRedisValue4String.SetRedisValue(redisValue.Value); } break; case RedisKeyType.List: { this.ucRedisValue4String.Visibility = Visibility.Collapsed; this.ucRedisValue4List.Visibility = Visibility.Visible; this.ucRedisValue4List.SetDataGrid(redisValue, RedisValueUtil.CreateDataGrid4List()); this.ucRedisValue4List.ItemsSource = redisValue.List; } break; case RedisKeyType.Set: { this.ucRedisValue4String.Visibility = Visibility.Collapsed; this.ucRedisValue4List.Visibility = Visibility.Visible; this.ucRedisValue4List.SetDataGrid(redisValue, RedisValueUtil.CreateDataGrid4Set()); this.ucRedisValue4List.ItemsSource = redisValue.Set; } break; case RedisKeyType.SortedSet: { this.ucRedisValue4String.Visibility = Visibility.Collapsed; this.ucRedisValue4List.Visibility = Visibility.Visible; this.ucRedisValue4List.SetDataGrid(redisValue, RedisValueUtil.CreateDataGrid4Zset()); this.ucRedisValue4List.ItemsSource = redisValue.SortedSet; } break; case RedisKeyType.Hash: { this.ucRedisValue4String.Visibility = Visibility.Collapsed; this.ucRedisValue4List.Visibility = Visibility.Visible; this.ucRedisValue4List.SetDataGrid(redisValue, RedisValueUtil.CreateDataGrid4Hash()); this.ucRedisValue4List.ItemsSource = redisValue.Hash; } break; } }); this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Collapsed; }); this.SetLog(this.tbLog, $"完成读取 {nodeInfo.Key} 的值。"); } catch (Exception e) { this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Collapsed; }); this.SetLog(this.tbLog, $"完成读取 {nodeInfo.Key} 的值。(附加信息:{nodeInfo.Key} 的值不是合法的。{e.Message})"); } }); } /// <summary> /// 刷新数据库列表 /// </summary> private void RefreshRoot() { this.currentSelectedTreeViewItem.Items.Clear(); this.CreateDBNode(this.currentSelectedTreeViewItem); this.currentSelectedTreeViewItem.IsExpanded = true; } /// <summary> /// 刷新数据库。 /// </summary> /// <param name="nodeInfo"></param> private void RefreshDB(NodeInfo nodeInfo) { Task.Run(() => { this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Visible; }); List<string> keys = GlobalBusiness.RedisCaches[nodeInfo.ConfigId].GetAllKeys(nodeInfo.DbIndex); if (keys == null || keys.Count <= 0) { this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Collapsed; }); MessageBox.Show("该库没有任何数据!"); return; } this.Dispatcher.Invoke(() => { this.CreateKeyNode(this.currentSelectedTreeViewItem, keys); }); this.Dispatcher.Invoke(() => { this.currentSelectedTreeViewItem.IsExpanded = true; this.gridLoading.Visibility = Visibility.Collapsed; }); }); } /// <summary> /// 刷新键/键文件夹节点 /// </summary> /// <param name="nodeInfo"></param> private void RefreshKey(NodeInfo nodeInfo) { Task.Factory.StartNew(() => { try { this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Visible; }); this.Dispatcher.Invoke(() => { this.currentSelectedTreeViewItem.Items.Clear(); }); List<string> keys = GlobalBusiness.RedisCaches[nodeInfo.ConfigId].GetAllKeys(nodeInfo.DbIndex); this.Dispatcher.Invoke(() => { this.CreateKeyNode(this.currentSelectedTreeViewItem, keys); }); this.Dispatcher.Invoke(() => { this.currentSelectedTreeViewItem.IsExpanded = true; }); this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Collapsed; }); } catch (Exception ex) { this.SetLog(this.tbLog, $"刷新键出错。{ex.Message}"); } }); } /// <summary> /// 清空数据库。 /// </summary> /// <param name="nodeInfo"></param> private void FlushDB(NodeInfo nodeInfo) { if (MessageBox.Show("确定要清空当前数据库?", "提示", MessageBoxButton.YesNo) != MessageBoxResult.Yes) { return; } Task.Factory.StartNew(() => { this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Visible; }); GlobalBusiness.RedisCaches[nodeInfo.ConfigId].FlushDb(nodeInfo.DbIndex); this.Dispatcher.Invoke(() => { this.RefreshKey(nodeInfo); }); this.Dispatcher.Invoke(() => { this.gridLoading.Visibility = Visibility.Collapsed; }); }); } /// <summary> /// 清空键文件夹。 /// </summary> /// <param name="nodeInfo"></param> private void FlushKeyFolder(NodeInfo nodeInfo) { if (MessageBox.Show($"确定要删除 {nodeInfo.Key} 下所有的键吗?", "删除提示", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { this.SetLog(this.tbLog, $"正在批量删除 {nodeInfo.Key} 下所有的键..."); //删除下级所有的键 IList<string> keys = new List<string>(); foreach (TreeViewItemWithOperator item in this.currentSelectedTreeViewItem.Items) { keys.Add(item.NodeInfo.Key); } GlobalBusiness.RedisCaches[nodeInfo.ConfigId].RemoveAll(keys, nodeInfo.DbIndex); TreeViewItemWithOperator parent = this.currentSelectedTreeViewItem.Parent as TreeViewItemWithOperator; parent.Items.Remove(this.currentSelectedTreeViewItem); } } /// <summary> /// 执行操作。 /// </summary> /// <param name="nodeInfo">节点信息。</param> private void Operate(NodeInfo nodeInfo) { if (nodeInfo == null) { return; } ConnectionConfig config = GlobalBusiness.DictConnectionConfig[nodeInfo.ConfigId]; if (OperateType.OPEN.Equals(nodeInfo.OperateTyp)) { if (this.currentSelectedTreeViewItem.HasItems) { return; } this.CreateDBNode(this.currentSelectedTreeViewItem); this.currentSelectedTreeViewItem.IsExpanded = true; return; } if (OperateType.REFRESH.Equals(nodeInfo.OperateTyp)) { this.RefreshRoot(); return; } if (OperateType.EDIT.Equals(nodeInfo.OperateTyp)) { if (this.currentSelectedTreeViewItem.HasItems && MessageBox.Show("该操作将关闭连接!是否继续?", "操作提示", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { this.currentSelectedTreeViewItem.Items.Clear(); } WinAddConnection winAddConnection = new WinAddConnection(nodeInfo.ConfigId, ConfigOperationType.EDIT); winAddConnection.SavedConnectionConfig += this.WinAddConnection_SavedConnectionConfig; winAddConnection.ShowDialog(); winAddConnection.SavedConnectionConfig -= this.WinAddConnection_SavedConnectionConfig; return; } if (OperateType.DELETE.Equals(nodeInfo.OperateTyp)) { if (MessageBox.Show($"确定删除{config.Name}连接配置吗?", "删除提示", MessageBoxButton.OKCancel) == MessageBoxResult.OK) { TreeView tree = this.currentSelectedTreeViewItem.Parent as TreeView; this.gridRedisList.Children.Remove(tree); GlobalBusiness.RemoveConfig(config.Id); } return; } if (OperateType.CLOSE.Equals(nodeInfo.OperateTyp)) { this.tbKey.Clear(); this.tblockTTL.Text = "0"; this.ucRedisValue4String.Clear(); this.currentSelectedTreeViewItem.Items.Clear(); this.currentSelectedTreeViewItem.IsExpanded = false; return; } } #endregion #region 委托方法 /// <summary> /// 当连接信息保存完毕时发生。 /// </summary> /// <param name="config">连接配置信息。</param> /// <param name="crudType">操作类型。</param> private void WinAddConnection_SavedConnectionConfig(ConnectionConfig config, ConfigOperationType crudType) { if (crudType == ConfigOperationType.ADD) { TreeView tree = this.CreateRootNode(config); this.gridRedisList.Children.Add(tree); } else if (crudType == ConfigOperationType.EDIT) { this.currentSelectedTreeViewItem.Items.Clear(); this.currentSelectedTreeViewItem.NodeInfo = new NodeInfo() { ConfigId = config.Id, Header = config.Name }; this.currentSelectedTreeViewItem.Header = config.Name; } } /// <summary> /// 当键重命名完成时发生。 /// </summary> /// <param name="newKey"></param> private void WinRenameKey_OnUpdatedKey(string newKey) { this.currentSelectedTreeViewItem.Header = newKey; NodeInfo nodeInfo = this.currentSelectedTreeViewItem.NodeInfo; nodeInfo.Header = newKey; nodeInfo.Key = newKey; } /// <summary> /// 当其它窗口业务出现错误是发生。 /// </summary> /// <param name="message"></param> private void Win_OnError(string message) { this.SetLog(this.tbLog, message); } #endregion #region 本地事件 /// <summary> /// 当窗口加载完成时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MainWindow_Loaded(object sender, RoutedEventArgs e) { this.InitTree(); } private void MainWindow_Closing(object sender, CancelEventArgs e) { string pathConfig = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "app.ini"); if (this.WindowState == WindowState.Minimized) { this.WindowState = WindowState.Normal; } IniUtil.WriteINI(pathConfig, "Window", "WindowState", this.WindowState.ToString()); IniUtil.WriteINI(pathConfig, "Window", "Width", this.Width.ToString()); IniUtil.WriteINI(pathConfig, "Window", "Height", this.Height.ToString()); } /// <summary> /// 当时鼠标点击“刷新”按钮时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BtnReload_Click(object sender, RoutedEventArgs e) { this.gridRedisList.Children.Clear(); this.InitTree(); } /// <summary> /// 当鼠标在点按下并释放时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Node_MouseUp(object sender, MouseButtonEventArgs e) { this.currentSelectedTreeViewItem = e.Source as TreeViewItemWithOperator; this.currentSelectedTreeViewItem.IsSelected = true; } /// <summary> /// 当鼠标点击树形列表右键菜单的选项时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuItem_Root_Click(object sender, RoutedEventArgs e) { MenuItem item = sender as MenuItem; NodeInfo nodeInfo = item.Tag as NodeInfo; this.Operate(nodeInfo); } /// <summary> /// 当鼠标点击树形列表右键菜单的选项时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuItem_DB_Click(object sender, RoutedEventArgs e) { MenuItem item = sender as MenuItem; NodeInfo nodeInfo = item.Tag as NodeInfo; if (OperateType.OPEN.Equals(nodeInfo.OperateTyp)) { if (this.currentSelectedTreeViewItem.HasItems) { return; } this.RefreshDB(nodeInfo); } if (OperateType.REFRESH.Equals(nodeInfo.OperateTyp)) { this.RefreshKey(nodeInfo); } if (OperateType.SEARCH.Equals(nodeInfo.OperateTyp)) { WinSearchKey winSearchKey = new WinSearchKey(nodeInfo.ConfigId, nodeInfo.DbIndex); winSearchKey.OnError += this.Win_OnError; winSearchKey.ShowDialog(); winSearchKey.OnError -= this.Win_OnError; } if (OperateType.CLOSE.Equals(nodeInfo.OperateTyp)) { } if (OperateType.FLUSH.Equals(nodeInfo.OperateTyp)) { this.FlushDB(nodeInfo); } } /// <summary> /// 当鼠标点击树形列表右键菜单的选项时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuItem_KeyFolder_Click(object sender, RoutedEventArgs e) { MenuItem menuItem = sender as MenuItem; NodeInfo nodeInfo = menuItem.Tag as NodeInfo; try { this.FlushKeyFolder(nodeInfo); } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { this.SetLog(this.tbLog, $"完成批量删除 {nodeInfo.Key} 下所有的键。"); } } /// <summary> /// 当鼠标点击树形列表右键菜单的选项时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuItem_Key_Click(object sender, RoutedEventArgs e) { MenuItem item = sender as MenuItem; NodeInfo nodeInfo = item.Tag as NodeInfo; this.DeleteKey(nodeInfo.ConfigId, nodeInfo.DbIndex, nodeInfo.Key); } /// <summary> /// 当鼠标双击根节点时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Root_MouseDoubleClick(object sender, MouseButtonEventArgs e) { TreeViewItemWithOperator item = sender as TreeViewItemWithOperator; if (item.HasItems) { return; } this.CreateDBNode(item); } /// <summary> /// 当鼠标双击DB节点时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DB_MouseDoubleClick(object sender, MouseButtonEventArgs e) { TreeViewItemWithOperator item = sender as TreeViewItemWithOperator; if (item.HasItems) { return; } this.OpenDB(item.NodeInfo, item); } /// <summary> /// 当鼠标在键的菜单项点下并释放按钮后发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void KeyItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { TreeViewItemWithOperator item = sender as TreeViewItemWithOperator; NodeInfo nodeInfo = item.NodeInfo; if (nodeInfo == null) { return; } if (string.Compare(nodeInfo.Key, this.tbKey.Text) == 0) { return; } this.ReadValue(nodeInfo); } /// <summary> /// 当鼠标点击菜单项的清空按钮时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void TreeViewItem_Clear(object sender, RoutedEventArgs e) { NodeInfo nodeInfo = e.Source as NodeInfo; switch (nodeInfo.NodeTyp) { case NodeType.DataBase: this.FlushDB(nodeInfo); break; case NodeType.Folder: this.FlushKeyFolder(nodeInfo); break; } } /// <summary> /// 当鼠标点击附加功能的删除按钮时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void TreeViewItem_Delete(object sender, RoutedEventArgs e) { NodeInfo nodeInfo = e.Source as NodeInfo; nodeInfo.OperateTyp = OperateType.DELETE; if (nodeInfo.NodeTyp == NodeType.Connection) { this.Operate(nodeInfo); return; } if (nodeInfo.NodeTyp == NodeType.Key) { this.DeleteKey(nodeInfo.ConfigId, nodeInfo.DbIndex, nodeInfo.Key); } } /// <summary> /// 当鼠标点击附加功能的添加按钮时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Item_OnAddKeyValue(object sender, RoutedEventArgs e) { NodeInfo nodeInfo = e.Source as NodeInfo; WinAddKey winAddKey = new WinAddKey(nodeInfo); winAddKey.OnAdded += (_key) => { this.CreateKeyNode(this.currentSelectedTreeViewItem, new List<string>() { _key }); }; winAddKey.ShowDialog(); } /// <summary> /// 当鼠标点击附加功能的刷新按钮时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void TreeViewItem_Refresh(object sender, RoutedEventArgs e) { NodeInfo nodeInfo = e.Source as NodeInfo; switch (nodeInfo.NodeTyp) { case NodeType.Connection: this.RefreshRoot(); break; case NodeType.DataBase: this.RefreshKey(nodeInfo); break; case NodeType.Folder: break; case NodeType.Key: this.ReadValue(nodeInfo); break; } } /// <summary> /// 当鼠标点击添加按钮时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BtnAdd_Click(object sender, RoutedEventArgs e) { WinAddConnection winAddConnection = new WinAddConnection(ConfigOperationType.ADD); winAddConnection.SavedConnectionConfig += this.WinAddConnection_SavedConnectionConfig; winAddConnection.ShowDialog(); winAddConnection.SavedConnectionConfig -= this.WinAddConnection_SavedConnectionConfig; } /// <summary> /// 当日志文本框内容变化时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void TbLog_TextChanged(object sender, TextChangedEventArgs e) { this.tbLog.ScrollToEnd(); } /// <summary> /// 当鼠标点击重命名按钮时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BtnRenameKey_Click(object sender, RoutedEventArgs e) { if (string.IsNullOrWhiteSpace(this.tbKey.Text.Trim())) { return; } NodeInfo nodeInfo = this.currentSelectedTreeViewItem.NodeInfo; WinRenameKey winRenameKey = new WinRenameKey(nodeInfo.ConfigId, nodeInfo.DbIndex, nodeInfo.Key); winRenameKey.OnUpdatedKey += WinRenameKey_OnUpdatedKey; winRenameKey.ShowDialog(); winRenameKey.OnUpdatedKey -= WinRenameKey_OnUpdatedKey; } /// <summary> /// 当鼠标点击删除按钮时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BtnDeleteKey_Click(object sender, RoutedEventArgs e) { NodeInfo nodeInfo = this.currentSelectedTreeViewItem.NodeInfo; this.DeleteKey(nodeInfo.ConfigId, nodeInfo.DbIndex, nodeInfo.Key); } /// <summary> /// 当鼠标点击刷新按钮时发生。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BtnRefresh_Click(object sender, RoutedEventArgs e) { NodeInfo nodeInfo = this.currentSelectedTreeViewItem.NodeInfo; this.ReadValue(nodeInfo); } #endregion } }