36 Commits

Author SHA1 Message Date
tdx d3587a16f1 chore(browser): sync current working implementation
Rollback tag: pre-current-browser-sync-20260818
2026-08-18 14:30:23 +08:00
tdx 6b78bbbf04 fix: 恢复 ModuleGridEx 组件容器管理 2026-08-15 22:37:07 +08:00
cyf 57dedb5e9d feat: 新增时间输入和Alt按钮快捷键 2026-08-15 22:26:11 +08:00
tdx a65dfab897 fix: synchronize module data cache cleanup 2026-08-15 18:39:26 +08:00
tdx d098dde830 chore(report): 清理临时资源诊断代码 2026-08-15 16:37:10 +08:00
tdx ef13d46fa2 Merge branch 'main' of http://192.168.0.7:4133/cyf/lserp_cs_6.0 2026-08-15 16:35:25 +08:00
tdx fc5faab65d fix(control): 修复金额单元格关闭阶段异常 2026-08-15 16:00:10 +08:00
cyf b091eca540 feat: 更新控件及表格功能 2026-08-15 14:42:21 +08:00
tdx 7d8ad77f5c merge: 合并初始化缓存与资源释放优化 2026-08-15 11:39:58 +08:00
tdx f72b153eb6 fix(pubbill): 恢复主表格界面布局 2026-08-15 10:30:58 +08:00
tdx c49015d390 fix: 收敛旧模块资源释放与诊断 2026-08-15 10:13:08 +08:00
cyf f665688d0b feat: 优化初始化缓存及控件功能 2026-08-14 20:33:43 +08:00
tdx 222ae3c08a feat: support BS menu opening mode 2026-08-12 17:53:50 +08:00
tdx a803070819 远望上传,个税代码调整 2026-08-11 14:18:01 +08:00
tdx a9c986f9d5 fix: 收敛旧控件资源与后台线程生命周期 2026-08-11 14:12:18 +08:00
tdx f1ce6ff658 fix: 优化左侧菜单高度与悬浮状态 2026-08-10 17:12:40 +08:00
tdx f92fd2f1cc feat: 将主页左侧菜单迁移到 TreeList 2026-08-10 17:12:40 +08:00
cyf 000a69ce15 feat: 更新业务、控件及单据功能 2026-08-10 09:59:46 +08:00
tdx c07220bbf0 fix: 保留未处理异常原始堆栈 2026-08-09 11:33:20 +08:00
tdx 219caba818 fix: optimize large file chunk upload stability 2026-08-06 18:02:11 +08:00
tdx 031fc34f12 fix_WPF_switch_user_main_loop_conflict 2026-08-05 17:27:47 +08:00
cyf 66cab000ea feat: 更新控件及相关业务功能 2026-08-04 13:49:05 +08:00
tdx 4fe8844e86 fix(control): use contains filtering in extended lookup 2026-07-31 14:00:51 +08:00
tdx d71657bcb2 docs: plan contains filtering for extended lookup 2026-07-31 13:56:06 +08:00
tdx a644184078 docs: design contains filtering for extended lookup 2026-07-31 13:51:13 +08:00
tdx 250f65b3d0 fix(core): enable SQL Server idle connection recovery 2026-07-31 11:33:13 +08:00
tdx 004778f2a8 feat(control): add grid extended lookup column search 2026-07-31 10:38:40 +08:00
tdx e06a67f002 feat(control): add form extended lookup column search 2026-07-31 10:35:25 +08:00
tdx 2acae8551f feat(control): add extended lookup filter UI 2026-07-31 10:32:29 +08:00
tdx 7e819b44b7 feat(control): support selected extended search columns 2026-07-31 10:30:15 +08:00
tdx c5b6466fab docs: plan extended return search filters 2026-07-31 10:21:55 +08:00
tdx 5c4682bbbd docs: design extended return search filters 2026-07-31 10:13:14 +08:00
SugarChes cc9bd1f0d1 fix(browser): accept nested values in row callbacks 2026-07-30 15:08:01 +08:00
SugarChes 5e6449cf1f fix(util): preserve complex JSON values in data tables 2026-07-30 15:01:56 +08:00
SugarChes 11e395aa0f docs: plan browser JSON complex field compatibility 2026-07-30 14:49:39 +08:00
SugarChes 79399b0ef4 docs: design browser JSON complex field compatibility 2026-07-30 14:40:04 +08:00
125 changed files with 10351 additions and 1762 deletions
@@ -0,0 +1,478 @@
# 浏览器 JSON 复杂字段兼容 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 让旧 WinForms 浏览器桥接能够把任意对象或数组字段保留为紧凑 JSON 字符串,并继续安全转换为 `DataTable`
**Architecture:**`Lskj.Util.JsonUtil` 增加一个只供明确调用方选用的转换入口:先扫描整批 JSON 行,确定复杂列,再把这些列统一字符串化,最后复用 Newtonsoft.Json 原有 `DataTableConverter``Lskj.Control` 只在网页右键和返回行两个边界调用新入口,其他 JSON 转换和 WPF 宿主保持不变。
**Tech Stack:** .NET Framework 4.0、C# 7.3、Newtonsoft.Json 13.0.1、`System.Data.DataTable`、MSBuild、无第三方测试框架的控制台回归测试程序。
## Global Constraints
- 保留对象和数组字段,不删除 `$styles` 或其他未来字段。
- 复杂值必须转换成无缩进的紧凑 JSON 字符串。
- 从未出现对象或数组的标量列继续使用现有 Newtonsoft.Json 类型推断。
- 不修改现有 `JsonUtil.ToDataTable``JsonUtil.ToDataRow` 的语义。
- 不修改全局 Newtonsoft.Json 设置,不替换项目中的其他 `DeserializeObject<DataTable>` 调用。
- 不修改 WPF、数据库、菜单查找、参数替换或 DLL 加载逻辑。
- 只接入 `BsOpenModuleHandler.OpenRightModule``BsOpenModuleHandler.AddReturnRow`
- 现有两个目标源码文件只有 CRLF/LF 换行差异;执行前必须确认没有语义差异,再机械归一化,避免产生整文件噪声提交。
---
### Task 1: 建立回归测试并实现公共转换器
**Files:**
- Create: `插件库/Lskj.Util.Tests/Lskj.Util.Tests.csproj`
- Create: `插件库/Lskj.Util.Tests/Program.cs`
- Modify: `插件库/Lskj.Util/JsonUtil.cs:1-190`
**Interfaces:**
- Consumes: Newtonsoft.Json `JToken``JArray``JObject` 和现有 `DataTableConverter`
- Produces: `public static DataTable JsonUtil.ToDataTablePreservingComplexValues(string json)`;接受顶层对象或对象数组,返回保留所有字段的 `DataTable`
- [ ] **Step 1: 确认目标源码没有未提交的语义改动**
Run:
```bash
git diff --ignore-space-at-eol --exit-code -- \
'插件库/Lskj.Util/JsonUtil.cs' \
'插件库/Lskj.Control/BrowserSetting/BsOpenModuleHandler.cs'
```
Expected: exit code `0`,无输出。当前普通 `git diff --numstat` 显示的是 CRLF/LF 差异,不代表业务代码变化。
- [ ] **Step 2: 机械归一化两个目标源码的换行符**
只有 Step 1 成功后执行:
```bash
perl -pi -e 's/\r$//' \
'插件库/Lskj.Util/JsonUtil.cs' \
'插件库/Lskj.Control/BrowserSetting/BsOpenModuleHandler.cs'
git diff --check -- \
'插件库/Lskj.Util/JsonUtil.cs' \
'插件库/Lskj.Control/BrowserSetting/BsOpenModuleHandler.cs'
```
Expected: `git diff --check` 无输出;此时两个文件不再显示整文件换行差异。
- [ ] **Step 3: 创建不依赖测试框架的回归测试项目**
Create `插件库/Lskj.Util.Tests/Lskj.Util.Tests.csproj`:
```xml
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8E501869-816F-4E3E-81EE-A3BF9C223D61}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Lskj.Util.Tests</RootNamespace>
<AssemblyName>Lskj.Util.Tests</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<OutputPath>bin\Debug\</OutputPath>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="Newtonsoft.Json, Version=13.0.1.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\引用DLL\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Lskj.Util\Lskj.Util.csproj">
<Project>{A51BF642-6543-4DE3-8948-83F558B72BD4}</Project>
<Name>Lskj.Util</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
```
Create `插件库/Lskj.Util.Tests/Program.cs`:
```csharp
using Lskj.Util;
using Newtonsoft.Json;
using System;
using System.Data;
namespace Lskj.Util.Tests
{
internal static class Program
{
private static int Main()
{
try
{
PreservesStylesObjectAsCompactJson();
PreservesArrayAsCompactJson();
NormalizesEveryValueInAMixedComplexColumn();
LeavesScalarColumnsEquivalentToExistingConverter();
AcceptsSingleObject();
RejectsInvalidTopLevelValues();
Console.WriteLine("PASS: JsonUtil complex-value conversion tests");
return 0;
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
return 1;
}
}
private static void PreservesStylesObjectAsCompactJson()
{
const string json = "[{\"id\":1,\"$styles\":{\"rowstyle\":\"{color:'#FFFF00','background-color':'#FF0000'}\"}}]";
DataTable table = JsonUtil.ToDataTablePreservingComplexValues(json);
AssertEqual(1, table.Rows.Count, "styles row count");
AssertEqual("{\"rowstyle\":\"{color:'#FFFF00','background-color':'#FF0000'}\"}",
table.Rows[0]["$styles"].ToString(), "styles JSON");
}
private static void PreservesArrayAsCompactJson()
{
const string json = "[{\"id\":1,\"items\":[{\"code\":\"A\"},{\"code\":\"B\"}]}]";
DataTable table = JsonUtil.ToDataTablePreservingComplexValues(json);
AssertEqual("[{\"code\":\"A\"},{\"code\":\"B\"}]",
table.Rows[0]["items"].ToString(), "array JSON");
}
private static void NormalizesEveryValueInAMixedComplexColumn()
{
const string json = "["
+ "{\"id\":1,\"payload\":5},"
+ "{\"id\":2,\"payload\":{\"code\":\"A\"}},"
+ "{\"id\":3,\"payload\":[1,2]},"
+ "{\"id\":4,\"payload\":null},"
+ "{\"id\":5,\"payload\":\"ready\"}]";
DataTable table = JsonUtil.ToDataTablePreservingComplexValues(json);
AssertEqual(typeof(string), table.Columns["payload"].DataType, "mixed column type");
AssertEqual("5", table.Rows[0]["payload"].ToString(), "numeric scalar text");
AssertEqual("{\"code\":\"A\"}", table.Rows[1]["payload"].ToString(), "object text");
AssertEqual("[1,2]", table.Rows[2]["payload"].ToString(), "array text");
AssertTrue(table.Rows[3].IsNull("payload"), "null remains null");
AssertEqual("ready", table.Rows[4]["payload"].ToString(), "string remains string");
}
private static void LeavesScalarColumnsEquivalentToExistingConverter()
{
const string json = "[{\"id\":1,\"title\":\"A\",\"active\":true},{\"id\":2,\"title\":\"B\",\"active\":false}]";
DataTable expected = JsonConvert.DeserializeObject<DataTable>(json);
DataTable actual = JsonUtil.ToDataTablePreservingComplexValues(json);
AssertEqual(expected.Columns.Count, actual.Columns.Count, "scalar column count");
AssertEqual(expected.Rows.Count, actual.Rows.Count, "scalar row count");
foreach (DataColumn column in expected.Columns)
{
AssertEqual(column.DataType, actual.Columns[column.ColumnName].DataType,
"scalar column type " + column.ColumnName);
for (int rowIndex = 0; rowIndex < expected.Rows.Count; rowIndex++)
{
AssertEqual(expected.Rows[rowIndex][column.ColumnName],
actual.Rows[rowIndex][column.ColumnName],
"scalar value " + column.ColumnName + " row " + rowIndex);
}
}
}
private static void AcceptsSingleObject()
{
const string json = "{\"ProductId\":\"P001\",\"meta\":{\"source\":\"web\"}}";
DataTable table = JsonUtil.ToDataTablePreservingComplexValues(json);
AssertEqual(1, table.Rows.Count, "single object row count");
AssertEqual("P001", table.Rows[0]["ProductId"].ToString(), "single object scalar");
AssertEqual("{\"source\":\"web\"}", table.Rows[0]["meta"].ToString(), "single object nested JSON");
}
private static void RejectsInvalidTopLevelValues()
{
AssertThrows<ArgumentException>(delegate { JsonUtil.ToDataTablePreservingComplexValues(" "); }, "empty input");
AssertThrows<JsonReaderException>(delegate { JsonUtil.ToDataTablePreservingComplexValues("{"); }, "invalid JSON");
AssertThrows<JsonSerializationException>(delegate { JsonUtil.ToDataTablePreservingComplexValues("[1]"); }, "non-object row");
}
private static void AssertThrows<TException>(Action action, string name) where TException : Exception
{
try { action(); }
catch (TException) { return; }
throw new InvalidOperationException("Expected " + typeof(TException).Name + ": " + name);
}
private static void AssertTrue(bool value, string name)
{
if (!value) throw new InvalidOperationException("Assertion failed: " + name);
}
private static void AssertEqual<T>(T expected, T actual, string name)
{
if (!object.Equals(expected, actual))
{
throw new InvalidOperationException(name + ": expected <" + expected + ">, actual <" + actual + ">");
}
}
}
}
```
- [ ] **Step 4: 构建测试项目并确认它先失败**
Run in Windows PowerShell from `E:\lserp_project\lserp_cs_6.0`:
```powershell
$msbuild = Get-ChildItem "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\*\MSBuild\Current\Bin\MSBuild.exe" |
Select-Object -First 1 -ExpandProperty FullName
if (-not $msbuild) { $msbuild = "$env:WINDIR\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" }
& $msbuild "插件库\Lskj.Util.Tests\Lskj.Util.Tests.csproj" /t:Rebuild /p:Configuration=Debug /p:Platform=AnyCPU
```
Expected: build fails with `CS0117` because `JsonUtil.ToDataTablePreservingComplexValues` does not exist yet. Dependency or SDK errors do not satisfy this step。
- [ ] **Step 5: 实现复杂字段归一化方法**
Add `using System.Globalization;` to `插件库/Lskj.Util/JsonUtil.cs`, then add this method to `JsonUtil` without changing existing methods:
```csharp
public static DataTable ToDataTablePreservingComplexValues(string json)
{
if (string.IsNullOrWhiteSpace(json))
{
throw new ArgumentException("网页行 JSON 不能为空。", "json");
}
JToken root = JToken.Parse(json);
JArray rows;
if (root.Type == JTokenType.Array)
{
rows = (JArray)root;
}
else if (root.Type == JTokenType.Object)
{
rows = new JArray(root);
}
else
{
throw new JsonSerializationException("网页行 JSON 的顶层必须是对象或对象数组。");
}
HashSet<string> complexColumns = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (JToken rowToken in rows)
{
if (rowToken.Type != JTokenType.Object)
{
throw new JsonSerializationException("网页行 JSON 数组中的每一项都必须是对象。");
}
foreach (JProperty property in ((JObject)rowToken).Properties())
{
if (property.Value.Type == JTokenType.Object || property.Value.Type == JTokenType.Array)
{
complexColumns.Add(property.Name);
}
}
}
foreach (JObject row in rows.Children<JObject>())
{
foreach (JProperty property in row.Properties().ToList())
{
if (!complexColumns.Contains(property.Name)
|| property.Value.Type == JTokenType.Null
|| property.Value.Type == JTokenType.Undefined)
{
continue;
}
string text;
if (property.Value.Type == JTokenType.Object || property.Value.Type == JTokenType.Array)
{
text = property.Value.ToString(Formatting.None);
}
else if (property.Value.Type == JTokenType.String)
{
text = property.Value.Value<string>();
}
else
{
JValue scalar = property.Value as JValue;
text = scalar == null || scalar.Value == null
? null
: Convert.ToString(scalar.Value, CultureInfo.InvariantCulture);
}
property.Value = text == null ? JValue.CreateNull() : new JValue(text);
}
}
return JsonConvert.DeserializeObject<DataTable>(rows.ToString(Formatting.None));
}
```
- [ ] **Step 6: 构建并运行转换级回归测试**
```powershell
& $msbuild "插件库\Lskj.Util.Tests\Lskj.Util.Tests.csproj" /t:Rebuild /p:Configuration=Debug /p:Platform=AnyCPU
if ($LASTEXITCODE -ne 0) { throw "Lskj.Util.Tests build failed" }
& "插件库\Lskj.Util.Tests\bin\Debug\Lskj.Util.Tests.exe"
if ($LASTEXITCODE -ne 0) { throw "Lskj.Util.Tests failed" }
```
Expected: build succeeds and executable prints `PASS: JsonUtil complex-value conversion tests`.
- [ ] **Step 7: 提交公共转换器和回归测试**
```bash
git add \
'插件库/Lskj.Util/JsonUtil.cs' \
'插件库/Lskj.Util.Tests/Lskj.Util.Tests.csproj' \
'插件库/Lskj.Util.Tests/Program.cs'
git diff --cached --check
git commit -m 'fix(util): preserve complex JSON values in data tables'
```
Expected: commit only contains the new test project and the focused `JsonUtil` method.
---
### Task 2: 在旧浏览器桥接的两个入口接入转换器
**Files:**
- Modify: `插件库/Lskj.Control/BrowserSetting/BsOpenModuleHandler.cs:101-116`
- Modify: `插件库/Lskj.Control/BrowserSetting/BsOpenModuleHandler.cs:322-334`
**Interfaces:**
- Consumes: `JsonUtil.ToDataTablePreservingComplexValues(string json)` from Task 1。
- Produces: `OpenRightModule``AddReturnRow` 对任意对象/数组字段的兼容行为;其他菜单及模块调用接口不变。
- [ ] **Step 1: 将右键入口切换到公共转换器**
Replace:
```csharp
DataTable dataTable = JsonConvert.DeserializeObject<DataTable>(arrayItem);
```
with:
```csharp
DataTable dataTable = JsonUtil.ToDataTablePreservingComplexValues(arrayItem);
```
Do not change the `BaseImpl.GetDataRowResult` query, `GridRightMenuModel`, `DynamicModel` or `menu.ExecRightMenu` calls.
- [ ] **Step 2: 将网页返回行入口切换到公共转换器并删除冗余包装**
Replace:
```csharp
JObject rowObject = JsonConvert.DeserializeObject<JObject>(rowdata);
JArray jArray = new JArray();
jArray.Add(rowObject);
DataTable dataTable = JsonConvert.DeserializeObject<DataTable>(JsonConvert.SerializeObject(jArray));
```
with:
```csharp
DataTable dataTable = JsonUtil.ToDataTablePreservingComplexValues(rowdata);
```
Remove the now-unused `using Newtonsoft.Json;` and `using Newtonsoft.Json.Linq;`. Keep product-prefix renaming and `StaticControl.ReturnRowLisy.Add` unchanged.
- [ ] **Step 3: 静态检查浏览器桥接范围**
```bash
rg -n 'DeserializeObject\s*<\s*DataTable\s*>|ToDataTablePreservingComplexValues' \
'插件库/Lskj.Control/BrowserSetting/BsOpenModuleHandler.cs'
git diff --check -- '插件库/Lskj.Control/BrowserSetting/BsOpenModuleHandler.cs'
```
Expected: only two `ToDataTablePreservingComplexValues` calls remain in this file;没有直接的 `DeserializeObject<DataTable>`,且 `git diff --check` 无输出。
- [ ] **Step 4: 重跑转换级测试并构建 Lskj.Control**
```powershell
& "插件库\Lskj.Util.Tests\bin\Debug\Lskj.Util.Tests.exe"
if ($LASTEXITCODE -ne 0) { throw "Lskj.Util.Tests failed" }
& $msbuild "插件库\Lskj.Control\Lskj.Control.csproj" /t:Rebuild /p:Configuration=Debug /p:Platform=AnyCPU
if ($LASTEXITCODE -ne 0) { throw "Lskj.Control build failed" }
```
Expected: tests print `PASS``Lskj.Control` build succeeds without new warnings or errors and refreshes `Debug\Lskj.Control.dll` plus referenced `Lskj.Util.dll`.
- [ ] **Step 5: 提交浏览器桥接改动**
```bash
git add '插件库/Lskj.Control/BrowserSetting/BsOpenModuleHandler.cs'
git diff --cached --check
git commit -m 'fix(browser): accept nested values in row callbacks'
```
Expected: commit only changes the two intended browser callback conversions and removes the two unused Newtonsoft `using` directives.
---
### Task 3: 最终构建与业务验收交接
**Files:**
- Verify: `Debug/Lskj.Util.dll`
- Verify: `Debug/Lskj.Control.dll`
- Verify: `Debug/Ls_NERP.exe`
**Interfaces:**
- Consumes: Task 1 的转换器和 Task 2 的浏览器接入。
- Produces: 可由用户分别从旧 WinForms 和 WPF 宿主进行验收的 Debug 运行目录。
- [ ] **Step 1: 执行最终自动验证**
```powershell
& $msbuild "插件库\Lskj.Util.Tests\Lskj.Util.Tests.csproj" /t:Rebuild /p:Configuration=Debug /p:Platform=AnyCPU
if ($LASTEXITCODE -ne 0) { throw "Lskj.Util.Tests build failed" }
& "插件库\Lskj.Util.Tests\bin\Debug\Lskj.Util.Tests.exe"
if ($LASTEXITCODE -ne 0) { throw "Lskj.Util.Tests failed" }
& $msbuild "插件库\Lskj.Control\Lskj.Control.csproj" /t:Rebuild /p:Configuration=Debug /p:Platform=AnyCPU
if ($LASTEXITCODE -ne 0) { throw "Lskj.Control build failed" }
Get-Item "Debug\Lskj.Util.dll", "Debug\Lskj.Control.dll" |
Select-Object FullName, Length, LastWriteTime
```
Expected: both builds succeed, test executable prints `PASS`, and both runtime DLL timestamps reflect the current build.
- [ ] **Step 2: 核对最终差异和提交历史**
```bash
git diff --check
git status --short
git log -4 --oneline --decorate
```
Expected: no uncommitted implementation changes;历史包含设计提交、公共转换器提交和浏览器桥接提交。构建输出和原有忽略文件不应进入 Git。
- [ ] **Step 3: 交给用户执行业务验收**
Provide this exact checklist:
```text
1. 从 WPF 宿主启动,进入同一待办任务页面并点击“待办任务”。
2. 确认不再出现 Path '[0].$styles' / StartObject 的 DataTable 反序列化错误。
3. 确认右键配置继续解析到 PUR_4004,并正常进入原有客户端模块加载流程。
4. 使用一个不包含对象/数组字段的旧网页右键功能,确认行为未变化。
5. 如可用,再从旧 WinForms 入口重复步骤 1-4,确认两个宿主行为一致。
6. 验证网页返回行功能,确认 ProductId 前缀和原有回填逻辑未变化。
```
No additional source commit is required for this manual acceptance step.
@@ -0,0 +1,96 @@
# 173/174 Popup Contains Filtering Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Make the DevExpress auto-filter row in 173/174 extended-return result popups use contains matching instead of starts-with matching.
**Architecture:** Keep the shared popup and query flow unchanged. Set `GridColumn.OptionsFilter.AutoFilterCondition` when each host dynamically creates result columns, following the existing `AutoFilterCondition.Contains` pattern already used elsewhere in Lskj.Control.
**Tech Stack:** C# on .NET Framework 4.0, WinForms, DevExpress GridControl/GridView.
## Global Constraints
- Work in `E:\lserp_project\lserp_cs_6.0` on `main` and preserve unrelated work.
- Do not change database search SQL, search-column selection, ResultFields mapping, clear, selection, or display translation behavior.
- Apply the behavior to both MyControl and GridControlEx 173/174 popup result columns.
- Do not add dependencies or require a framework newer than .NET Framework 4.0.
- Do not push unless the user explicitly requests it.
---
### Task 1: Set dynamic popup result columns to contains filtering
**Files:**
- Modify: `插件库/Lskj.Control/AutoGridLookUp/LabelExtendedReturnSearchEdit.cs`
- Modify: `插件库/Lskj.Control/GridControlEx.ExtendedReturn.cs`
**Interfaces:**
- Consumes: DevExpress `GridColumn.OptionsFilter.AutoFilterCondition` and `DevExpress.XtraGrid.Columns.AutoFilterCondition.Contains`.
- Produces: Contains-based local auto-filter behavior for every visible and hidden dynamic result column in both popup hosts.
- [ ] **Step 1: Run the failing structural contract**
Run from the repository root:
```powershell
$formPath = '插件库\Lskj.Control\AutoGridLookUp\LabelExtendedReturnSearchEdit.cs'
$gridPath = '插件库\Lskj.Control\GridControlEx.ExtendedReturn.cs'
$form = Get-Content -LiteralPath $formPath -Raw
$grid = Get-Content -LiteralPath $gridPath -Raw
$setting = 'column.OptionsFilter.AutoFilterCondition = AutoFilterCondition.Contains;'
if (-not $form.Contains($setting)) { throw 'MyControl result columns do not use contains filtering.' }
if (-not $grid.Contains($setting)) { throw 'GridControlEx result columns do not use contains filtering.' }
```
Expected: fail on the MyControl assertion because neither dynamic result-column loop currently sets the condition.
- [ ] **Step 2: Implement the minimal per-column setting**
In `LabelExtendedReturnSearchEdit.ConfigureResultColumns`, immediately after assigning `column.Visible`, add:
```csharp
column.OptionsFilter.AutoFilterCondition = AutoFilterCondition.Contains;
```
In `GridControlEx.ConfigureExtendedReturnViewColumns`, immediately after assigning `column.Visible`, add the identical line:
```csharp
column.OptionsFilter.AutoFilterCondition = AutoFilterCondition.Contains;
```
Both files already import `DevExpress.XtraGrid.Columns`, so no new using directive is needed.
- [ ] **Step 3: Re-run the structural contract**
Run the exact PowerShell contract from Step 1.
Expected: exit code `0` with no exception.
- [ ] **Step 4: Compile the dependency chain in isolation**
Upload `/Users/langsukeji/Documents/MyApps/lserp_project/codex_compile_project.ps1` to `E:\lserp_project\codex_compile_project.ps1`. Create `E:\lserp_project\lserp_cs_6.0\DebugCodexFilterContains`, copy `Debug\*.dll` into it, then invoke the helper for these projects in order, using the temporary directory as both `DebugDirectory` and the output DLL directory:
1. `插件库\Lskj.Model\Lskj.Model.csproj`
2. `插件库\Lskj.Util\Lskj.Util.csproj`
3. `插件库\Lskj.Business\Lskj.Business.csproj`
4. `插件库\Lskj.Control\Lskj.Control.csproj`
Expected: all compiler exits are `0`; the existing `CS2023 /noconfig` warning is acceptable.
Delete the uploaded helper and `DebugCodexFilterContains` after compilation.
- [ ] **Step 5: Inspect and commit only the two source files**
```bat
git diff --check
git add -- "插件库/Lskj.Control/AutoGridLookUp/LabelExtendedReturnSearchEdit.cs" "插件库/Lskj.Control/GridControlEx.ExtendedReturn.cs"
git diff --cached --check
git commit -m "fix(control): use contains filtering in extended lookup"
git status --short
```
Expected: commit succeeds and the working tree is clean.
- [ ] **Step 6: Hand off runtime verification**
Ask the user to verify both MyControl and GridControlEx 173/174 popups by entering a middle substring such as `板` into the auto-filter row for a value such as `钢板/Q235B`. Do not push automatically.
@@ -0,0 +1,652 @@
# 173/174 Extended Return Search Column and Local Filter Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add a persistent search-column selector and DevExpress in-memory auto-filter row to the shared 173/174 popup without changing existing value display, ResultFields mapping, clearing, or selection behavior.
**Architecture:** Extend the shared SQL builder to distinguish visible searchable columns from hidden technical columns, then extend the shared popup to own column selection and local filtering state. The MyControl and grid hosts continue to own caption translation and asynchronous schema/query lifecycles; each request snapshots the selected real field name so background execution is deterministic.
**Tech Stack:** C# on .NET Framework 4.0, WinForms, DevExpress `PopupContainerEdit`/`ComboBoxEdit`/`GridControl`/`GridView`, ADO.NET provider factory, SQL Server-compatible derived-table SQL.
## Global Constraints
- Work in `E:\lserp_project\lserp_cs_6.0` on the current `main` branch and preserve unrelated work.
- Do not add NuGet dependencies or require a framework newer than .NET Framework 4.0.
- Keep 173 module SQL resolution and 174 configured SourceSql resolution unchanged.
- Keep ResultFields, ValueMember, TextMember, display-value translation, clear, mouse selection, arrow navigation, and Enter selection unchanged.
- Do not load complete lookup data during parent control initialization.
- Opening the popup may asynchronously execute only the existing `top 0` structure query.
- The selector displays translated result-grid captions but stores real source field names.
- Columns whose real names start with `_` are hidden from the selector and excluded from “所有列” database predicates.
- A new database search clears old DevExpress local filters and old results.
- DevExpress auto-filtering operates only on the returned result table and must not issue a database request.
- Preserve the last valid selector choice per popup instance; fall back to “所有列” only after a loaded schema proves that field no longer exists.
- The automatic popup-open lookup for an existing business value always searches all visible columns; it must not consume or reset the user's preserved selector choice.
- Keep the database result limit at 100 rows and continue using `@lookupKeyword` with existing LIKE escaping.
---
## File Map
- Modify `插件库/Lskj.Control/Model/ExtendedReturnSupport.cs`: central hidden-column rule and selected-column SQL generation.
- Modify `插件库/Lskj.Control/AutoGridLookUp/ExtendedReturnSearchPopup.cs`: selector UI, selection persistence, result/filter reset, and auto-filter row.
- Modify `插件库/Lskj.Control/AutoGridLookUp/LabelExtendedReturnSearchEdit.cs`: MyControl schema-only requests, translated selector options, and selected-field request snapshots.
- Modify `插件库/Lskj.Control/GridControlEx.ExtendedReturn.cs`: grid schema-only requests, source-aware schema cache, translated selector options, and selected-field request snapshots.
- Do not add production source files or change `Lskj.Control.csproj`.
---
### Task 1: Make selected-column SQL generation a tested shared contract
**Files:**
- Modify: `插件库/Lskj.Control/Model/ExtendedReturnSupport.cs:22-149`
- Test temporarily: `E:\lserp_project\codex_extended_return_support_tests.cs`
**Interfaces:**
- Consumes: `string sourceSql`, `DataColumnCollection columns`, `int maxRows`, and optional real `string searchField`.
- Produces: `IsSearchableColumn(string columnName)` and the overload `BuildSearchSql(string sourceSql, DataColumnCollection columns, int maxRows, string searchField)` while preserving the existing three-argument overload.
- [ ] **Step 1: Write the failing SQL contract harness**
Create the temporary test source with this exact behavior:
```csharp
using System;
using System.Data;
using Lskj.Control.Model;
internal static class ExtendedReturnSupportContractTests
{
private static void Require(bool value, string message)
{
if (!value) throw new InvalidOperationException(message);
}
private static void RequireThrows(Action action, string message)
{
try
{
action();
}
catch (InvalidOperationException)
{
return;
}
throw new InvalidOperationException(message);
}
public static int Main()
{
DataTable schema = new DataTable();
schema.Columns.Add("productid");
schema.Columns.Add("appellation");
schema.Columns.Add("_rowid");
string allSql = ExtendedReturnSupport.BuildSearchSql(
"select productid, appellation, _rowid from p_ProductTab",
schema.Columns,
100,
string.Empty);
Require(allSql.Contains("[productid]"), "all columns omitted productid");
Require(allSql.Contains("[appellation]"), "all columns omitted appellation");
Require(!allSql.Contains("[_rowid]"), "all columns included hidden field");
string oneSql = ExtendedReturnSupport.BuildSearchSql(
"select productid, appellation, _rowid from p_ProductTab",
schema.Columns,
100,
"appellation");
Require(oneSql.Contains("[appellation]"), "selected column omitted appellation");
Require(!oneSql.Contains("[productid]"), "selected column included productid");
Require(!oneSql.Contains("[_rowid]"), "selected column included hidden field");
Require(!ExtendedReturnSupport.IsSearchableColumn("_rowid"), "hidden field is searchable");
Require(ExtendedReturnSupport.IsSearchableColumn("productid"), "business field is not searchable");
RequireThrows(delegate
{
ExtendedReturnSupport.BuildSearchSql("select 1", schema.Columns, 100, "_rowid");
}, "hidden selected field did not fail");
RequireThrows(delegate
{
ExtendedReturnSupport.BuildSearchSql("select 1", schema.Columns, 100, "missing");
}, "missing selected field did not fail");
Console.WriteLine("ExtendedReturnSupport contract tests passed.");
return 0;
}
}
```
- [ ] **Step 2: Compile the harness to prove it fails before implementation**
Run the production support file and harness through the installed Roslyn compiler with .NET Framework 4.0 references:
```bat
dotnet "C:\Program Files\dotnet\sdk\10.0.201\Roslyn\bincore\csc.dll" /nologo /target:exe /out:"E:\lserp_project\codex_extended_return_support_tests.exe" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\mscorlib.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Data.dll" "插件库\Lskj.Control\Model\ExtendedReturnSupport.cs" "E:\lserp_project\codex_extended_return_support_tests.cs"
```
Expected: compilation fails because the four-argument overload and `IsSearchableColumn` do not exist.
- [ ] **Step 3: Implement the visible-column rule and overload**
Keep the old overload as a compatibility wrapper and select columns using case-insensitive real field names:
```csharp
public static bool IsSearchableColumn(string columnName)
{
return !string.IsNullOrWhiteSpace(columnName) &&
!columnName.StartsWith("_", StringComparison.Ordinal);
}
public static string BuildSearchSql(
string sourceSql,
DataColumnCollection columns,
int maxRows)
{
return BuildSearchSql(sourceSql, columns, maxRows, string.Empty);
}
public static string BuildSearchSql(
string sourceSql,
DataColumnCollection columns,
int maxRows,
string searchField)
{
if (columns == null || columns.Count == 0)
throw new InvalidOperationException("搜索 SQL 没有返回任何可查询列。");
if (maxRows <= 0)
throw new ArgumentOutOfRangeException("maxRows", "最大返回行数必须大于零。");
List<DataColumn> selectedColumns = new List<DataColumn>();
foreach (DataColumn column in columns)
{
if (!IsSearchableColumn(column.ColumnName)) continue;
if (string.IsNullOrWhiteSpace(searchField) ||
string.Equals(column.ColumnName, searchField, StringComparison.OrdinalIgnoreCase))
{
selectedColumns.Add(column);
}
}
if (selectedColumns.Count == 0)
{
throw new InvalidOperationException(string.IsNullOrWhiteSpace(searchField)
? "搜索 SQL 没有返回可见业务列。"
: string.Format("搜索字段“{0}”不存在或属于隐藏技术列。", searchField));
}
string alias = QuoteIdentifier(SearchAlias);
StringBuilder builder = new StringBuilder();
builder.AppendFormat("select top ({0}) * from ({1}) as {2} where ",
maxRows, NormalizeSourceSql(sourceSql), alias);
for (int i = 0; i < selectedColumns.Count; i++)
{
if (i > 0) builder.Append(" or ");
builder.Append("convert(nvarchar(4000), ");
builder.Append(alias);
builder.Append('.');
builder.Append(QuoteIdentifier(selectedColumns[i].ColumnName));
builder.Append(") like ");
builder.Append(SearchParameterName);
builder.Append(" escape N'\\'");
}
return builder.ToString();
}
```
- [ ] **Step 4: Compile and run the contract harness**
Run the same compiler command, then:
```bat
E:\lserp_project\codex_extended_return_support_tests.exe
```
Expected: exit code `0` and `ExtendedReturnSupport contract tests passed.`
- [ ] **Step 5: Remove temporary harness artifacts and commit Task 1**
```bat
del "E:\lserp_project\codex_extended_return_support_tests.cs"
del "E:\lserp_project\codex_extended_return_support_tests.exe"
git add -- "插件库/Lskj.Control/Model/ExtendedReturnSupport.cs"
git diff --cached --check
git commit -m "feat(control): support selected extended search columns"
```
---
### Task 2: Add selector persistence and local filter UI to the shared popup
**Files:**
- Modify: `插件库/Lskj.Control/AutoGridLookUp/ExtendedReturnSearchPopup.cs:14-232`
**Interfaces:**
- Consumes: translated column options as `IEnumerable<KeyValuePair<string, string>>`, where key is the real field and value is the displayed caption.
- Produces: `SelectedSearchField`, `SetSearchColumns(...)`, and `ClearResultAndFilter()` for both hosts.
- [ ] **Step 1: Record failing structural assertions**
Run this PowerShell check before editing:
```powershell
$path = '插件库\Lskj.Control\AutoGridLookUp\ExtendedReturnSearchPopup.cs'
$text = Get-Content -LiteralPath $path -Raw
$required = @(
'ComboBoxEdit searchFieldEdit',
'searchPanel.ColumnCount = 4',
'ShowAutoFilterRow = true',
'SelectedSearchField',
'SetSearchColumns',
'ClearResultAndFilter'
)
foreach ($item in $required) {
if (-not $text.Contains($item)) { throw "Missing popup contract: $item" }
}
```
Expected: failure on the first missing popup contract.
- [ ] **Step 2: Add the selector option model and public popup contract**
Add `using Lskj.Control.Model;` and `using System.Collections.Generic;`. Inside `ExtendedReturnSearchPopup`, add a private option object and the host-facing API:
```csharp
private sealed class SearchColumnOption
{
public SearchColumnOption(string fieldName, string caption)
{
FieldName = fieldName ?? string.Empty;
Caption = caption ?? string.Empty;
}
public string FieldName { get; private set; }
public string Caption { get; private set; }
public override string ToString() { return Caption; }
}
public string SelectedSearchField
{
get
{
SearchColumnOption option = searchFieldEdit.SelectedItem as SearchColumnOption;
return option == null ? string.Empty : option.FieldName;
}
}
public void SetSearchColumns(IEnumerable<KeyValuePair<string, string>> columns)
{
string preferredField = selectedSearchField;
searchFieldEdit.Properties.BeginUpdate();
try
{
searchFieldEdit.Properties.Items.Clear();
SearchColumnOption all = new SearchColumnOption(string.Empty, "所有列");
searchFieldEdit.Properties.Items.Add(all);
SearchColumnOption selected = null;
if (columns != null)
{
foreach (KeyValuePair<string, string> column in columns)
{
if (!ExtendedReturnSupport.IsSearchableColumn(column.Key)) continue;
SearchColumnOption option = new SearchColumnOption(column.Key, column.Value);
searchFieldEdit.Properties.Items.Add(option);
if (string.Equals(option.FieldName, preferredField, StringComparison.OrdinalIgnoreCase))
selected = option;
}
}
searchFieldEdit.SelectedItem = selected ?? all;
selectedSearchField = selected == null ? string.Empty : selected.FieldName;
}
finally
{
searchFieldEdit.Properties.EndUpdate();
}
}
```
Add `selectedSearchField` and update it from `SelectedIndexChanged`; `PrepareForOpen()` must not reset it.
- [ ] **Step 3: Change the top layout and keep input focus behavior**
Instantiate a `ComboBoxEdit`, set `TextEditStyle = TextEditStyles.DisableTextEditor`, and change the layout to four columns:
```csharp
searchPanel.ColumnCount = 4;
searchPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 120F));
searchPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
searchPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 72F));
searchPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 72F));
searchPanel.Controls.Add(searchFieldEdit, 0, 0);
searchPanel.Controls.Add(searchEdit, 1, 0);
searchPanel.Controls.Add(queryButton, 2, 0);
searchPanel.Controls.Add(clearButton, 3, 0);
```
Set selector/input/query/clear tab indices to `0/1/2/3`. Keep `FocusSearchEditor()` focused on `searchEdit` so opening the popup still allows immediate typing.
- [ ] **Step 4: Enable and reset DevExpress local filtering**
Enable the built-in filter row and centralize clearing:
```csharp
resultView.OptionsView.ShowAutoFilterRow = true;
public void ClearResultAndFilter()
{
resultView.ClearColumnsFilter();
resultGrid.DataSource = null;
}
public void PrepareForOpen()
{
searchEdit.Text = string.Empty;
ClearResultAndFilter();
}
```
Do not attach the selector or auto-filter row to `SearchRequested`; only Enter in `searchEdit` and the query button raise database search events.
- [ ] **Step 5: Run structural assertions and compile `Lskj.Control`**
Run the Step 1 PowerShell check and the repositorys isolated C# compile helper. Expected: structural check exit `0` and `Lskj.Control` compile exit `0`.
- [ ] **Step 6: Commit Task 2**
```bat
git add -- "插件库/Lskj.Control/AutoGridLookUp/ExtendedReturnSearchPopup.cs"
git diff --cached --check
git commit -m "feat(control): add extended lookup filter UI"
```
---
### Task 3: Integrate schema-only loading and selected fields in MyControl
**Files:**
- Modify: `插件库/Lskj.Control/AutoGridLookUp/LabelExtendedReturnSearchEdit.cs:37-60,294-360,616-760`
**Interfaces:**
- Consumes: `popup.SelectedSearchField`, `popup.SetSearchColumns(...)`, the existing `GetSchema(...)`, and the four-argument SQL builder.
- Produces: schema-only asynchronous requests and result delivery that configures selector options before optionally binding rows.
- [ ] **Step 1: Record failing MyControl integration assertions**
```powershell
$path = '插件库\Lskj.Control\AutoGridLookUp\LabelExtendedReturnSearchEdit.cs'
$text = Get-Content -LiteralPath $path -Raw
$required = @(
'public string SearchField;',
'public bool SchemaOnly;',
'public DataTable Schema;',
'popup.SelectedSearchField',
'popup.SetSearchColumns',
'MaxRows, request.SearchField'
)
foreach ($item in $required) {
if (-not $text.Contains($item)) { throw "Missing MyControl integration: $item" }
}
```
Expected: failure before implementation.
- [ ] **Step 2: Extend request/result snapshots**
Add exact state to the existing nested classes:
```csharp
private sealed class SearchRequest
{
public int Version;
public string SourceSql;
public string Keyword;
public string SearchField;
public string ConnectionString;
public bool SchemaOnly;
}
private sealed class QueryResult
{
public DataTable Schema;
public DataTable Table;
public Exception Error;
}
```
- [ ] **Step 3: Queue schema-only work on popup open**
Resolve `sourceSql` once in `PopupEdit_QueryPopUp`. After `PrepareForOpen()`:
```csharp
DataTable cachedSchema = TryGetSchema(sourceSql);
if (cachedSchema != null) ConfigureSearchColumns(cachedSchema);
if (!string.IsNullOrWhiteSpace(EditValue))
QueueSearch(sourceSql, EditValue, string.Empty, false);
else if (cachedSchema == null)
QueueSearch(sourceSql, string.Empty, string.Empty, true);
else
CancelSearch();
```
`TryGetSchema` must take `schemaSyncRoot` and return the cached table only when `schemaSql` equals the resolved SQL. `QueueSearch` replaces the old `StartSearch` request construction and snapshots `SearchField` and `SchemaOnly`. The popup-open lookup deliberately uses an empty search field so an existing actual ID is found independently of the preserved selector; only explicit Enter/query actions use `popup.SelectedSearchField`.
- [ ] **Step 4: Build translated options from schema**
Use existing caption translation and shared visibility rules:
```csharp
private void ConfigureSearchColumns(DataTable sourceSchema)
{
List<KeyValuePair<string, string>> options = new List<KeyValuePair<string, string>>();
IList<ExtendedReturnFieldMapping> mappings =
ExtendedReturnSupport.ParseResultFields(Model.ResultFields);
foreach (DataColumn column in sourceSchema.Columns)
{
if (!ExtendedReturnSupport.IsSearchableColumn(column.ColumnName)) continue;
options.Add(new KeyValuePair<string, string>(
column.ColumnName,
GetColumnCaption(column.ColumnName, mappings)));
}
popup.SetSearchColumns(options);
}
```
- [ ] **Step 5: Make query and delivery schema-aware**
`Query(SearchRequest request)` must always load and validate schema, set `result.Schema`, and execute row SQL only when `!request.SchemaOnly`:
```csharp
DataTable sourceSchema = GetSchema(request.SourceSql, request.ConnectionString);
result.Schema = sourceSchema;
IList<ExtendedReturnFieldMapping> mappings =
ExtendedReturnSupport.ParseResultFields(Model.ResultFields);
ValidateSourceColumns(sourceSchema.Columns, mappings);
if (!request.SchemaOnly)
{
string searchSql = ExtendedReturnSupport.BuildSearchSql(
request.SourceSql, sourceSchema.Columns, MaxRows, request.SearchField);
result.Table = ExecuteQuery(
searchSql,
ExtendedReturnSupport.BuildLikeParameterValue(request.Keyword),
request.ConnectionString);
}
```
Change delivery to receive the request, reject stale versions, call `ConfigureSearchColumns(result.Schema)`, and bind/configure result rows only when `result.Table != null`.
- [ ] **Step 6: Clear local filters on explicit database search**
In `Popup_SearchRequested`, call `popup.ClearResultAndFilter()` before queuing any non-empty keyword. Capture `popup.SelectedSearchField` in that same UI event. Empty keywords cancel work and leave a cleared result.
- [ ] **Step 7: Run assertions and compile through `Lskj.Control`**
Run the Step 1 check. Compile `Lskj.Model`, `Lskj.Util`, `Lskj.Business`, then `Lskj.Control` into an isolated dependency directory. Expected: all exits `0`.
- [ ] **Step 8: Commit Task 3**
```bat
git add -- "插件库/Lskj.Control/AutoGridLookUp/LabelExtendedReturnSearchEdit.cs"
git diff --cached --check
git commit -m "feat(control): add form extended lookup column search"
```
---
### Task 4: Integrate schema-only loading and selected fields in GridControlEx
**Files:**
- Modify: `插件库/Lskj.Control/GridControlEx.ExtendedReturn.cs:32-85,323-449,621-905,1189-1220`
**Interfaces:**
- Consumes: the shared popup contract and selected-column SQL builder from Tasks 1-2.
- Produces: per-grid-column source-aware schema caching, schema-only requests, and selected-field request snapshots within the existing serialized request state machine.
- [ ] **Step 1: Record failing grid integration assertions**
```powershell
$path = '插件库\Lskj.Control\GridControlEx.ExtendedReturn.cs'
$text = Get-Content -LiteralPath $path -Raw
$required = @(
'mExtendedReturnSchemaSqls',
'public string SearchField;',
'public bool SchemaOnly;',
'public DataTable Schema;',
'popup.SelectedSearchField',
'popup.SetSearchColumns',
'request.SearchField'
)
foreach ($item in $required) {
if (-not $text.Contains($item)) { throw "Missing grid integration: $item" }
}
```
Expected: failure before implementation.
- [ ] **Step 2: Make cached schemas source-aware**
Add:
```csharp
private readonly Dictionary<string, string> mExtendedReturnSchemaSqls =
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
```
`GetExtendedReturnSchema` and a new `TryGetExtendedReturnSchema` must return a cached table only when both field name and resolved `sourceSql` match. Store the SQL beside each cached table and clear both dictionaries in `ResetExtendedReturnState()`.
- [ ] **Step 3: Extend grid request/result snapshots**
Add `SearchField` and `SchemaOnly` to `ExtendedLookupRequest`, plus `Schema` to `ExtendedLookupQueryResult`. Preserve the existing version, pending-request, and single-worker-per-field rules.
- [ ] **Step 4: Configure or asynchronously load schema on popup open**
In `ExtendedReturnSearch_QueryPopUp`, resolve source SQL after the business row is known. Configure selector options immediately from a matching cache. If the actual business value is empty and no schema is cached, enqueue a schema-only request; if it is non-empty, enqueue the normal initial search with an empty search field so it searches all visible columns without changing the preserved selector.
Use the existing caption method when building options:
```csharp
private void ConfigureExtendedReturnSearchColumns(
ExtendedReturnPopupContext context,
DataTable sourceSchema)
{
List<KeyValuePair<string, string>> options = new List<KeyValuePair<string, string>>();
IList<ExtendedReturnFieldMapping> mappings =
ExtendedReturnSupport.ParseResultFields(context.Model.ResultFields);
foreach (DataColumn column in sourceSchema.Columns)
{
if (!ExtendedReturnSupport.IsSearchableColumn(column.ColumnName)) continue;
options.Add(new KeyValuePair<string, string>(
column.ColumnName,
GetExtendedReturnColumnCaption(column.ColumnName, mappings)));
}
context.Popup.SetSearchColumns(options);
}
```
- [ ] **Step 5: Snapshot selector state for explicit searches**
`ExtendedReturnSearch_SearchRequested` must pass `popup.SelectedSearchField`. `StartExtendedReturnSearch` must clear the popups filters/results, reject an empty keyword, validate business configuration, resolve SQL, and enqueue a non-schema-only request containing the selected field.
- [ ] **Step 6: Make the worker result schema-aware without weakening stale-result guards**
`QueryExtendedReturn` must always populate `result.Schema`; it calls the four-argument SQL builder only for non-schema-only requests. In `BeginInvokeExtendedReturnResult`:
1. Keep every existing editor, focused column, business row, and request-version guard.
2. Configure selector options from `result.Schema`.
3. For schema-only requests, stop without setting `DeliveredVersion` or binding a result table.
4. For row requests, set `DeliveredVersion`, bind the result table, configure result columns, and retain existing popup visibility behavior.
- [ ] **Step 7: Run assertions and compile through `Lskj.Control`**
Run the Step 1 check and the isolated four-project compile chain. Expected: all exits `0`.
- [ ] **Step 8: Commit Task 4**
```bat
git add -- "插件库/Lskj.Control/GridControlEx.ExtendedReturn.cs"
git diff --cached --check
git commit -m "feat(control): add grid extended lookup column search"
```
---
### Task 5: Final compatibility verification and delivery
**Files:**
- Verify: `插件库/Lskj.Control/Model/ExtendedReturnSupport.cs`
- Verify: `插件库/Lskj.Control/AutoGridLookUp/ExtendedReturnSearchPopup.cs`
- Verify: `插件库/Lskj.Control/AutoGridLookUp/LabelExtendedReturnSearchEdit.cs`
- Verify: `插件库/Lskj.Control/GridControlEx.ExtendedReturn.cs`
- Verify: `docs/superpowers/specs/2026-07-31-extended-return-search-column-filter-design.md`
**Interfaces:**
- Consumes: all contracts created in Tasks 1-4.
- Produces: a clean, compiled local `main` ready for user runtime verification and later push authorization.
- [ ] **Step 1: Re-run the SQL contract harness from a clean temporary file**
Recreate the exact Task 1 harness, compile it with the final support source, run it, and confirm exit `0`. Delete the temporary `.cs` and `.exe` afterward.
- [ ] **Step 2: Run final structural behavior checks**
Assert all of the following exact invariants with PowerShell `Get-Content -Raw` checks:
- Popup layout has four columns and `ShowAutoFilterRow = true`.
- `PrepareForOpen()` does not reset `selectedSearchField`.
- Both explicit search handlers read `SelectedSearchField` and call `ClearResultAndFilter()`.
- Both query paths call the four-argument SQL builder.
- Both schema delivery paths call `SetSearchColumns`.
- Grid reset clears both schema dictionaries.
- Existing `ClearRequested`, `ResultSelected`, row indicator, arrow-key, and Enter-key event hookups remain present.
- [ ] **Step 3: Compile the final dependency chain in isolation**
Use `E:\lserp_project\codex_compile_project.ps1` with a fresh `DebugCodexExtendedFilter` directory. Compile in this exact order:
1. `插件库\Lskj.Model\Lskj.Model.csproj`
2. `插件库\Lskj.Util\Lskj.Util.csproj`
3. `插件库\Lskj.Business\Lskj.Business.csproj`
4. `插件库\Lskj.Control\Lskj.Control.csproj`
Expected: each compiler exit is `0`; the known `CS2023 /noconfig` warning is acceptable.
- [ ] **Step 4: Inspect repository scope**
```bat
git diff --check origin/main...main
git status --short
git log --oneline --decorate -8
```
Expected: no whitespace errors, no temporary artifacts, and only the approved design/plan documents plus four production source files differ from the pre-feature base.
- [ ] **Step 5: Hand off runtime verification scenarios**
Report the ten scenarios in the design spec, emphasizing:
- selector captions and hidden-column exclusion;
- all-column versus single-column database behavior;
- selector persistence and fallback;
- auto-filter row local-only behavior and reset on new search;
- mouse/keyboard selection, clear, display translation, and ResultFields mapping for MyControl/grid with both 173 and 174.
Do not push until the user explicitly requests it.
@@ -0,0 +1,124 @@
# 浏览器 JSON 复杂字段兼容设计
## 背景
网页通过 `OpenOnRightClick` 将选中行 JSON 传入旧 WinForms 客户端。当前代码直接使用 Newtonsoft.Json 将 JSON 数组反序列化为 `DataTable`。当行数据包含对象或数组字段时,例如:
```json
{
"$styles": {
"rowstyle": "{color:'#FFFF00','background-color':'#FF0000'}"
}
}
```
`DataTableConverter` 无法把 `StartObject``StartArray` 直接写入普通 `DataColumn`,因此抛出 `Unexpected JSON token when reading DataTable`。字段名 `$styles` 本身合法,真正的问题是字段值为嵌套对象。
## 目标
- 保留对象和数组字段,不删除 `$styles` 或其他未来字段。
- 将复杂值转换成紧凑 JSON 字符串后再生成 `DataTable`
- 保持纯标量字段现有的列名、值和类型推断行为。
- 只影响网页与旧客户端交互的数据边界,不改变全局 Newtonsoft.Json 行为。
- 同时兼容右键调用和网页返回行两个浏览器入口。
## 非目标
- 不修改 WPF 启动、窗口或宿主逻辑。
- 不修改数据库中的 JSON。
- 不扁平化嵌套对象,不删除未知字段。
- 不替换项目中所有 `DeserializeObject<DataTable>` 调用。
- 不改变旧模块的菜单查找、参数替换和 DLL 加载流程。
## 方案比较
### 方案一:在浏览器边界归一化复杂列(采用)
解析网页 JSON,扫描整批记录,找出任一行中出现对象或数组值的列。将这些列的所有非空值统一转换为字符串,其中对象和数组使用紧凑 JSON;其他纯标量列保持不变。归一化后继续使用现有 Newtonsoft.Json `DataTable` 转换。
优点:影响范围小;保留现有标量类型;能处理未来任意字段名;可复用在两个浏览器入口。
### 方案二:手工构造全部为 `object` 的 DataTable
可以容纳复杂值,但会改变所有列的类型,可能影响比较、筛选、参数替换和旧模块中的类型判断,兼容风险较大。
### 方案三:注册全局 Newtonsoft.Json 转换器
可以统一处理,但会影响整个旧系统中大量 JSON 反序列化入口,难以证明不会改变其他模块行为,范围过宽。
## 详细设计
### 公共转换入口
`Lskj.Util.JsonUtil` 中增加一个含义明确的新方法,专门把可能包含复杂字段的网页行 JSON 转为 `DataTable`。不修改现有 `ToDataTable``ToDataRow` 的语义,避免影响未知调用方。
该方法接受:
- 顶层 JSON 数组,用于网页右键选中行。
- 顶层单个 JSON 对象,用于网页返回一行数据;内部统一包装成数组处理。
空输入、非对象行或其他不符合约定的顶层结构视为无效输入,抛出可诊断异常,继续交给当前宿主的既有异常保护策略处理。
### 复杂列识别
必须先扫描全部记录,再执行转换。只要某列在任意一行中的值为 `JObject``JArray`,该列就被标记为复杂列。
不能只转换当前遇到的复杂值。例如第一行是数字、第二行是对象时,如果第一行已让 `DataTable` 将列推断为数值类型,第二行即使变成字符串仍会发生类型冲突。
### 值归一化规则
对于复杂列:
- `JObject` 转换为不带缩进和额外空白的 JSON 字符串。
- `JArray` 转换为不带缩进和额外空白的 JSON 字符串。
- 同列中的字符串保持原字符串内容。
- 同列中的数字、布尔值等标量转换为稳定的字符串表示,确保整列类型一致。
- `null` 保留为空值,不转换为空字符串。
对于从未出现对象或数组的列,不进行任何预处理,由现有 `DataTableConverter` 继续推断原有类型。
### 调用点
仅替换以下两个浏览器桥接入口的直接反序列化:
1. `Lskj.Control.BrowserSetting.BsOpenModuleHandler.OpenRightModule`
2. `Lskj.Control.BrowserSetting.BsOpenModuleHandler.AddReturnRow`
`OpenRightModule` 后续仍把原有 `DataRow[]` 交给 `BaseRightMenu.ExecRightMenu`。菜单 ID 查询、占位符替换、`PUR_4004` 模块解析和 DLL 加载逻辑不变。
`AddReturnRow` 后续仍执行现有产品前缀处理并加入 `StaticControl.ReturnRowLisy`
### 下游兼容性
经过归一化的 `DataRow` 再序列化传给动态模块时,复杂字段已经是普通字符串。下游 `DynamicModuleModel``DynamicModuleDetailModel` 等现有 `DataTable` 反序列化可继续工作,无需全局改造。
## 异常处理
- 合法对象/数组字段不再产生 `StartObject``StartArray` 异常。
- 语法错误的 JSON、非对象行等仍作为真实错误报告,不静默删除数据。
- 转换方法不吞异常;沿用当前宿主已经建立的异常保护策略,避免用空表或残缺数据掩盖真实输入错误。
- 错误信息应保留原始异常,便于定位具体字段和输入。
## 验证方案
### 转换级测试
1. 当前实际 `$styles` 对象:成功生成一行,`$styles` 为紧凑 JSON 字符串。
2. 任意名称的嵌套对象字段:成功并保留字段名和内容。
3. 数组字段:成功并保留为紧凑 JSON 字符串。
4. 同一复杂列在不同行中分别为对象、字符串、数字和 `null`:整列稳定转换,不发生类型冲突。
5. 只有标量的原有 JSON:列和值与修改前一致。
6. 单对象输入:用于 `AddReturnRow` 时成功生成一行。
7. 无效 JSON 和非对象数组元素:明确失败,不产生不完整数据。
### 集成验证
1. 使用当前待办任务 JSON 点击网页“待办任务”,不再出现 `$styles``DataTable` 反序列化错误。
2. 右键配置 ID 能继续解析,模块编号 `PUR_4004` 正常传入原 DLL 加载流程。
3. 不含复杂字段的网页右键功能行为不变。
4. 网页返回行功能仍可回填,包含复杂字段时不崩溃。
5. 分别通过旧 WinForms 启动和 WPF 宿主启动验证相同行为。
## 构建与交付
改动位于旧代码项目。完成后重新编译并更新运行目录使用的 `Lskj.Util.dll``Lskj.Control.dll`WPF 项目无需为本修复修改代码。
@@ -0,0 +1,32 @@
# 173/174 弹窗本地筛选改为包含匹配
## 目标
将 173/174 扩展返回弹窗中 DevExpress 自动筛选行的文本匹配方式,从默认的“开头匹配”改为“包含匹配”。例如在“物料名称”筛选框输入“板”,应匹配“钢板/Q235B”。
## 根因
共享弹窗已经启用 `ShowAutoFilterRow`,但 MyControl 与 GridControlEx 在查询完成后动态创建结果列时,没有设置 `GridColumn.OptionsFilter.AutoFilterCondition`,因此沿用了 DevExpress 默认的开头匹配。
项目内其他表格列已普遍使用 `AutoFilterCondition.Contains`,可直接沿用这一兼容写法。
## 设计
仅修改两处动态结果列创建逻辑:
- `LabelExtendedReturnSearchEdit.ConfigureResultColumns`
- `GridControlEx.ConfigureExtendedReturnViewColumns`
每个结果列创建后设置:
```csharp
column.OptionsFilter.AutoFilterCondition = AutoFilterCondition.Contains;
```
不修改共享弹窗事件,不增加自定义筛选处理,不改变数据库查询 SQL、搜索列下拉框、ResultFields 映射、清空、选择和显示翻译逻辑。
## 验证
- 结构检查确认两处动态列均设置 `Contains`
- 编译 `Lskj.Model``Lskj.Util``Lskj.Business``Lskj.Control`
- 运行时由用户确认:自动筛选行输入位于文本中间的内容时仍能命中结果。
@@ -0,0 +1,130 @@
# 173/174 扩展返回搜索列与本地筛选设计
## 背景
173“模块选择返回 Id-扩展”和 174“搜索返回 Id-扩展”目前共用 `ExtendedReturnSearchPopup`。弹窗只提供一个搜索输入框,数据库查询会对数据源返回的全部列拼接 `OR LIKE`。结果表格已使用 DevExpress `GridView`,但没有显示自动筛选行。
本次改动在不改变现有数据源解析、ResultFields 回填、显示值翻译和键盘选择行为的前提下,增加数据库搜索列选择及结果集本地二次筛选。
## 目标
- 弹窗顶部增加搜索列下拉框。
- 支持“所有列”数据库搜索和指定单列数据库搜索。
- 下拉项显示与结果表头一致的中文标题,内部使用真实数据源字段名。
- `_` 开头的隐藏技术列不进入下拉,也不参与“所有列”搜索。
- 下方 DevExpress 表格显示自动筛选行,对数据库已返回的数据进行本地二次筛选。
- 173、174 在表格控件和 MyControl 中保持一致行为。
- 保留原有清空、选择、回填、显示和键盘操作。
## 非目标
- 不修改 173 的模块数据源解析规则。
- 不修改 174 的 SourceSql 配置规则。
- 不修改 ResultFields、ValueMember、TextMember 的含义或校验。
- 不把 DevExpress 自动筛选条件发送到数据库。
- 不在控件初始化阶段加载完整业务数据。
- 不跨应用重启持久化搜索列选择。
## 交互设计
弹窗顶部从左到右排列:
1. 搜索列下拉框。
2. 搜索文本输入框。
3. “查询”按钮。
4. “清空”按钮。
下拉框规则:
- 第一项固定为“所有列”。
- 后续项来自实际数据源结构,只包含名称不以 `_` 开头的列。
- 显示文本复用结果表格现有列标题翻译逻辑;选项内部保存真实字段名。
- 每个 173/174 控件实例在内存中保留最后一次选择,关闭并重新打开弹窗时不重置。
- 数据源结构变化且原选择字段已不存在时,自动回退到“所有列”。
输入框仍按现有方式仅在回车或点击“查询”时访问数据库。上下键进入结果表、结果表回车选择、鼠标点击选择和“清空”按钮行为保持不变。
## 数据结构加载
弹窗打开时只异步执行现有 `top 0` 结构查询,用于取得列名,不加载完整业务数据。
- 已有缓存结构时立即构建下拉项,不重复访问数据库。
- 首次打开且尚无缓存时,下拉先保留“所有列”,结构查询完成后补充列项。
- 如果当前业务值非空,现有首次搜索请求同时取得并缓存结构,无需额外加载完整数据。
- 弹窗关闭、控件销毁或请求版本已过期时丢弃后台返回结果,不更新已经失效的界面。
## 数据库搜索
`ExtendedReturnSupport.BuildSearchSql` 增加可选搜索字段参数:
- “所有列”:只对所有可见业务列生成 `OR LIKE` 条件。
- 指定列:校验字段存在且不是隐藏列,只为该列生成 `LIKE` 条件。
- 返回结果仍保留数据源的全部列,包括隐藏技术列,以免破坏 ResultFields 回填。
- 继续使用现有 `@lookupKeyword` 参数、LIKE 转义和字段名引用,不把输入文本或下拉显示标题直接拼入 SQL。
- 最大返回行数继续保持 100。
搜索请求必须在提交时同时快照关键字和真实字段名,避免后台查询期间用户切换下拉导致请求含义变化。
## 本地二次筛选
共享结果 `GridView` 启用 DevExpress `OptionsView.ShowAutoFilterRow`
- 自动筛选只作用于当前绑定的最多 100 行结果,不触发数据库查询。
- 每次按回车或点击“查询”发起新的数据库搜索前,清除全部本地筛选条件和旧结果。
- 关闭并重新打开弹窗时不保留上一次的本地筛选条件。
- 自动筛选后的焦点行仍可通过回车或鼠标点击执行原有 ResultFields 回填。
## 代码边界
### `ExtendedReturnSearchPopup`
- 负责下拉框、输入框、按钮和结果表的布局。
- 暴露当前真实搜索字段,不包含 SQL 或业务映射逻辑。
- 接收调用方生成的“真实字段名 + 中文标题”选项。
- 负责保留有效选择、无效选择回退、清空本地筛选及启用自动筛选行。
### `ExtendedReturnSupport`
- 统一生成“所有可见列”或“指定可见列”的参数化搜索 SQL。
- 统一判定 `_` 开头的隐藏技术列,避免表格和 MyControl 产生不同规则。
- 对不存在、隐藏或空白的指定字段给出明确配置错误。
### `LabelExtendedReturnSearchEdit`
- 为 MyControl 173/174 异步加载和缓存数据源结构。
- 使用现有业务控件标签生成中文列标题。
- 把下拉选择快照带入后台搜索请求。
### `GridControlEx.ExtendedReturn`
- 为表格 173/174 异步加载和缓存每个字段的数据源结构。
- 使用现有表格列标题翻译逻辑生成中文列标题。
- 把下拉选择快照带入现有每列串行查询状态机。
## 兼容性与错误处理
- 默认选择“所有列”时,用户操作方式与现有版本一致,但隐藏技术列不再参与模糊搜索。
- 173 继续通过模块编号解析 SQL,174 继续直接使用配置 SQL。
- 结构查询或业务查询失败时沿用现有提示机制,不能覆盖当前业务值或 ResultFields 字段。
- 后台返回旧版本结果时继续丢弃,不覆盖更新的搜索结果。
- 清空按钮仍清空当前业务行全部 ResultFields 映射字段并关闭弹窗。
- 原业务列仍为只读弹出编辑器,弹窗搜索文本不参与业务字段显示或保存。
## 验收场景
1. 首次打开空值控件,只执行结构查询,下拉最终显示“所有列”和所有可见中文列名。
2. 选择“所有列”搜索时,SQL 条件只包含非 `_` 开头的列。
3. 选择单列搜索时,SQL 条件只包含该真实字段。
4. 关闭后重开同一控件,保留上次有效搜索列;数据源缺少该列时回退到“所有列”。
5. 新数据库搜索会清除旧自动筛选条件。
6. 自动筛选行改变可见结果但不产生数据库请求。
7. 筛选后鼠标点击、上下键和回车仍能选择正确 DataRow 并完成 ResultFields 回填。
8. `_` 开头的列不显示、不进入下拉、不参与“所有列”搜索,但仍可作为 ResultFields 映射来源。
9. 表格和 MyControl 的 173、174 四种组合行为一致。
10. 原有清空、显示值翻译、实际值保存和模块数据源加载保持正常。
## 验证范围
- 对 SQL 构建规则、隐藏列排除、指定列校验和选择回退进行结构化检查。
- 编译 `Lskj.Model``Lskj.Util``Lskj.Business``Lskj.Control`
- 运行时验收由实际 ERP 界面对上述十个场景进行人工验证。
@@ -71,24 +71,24 @@ namespace NewMyFormDesigner
}
//DialogResult dr = MessageBox.Show("是否为达梦数据库?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
//if (dr == System.Windows.Forms.DialogResult.Yes)
//{
// if (!string.IsNullOrWhiteSpace(ServerName) && !string.IsNullOrWhiteSpace(DatabaseName) && !string.IsNullOrWhiteSpace(AccountNumber))
// {
// string connect = "Nzg5REZBQ0IzMjYzQkQzRTZFRTExNjY5MThCNjUwQTVFRUQyMDMxQzI5REIwODY5REIwMkVCQzQ4MTMzRDhDNEU1N0JFREI0MDM3MTQ1MDZGQzdGOEQxQTE4MkQ2QzgyNEE4RkMzRDQzQUM4MzgyOEQ2REZERTIzQzBDMjJGQUE=";
// string hostname = Environment.MachineName;
// if (!string.IsNullOrWhiteSpace(Password))
// {
// LinkString = string.Format("Server={0}; schema={1}; UserId={2}; PWD={3};host={4}", ServerName, DatabaseName, AccountNumber, Password, hostname);
// }
// else
// {
// LinkString = string.Format(Lskj.Util.AESUtil.Decrypt(connect), ServerName, DatabaseName, AccountNumber, hostname);
// }
// connectionType = ConnectionType.DmServer;
// }
//}
DialogResult dr = MessageBox.Show("是否为达梦数据库?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (dr == System.Windows.Forms.DialogResult.Yes)
{
if (!string.IsNullOrWhiteSpace(ServerName) && !string.IsNullOrWhiteSpace(DatabaseName) && !string.IsNullOrWhiteSpace(AccountNumber))
{
string connect = "Nzg5REZBQ0IzMjYzQkQzRTZFRTExNjY5MThCNjUwQTVFRUQyMDMxQzI5REIwODY5REIwMkVCQzQ4MTMzRDhDNEU1N0JFREI0MDM3MTQ1MDZGQzdGOEQxQTE4MkQ2QzgyNEE4RkMzRDQzQUM4MzgyOEQ2REZERTIzQzBDMjJGQUE=";
string hostname = Environment.MachineName;
if (!string.IsNullOrWhiteSpace(Password))
{
LinkString = string.Format("Server={0}; schema={1}; UserId={2}; PWD={3};host={4}", ServerName, DatabaseName, AccountNumber, Password, hostname);
}
else
{
LinkString = string.Format(Lskj.Util.AESUtil.Decrypt(connect), ServerName, DatabaseName, AccountNumber, hostname);
}
connectionType = ConnectionType.DmServer;
}
}
//MessageBox.Show(LinkString);
+2 -2
View File
@@ -32,10 +32,10 @@ namespace NewMyFormDesigner
//myFormDesigner.ServerName = "110.185.161.104:5236";
//myFormDesigner.ServerName = "222.211.229.79:5238";
//myFormDesigner.DatabaseName = "LSERP_JTCS";
//myFormDesigner.AccountNumber = "lserpAdmin";
//myFormDesigner.Password = "DWlserp1101";//XDerp20210411%
//myFormDesigner.Password = "Lserp110";//XDerp20210411%
//MessageBox.Show(args.Length + "");
//MessageBox.Show("1:"+args[0]);
+15 -6
View File
@@ -162,18 +162,27 @@ namespace Lskj.AutoWordFile
}
private DataSet Worddata(string modid, int tagid, int mid)
{
SqlParameter[] param =
try
{
SqlParameter[] param =
{
new SqlParameter("@modid",SqlDbType.VarChar,15),
new SqlParameter("@tagid",SqlDbType.Int),
new SqlParameter("@Mid",SqlDbType.Int)
};
param[0].Value = modid;
param[1].Value = tagid;
param[2].Value = mid;
DataSet ds = SqlHelper.ExecuteDataSet(CommandType.StoredProcedure, "pr_system_File01", "#ba_firstpage", param);
return ds;
param[0].Value = modid;
param[1].Value = tagid;
param[2].Value = mid;
DataSet ds = SqlHelper.ExecuteDataSet(CommandType.StoredProcedure, "pr_system_File01", "#ba_firstpage", param);
return ds;
}
catch (Exception ex)
{
throw;
}
}
public void Mulu()
{
@@ -13,9 +13,13 @@
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -103,7 +107,7 @@
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(80, 28);
this.btnCancel.TabIndex = 4;
this.btnCancel.Text = "退出(&C)";
this.btnCancel.Text = "退出(C)";
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// btnFileManger
@@ -171,7 +175,7 @@
this.btnSave.Name = "btnSave";
this.btnSave.Size = new System.Drawing.Size(80, 28);
this.btnSave.TabIndex = 11;
this.btnSave.Text = "保存(&S)";
this.btnSave.Text = "保存(S)";
this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
//
// dpb_Tools
@@ -454,7 +458,7 @@
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(58, 23);
this.btnClose.TabIndex = 12;
this.btnClose.Text = "关闭(&Q)";
this.btnClose.Text = "关闭(Q)";
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// labeltxt_managerAudit
@@ -666,4 +670,4 @@
private Control.TabControlEx tab_basicInfo;
private DevExpress.XtraEditors.DropDownButton btnPrint;
}
}
}
@@ -39,6 +39,9 @@ namespace Lskj.BaseAccraditation
{
public partial class FrmBaseAccraditation : BaseForm
{
private readonly AltButtonShortcutManager mAltButtonShortcuts =
new AltButtonShortcutManager();
#region
/// <summary>
/// 审批模型
@@ -64,6 +67,7 @@ namespace Lskj.BaseAccraditation
/// 主表控件
/// </summary>
public MyControl ControlObj;
private bool mResourcesReleased;
#endregion
@@ -189,6 +193,59 @@ namespace Lskj.BaseAccraditation
public FrmBaseAccraditation()
{
InitializeComponent();
InitializeAltButtonShortcuts();
}
private void InitializeAltButtonShortcuts()
{
mAltButtonShortcuts.Register(btnCancel, Keys.C);
mAltButtonShortcuts.Register(btnSave, Keys.S);
mAltButtonShortcuts.Register(btnAudit, Keys.Y);
mAltButtonShortcuts.Register(btnClose, Keys.Q);
mAltButtonShortcuts.Register(btnReturnd, Keys.N);
}
protected override bool ProcessCmdKey(
ref System.Windows.Forms.Message msg, Keys keyData)
{
return mAltButtonShortcuts.ProcessKey(keyData) ||
base.ProcessCmdKey(ref msg, keyData);
}
private void ReleaseResourcesForDispose()
{
if (mResourcesReleased)
{
return;
}
mResourcesReleased = true;
PrintUtil.OnAfterPrint -= OnReportPrintAfter;
MyControl control = ControlObj;
ControlObj = null;
if (control != null)
{
control.OnDataSourceBindCallBack -=
OnControlObjOnDataSourceBindCallBack;
control.Dispose();
}
try
{
if (tab_basicInfo != null)
{
tab_basicInfo.ParentControlEx = null;
}
if (SysModel != null && SysModel.DataCaches != null)
{
SysModel.DataCaches.RemoveCache(this);
}
}
catch
{
// A partially disposed child must not stop form cleanup.
}
}
public override void SetFormSize()
@@ -615,7 +672,7 @@ namespace Lskj.BaseAccraditation
{
this._flowRowData = BaseAuditImpl.GetCurrentFlowRowData(this.ModuleModelObj.MenuTable, this.ModuleModelObj.ParmaryKey, this.SysModel.PrimaryValue);
}
this.UpdateCirculationData();
string billType = this._flowRowData != null ? _flowRowData[this.ModuleModelObj.BillType] + "" : "";
if (string.IsNullOrEmpty(billType) || billType == "0")
{
@@ -1443,7 +1500,7 @@ namespace Lskj.BaseAccraditation
{
this.btnAudit.Enabled = true;
this.btnClose.Visible = this.btnRemindAccradit.Visible = this.btnRemindBack.Visible = this.btnSave.Visible = this.btnReturnd.Visible = false;
this.btnAudit.Text = "确认(&Y)";
this.btnAudit.Text = "确认(Y)";
this.label_auditPerson.Text = "确认意见";
this.labeltxt_managerAudit.Text = "会签人";
this.txt_remark.Text = "确认";
@@ -1733,6 +1790,7 @@ namespace Lskj.BaseAccraditation
{
string printFile = e.Item.Tag + "";
this._flowRowData = BaseAuditImpl.GetCurrentFlowRowData(this.ModuleModelObj.MenuTable, this.ModuleModelObj.ParmaryKey, this.SysModel.PrimaryValue);
this.UpdateCirculationData();
string printPath = PubUtil.PrintFileAbsolutelyPath;
if (!File.Exists(printPath))
{
@@ -1911,6 +1969,7 @@ namespace Lskj.BaseAccraditation
if (this.ModuleModelObj.SaveSuccessfullyRefresh && !isSuccess) return;//保存成功才刷新
// 刷新主表
this._flowRowData = BaseAuditImpl.GetCurrentFlowRowData(this.ModuleModelObj.MenuTable, this.ModuleModelObj.ParmaryKey, this.SysModel.PrimaryValue);
this.UpdateCirculationData();
this._baseRowData = BaseAuditImpl.GetCurrentControlData(ReplaceHelper.ReplaceWhereCond(ReplaceHelper.ReplaceUserInfo(this.ModuleModelObj.MenuSql)), this.ModuleModelObj.ParmaryKey, this.SysModel.PrimaryValue);
if (this._baseRowData == null) this._baseRowData = this._flowRowData;
this.ControlObj.CanExecControl = false;
@@ -2915,5 +2974,25 @@ namespace Lskj.BaseAccraditation
}
}
/// <summary>
/// 更新当前流转数据
/// </summary>
public void UpdateCirculationData()
{
if (SystemInfo.Instance.IsSpecialAuditSave)
{
DataTable snapshotTable = this._flowRowData.Table.Clone();
DataRow snapshotRow = snapshotTable.NewRow();
snapshotRow.ItemArray = (object[])this._flowRowData.ItemArray.Clone();
snapshotTable.Rows.Add(snapshotRow);
snapshotTable.AcceptChanges();
this.ControlObj.beforeData = snapshotRow;
}
}
}
}
+10 -9
View File
@@ -290,15 +290,16 @@ namespace Lskj.Business.Impl
return 1;
}
//2026-08-08 pz说不要判断,工具统一处理
//P_MessageToolLinkDllTab表中cardId=-99为通用模块(右侧快捷通道通用模块),默认有权限 2023-12-4 徐成说的cardId=-99的配置
string sql = string.Format("select a.*,b.PurviewId,b.MouseOutImg,b.MouseOverImg1 from("
+ " select * from P_MessageToolLinkDllTab where cardId=-99 and ( grouptagid=2 or grouptagid=1) "
+ ")a join p_formmenuconfigtab b on a.LMenuId=b.MenuId where LinkModeTag=1 and LMenuid='{1}' order by grouptagid,ItemTagId", ERPInfo.Instance.UserId, menuId);
DataTable table = SqlHelper.ExecuteDataTable(sql);
if (table.Rows.Count > 0)
{
return 1;
}
//string sql = string.Format("select a.*,b.PurviewId,b.MouseOutImg,b.MouseOverImg1 from("
// + " select * from P_MessageToolLinkDllTab where cardId=-99 and ( grouptagid=2 or grouptagid=1) "
// + ")a join p_formmenuconfigtab b on a.LMenuId=b.MenuId where LinkModeTag=1 and LMenuid='{1}' order by grouptagid,ItemTagId", ERPInfo.Instance.UserId, menuId);
//DataTable table = SqlHelper.ExecuteDataTable(sql);
//if (table.Rows.Count > 0)
//{
// return 1;
//}
if (ERPInfo.Instance.UserName == ERPInfo.Instance.UserManager)
return 1;
@@ -1234,7 +1235,7 @@ namespace Lskj.Business.Impl
public static bool GetOpenRestrictions(string MenuId)
{
if (BaseImpl.HasExistsColumn("p_formmenuconfigtab", "SingleOpenMode"))
if (ERPInfo.Instance.SingleOpenMode)
{
string sqlValue = string.Format("SELECT SingleOpenMode from p_formmenuconfigtab where MenuId='{0}'", MenuId);
DataTable dtTable = SqlHelper.ExecuteDataTable(sqlValue);
+121 -43
View File
@@ -926,7 +926,15 @@ namespace Lskj.Business.Impl
{
string field = string.Empty;
DataTable dataTable = GetTableColumns("p_systembillsourcecond");
DataTable dataTable;
try
{
dataTable = InitialParamCache.GetTableColumns("p_systembillsourcecond", delegate { return GetTableColumns("p_systembillsourcecond"); });
}
catch (Exception)
{
dataTable = GetTableColumns("p_systembillsourcecond");
}
if (dataTable.Columns.Contains("FontSize"))
{
@@ -1015,6 +1023,7 @@ namespace Lskj.Business.Impl
/// <exception cref="System.NotImplementedException"></exception>
public static DataTable GetSchemesList(int moduleId)
{
if (moduleId <= 0) return new DataTable();
try
{
string sqlValue = "select * from P_SystemReportProjectTab where ProjectMode=1 and operatorId=@userid and ModuleId=@moduleId";
@@ -1141,7 +1150,16 @@ namespace Lskj.Business.Impl
switch (type)
{
case ModuleType.MrpClickBtn:
if (BaseImpl.HasExistsColumn("P_systempopupmenu", "isMrpClickBtn", "int"))
bool isMrpClickBtnExists;
try
{
isMrpClickBtnExists = InitialParamCache.GetColumnExists("P_systempopupmenu", "isMrpClickBtn", "int", delegate { return BaseImpl.HasExistsColumn("P_systempopupmenu", "isMrpClickBtn", "int"); });
}
catch (Exception)
{
isMrpClickBtnExists = BaseImpl.HasExistsColumn("P_systempopupmenu", "isMrpClickBtn", "int");
}
if (isMrpClickBtnExists)
{
where = " and isnull(isMrpClickBtn,0)=1 and visible1=0 ";
}
@@ -1168,26 +1186,86 @@ namespace Lskj.Business.Impl
where = " and isnull(menutype,0)=0";
break;
}
string sqlTemplate = @"WITH UserRoles AS (
SELECT r.roleName
FROM p_systemRoleOperSetTab AS ro
JOIN p_systemRoleSetTab AS r ON r.id = ro.roleId
WHERE ro.operatorname = '{0}'
)
SELECT pm.*
FROM P_systempopupmenu AS pm WITH (NOLOCK)
WHERE ISNULL(pm.visible, 0) = 0
AND pm.tab = '{1}'
AND (
ISNULL(pm.privilegeOper, '') = ''
OR CHARINDEX(',' + '{0}' + ',', ',' + pm.privilegeOper + ',') > 0
OR EXISTS (
SELECT 1
FROM UserRoles AS ur
WHERE CHARINDEX('{{&' + ur.roleName + '&}}', pm.privilegeOper) > 0)
) {2} ORDER BY pm.orderid;";
string sqlValue = string.Format(sqlTemplate, ERPInfo.Instance.UserName, key, where);
return SqlHelper.ExecuteDataTable(sqlValue);
string sqlValue = string.Format(@"SELECT pm.*
FROM P_systempopupmenu AS pm WITH (NOLOCK)
WHERE ISNULL(pm.visible, 0) = 0
AND pm.tab = @tab {0}
ORDER BY pm.orderid;", where);
DataTable rightMenuTable = SqlHelper.ExecuteDataTable(sqlValue,
new SqlParameter[] { new SqlParameter("@tab", key) });
return FilterRowsByOperatorPrivilege(rightMenuTable, "privilegeOper");
}
/// <summary>
/// 根据人员或角色权限过滤配置数据,只有存在角色配置时才读取角色表。
/// </summary>
internal static DataTable FilterRowsByOperatorPrivilege(DataTable sourceTable, string privilegeField)
{
if (sourceTable == null || !sourceTable.Columns.Contains(privilegeField))
{
return sourceTable;
}
string operatorName = ERPInfo.Instance.UserName;
string operatorToken = "," + operatorName + ",";
List<DataRow> rolePermissionRows = new List<DataRow>();
HashSet<DataRow> allowedRows = new HashSet<DataRow>();
foreach (DataRow row in sourceTable.Rows)
{
string privilegeOper = row[privilegeField] + "";
if (string.IsNullOrWhiteSpace(privilegeOper) ||
("," + privilegeOper + ",").IndexOf(operatorToken, StringComparison.OrdinalIgnoreCase) >= 0)
{
allowedRows.Add(row);
continue;
}
// 只配置人员且当前人员不匹配时,无需读取角色表。
if (privilegeOper.IndexOf("{&", StringComparison.Ordinal) >= 0 &&
privilegeOper.IndexOf("&}", StringComparison.Ordinal) >= 0)
{
rolePermissionRows.Add(row);
}
}
if (rolePermissionRows.Count == 0)
{
DataTable resultTable = sourceTable.Clone();
foreach (DataRow row in sourceTable.Rows)
{
if (allowedRows.Contains(row)) resultTable.ImportRow(row);
}
return resultTable;
}
string roleSql = @"SELECT r.roleName
FROM p_systemRoleOperSetTab AS ro
JOIN p_systemRoleSetTab AS r ON r.id = ro.roleId
WHERE ro.operatorname = @operatorname";
DataTable roleTable = SqlHelper.ExecuteDataTable(roleSql,
new SqlParameter[] { new SqlParameter("@operatorname", operatorName) });
string[] roleTokens = roleTable.Rows.Cast<DataRow>()
.Select(row => row["roleName"] + "")
.Where(roleName => !string.IsNullOrWhiteSpace(roleName))
.Select(roleName => "{&" + roleName + "&}")
.ToArray();
foreach (DataRow row in rolePermissionRows)
{
string privilegeOper = row[privilegeField] + "";
if (roleTokens.Any(token => privilegeOper.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0))
{
allowedRows.Add(row);
}
}
DataTable resultTableWithRoles = sourceTable.Clone();
foreach (DataRow row in sourceTable.Rows)
{
if (allowedRows.Contains(row)) resultTableWithRoles.ImportRow(row);
}
return resultTableWithRoles;
}
/// <summary>
/// 获取单个右键菜单
@@ -1401,26 +1479,14 @@ namespace Lskj.Business.Impl
{
try
{
string sqlTemplate = @"WITH UserRoles AS (
SELECT r.roleName
FROM p_systemRoleOperSetTab AS ro
JOIN p_systemRoleSetTab AS r ON r.id = ro.roleId
WHERE ro.operatorname = '{0}'
)
SELECT pm.*
FROM p_systemDlltabDetail AS pm WITH (NOLOCK)
WHERE ISNULL(pm.isvisible, 0) = 0
AND pm.tab = '{1}'
AND (
ISNULL(pm.privilegeOper, '') = ''
OR CHARINDEX(',' + '{0}' + ',', ',' + pm.privilegeOper + ',') > 0
OR EXISTS (
SELECT 1
FROM UserRoles AS ur
WHERE CHARINDEX('{{&' + ur.roleName + '&}}', pm.privilegeOper) > 0)
) ORDER BY pm.orderid;";
string sqlValue = string.Format(sqlTemplate, ERPInfo.Instance.UserName, menuCode);
return SqlHelper.ExecuteDataTable(sqlValue);
string sqlValue = @"SELECT pm.*
FROM p_systemDlltabDetail AS pm WITH (NOLOCK)
WHERE ISNULL(pm.isvisible, 0) = 0
AND pm.tab = @tab
ORDER BY pm.orderid;";
DataTable detailPageTable = SqlHelper.ExecuteDataTable(sqlValue,
new SqlParameter[] { new SqlParameter("@tab", menuCode) });
return FilterRowsByOperatorPrivilege(detailPageTable, "privilegeOper");
}
catch (Exception)
{
@@ -1515,7 +1581,19 @@ namespace Lskj.Business.Impl
//保存条件表
public static DataTable GetClientCond(string MenuCode)
{
if (BaseImpl.HasExistsTable("P_SystemClientCondTab"))
const string tableName = "P_SystemClientCondTab";
bool tableExists;
try
{
tableExists = InitialParamCache.GetTableExists(tableName, delegate { return BaseImpl.HasExistsTable(tableName); });
}
catch (Exception)
{
// 缓存未能正常读取或记录时,重新查询,避免影响原有功能。
tableExists = BaseImpl.HasExistsTable(tableName);
}
if (tableExists)
{
string sqlValue = string.Format(@"select * from P_SystemClientCondTab where tab='{0}' and disableflag=0 order by orderid ", MenuCode);
return GetDataTableResult(sqlValue);
+23 -19
View File
@@ -677,33 +677,37 @@ namespace Lskj.Business.Impl
conditions = "and isnull(mxflag,0)=0";
}
string cond = !string.IsNullOrEmpty(sourceCond) ? string.Format(" and id in ({0})", sourceCond.Trim(',')) : string.Empty;
string sqlValue = string.Format(@"WITH UserRoles AS (
SELECT r.roleName
FROM p_systemRoleOperSetTab AS ro
JOIN p_systemRoleSetTab AS r ON r.id = ro.roleId
WHERE ro.operatorname = '{0}'
)
select * from p_systembillsource where typeCode=@typeCode" + cond +
@" and isnull(isVisible,0)=0 and (isnull(viewOper,'')='' or CHARINDEX(',' + '{0}' + ',', ',' + viewOper + ',')>0 OR EXISTS (
SELECT 1 FROM UserRoles AS ur WHERE CHARINDEX('{{&' + ur.roleName + '&}}', viewOper) > 0)) order by orderid", ERPInfo.Instance.UserName);
string sqlDetail = string.Format(@"WITH UserRoles AS (
SELECT r.roleName
FROM p_systemRoleOperSetTab AS ro
JOIN p_systemRoleSetTab AS r ON r.id = ro.roleId
WHERE ro.operatorname = '{1}'
)
SELECT id,sourceId,fieldName,sysName,userName,orderid,isVisible,sourceKey,privilegeView,DataFormat,isSum,ifmerge,{2}
string sqlValue = @"select * from p_systembillsource
where typeCode=@typeCode" + cond + @"
and isnull(isVisible,0)=0
order by orderid";
DataTable sourceTable = SqlHelper.ExecuteDataTable(sqlValue,
new SqlParameter[] { new SqlParameter("@typeCode", menuCode) });
sourceTable = BaseModuleImpl.FilterRowsByOperatorPrivilege(sourceTable, "viewOper");
htTable["master"] = sourceTable;
string sqlDetail = string.Format(@"SELECT id,sourceId,fieldName,sysName,userName,orderid,isVisible,sourceKey,privilegeView,DataFormat,isSum,ifmerge,{2}
isnull(CASE WHEN isVisible=1 OR (ISNULL(b.userList,'')='' AND ISNULL(a.PrivilegeView,'')<>'') THEN 0 ELSE width END,0) width
FROM p_systembillsourcedetail a
LEFT JOIN (
SELECT userList,privTypeId from p_systemPrivilege b where modId = '{0}'
AND CHARINDEX(',' + '{1}' + ',', ',' + userList + ',') > 0
) b on CHARINDEX(',' + CAST(b.privTypeId AS VARCHAR(5)) + ',',',' + PrivilegeView + ',') > 0
where sourceId in (select id from p_systembillsource where typeCode=@typeCode" + cond + @" and isnull(isVisible,0)=0 and (isnull(viewOper,'')='' or CHARINDEX(',' + '{1}' + ',', ',' + viewOper + ',')>0) OR EXISTS (
SELECT 1 FROM UserRoles AS ur WHERE CHARINDEX('{{&' + ur.roleName + '&}}', viewOper) > 0)) {3} ", menuCode, ERPInfo.Instance.UserName, otherfield, conditions);
htTable["master"] = SqlHelper.ExecuteDataTable(sqlValue, new SqlParameter[] { new SqlParameter("@typeCode", menuCode) });
where sourceId in (select id from p_systembillsource where typeCode=@typeCode" + cond + @" and isnull(isVisible,0)=0) {3} ", menuCode, ERPInfo.Instance.UserName, otherfield, conditions);
DataTable detailTable= SqlHelper.ExecuteDataTable(sqlDetail, new SqlParameter[] { new SqlParameter("@typeCode", menuCode) });
HashSet<string> sourceIds = new HashSet<string>(
sourceTable.Rows.Cast<DataRow>().Select(row => row["id"] + ""));
if (detailTable != null && detailTable.Rows.Count > 0)
{
DataTable allowedDetailTable = detailTable.Clone();
foreach (DataRow row in detailTable.Rows)
{
if (sourceIds.Contains(row["sourceId"] + "")) allowedDetailTable.ImportRow(row);
}
detailTable = allowedDetailTable;
}
// order by sourceId,orderid 数据库不排序,在表格中排序(解决慢查询)
if (detailTable != null && detailTable.Rows.Count > 0)
{
@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.Data;
namespace Lskj.Business.Impl
{
/// <summary>
/// 单次模块初始化期间复用的参数缓存。
/// </summary>
public static class InitialParamCache
{
private static readonly object SyncRoot = new object();
private static readonly Dictionary<string, bool> TableExistsCache =
new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
private static readonly Dictionary<string, bool> ColumnExistsCache =
new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
private static readonly Dictionary<string, DataTable> TableColumnsCache =
new Dictionary<string, DataTable>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// 获取表是否存在。没有缓存时执行查询,并记录查询结果。
/// </summary>
public static bool GetTableExists(string tableName, Func<bool> query)
{
if (string.IsNullOrWhiteSpace(tableName))
{
throw new ArgumentException("表名不能为空。", "tableName");
}
if (query == null)
{
throw new ArgumentNullException("query");
}
lock (SyncRoot)
{
bool tableExists;
if (TableExistsCache.TryGetValue(tableName, out tableExists))
{
return tableExists;
}
tableExists = query();
TableExistsCache[tableName] = tableExists;
return tableExists;
}
}
/// <summary>
/// 获取字段是否存在。没有缓存时执行查询,并记录查询结果。
/// </summary>
public static bool GetColumnExists(string tableName, string columnName, string columnType, Func<bool> query)
{
if (string.IsNullOrWhiteSpace(tableName))
{
throw new ArgumentException("表名不能为空。", "tableName");
}
if (string.IsNullOrWhiteSpace(columnName))
{
throw new ArgumentException("字段名不能为空。", "columnName");
}
if (query == null)
{
throw new ArgumentNullException("query");
}
string cacheKey = tableName + "|" + columnName + "|" + (columnType ?? string.Empty);
lock (SyncRoot)
{
bool columnExists;
if (ColumnExistsCache.TryGetValue(cacheKey, out columnExists))
{
return columnExists;
}
columnExists = query();
ColumnExistsCache[cacheKey] = columnExists;
return columnExists;
}
}
/// <summary>
/// 获取表结构。没有缓存时执行查询,并缓存不包含数据的结构模板。
/// </summary>
public static DataTable GetTableColumns(string tableName, Func<DataTable> query)
{
if (string.IsNullOrWhiteSpace(tableName))
{
throw new ArgumentException("表名不能为空。", "tableName");
}
if (query == null)
{
throw new ArgumentNullException("query");
}
lock (SyncRoot)
{
DataTable tableColumns;
if (!TableColumnsCache.TryGetValue(tableName, out tableColumns))
{
DataTable queryResult = query();
if (queryResult == null)
{
throw new InvalidOperationException("获取表结构失败。" + tableName);
}
tableColumns = queryResult.Clone();
TableColumnsCache[tableName] = tableColumns;
}
return tableColumns.Clone();
}
}
/// <summary>
/// 清空上一次模块初始化记录的参数。
/// </summary>
public static void Clear()
{
lock (SyncRoot)
{
TableExistsCache.Clear();
ColumnExistsCache.Clear();
TableColumnsCache.Clear();
}
}
}
}
+20 -20
View File
@@ -42,18 +42,18 @@ namespace Lskj.Business
{
try
{
if (!BaseImpl.HasExistsColumn("P_LogTab", "IPAddress"))
{
SqlHelper.ExecuteNonQuery("alter table P_LogTab add IPAddress varchar(500)");
}
if (!BaseImpl.HasExistsColumn("P_LogTab", "MacAddress"))
{
SqlHelper.ExecuteNonQuery("alter table P_LogTab add MacAddress varchar(500)");
}
if (!BaseImpl.HasExistsColumn("P_LogTab", "ModuleId"))
{
SqlHelper.ExecuteNonQuery("alter table P_LogTab add ModuleId varchar(500)");
}
//if (!BaseImpl.HasExistsColumn("P_LogTab", "IPAddress"))
//{
// SqlHelper.ExecuteNonQuery("alter table P_LogTab add IPAddress varchar(500)");
//}
//if (!BaseImpl.HasExistsColumn("P_LogTab", "MacAddress"))
//{
// SqlHelper.ExecuteNonQuery("alter table P_LogTab add MacAddress varchar(500)");
//}
//if (!BaseImpl.HasExistsColumn("P_LogTab", "ModuleId"))
//{
// SqlHelper.ExecuteNonQuery("alter table P_LogTab add ModuleId varchar(500)");
//}
//string ModuleCode = string.Empty;
//string ModuleId = string.Empty;
@@ -108,14 +108,14 @@ namespace Lskj.Business
string exmessage = Regex.Replace(ex.Message, "'", "''");
if (!BaseImpl.HasExistsColumn("p_errlogtab", "IPAddress"))
{
SqlHelper.ExecuteNonQuery("alter table p_errlogtab add IPAddress varchar(500)");
}
if (!BaseImpl.HasExistsColumn("p_errlogtab", "MacAddress"))
{
SqlHelper.ExecuteNonQuery("alter table p_errlogtab add MacAddress varchar(500)");
}
//if (!BaseImpl.HasExistsColumn("p_errlogtab", "IPAddress"))
//{
// SqlHelper.ExecuteNonQuery("alter table p_errlogtab add IPAddress varchar(500)");
//}
//if (!BaseImpl.HasExistsColumn("p_errlogtab", "MacAddress"))
//{
// SqlHelper.ExecuteNonQuery("alter table p_errlogtab add MacAddress varchar(500)");
//}
string sqlValue = string.Format("insert into p_errlogtab(Operatedate,Operator,Content,ErrMsg,Ws,IPAddress,MacAddress) values(getdate(),'{0}','{1}','{2}','{3}','{4}','{5}')",
ERPInfo.Instance.UserName, content, exmessage + "\r\n" + ex.StackTrace, ERPInfo.Instance.WindowName, ERPInfo.Instance.LoginIPV4, ERPInfo.Instance.MacAddress);
+32 -1
View File
@@ -663,6 +663,37 @@ namespace Lskj.Business.Impl
}
}
/// <summary>
/// 获取菜单是否使用 BS 网页方式打开。
/// </summary>
/// <param name="menuId">菜单 ID。</param>
/// <returns>1 表示使用 BS 网页方式打开;其他值按原 CS 方式打开。</returns>
public static int GetBsOpenMode(string menuId)
{
if (string.IsNullOrWhiteSpace(menuId) || !HasExistsColumn("P_FormMenuConfigTab", "BsOpenMode"))
{
return 0;
}
try
{
const string sqlValue = @"select ISNULL(BsOpenMode,0) as BsOpenMode
from P_FormMenuConfigTab
where MenuId=@MenuId";
DataTable dataTable = SqlHelper.ExecuteDataTable(
sqlValue,
new SqlParameter("@MenuId", menuId));
int bsOpenMode;
return dataTable.Rows.Count > 0 &&
int.TryParse(dataTable.Rows[0]["BsOpenMode"] + "", out bsOpenMode)
? bsOpenMode
: 0;
}
catch (Exception)
{
return 0;
}
}
/// <summary>
/// <para>说明:根据配置MenuType加载菜单</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2017-08-16 </para>
@@ -1358,4 +1389,4 @@ namespace Lskj.Business.Impl
}
}
}
}
+16 -2
View File
@@ -66,6 +66,9 @@ namespace Lskj.Business
if (item.Table.Columns.Contains("UpdateAddressXp") && ERPInfo.Instance.SystemVersion.Contains("Windows XP"))
Instance.UpdateAddress = !string.IsNullOrEmpty(item["UpdateAddressXp"] + "") ? item["UpdateAddressXp"] + "" : "";
//内网对应的升级地址
Instance.UpdateAddress = DBConfig.Instance.IsInternalNetwork && item.Table.Columns.Contains("InternalUpdateAddress") && !string.IsNullOrEmpty(item["InternalUpdateAddress"] + "") ? item["InternalUpdateAddress"] + "" : Instance.UpdateAddress;
Instance.OAUrl = DBConfig.Instance.Internet && item.Table.Columns.Contains("localOAUrl") && !string.IsNullOrEmpty(item["localOAUrl"] + "") ? item["localOAUrl"] + "" : item["OAUrl"] + "";
@@ -336,6 +339,9 @@ namespace Lskj.Business
{
ResourceDynamic.PubBrower = System.Environment.OSVersion.Version.Major == 5 && (System.Environment.OSVersion.Version.Minor == 1 || System.Environment.OSVersion.Version.Minor == 2) ? "Lskj.PubBrowerXp.dll" : "Lskj.PubBrower2.dll";
}
Instance.IsSpecialAuditSave = item.Table.Columns.Contains("IsSpecialAuditSave") && !string.IsNullOrEmpty(item["IsSpecialAuditSave"] + "") ? "1".Equals(item["IsSpecialAuditSave"] + "") : false;
}
/// <summary>
/// 高拍仪AccessKey
@@ -1161,9 +1167,17 @@ namespace Lskj.Business
/// </summary>
public string DeadlockPrompt;
/// <summary>
/// 附件浏览器自带逻辑
/// 附件按钮打开Lskj.PubBrower2.dll
/// </summary>
public bool SpecialAttachmentBrowser;
/// <summary>
/// 特殊审核保存模式(修改语句只拼接修改后的控件)
/// </summary>
public bool IsSpecialAuditSave;
/// <summary>
/// 默认权限模块
/// P_MessageToolLinkDllTab表中cardId=-99为通用模块(右侧快捷通道通用模块) 2023-12-4 徐成说的cardId=-99的配置
/// </summary>
//public DataTable DefaultPermissionTable;
}
}
@@ -87,6 +87,7 @@
<Compile Include="Impl\BillImpl.cs" />
<Compile Include="Impl\ConditionalCaching.cs" />
<Compile Include="Impl\ErrorMessage.cs" />
<Compile Include="Impl\InitialParamCache.cs" />
<Compile Include="Impl\LanguageTranslation.cs" />
<Compile Include="Impl\MainImpl.cs" />
<Compile Include="Impl\BillAuditImpl.cs" />
+15 -10
View File
@@ -13,9 +13,14 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
Lskj.Control.Model.PrintUtil.OnAfterPrint -=
new System.EventHandler(OnReportPrintAfter);
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -170,7 +175,7 @@
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(75, 26);
this.btnClose.TabIndex = 22;
this.btnClose.Text = "关闭(&Q)";
this.btnClose.Text = "关闭(Q)";
//
// btnBack
//
@@ -182,7 +187,7 @@
this.btnBack.Name = "btnBack";
this.btnBack.Size = new System.Drawing.Size(75, 26);
this.btnBack.TabIndex = 21;
this.btnBack.Text = "返退(&N)";
this.btnBack.Text = "返退(N)";
this.btnBack.Click += new System.EventHandler(this.btnReturn_Click);
//
// btnSave
@@ -195,7 +200,7 @@
this.btnSave.Name = "btnSave";
this.btnSave.Size = new System.Drawing.Size(75, 26);
this.btnSave.TabIndex = 25;
this.btnSave.Text = "保存(&S)";
this.btnSave.Text = "保存(S)";
this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
//
// btnAccradit
@@ -208,7 +213,7 @@
this.btnAccradit.Name = "btnAccradit";
this.btnAccradit.Size = new System.Drawing.Size(75, 26);
this.btnAccradit.TabIndex = 20;
this.btnAccradit.Text = "审核(&Y)";
this.btnAccradit.Text = "审核(Y)";
this.btnAccradit.Click += new System.EventHandler(this.btnAccradit_Click);
//
// btnPrint
@@ -251,7 +256,7 @@
this.btnSpare.Name = "btnSpare";
this.btnSpare.Size = new System.Drawing.Size(75, 26);
this.btnSpare.TabIndex = 27;
this.btnSpare.Text = "分单(&P)";
this.btnSpare.Text = "分单(P)";
this.btnSpare.Click += new System.EventHandler(this.btnSpare_Click);
//
// pcTool
@@ -376,7 +381,7 @@
this.btnReflash.Name = "btnReflash";
this.btnReflash.Size = new System.Drawing.Size(75, 26);
this.btnReflash.TabIndex = 27;
this.btnReflash.Text = "刷新(&R)";
this.btnReflash.Text = "刷新(R)";
this.btnReflash.Click += new System.EventHandler(this.btnReflash_Click);
//
// panelControl1
@@ -518,7 +523,7 @@
this.btnSearch.Name = "btnSearch";
this.btnSearch.Size = new System.Drawing.Size(72, 26);
this.btnSearch.TabIndex = 6;
this.btnSearch.Text = "搜索(&Q)";
this.btnSearch.Text = "搜索(Q)";
this.btnSearch.Click += new System.EventHandler(this.btnSearch_Click);
//
// labeldate_end
@@ -566,7 +571,7 @@
this.btnBackTop.Name = "btnBackTop";
this.btnBackTop.Size = new System.Drawing.Size(72, 26);
this.btnBackTop.TabIndex = 8;
this.btnBackTop.Text = "返审(&W)";
this.btnBackTop.Text = "返审(W)";
this.btnBackTop.Click += new System.EventHandler(this.btnBack_Click);
//
// pcBillDetail
+42 -3
View File
@@ -29,11 +29,35 @@ namespace Lskj.Control
{
public partial class AuditPanel2 : UserControl
{
private readonly AltButtonShortcutManager mAltButtonShortcuts =
new AltButtonShortcutManager();
public AuditPanel2()
{
InitializeComponent();
InitializeAltButtonShortcuts();
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.Selectable | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.SupportsTransparentBackColor, true);
}
private void InitializeAltButtonShortcuts()
{
mAltButtonShortcuts.Register(btnClose, Keys.Q);
mAltButtonShortcuts.Register(btnBack, Keys.N);
mAltButtonShortcuts.Register(btnSave, Keys.S);
mAltButtonShortcuts.Register(btnAccradit, Keys.Y);
mAltButtonShortcuts.Register(btnSpare, Keys.P);
mAltButtonShortcuts.Register(btnReflash, Keys.R);
mAltButtonShortcuts.Register(btnSearch, Keys.Q);
mAltButtonShortcuts.Register(btnBackTop, Keys.W);
}
protected override bool ProcessCmdKey(
ref System.Windows.Forms.Message msg, Keys keyData)
{
return mAltButtonShortcuts.ProcessKey(keyData) ||
base.ProcessCmdKey(ref msg, keyData);
}
#region
public string modelkeyName = "";
/// <summary>
@@ -1601,7 +1625,7 @@ namespace Lskj.Control
this.btnClose.Enabled = this.btnSave.Enabled = this.btnAccradit.Enabled = this.btnBack.Enabled = this.btnSpare.Enabled = false;
this.btnSave.Visible = this.btnClose.Visible = this.btnBack.Visible = this.pcTool.Visible = true;
this.btnAccradit.Text = "确认(&Y)";
this.btnAccradit.Text = "确认(Y)";
return;
}
@@ -2016,7 +2040,7 @@ namespace Lskj.Control
}
//选中上一次选中行行号
if (SelectGridControlEx != null && oldRowHandle > 0)
if (SelectGridControlEx != null && oldRowHandle >= 0)
{
SelectGridControlEx.GridView.SelectRowHandler(oldRowHandle);
OnPcgridRowCellClick(SelectGridControlEx.GridView, null);
@@ -2057,10 +2081,25 @@ namespace Lskj.Control
string fieldValue = this.ControlObj.GetControlValue(model);
if (fieldValue == "****") continue;
if (SystemInfo.Instance.IsSpecialAuditSave &&
this._drBillInfoMsg != null &&
this._drBillInfoMsg.Table != null &&
this._drBillInfoMsg.Table.Columns.Contains(model.FieldName) &&
AuditChangeLog.IsSameValue(this._drBillInfoMsg[model.FieldName] + "", fieldValue))
{
continue;
}
//updateBuilder.AppendFormat("{0}='{1}',", model.FieldName, fieldValue);
updateBuilder.Append(string.IsNullOrEmpty(fieldValue) ? string.Format("{0}={1}", model.FieldName, this.ControlObj.GetNullValue(model)) : string.Format("{0}=N'{1}',", model.FieldName, fieldValue.Contains("'") ? fieldValue.Replace("'", "''") : fieldValue));
}
}
string updateFields = updateBuilder.ToString().TrimEnd(',');
if (string.IsNullOrEmpty(updateFields))
{
return string.Empty;
}
return string.Format("update {0} set {1} where {2}='{3}'", this.BillModelObj.MasterTable, updateBuilder.ToString().TrimEnd(','), BillModelObj.PrimaryKey, this.SysModel.BillDocumentId);
}
#endregion
@@ -3609,4 +3648,4 @@ namespace Lskj.Control
}
}
}
}
+216 -212
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -28,22 +32,6 @@
/// </summary>
private void InitializeComponent()
{
this.tabMain = new DevExpress.XtraTab.XtraTabControl();
this.tabpage_finish = new DevExpress.XtraTab.XtraTabPage();
this.gridFinish = new Lskj.Control.GridControlEx();
this.splitBelow = new DevExpress.XtraEditors.SplitContainerControl();
this.gridFlow = new Lskj.Control.GridControlEx();
this.gridDetail = new Lskj.Control.GridControlEx();
this.pl_top = new DevExpress.XtraEditors.PanelControl();
this.pl_top_searchCond = new DevExpress.XtraEditors.PanelControl();
this.labeldate_start = new Lskj.Control.LabelCheckDateEdit();
this.labelcheck_finalAuditor = new Lskj.Control.LabelCheckAutoTextEdit();
this.labeltxt_dataFlag = new Lskj.Control.LabelTextEdit();
this.btnSearch = new DevExpress.XtraEditors.SimpleButton();
this.labeldate_end = new Lskj.Control.LabelCheckDateEdit();
this.pl_top_right = new DevExpress.XtraEditors.PanelControl();
this.simpleButton1 = new DevExpress.XtraEditors.SimpleButton();
this.btnBack = new DevExpress.XtraEditors.SimpleButton();
this.label_tips = new DevExpress.XtraEditors.LabelControl();
this.label_date = new DevExpress.XtraEditors.LabelControl();
this.pl_bottom = new DevExpress.XtraEditors.PanelControl();
@@ -59,8 +47,26 @@
this.btnOkAudit = new DevExpress.XtraEditors.SimpleButton();
this.btnBackAudit = new DevExpress.XtraEditors.SimpleButton();
this.btnRefresh = new DevExpress.XtraEditors.SimpleButton();
((System.ComponentModel.ISupportInitialize)(this.tabMain)).BeginInit();
this.tabMain.SuspendLayout();
this.tabpage_finish = new DevExpress.XtraTab.XtraTabPage();
this.gridFinish = new Lskj.Control.GridControlEx();
this.splitBelow = new DevExpress.XtraEditors.SplitContainerControl();
this.gridFlow = new Lskj.Control.GridControlEx();
this.gridDetail = new Lskj.Control.GridControlEx();
this.pl_top = new DevExpress.XtraEditors.PanelControl();
this.pl_top_searchCond = new DevExpress.XtraEditors.PanelControl();
this.labeldate_start = new Lskj.Control.LabelCheckDateEdit();
this.labelcheck_finalAuditor = new Lskj.Control.LabelCheckAutoTextEdit();
this.labeltxt_dataFlag = new Lskj.Control.LabelTextEdit();
this.btnSearch = new DevExpress.XtraEditors.SimpleButton();
this.labeldate_end = new Lskj.Control.LabelCheckDateEdit();
this.pl_top_right = new DevExpress.XtraEditors.PanelControl();
this.simpleButton1 = new DevExpress.XtraEditors.SimpleButton();
this.btnBack = new DevExpress.XtraEditors.SimpleButton();
this.tabMain = new DevExpress.XtraTab.XtraTabControl();
((System.ComponentModel.ISupportInitialize)(this.pl_bottom)).BeginInit();
this.pl_bottom.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.p_menu)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.barManager1)).BeginInit();
this.tabpage_finish.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.splitBelow)).BeginInit();
this.splitBelow.SuspendLayout();
@@ -70,24 +76,166 @@
this.pl_top_searchCond.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pl_top_right)).BeginInit();
this.pl_top_right.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pl_bottom)).BeginInit();
this.pl_bottom.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.p_menu)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.barManager1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.tabMain)).BeginInit();
this.tabMain.SuspendLayout();
this.SuspendLayout();
//
// tabMain
// label_tips
//
this.tabMain.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabMain.HeaderLocation = DevExpress.XtraTab.TabHeaderLocation.Bottom;
this.tabMain.Location = new System.Drawing.Point(0, 0);
this.tabMain.Name = "tabMain";
this.tabMain.SelectedTabPage = this.tabpage_finish;
this.tabMain.Size = new System.Drawing.Size(1051, 701);
this.tabMain.TabIndex = 20;
this.tabMain.TabPages.AddRange(new DevExpress.XtraTab.XtraTabPage[] {
this.tabpage_finish});
this.label_tips.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.label_tips.Appearance.ForeColor = System.Drawing.Color.Red;
this.label_tips.Location = new System.Drawing.Point(221, 9);
this.label_tips.Name = "label_tips";
this.label_tips.Size = new System.Drawing.Size(204, 12);
this.label_tips.TabIndex = 4;
this.label_tips.Text = "友情提示:双击单据信息进入单据审核";
//
// label_date
//
this.label_date.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.label_date.Appearance.ForeColor = System.Drawing.Color.Red;
this.label_date.Location = new System.Drawing.Point(7, 9);
this.label_date.Name = "label_date";
this.label_date.Size = new System.Drawing.Size(198, 12);
this.label_date.TabIndex = 3;
this.label_date.Text = "上次刷新时间:2014-12-15 12:30:30";
//
// pl_bottom
//
this.pl_bottom.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
this.pl_bottom.Controls.Add(this.btnReverseSelection);
this.pl_bottom.Controls.Add(this.btnSelectAll);
this.pl_bottom.Controls.Add(this.dpb_Tools);
this.pl_bottom.Controls.Add(this.btnOkAudit);
this.pl_bottom.Controls.Add(this.btnBackAudit);
this.pl_bottom.Controls.Add(this.btnRefresh);
this.pl_bottom.Controls.Add(this.label_tips);
this.pl_bottom.Controls.Add(this.label_date);
this.pl_bottom.Dock = System.Windows.Forms.DockStyle.Bottom;
this.pl_bottom.Location = new System.Drawing.Point(0, 1036);
this.pl_bottom.Name = "pl_bottom";
this.pl_bottom.Size = new System.Drawing.Size(1576, 36);
this.pl_bottom.TabIndex = 21;
//
// btnReverseSelection
//
this.btnReverseSelection.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnReverseSelection.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.btnReverseSelection.Appearance.Options.UseFont = true;
this.btnReverseSelection.Location = new System.Drawing.Point(1111, 7);
this.btnReverseSelection.Name = "btnReverseSelection";
this.btnReverseSelection.Size = new System.Drawing.Size(55, 26);
this.btnReverseSelection.TabIndex = 13;
this.btnReverseSelection.Text = "反选";
this.btnReverseSelection.Visible = false;
this.btnReverseSelection.Click += new System.EventHandler(this.btnReverseSelection_Click);
//
// btnSelectAll
//
this.btnSelectAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnSelectAll.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.btnSelectAll.Appearance.Options.UseFont = true;
this.btnSelectAll.Location = new System.Drawing.Point(1172, 7);
this.btnSelectAll.Name = "btnSelectAll";
this.btnSelectAll.Size = new System.Drawing.Size(55, 26);
this.btnSelectAll.TabIndex = 12;
this.btnSelectAll.Text = "全选";
this.btnSelectAll.Visible = false;
this.btnSelectAll.Click += new System.EventHandler(this.btnSelectAll_Click);
//
// dpb_Tools
//
this.dpb_Tools.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.dpb_Tools.Appearance.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.dpb_Tools.Appearance.Options.UseFont = true;
this.dpb_Tools.DropDownArrowStyle = DevExpress.XtraEditors.DropDownArrowStyle.Show;
this.dpb_Tools.DropDownControl = this.p_menu;
this.dpb_Tools.Location = new System.Drawing.Point(1413, 7);
this.dpb_Tools.Name = "dpb_Tools";
this.dpb_Tools.Size = new System.Drawing.Size(80, 26);
this.dpb_Tools.TabIndex = 11;
this.dpb_Tools.Text = "常用工具";
//
// p_menu
//
this.p_menu.Manager = this.barManager1;
this.p_menu.MenuDrawMode = DevExpress.XtraBars.MenuDrawMode.SmallImagesText;
this.p_menu.Name = "p_menu";
//
// barManager1
//
this.barManager1.DockControls.Add(this.barDockControlTop);
this.barManager1.DockControls.Add(this.barDockControlBottom);
this.barManager1.DockControls.Add(this.barDockControlLeft);
this.barManager1.DockControls.Add(this.barDockControlRight);
this.barManager1.Form = this;
this.barManager1.MaxItemId = 0;
//
// barDockControlTop
//
this.barDockControlTop.CausesValidation = false;
this.barDockControlTop.Dock = System.Windows.Forms.DockStyle.Top;
this.barDockControlTop.Location = new System.Drawing.Point(0, 0);
this.barDockControlTop.Size = new System.Drawing.Size(1576, 0);
//
// barDockControlBottom
//
this.barDockControlBottom.CausesValidation = false;
this.barDockControlBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
this.barDockControlBottom.Location = new System.Drawing.Point(0, 1072);
this.barDockControlBottom.Size = new System.Drawing.Size(1576, 0);
//
// barDockControlLeft
//
this.barDockControlLeft.CausesValidation = false;
this.barDockControlLeft.Dock = System.Windows.Forms.DockStyle.Left;
this.barDockControlLeft.Location = new System.Drawing.Point(0, 0);
this.barDockControlLeft.Size = new System.Drawing.Size(0, 1072);
//
// barDockControlRight
//
this.barDockControlRight.CausesValidation = false;
this.barDockControlRight.Dock = System.Windows.Forms.DockStyle.Right;
this.barDockControlRight.Location = new System.Drawing.Point(1576, 0);
this.barDockControlRight.Size = new System.Drawing.Size(0, 1072);
//
// btnOkAudit
//
this.btnOkAudit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnOkAudit.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.btnOkAudit.Appearance.Options.UseFont = true;
this.btnOkAudit.Location = new System.Drawing.Point(1233, 7);
this.btnOkAudit.Name = "btnOkAudit";
this.btnOkAudit.Size = new System.Drawing.Size(82, 26);
this.btnOkAudit.TabIndex = 7;
this.btnOkAudit.Text = "批量审核(Y)";
this.btnOkAudit.Visible = false;
this.btnOkAudit.Click += new System.EventHandler(this.OnBtnOkAuditClick);
//
// btnBackAudit
//
this.btnBackAudit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnBackAudit.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.btnBackAudit.Appearance.Options.UseFont = true;
this.btnBackAudit.Location = new System.Drawing.Point(1321, 7);
this.btnBackAudit.Name = "btnBackAudit";
this.btnBackAudit.Size = new System.Drawing.Size(86, 26);
this.btnBackAudit.TabIndex = 6;
this.btnBackAudit.Text = "批量返审(B)";
this.btnBackAudit.Visible = false;
this.btnBackAudit.Click += new System.EventHandler(this.OnBtnBackAuditClick);
//
// btnRefresh
//
this.btnRefresh.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnRefresh.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.btnRefresh.Appearance.Options.UseFont = true;
this.btnRefresh.Location = new System.Drawing.Point(1499, 7);
this.btnRefresh.Name = "btnRefresh";
this.btnRefresh.Size = new System.Drawing.Size(72, 26);
this.btnRefresh.TabIndex = 5;
this.btnRefresh.Text = "刷新(R)";
this.btnRefresh.Click += new System.EventHandler(this.BtnReflash_Click);
//
// tabpage_finish
//
@@ -95,7 +243,7 @@
this.tabpage_finish.Controls.Add(this.splitBelow);
this.tabpage_finish.Controls.Add(this.pl_top);
this.tabpage_finish.Name = "tabpage_finish";
this.tabpage_finish.Size = new System.Drawing.Size(1045, 672);
this.tabpage_finish.Size = new System.Drawing.Size(1570, 1007);
this.tabpage_finish.Text = "已完成单据";
//
// gridFinish
@@ -107,20 +255,20 @@
this.gridFinish.Margin = new System.Windows.Forms.Padding(4);
this.gridFinish.Name = "gridFinish";
this.gridFinish.SiftEnumObj = Lskj.Control.GridControlEx.HeaderSiftEnum.Sum;
this.gridFinish.Size = new System.Drawing.Size(1045, 340);
this.gridFinish.Size = new System.Drawing.Size(1570, 675);
this.gridFinish.SysModel = null;
this.gridFinish.TabIndex = 29;
//
// splitBelow
//
this.splitBelow.Dock = System.Windows.Forms.DockStyle.Bottom;
this.splitBelow.Location = new System.Drawing.Point(0, 379);
this.splitBelow.Location = new System.Drawing.Point(0, 714);
this.splitBelow.Name = "splitBelow";
this.splitBelow.Panel1.Controls.Add(this.gridFlow);
this.splitBelow.Panel1.Text = "Panel1";
this.splitBelow.Panel2.Controls.Add(this.gridDetail);
this.splitBelow.Panel2.Text = "Panel2";
this.splitBelow.Size = new System.Drawing.Size(1045, 293);
this.splitBelow.Size = new System.Drawing.Size(1570, 293);
this.splitBelow.SplitterPosition = 453;
this.splitBelow.TabIndex = 28;
this.splitBelow.Text = "splitContainerControl1";
@@ -145,7 +293,7 @@
this.gridDetail.Margin = new System.Windows.Forms.Padding(4);
this.gridDetail.Name = "gridDetail";
this.gridDetail.SiftEnumObj = Lskj.Control.GridControlEx.HeaderSiftEnum.Sum;
this.gridDetail.Size = new System.Drawing.Size(587, 293);
this.gridDetail.Size = new System.Drawing.Size(1112, 293);
this.gridDetail.SysModel = null;
this.gridDetail.TabIndex = 20;
//
@@ -156,7 +304,7 @@
this.pl_top.Dock = System.Windows.Forms.DockStyle.Top;
this.pl_top.Location = new System.Drawing.Point(0, 0);
this.pl_top.Name = "pl_top";
this.pl_top.Size = new System.Drawing.Size(1045, 39);
this.pl_top.Size = new System.Drawing.Size(1570, 39);
this.pl_top.TabIndex = 25;
//
// pl_top_searchCond
@@ -170,7 +318,7 @@
this.pl_top_searchCond.Dock = System.Windows.Forms.DockStyle.Fill;
this.pl_top_searchCond.Location = new System.Drawing.Point(2, 2);
this.pl_top_searchCond.Name = "pl_top_searchCond";
this.pl_top_searchCond.Size = new System.Drawing.Size(778, 35);
this.pl_top_searchCond.Size = new System.Drawing.Size(1303, 35);
this.pl_top_searchCond.TabIndex = 23;
//
// labeldate_start
@@ -235,7 +383,7 @@
this.btnSearch.Name = "btnSearch";
this.btnSearch.Size = new System.Drawing.Size(72, 26);
this.btnSearch.TabIndex = 6;
this.btnSearch.Text = "搜索(&Q)";
this.btnSearch.Text = "搜索(Q)";
this.btnSearch.Click += new System.EventHandler(this.btnSearch_Click);
//
// labeldate_end
@@ -262,7 +410,7 @@
this.pl_top_right.Controls.Add(this.simpleButton1);
this.pl_top_right.Controls.Add(this.btnBack);
this.pl_top_right.Dock = System.Windows.Forms.DockStyle.Right;
this.pl_top_right.Location = new System.Drawing.Point(780, 2);
this.pl_top_right.Location = new System.Drawing.Point(1305, 2);
this.pl_top_right.Name = "pl_top_right";
this.pl_top_right.Size = new System.Drawing.Size(263, 35);
this.pl_top_right.TabIndex = 24;
@@ -288,165 +436,21 @@
this.btnBack.Name = "btnBack";
this.btnBack.Size = new System.Drawing.Size(82, 26);
this.btnBack.TabIndex = 8;
this.btnBack.Text = "返审(&W)";
this.btnBack.Text = "返审(W)";
this.btnBack.Click += new System.EventHandler(this.btnBack_Click);
//
// label_tips
// tabMain
//
this.label_tips.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.label_tips.Appearance.ForeColor = System.Drawing.Color.Red;
this.label_tips.Location = new System.Drawing.Point(221, 9);
this.label_tips.Name = "label_tips";
this.label_tips.Size = new System.Drawing.Size(204, 12);
this.label_tips.TabIndex = 4;
this.label_tips.Text = "友情提示:双击单据信息进入单据审核";
//
// label_date
//
this.label_date.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.label_date.Appearance.ForeColor = System.Drawing.Color.Red;
this.label_date.Location = new System.Drawing.Point(7, 9);
this.label_date.Name = "label_date";
this.label_date.Size = new System.Drawing.Size(198, 12);
this.label_date.TabIndex = 3;
this.label_date.Text = "上次刷新时间:2014-12-15 12:30:30";
//
// pl_bottom
//
this.pl_bottom.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
this.pl_bottom.Controls.Add(this.btnReverseSelection);
this.pl_bottom.Controls.Add(this.btnSelectAll);
this.pl_bottom.Controls.Add(this.dpb_Tools);
this.pl_bottom.Controls.Add(this.btnOkAudit);
this.pl_bottom.Controls.Add(this.btnBackAudit);
this.pl_bottom.Controls.Add(this.btnRefresh);
this.pl_bottom.Controls.Add(this.label_tips);
this.pl_bottom.Controls.Add(this.label_date);
this.pl_bottom.Dock = System.Windows.Forms.DockStyle.Bottom;
this.pl_bottom.Location = new System.Drawing.Point(0, 693);
this.pl_bottom.Name = "pl_bottom";
this.pl_bottom.Size = new System.Drawing.Size(1051, 21);
this.pl_bottom.TabIndex = 21;
//
// btnReverseSelection
//
this.btnReverseSelection.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnReverseSelection.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.btnReverseSelection.Appearance.Options.UseFont = true;
this.btnReverseSelection.Location = new System.Drawing.Point(586, -8);
this.btnReverseSelection.Name = "btnReverseSelection";
this.btnReverseSelection.Size = new System.Drawing.Size(55, 26);
this.btnReverseSelection.TabIndex = 13;
this.btnReverseSelection.Text = "反选";
this.btnReverseSelection.Visible = false;
this.btnReverseSelection.Click += new System.EventHandler(this.btnReverseSelection_Click);
//
// btnSelectAll
//
this.btnSelectAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnSelectAll.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.btnSelectAll.Appearance.Options.UseFont = true;
this.btnSelectAll.Location = new System.Drawing.Point(647, -8);
this.btnSelectAll.Name = "btnSelectAll";
this.btnSelectAll.Size = new System.Drawing.Size(55, 26);
this.btnSelectAll.TabIndex = 12;
this.btnSelectAll.Text = "全选";
this.btnSelectAll.Visible = false;
this.btnSelectAll.Click += new System.EventHandler(this.btnSelectAll_Click);
//
// dpb_Tools
//
this.dpb_Tools.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.dpb_Tools.Appearance.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.dpb_Tools.Appearance.Options.UseFont = true;
this.dpb_Tools.DropDownArrowStyle = DevExpress.XtraEditors.DropDownArrowStyle.Show;
this.dpb_Tools.DropDownControl = this.p_menu;
this.dpb_Tools.Location = new System.Drawing.Point(888, -8);
this.dpb_Tools.Name = "dpb_Tools";
this.dpb_Tools.Size = new System.Drawing.Size(80, 26);
this.dpb_Tools.TabIndex = 11;
this.dpb_Tools.Text = "常用工具";
//
// p_menu
//
this.p_menu.Manager = this.barManager1;
this.p_menu.MenuDrawMode = DevExpress.XtraBars.MenuDrawMode.SmallImagesText;
this.p_menu.Name = "p_menu";
//
// barManager1
//
this.barManager1.DockControls.Add(this.barDockControlTop);
this.barManager1.DockControls.Add(this.barDockControlBottom);
this.barManager1.DockControls.Add(this.barDockControlLeft);
this.barManager1.DockControls.Add(this.barDockControlRight);
this.barManager1.Form = this;
this.barManager1.MaxItemId = 0;
//
// barDockControlTop
//
this.barDockControlTop.CausesValidation = false;
this.barDockControlTop.Dock = System.Windows.Forms.DockStyle.Top;
this.barDockControlTop.Location = new System.Drawing.Point(0, 0);
this.barDockControlTop.Size = new System.Drawing.Size(1051, 0);
//
// barDockControlBottom
//
this.barDockControlBottom.CausesValidation = false;
this.barDockControlBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
this.barDockControlBottom.Location = new System.Drawing.Point(0, 715);
this.barDockControlBottom.Size = new System.Drawing.Size(1051, 0);
//
// barDockControlLeft
//
this.barDockControlLeft.CausesValidation = false;
this.barDockControlLeft.Dock = System.Windows.Forms.DockStyle.Left;
this.barDockControlLeft.Location = new System.Drawing.Point(0, 0);
this.barDockControlLeft.Size = new System.Drawing.Size(0, 715);
//
// barDockControlRight
//
this.barDockControlRight.CausesValidation = false;
this.barDockControlRight.Dock = System.Windows.Forms.DockStyle.Right;
this.barDockControlRight.Location = new System.Drawing.Point(1051, 0);
this.barDockControlRight.Size = new System.Drawing.Size(0, 715);
//
// btnOkAudit
//
this.btnOkAudit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnOkAudit.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.btnOkAudit.Appearance.Options.UseFont = true;
this.btnOkAudit.Location = new System.Drawing.Point(708, -8);
this.btnOkAudit.Name = "btnOkAudit";
this.btnOkAudit.Size = new System.Drawing.Size(82, 26);
this.btnOkAudit.TabIndex = 7;
this.btnOkAudit.Text = "批量审核(&Y)";
this.btnOkAudit.Visible = false;
this.btnOkAudit.Click += new System.EventHandler(this.OnBtnOkAuditClick);
//
// btnBackAudit
//
this.btnBackAudit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnBackAudit.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.btnBackAudit.Appearance.Options.UseFont = true;
this.btnBackAudit.Location = new System.Drawing.Point(796, -8);
this.btnBackAudit.Name = "btnBackAudit";
this.btnBackAudit.Size = new System.Drawing.Size(86, 26);
this.btnBackAudit.TabIndex = 6;
this.btnBackAudit.Text = "批量返审(&B)";
this.btnBackAudit.Visible = false;
this.btnBackAudit.Click += new System.EventHandler(this.OnBtnBackAuditClick);
//
// btnRefresh
//
this.btnRefresh.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnRefresh.Appearance.Font = new System.Drawing.Font("宋体", 9F);
this.btnRefresh.Appearance.Options.UseFont = true;
this.btnRefresh.Location = new System.Drawing.Point(974, -8);
this.btnRefresh.Name = "btnRefresh";
this.btnRefresh.Size = new System.Drawing.Size(72, 26);
this.btnRefresh.TabIndex = 5;
this.btnRefresh.Text = "刷新(&R)";
this.btnRefresh.Click += new System.EventHandler(this.BtnReflash_Click);
this.tabMain.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabMain.HeaderLocation = DevExpress.XtraTab.TabHeaderLocation.Bottom;
this.tabMain.Location = new System.Drawing.Point(0, 0);
this.tabMain.Name = "tabMain";
this.tabMain.SelectedTabPage = this.tabpage_finish;
this.tabMain.Size = new System.Drawing.Size(1576, 1036);
this.tabMain.TabIndex = 20;
this.tabMain.TabPages.AddRange(new DevExpress.XtraTab.XtraTabPage[] {
this.tabpage_finish});
//
// AuditPanelEx
//
@@ -459,8 +463,11 @@
this.Controls.Add(this.barDockControlTop);
this.Name = "AuditPanelEx";
this.Size = new System.Drawing.Size(1576, 1072);
((System.ComponentModel.ISupportInitialize)(this.tabMain)).EndInit();
this.tabMain.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pl_bottom)).EndInit();
this.pl_bottom.ResumeLayout(false);
this.pl_bottom.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.p_menu)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.barManager1)).EndInit();
this.tabpage_finish.ResumeLayout(false);
this.tabpage_finish.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.splitBelow)).EndInit();
@@ -471,18 +478,14 @@
this.pl_top_searchCond.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pl_top_right)).EndInit();
this.pl_top_right.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pl_bottom)).EndInit();
this.pl_bottom.ResumeLayout(false);
this.pl_bottom.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.p_menu)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.barManager1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.tabMain)).EndInit();
this.tabMain.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private DevExpress.XtraTab.XtraTabControl tabMain;
private DevExpress.XtraEditors.LabelControl label_date;
private DevExpress.XtraEditors.LabelControl label_tips;
private DevExpress.XtraEditors.PanelControl pl_bottom;
@@ -498,7 +501,12 @@
private DevExpress.XtraBars.BarDockControl barDockControlRight;
private DevExpress.XtraEditors.SimpleButton btnSelectAll;
private DevExpress.XtraEditors.SimpleButton btnReverseSelection;
private DevExpress.XtraTab.XtraTabControl tabMain;
private DevExpress.XtraTab.XtraTabPage tabpage_finish;
private GridControlEx gridFinish;
private DevExpress.XtraEditors.SplitContainerControl splitBelow;
private GridControlEx gridFlow;
private GridControlEx gridDetail;
private DevExpress.XtraEditors.PanelControl pl_top;
private DevExpress.XtraEditors.PanelControl pl_top_searchCond;
private LabelCheckDateEdit labeldate_start;
@@ -509,9 +517,5 @@
private DevExpress.XtraEditors.PanelControl pl_top_right;
private DevExpress.XtraEditors.SimpleButton simpleButton1;
private DevExpress.XtraEditors.SimpleButton btnBack;
private DevExpress.XtraEditors.SplitContainerControl splitBelow;
private GridControlEx gridFlow;
private GridControlEx gridFinish;
private GridControlEx gridDetail;
}
}
+95 -16
View File
@@ -41,9 +41,96 @@ namespace Lskj.Control
{
public partial class AuditPanelEx : UserControl
{
private bool mResourcesReleased;
private readonly AltButtonShortcutManager mAltButtonShortcuts =
new AltButtonShortcutManager();
public AuditPanelEx()
{
InitializeComponent();
InitializeAltButtonShortcuts();
}
private void InitializeAltButtonShortcuts()
{
mAltButtonShortcuts.Register(btnOkAudit, Keys.Y);
mAltButtonShortcuts.Register(btnBackAudit, Keys.B);
mAltButtonShortcuts.Register(btnRefresh, Keys.R);
mAltButtonShortcuts.Register(btnBack, Keys.W);
mAltButtonShortcuts.Register(btnSearch, Keys.Q);
}
protected override bool ProcessCmdKey(
ref System.Windows.Forms.Message msg, Keys keyData)
{
return mAltButtonShortcuts.ProcessKey(keyData) ||
base.ProcessCmdKey(ref msg, keyData);
}
internal void ReleaseResourcesForDispose()
{
if (mResourcesReleased)
{
return;
}
mResourcesReleased = true;
MyControl searchControl = _searchContrl;
_searchContrl = null;
if (searchControl != null)
{
searchControl.Dispose();
}
try
{
if (gridFinish != null && gridFinish.GridView != null)
{
gridFinish.GridView.SelectionChanged -= GvFinish_SelectionChangedClick;
gridFinish.GridView.DoubleClick -= GvFinish_DoubleClick;
}
foreach (TabPageObj tabPage in _tabPageObjs)
{
foreach (TabPageItemObj item in tabPage.TabPageItemObjs)
{
if (item.GridControlObj != null &&
item.GridControlObj.GridView != null)
{
item.GridControlObj.GridView.DoubleClick -=
OnGridViewDoubleClick;
item.GridControlObj.Model = null;
}
}
tabPage.TabPageItemObjs.Clear();
}
}
catch
{
// A partially disposed DevExpress view must not stop cleanup.
}
try
{
if (SysModel != null && SysModel.DataCaches != null)
{
SysModel.DataCaches.RemoveCache(this);
}
}
catch
{
// Cache cleanup must not interrupt control disposal.
}
_tabPageObjs.Clear();
_tabPageCount.Clear();
OnGridViewDoubleCallBack = null;
OnGridFinshViewDoubleCallBack = null;
OnBtnSearchCallBack = null;
SectionAccradit = null;
AuditComModelObj = null;
BaseAccraditModelObj = null;
PubSysModel = null;
SysModel = null;
}
#region
@@ -299,17 +386,12 @@ namespace Lskj.Control
{
return new AccraditationModel(dataRow);
}));
Task<GridControlEx> gridControlExTask = cachesDic.AddTask(dataRow, "GridControlEx", new Task<GridControlEx>(() =>
{
return new GridControlEx();
}));
GridControlEx gridControlEx = gridControlExTask.Result;
string key = "FLOWSTEP_" + dynamicModel.ModuleCode + "_" + flowTypeStepModelTask.Result.StepCode + "_" + accraditationModelTask.Result.Id + "";
Task<DataTable> baseGridRowColorsTask = cachesDic.AddTask(gridControlEx, "BaseGridRowColors", new Task<DataTable>(() =>
Task<DataTable> baseGridRowColorsTask = cachesDic.AddTask(dataRow, "BaseGridRowColors", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRowColors(key);
}));
Task<DataTable> flowstepGridRightMenusTask = cachesDic.AddTask(gridControlEx, "FlowstepGridRightMenus", new Task<DataTable>(() =>
Task<DataTable> flowstepGridRightMenusTask = cachesDic.AddTask(dataRow, "FlowstepGridRightMenus", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRightMenus($"FLOWSTEP_{accraditationModelTask.Result.Formkey}");
}));
@@ -317,10 +399,6 @@ namespace Lskj.Control
//{
// return BaseImpl.GetDataTableResult(accraditationModelTask.Result.StepSql);
//}));
string modelkeyName = isBill ? GridCustomColumnStruct.AuditMainGridView : GridCustomColumnStruct.BaseAuditMainGridView;
string customColumKey = modelkeyName + key;
cachesDic.AddTask(gridControlEx, "DynamicModel", dynamicModelTask);
gridControlEx.GetDataCaches(cachesDic, customColumKey);
}
return flowList;
}));
@@ -613,18 +691,19 @@ namespace Lskj.Control
gridPanel.Padding = new System.Windows.Forms.Padding(2);
gridPanel.Dock = DockStyle.Right;
gridPanel.BorderStyle = BorderStyles.NoBorder;
if (!dataCaches.GetValue(dataRow, "GridControlEx", out GridControlEx grid))
GridControlEx grid = new GridControlEx();
if (dataCaches != null)
{
grid = new GridControlEx();
grid.GetDataCaches(dataCaches, modelkeyName + key);
}
grid.Parent = gridPanel;
grid.Dock = DockStyle.Fill;
grid.BorderStyle = BorderStyle.None;
if (!dataCaches.GetValue(grid, "BaseGridRowColors", out DataTable dtGridRowColors))
if (!dataCaches.GetValue(dataRow, "BaseGridRowColors", out DataTable dtGridRowColors))
{
dtGridRowColors = BaseModuleImpl.GetBaseGridRowColors(key);
}
if (!dataCaches.GetValue(grid, "FlowstepGridRightMenus", out DataTable dtGridRightMenus))
if (!dataCaches.GetValue(dataRow, "FlowstepGridRightMenus", out DataTable dtGridRightMenus))
{
dtGridRightMenus = BaseModuleImpl.GetBaseGridRightMenus($"FLOWSTEP_{accrModel.Formkey}");
}
@@ -1906,4 +1985,4 @@ namespace Lskj.Control
}
}
}
}
@@ -52,6 +52,13 @@ namespace Lskj.Control
/// </summary>
private bool _working = false;
private List<string> _queryQueue = new List<string>();
private LatestValueWorker<PopupQueryRequest> _queryWorker;
private sealed class PopupQueryRequest
{
public string SqlValue;
public bool IsNewPopup;
}
/// <summary>
/// The _popup
/// </summary>
@@ -246,9 +253,7 @@ namespace Lskj.Control
public void OnAutoPopupShow()
{
this.CalcPopupLocation();
Thread queryThread = new Thread(CalcPopupSize);
queryThread.IsBackground = true;
queryThread.Start(Popup);
ThreadPool.QueueUserWorkItem(CalcPopupSize, Popup);
//// 在主线程中显示等待对话框,并在后台线程中执行查询和数据绑定
//Task.Run(() =>
@@ -339,6 +344,7 @@ namespace Lskj.Control
public AutoGridLookUp()
{
InitializePopup();
_queryWorker = new LatestValueWorker<PopupQueryRequest>(ExecuteLatestPopupQuery);
InitializeEvent();
this.Disposed += OnDisposed;
}
@@ -390,9 +396,7 @@ namespace Lskj.Control
this.ShowPopup();
}
Thread queryThread = new Thread(CalcPopupSize);
queryThread.IsBackground = true;
queryThread.Start(Popup);
ThreadPool.QueueUserWorkItem(CalcPopupSize, Popup);
}
/// <summary>
/// <para>说明:计算弹出控件位置</para>
@@ -600,16 +604,7 @@ namespace Lskj.Control
sqlValue = ControlObj.ReplaceControlValue(sourceSql);
}
if (!this._working)
{
Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSource));
thread.IsBackground = true;
thread.Start(sqlValue);
}
else
{
this._queryQueue.Add(sqlValue);
}
QueuePopupQuery(sqlValue, false);
}
}
@@ -709,9 +704,9 @@ namespace Lskj.Control
string sql = MainImpl.GetDefaultValue(this._queryQueue.Last());
sql = ReplaceHelper.ReplaceParam(sql);
// 在检索过程中还存在输入数据,则拿最后一次数据在进行匹配一次
Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSource));
thread.IsBackground = true;
thread.Start(sql);
ThreadPool.QueueUserWorkItem(
RefreshPopupDataSource,
sql);
this._queryQueue.Clear();
}
@@ -1601,17 +1596,74 @@ namespace Lskj.Control
}
sqlValue = ControlObj.ReplaceControlValue(sourceSql.Replace("#", ""));
}
if (!this._working)
QueuePopupQuery(sqlValue, true);
}
}
private void QueuePopupQuery(string sqlValue, bool isNewPopup)
{
if (_queryWorker == null || IsDisposed || Disposing)
{
return;
}
_working = true;
if (Popup != null)
{
Popup.LabelObj.Text = "正在筛选数据,请稍后...";
Popup.BottomPanelObj.Visible = true;
}
_queryWorker.Queue(new PopupQueryRequest
{
SqlValue = sqlValue,
IsNewPopup = isNewPopup
});
}
private void ExecuteLatestPopupQuery(PopupQueryRequest request, int version)
{
DateTime beginTime = DateTime.Now;
DataTable table = new DataTable();
if (request != null && !string.IsNullOrWhiteSpace(request.SqlValue))
{
try
{
Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSourceNew));
thread.IsBackground = true;
thread.Start(sqlValue);
table = SqlHelper.ExecuteDataTable(request.SqlValue);
}
else
catch
{
this._queryQueue.Add(sqlValue);
table = new DataTable();
}
}
DateTime endTime = DateTime.Now;
if (_queryWorker == null || !_queryWorker.IsCurrent(version) || IsDisposed || Disposing || !IsHandleCreated)
{
return;
}
try
{
BeginInvoke(new MethodInvoker(delegate
{
if (_queryWorker == null || !_queryWorker.IsCurrent(version) || IsDisposed || Disposing || Popup == null)
{
return;
}
int second = Convert.ToInt32((endTime - beginTime).TotalSeconds);
string tipMsg = "数据筛选完成.";
Popup.LabelObj.Text = second > 0 ? string.Format(tipMsg + "(耗时{0}秒)", second) : tipMsg;
Popup.GridControlObj.DataSource = table;
_working = false;
CalcFormAndGrid(request != null && request.IsNewPopup);
}));
}
catch (InvalidOperationException)
{
}
}
private void RefreshPopupDataSourceNew(object sqlValue)
@@ -1646,9 +1698,9 @@ namespace Lskj.Control
if (this._queryQueue.Count > 0)
{
// 在检索过程中还存在输入数据,则拿最后一次数据在进行匹配一次
Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSourceNew));
thread.IsBackground = true;
thread.Start(this._queryQueue.Last());
ThreadPool.QueueUserWorkItem(
RefreshPopupDataSourceNew,
this._queryQueue.Last());
this._queryQueue.Clear();
}
else
@@ -1681,8 +1733,15 @@ namespace Lskj.Control
/// <param name="e"></param>
private void OnDisposed(object sender, EventArgs e)
{
if (_queryWorker != null)
{
_queryWorker.Dispose();
_queryWorker = null;
}
_working = false;
_queryQueue.Clear();
this._popup?.Dispose();
this._popup = null;
}
}
}
}
@@ -46,6 +46,13 @@ namespace Lskj.Control
/// </summary>
private bool _working = false;
private List<string> _queryQueue = new List<string>();
private LatestValueWorker<PopupQueryRequest> _queryWorker;
private sealed class PopupQueryRequest
{
public string SqlValue;
public bool IsNewPopup;
}
/// <summary>
/// The _popup
/// </summary>
@@ -318,6 +325,7 @@ namespace Lskj.Control
public AutoGridRevLookUp()
{
InitializePopup();
_queryWorker = new LatestValueWorker<PopupQueryRequest>(ExecuteLatestPopupQuery);
InitializeEvent();
this.Disposed += OnDisposed;
}
@@ -360,9 +368,7 @@ namespace Lskj.Control
}
private void CalcFormAndGrid()
{
Thread queryThread = new Thread(CalcPopupSize);
queryThread.IsBackground = true;
queryThread.Start(Popup);
ThreadPool.QueueUserWorkItem(CalcPopupSize, Popup);
}
/// <summary>
/// <para>说明:计算弹出控件位置</para>
@@ -527,16 +533,7 @@ namespace Lskj.Control
}
sqlValue = ControlObj.ReplaceControlValue(sourceSql.Replace("#", ""));
}
if (!this._working)
{
Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSource));
thread.IsBackground = true;
thread.Start(sqlValue);
}
else
{
this._queryQueue.Add(sqlValue);
}
QueuePopupQuery(sqlValue, false);
}
}
@@ -627,9 +624,9 @@ namespace Lskj.Control
string sql = MainImpl.GetDefaultValue(this._queryQueue.Last());
sql = ReplaceHelper.ReplaceParam(sql);
// 在检索过程中还存在输入数据,则拿最后一次数据在进行匹配一次
Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSource));
thread.IsBackground = true;
thread.Start(sql);
ThreadPool.QueueUserWorkItem(
RefreshPopupDataSource,
sql);
this._queryQueue.Clear();
}
else
@@ -1022,15 +1019,23 @@ namespace Lskj.Control
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
protected void OnAutoGridLookUpGotFocus(object sender, EventArgs e)
{
System.Threading.Thread thread = new Thread(() =>
ThreadPool.QueueUserWorkItem(delegate
{
while (!this.IsSetDataSource)
{
if (IsDisposed || Disposing)
{
return;
}
Thread.Sleep(10);
}
if (IsDisposed || Disposing)
{
return;
}
this.HandPopupSqlValue(this.Text);
ShowPopup();
});
thread.Start();
}
/// <summary>
/// 鼠标单击控件时
@@ -1041,15 +1046,23 @@ namespace Lskj.Control
{
if (this._popup.Visible == false)
{
System.Threading.Thread thread = new Thread(() =>
ThreadPool.QueueUserWorkItem(delegate
{
while (!this.IsSetDataSource)
{
if (IsDisposed || Disposing)
{
return;
}
Thread.Sleep(10);
}
if (IsDisposed || Disposing)
{
return;
}
this.HandPopupSqlValue(this.Text);
ShowPopup();
});
thread.Start();
}
}
/// <summary>
@@ -1327,17 +1340,78 @@ namespace Lskj.Control
}
sqlValue = ControlObj.ReplaceControlValue(sourceSql.Replace("#", ""));
}
if (!this._working)
QueuePopupQuery(sqlValue, true);
}
}
private void QueuePopupQuery(string sqlValue, bool isNewPopup)
{
if (_queryWorker == null || IsDisposed || Disposing)
{
return;
}
_working = true;
if (Popup != null)
{
Popup.LabelObj.Text = "正在筛选数据,请稍后...";
Popup.BottomPanelObj.Visible = true;
Popup.GridControlObj.DataSourceTable().Clear();
}
_queryWorker.Queue(new PopupQueryRequest
{
SqlValue = sqlValue,
IsNewPopup = isNewPopup
});
}
private void ExecuteLatestPopupQuery(PopupQueryRequest request, int version)
{
DateTime beginTime = DateTime.Now;
DataTable table = new DataTable();
if (request != null && !string.IsNullOrWhiteSpace(request.SqlValue))
{
try
{
Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSourceNew));
thread.IsBackground = true;
thread.Start(sqlValue);
table = SqlHelper.ExecuteDataTable(request.SqlValue);
}
else
catch
{
this._queryQueue.Add(sqlValue);
table = new DataTable();
}
}
DateTime endTime = DateTime.Now;
if (_queryWorker == null || !_queryWorker.IsCurrent(version) || IsDisposed || Disposing || !IsHandleCreated)
{
return;
}
try
{
BeginInvoke(new MethodInvoker(delegate
{
if (_queryWorker == null || !_queryWorker.IsCurrent(version) || IsDisposed || Disposing || Popup == null)
{
return;
}
int second = Convert.ToInt32((endTime - beginTime).TotalSeconds);
string tipMsg = "数据筛选完成.";
Popup.LabelObj.Text = second > 0 ? string.Format(tipMsg + "(耗时{0}秒)", second) : tipMsg;
Popup.GridControlObj.DataSource = table;
_working = false;
if (request != null && !request.IsNewPopup)
{
CalcFormAndGrid();
}
}));
}
catch (InvalidOperationException)
{
}
}
private void RefreshPopupDataSourceNew(object sqlValue)
{
@@ -1372,9 +1446,9 @@ namespace Lskj.Control
if (this._queryQueue.Count > 0)
{
// 在检索过程中还存在输入数据,则拿最后一次数据在进行匹配一次
Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSourceNew));
thread.IsBackground = true;
thread.Start(this._queryQueue.Last());
ThreadPool.QueueUserWorkItem(
RefreshPopupDataSourceNew,
this._queryQueue.Last());
this._queryQueue.Clear();
}
@@ -1419,8 +1493,15 @@ namespace Lskj.Control
/// <param name="e"></param>
private void OnDisposed(object sender, EventArgs e)
{
if (_queryWorker != null)
{
_queryWorker.Dispose();
_queryWorker = null;
}
_working = false;
_queryQueue.Clear();
this._popup?.Dispose();
this._popup = null;
}
}
}
}
@@ -3,22 +3,44 @@ using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Views.Grid.ViewInfo;
using DevExpress.Utils;
using Lskj.Control.Model;
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace Lskj.Control
{
/// <summary>
/// 181 扩展搜索专用弹窗。查询文本只存在于本控件中,不参与业务列绑定。
/// 173/174 扩展搜索专用弹窗。查询文本只存在于本控件中,不参与业务列绑定。
/// </summary>
internal sealed class ExtendedReturnSearchPopup : UserControl
{
private sealed class SearchColumnOption
{
public SearchColumnOption(string fieldName, string caption)
{
FieldName = fieldName ?? string.Empty;
Caption = caption ?? string.Empty;
}
public string FieldName { get; private set; }
public string Caption { get; private set; }
public override string ToString()
{
return Caption;
}
}
private readonly TableLayoutPanel searchPanel;
private readonly ComboBoxEdit searchFieldEdit;
private readonly TextEdit searchEdit;
private readonly SimpleButton queryButton;
private readonly SimpleButton clearButton;
private readonly GridControl resultGrid;
private readonly GridView resultView;
private string selectedSearchField = string.Empty;
public event EventHandler SearchRequested;
public event EventHandler ClearRequested;
@@ -27,6 +49,7 @@ namespace Lskj.Control
public ExtendedReturnSearchPopup()
{
searchPanel = new TableLayoutPanel();
searchFieldEdit = new ComboBoxEdit();
searchEdit = new TextEdit();
queryButton = new SimpleButton();
clearButton = new SimpleButton();
@@ -35,6 +58,7 @@ namespace Lskj.Control
SuspendLayout();
searchPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(searchFieldEdit.Properties)).BeginInit();
((System.ComponentModel.ISupportInitialize)(searchEdit.Properties)).BeginInit();
((System.ComponentModel.ISupportInitialize)(resultGrid)).BeginInit();
((System.ComponentModel.ISupportInitialize)(resultView)).BeginInit();
@@ -42,7 +66,8 @@ namespace Lskj.Control
searchPanel.Dock = DockStyle.Top;
searchPanel.Height = 36;
searchPanel.Padding = new Padding(4);
searchPanel.ColumnCount = 3;
searchPanel.ColumnCount = 4;
searchPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 120F));
searchPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
searchPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 72F));
searchPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 72F));
@@ -53,26 +78,34 @@ namespace Lskj.Control
queryButton.Dock = DockStyle.Fill;
queryButton.Margin = new Padding(4, 0, 0, 0);
queryButton.Text = "查询";
queryButton.TabIndex = 1;
queryButton.TabIndex = 2;
queryButton.Click += QueryButton_Click;
clearButton.Dock = DockStyle.Fill;
clearButton.Margin = new Padding(4, 0, 0, 0);
clearButton.Text = "清空";
clearButton.TabIndex = 2;
clearButton.TabIndex = 3;
clearButton.Click += ClearButton_Click;
searchFieldEdit.Dock = DockStyle.Fill;
searchFieldEdit.Margin = new Padding(0, 0, 4, 0);
searchFieldEdit.TabIndex = 0;
searchFieldEdit.Properties.AutoHeight = false;
searchFieldEdit.Properties.TextEditStyle = DevExpress.XtraEditors.Controls.TextEditStyles.DisableTextEditor;
searchFieldEdit.SelectedIndexChanged += SearchFieldEdit_SelectedIndexChanged;
searchEdit.Dock = DockStyle.Fill;
searchEdit.Margin = new Padding(0);
searchEdit.TabIndex = 0;
searchEdit.TabIndex = 1;
searchEdit.Properties.AutoHeight = false;
searchEdit.Properties.NullValuePrompt = "输入查询内容后按回车";
searchEdit.Properties.NullValuePromptShowForEmptyValue = true;
searchEdit.KeyDown += SearchEdit_KeyDown;
searchPanel.Controls.Add(searchEdit, 0, 0);
searchPanel.Controls.Add(queryButton, 1, 0);
searchPanel.Controls.Add(clearButton, 2, 0);
searchPanel.Controls.Add(searchFieldEdit, 0, 0);
searchPanel.Controls.Add(searchEdit, 1, 0);
searchPanel.Controls.Add(queryButton, 2, 0);
searchPanel.Controls.Add(clearButton, 3, 0);
resultGrid.Dock = DockStyle.Fill;
resultGrid.MainView = resultView;
@@ -83,6 +116,7 @@ namespace Lskj.Control
resultView.OptionsSelection.EnableAppearanceFocusedCell = false;
resultView.OptionsView.ShowGroupPanel = false;
resultView.OptionsView.ShowIndicator = true;
resultView.OptionsView.ShowAutoFilterRow = true;
resultView.OptionsView.ColumnAutoWidth = false;
resultView.IndicatorWidth = 40;
resultView.CustomDrawRowIndicator += ResultView_CustomDrawRowIndicator;
@@ -97,8 +131,11 @@ namespace Lskj.Control
((System.ComponentModel.ISupportInitialize)(resultView)).EndInit();
((System.ComponentModel.ISupportInitialize)(resultGrid)).EndInit();
((System.ComponentModel.ISupportInitialize)(searchEdit.Properties)).EndInit();
((System.ComponentModel.ISupportInitialize)(searchFieldEdit.Properties)).EndInit();
searchPanel.ResumeLayout(false);
ResumeLayout(false);
SetSearchColumns(null);
}
public GridControl ResultGrid
@@ -116,9 +153,64 @@ namespace Lskj.Control
get { return (searchEdit.Text ?? string.Empty).Trim(); }
}
public string SelectedSearchField
{
get
{
SearchColumnOption option = searchFieldEdit.SelectedItem as SearchColumnOption;
return option == null ? string.Empty : option.FieldName;
}
}
public void SetSearchColumns(IEnumerable<KeyValuePair<string, string>> columns)
{
string preferredField = selectedSearchField;
SearchColumnOption all = new SearchColumnOption(string.Empty, "所有列");
SearchColumnOption selected = null;
HashSet<string> fields = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
searchFieldEdit.Properties.BeginUpdate();
try
{
searchFieldEdit.Properties.Items.Clear();
searchFieldEdit.Properties.Items.Add(all);
if (columns != null)
{
foreach (KeyValuePair<string, string> column in columns)
{
if (!ExtendedReturnSupport.IsSearchableColumn(column.Key) || !fields.Add(column.Key))
{
continue;
}
string caption = string.IsNullOrWhiteSpace(column.Value) ? column.Key : column.Value;
SearchColumnOption option = new SearchColumnOption(column.Key, caption);
searchFieldEdit.Properties.Items.Add(option);
if (string.Equals(option.FieldName, preferredField, StringComparison.OrdinalIgnoreCase))
{
selected = option;
}
}
}
searchFieldEdit.SelectedItem = selected ?? all;
selectedSearchField = selected == null ? string.Empty : selected.FieldName;
}
finally
{
searchFieldEdit.Properties.EndUpdate();
}
}
public void PrepareForOpen()
{
searchEdit.Text = string.Empty;
ClearResultAndFilter();
}
public void ClearResultAndFilter()
{
resultView.ClearColumnsFilter();
resultGrid.DataSource = null;
}
@@ -154,6 +246,12 @@ namespace Lskj.Control
RaiseSearchRequested();
}
private void SearchFieldEdit_SelectedIndexChanged(object sender, EventArgs e)
{
SearchColumnOption option = searchFieldEdit.SelectedItem as SearchColumnOption;
selectedSearchField = option == null ? string.Empty : option.FieldName;
}
private void FocusResultRow(bool focusLastRow)
{
if (resultView.DataRowCount <= 0) return;
@@ -50,11 +50,14 @@ namespace Lskj.Control
public int Version;
public string SourceSql;
public string Keyword;
public string SearchField;
public string ConnectionString;
public bool SchemaOnly;
}
private sealed class QueryResult
{
public DataTable Schema;
public DataTable Table;
public Exception Error;
}
@@ -302,10 +305,20 @@ namespace Lskj.Control
popupEdit.Properties.PopupFormSize = popupSize;
popupEdit.Properties.PopupFormMinSize = popupSize;
popup.PrepareForOpen();
string sourceSql = BuildSourceSql();
DataTable cachedSchema = TryGetSchema(sourceSql);
if (cachedSchema != null)
{
ConfigureSearchColumns(cachedSchema);
}
if (!string.IsNullOrWhiteSpace(EditValue))
{
StartSearch(EditValue);
QueueSearch(sourceSql, EditValue, string.Empty, false);
}
else if (cachedSchema == null)
{
QueueSearch(sourceSql, string.Empty, string.Empty, true);
}
else
{
@@ -336,7 +349,7 @@ namespace Lskj.Control
private void PopupEdit_Closed(object sender, ClosedEventArgs e)
{
CancelSearch();
popup.ResultGrid.DataSource = null;
popup.ClearResultAndFilter();
RefreshDisplayText();
}
@@ -346,13 +359,14 @@ namespace Lskj.Control
{
ValidateBusinessConfiguration();
string keyword = popup.SearchText;
string searchField = popup.SelectedSearchField;
popup.ClearResultAndFilter();
if (string.IsNullOrWhiteSpace(keyword))
{
CancelSearch();
popup.ResultGrid.DataSource = null;
return;
}
StartSearch(keyword);
QueueSearch(BuildSourceSql(), keyword, searchField, false);
}
catch (Exception ex)
{
@@ -613,13 +627,15 @@ namespace Lskj.Control
return Model.SourceSql;
}
private void StartSearch(string keyword)
private void QueueSearch(string sourceSql, string keyword, string searchField, bool schemaOnly)
{
SearchRequest request = new SearchRequest();
request.Version = Interlocked.Increment(ref queryVersion);
request.SourceSql = BuildSourceSql();
request.SourceSql = sourceSql;
request.Keyword = keyword;
request.SearchField = searchField;
request.ConnectionString = SqlHelper._connection.ConnectionString;
request.SchemaOnly = schemaOnly;
bool startWorker = false;
lock (querySyncRoot)
@@ -653,27 +669,29 @@ namespace Lskj.Control
}
}
QueryResult result = Query(
request.SourceSql,
request.Keyword,
request.ConnectionString);
DeliverResult(request.Version, result);
QueryResult result = Query(request);
DeliverResult(request, result);
}
}
private QueryResult Query(string sourceSql, string keyword, string connectionString)
private QueryResult Query(SearchRequest request)
{
QueryResult result = new QueryResult();
try
{
DataTable sourceSchema = GetSchema(sourceSql, connectionString);
DataTable sourceSchema = GetSchema(request.SourceSql, request.ConnectionString);
result.Schema = sourceSchema;
IList<ExtendedReturnFieldMapping> mappings = ExtendedReturnSupport.ParseResultFields(Model.ResultFields);
ValidateSourceColumns(sourceSchema.Columns, mappings);
string searchSql = ExtendedReturnSupport.BuildSearchSql(sourceSql, sourceSchema.Columns, MaxRows);
result.Table = ExecuteQuery(
searchSql,
ExtendedReturnSupport.BuildLikeParameterValue(keyword),
connectionString);
if (!request.SchemaOnly)
{
string searchSql = ExtendedReturnSupport.BuildSearchSql(
request.SourceSql, sourceSchema.Columns, MaxRows, request.SearchField);
result.Table = ExecuteQuery(
searchSql,
ExtendedReturnSupport.BuildLikeParameterValue(request.Keyword),
request.ConnectionString);
}
}
catch (Exception ex)
{
@@ -682,6 +700,18 @@ namespace Lskj.Control
return result;
}
private DataTable TryGetSchema(string sourceSql)
{
lock (schemaSyncRoot)
{
if (schema != null && string.Equals(schemaSql, sourceSql, StringComparison.Ordinal))
{
return schema;
}
return null;
}
}
private DataTable GetSchema(string sourceSql, string connectionString)
{
lock (schemaSyncRoot)
@@ -730,21 +760,25 @@ namespace Lskj.Control
return table;
}
private void DeliverResult(int version, QueryResult result)
private void DeliverResult(SearchRequest request, QueryResult result)
{
if (disposed || !IsHandleCreated) return;
MethodInvoker deliver = new MethodInvoker(delegate
{
if (disposed || IsDisposed || version != queryVersion || !popupEdit.IsPopupOpen) return;
if (disposed || IsDisposed || request.Version != queryVersion || !popupEdit.IsPopupOpen) return;
ConfigureSearchColumns(result.Schema);
if (result.Error != null)
{
MessageUtil.Show("扩展搜索查询失败:" + result.Error.Message);
return;
}
popup.ResultGrid.DataSource = result.Table;
ConfigureResultColumns(result.Table);
if (result.Table != null)
{
popup.ResultGrid.DataSource = result.Table;
ConfigureResultColumns(result.Table);
}
});
try
@@ -759,6 +793,24 @@ namespace Lskj.Control
}
}
private void ConfigureSearchColumns(DataTable sourceSchema)
{
if (sourceSchema == null) return;
List<KeyValuePair<string, string>> options = new List<KeyValuePair<string, string>>();
IList<ExtendedReturnFieldMapping> mappings =
ExtendedReturnSupport.ParseResultFields(Model.ResultFields);
foreach (DataColumn column in sourceSchema.Columns)
{
if (!ExtendedReturnSupport.IsSearchableColumn(column.ColumnName)) continue;
options.Add(new KeyValuePair<string, string>(
column.ColumnName,
GetColumnCaption(column.ColumnName, mappings)));
}
popup.SetSearchColumns(options);
}
private void ConfigureResultColumns(DataTable table)
{
if (table == null) return;
@@ -771,6 +823,7 @@ namespace Lskj.Control
column.Name = column.FieldName = dataColumn.ColumnName;
column.Caption = GetColumnCaption(dataColumn.ColumnName, mappings);
column.Visible = !dataColumn.ColumnName.StartsWith("_", StringComparison.Ordinal);
column.OptionsFilter.AutoFilterCondition = AutoFilterCondition.Contains;
popup.ResultView.Columns.Add(column);
}
@@ -46,6 +46,13 @@ namespace Lskj.Control
/// </summary>
private bool _working = false;
private List<string> _queryQueue = new List<string>();
private LatestValueWorker<PopupQueryRequest> _queryWorker;
private sealed class PopupQueryRequest
{
public string SqlValue;
public bool IsNewPopup;
}
/// <summary>
/// The _popup
/// </summary>
@@ -307,7 +314,9 @@ namespace Lskj.Control
{
InitializeComponent();
InitializePopup();
_queryWorker = new LatestValueWorker<PopupQueryRequest>(ExecuteLatestPopupQuery);
InitializeEvent();
this.Disposed += OnDisposed;
//this.Properties.Buttons[0].Kind = DevExpress.XtraEditors.Controls.ButtonPredefines.Down;
}
@@ -361,9 +370,7 @@ namespace Lskj.Control
this.ShowPopup();
}
Thread queryThread = new Thread(CalcPopupSize);
queryThread.IsBackground = true;
queryThread.Start(Popup);
ThreadPool.QueueUserWorkItem(CalcPopupSize, Popup);
}
/// <summary>
/// <para>说明:计算弹出控件位置</para>
@@ -551,16 +558,7 @@ namespace Lskj.Control
sqlValue = ControlObj.ReplaceControlValue(sourceSql);
}
if (!this._working)
{
Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSource));
thread.IsBackground = true;
thread.Start(sqlValue);
}
else
{
this._queryQueue.Add(sqlValue);
}
QueuePopupQuery(sqlValue, false);
}
}
@@ -656,9 +654,9 @@ namespace Lskj.Control
string sql = MainImpl.GetDefaultValue(this._queryQueue.Last());
sql = ReplaceHelper.ReplaceParam(sql);
// 在检索过程中还存在输入数据,则拿最后一次数据在进行匹配一次
Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSource));
thread.IsBackground = true;
thread.Start(sql);
ThreadPool.QueueUserWorkItem(
RefreshPopupDataSource,
sql);
this._queryQueue.Clear();
}
@@ -1403,17 +1401,78 @@ namespace Lskj.Control
sqlValue = ControlObj.ReplaceControlValue(sourceSql.Replace("#", ""));
}
if (!this._working)
QueuePopupQuery(sqlValue, true);
}
}
private void QueuePopupQuery(string sqlValue, bool isNewPopup)
{
if (_queryWorker == null || IsDisposed || Disposing)
{
return;
}
_working = true;
if (Popup != null)
{
Popup.LabelObj.Text = "正在筛选数据,请稍后...";
Popup.BottomPanelObj.Visible = true;
Popup.GridControlObj.DataSourceTable().Clear();
}
_queryWorker.Queue(new PopupQueryRequest
{
SqlValue = sqlValue,
IsNewPopup = isNewPopup
});
}
private void ExecuteLatestPopupQuery(PopupQueryRequest request, int version)
{
DateTime beginTime = DateTime.Now;
DataTable table = new DataTable();
if (request != null && !string.IsNullOrWhiteSpace(request.SqlValue))
{
try
{
Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSourceNew));
thread.IsBackground = true;
thread.Start(sqlValue);
table = SqlHelper.ExecuteDataTable(request.SqlValue);
}
else
catch
{
this._queryQueue.Add(sqlValue);
table = new DataTable();
}
}
DateTime endTime = DateTime.Now;
if (_queryWorker == null || !_queryWorker.IsCurrent(version) || IsDisposed || Disposing || !IsHandleCreated)
{
return;
}
try
{
BeginInvoke(new MethodInvoker(delegate
{
if (_queryWorker == null || !_queryWorker.IsCurrent(version) || IsDisposed || Disposing || Popup == null)
{
return;
}
int second = Convert.ToInt32((endTime - beginTime).TotalSeconds);
string tipMsg = "数据筛选完成.";
Popup.LabelObj.Text = second > 0 ? string.Format(tipMsg + "(耗时{0}秒)", second) : tipMsg;
Popup.GridControlObj.DataSource = table;
_working = false;
if (request != null && !request.IsNewPopup)
{
CalcFormAndGrid();
}
}));
}
catch (InvalidOperationException)
{
}
}
private void RefreshPopupDataSourceNew(object sqlValue)
@@ -1449,9 +1508,9 @@ namespace Lskj.Control
if (this._queryQueue.Count > 0)
{
// 在检索过程中还存在输入数据,则拿最后一次数据在进行匹配一次
Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSourceNew));
thread.IsBackground = true;
thread.Start(this._queryQueue.Last());
ThreadPool.QueueUserWorkItem(
RefreshPopupDataSourceNew,
this._queryQueue.Last());
this._queryQueue.Clear();
}
@@ -1478,5 +1537,21 @@ namespace Lskj.Control
}
}
private void OnDisposed(object sender, EventArgs e)
{
if (_queryWorker != null)
{
_queryWorker.Dispose();
_queryWorker = null;
}
_working = false;
_queryQueue.Clear();
if (_popup != null)
{
_popup.Dispose();
_popup = null;
}
}
}
}
}
@@ -258,7 +258,8 @@ namespace Lskj.Control
DataRow gridRow = this.GridView.GetDataRow(e.RowHandle);
foreach (DataRow item in this.GridRowColorsTable.Rows)
{
string cond = ReplaceHelper.ReplaceRowParam(gridRow, item["condition"] + "");
//string cond = ReplaceHelper.ReplaceRowParam(gridRow, item["condition"] + "");
string cond = ReplaceHelper.ReplaceRowParamEmptyWrapQuote(gridRow, item["condition"] + "");
try
{
if (!string.IsNullOrWhiteSpace(cond) && ReplaceHelper.EvalCond(cond))
@@ -360,7 +361,8 @@ namespace Lskj.Control
continue;
}
}
cond = ReplaceHelper.ReplaceRowParam(gridRow, item["condition"] + "").ReplaceColumnParam(e.Column.Name, e.Column.Caption, e.CellValue + "");
//cond = ReplaceHelper.ReplaceRowParam(gridRow, item["condition"] + "").ReplaceColumnParam(e.Column.Name, e.Column.Caption, e.CellValue + "");
cond = ReplaceHelper.ReplaceRowParamEmptyWrapQuote(gridRow, item["condition"] + "").ReplaceColumnParam(e.Column.Name, e.Column.Caption, e.CellValue + "");
try
{
if (!string.IsNullOrWhiteSpace(cond) && ReplaceHelper.EvalCond(cond) && (!string.IsNullOrEmpty(e.CellValue + "") || isLaterDatePresent|| SystemInfo.Instance.isBlankCellColor))
+4 -2
View File
@@ -75,12 +75,14 @@ namespace Lskj.Control
case ControlType.LabDate:
case ControlType.LabDateTime:
case ControlType.LabDateTimeShort:
case ControlType.LabTime:
case ControlType.LabShortTime:
// 日期控件
LabelDateEdit dateEdit = this as LabelDateEdit;
UpdContrast = dateEdit.TextEdit.EditValue == null ? dateEdit.EditText : dateEdit.TextEdit.EditValue.ToString();
break;
case ControlType.LabTime:
case ControlType.LabShortTime:
LabelTimeEdit timeEdit = this as LabelTimeEdit;
return timeEdit != null && !timeEdit.IsSameTime(this.Model.Text);
}
return this.Model == null || this.Model.Text == null || !this.Model.Text.Equals(UpdContrast, StringComparison.OrdinalIgnoreCase);
}
@@ -7,8 +7,6 @@ using Lskj.Control.Model;
using Lskj.Data;
using Lskj.Model;
using Lskj.Util;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
@@ -108,7 +106,7 @@ namespace Lskj.Control.BrowserSetting
menu.Model = new DynamicModel(new string[] { MenuName, ERPInfo.Instance.UserId, ERPInfo.Instance.UserName, "1", mMenuCode });
//DataRow[] dataRows = JsonHandler.ParseJsonArrayToDataRows(arrayItem);
//JArray jArray = (JArray)JsonConvert.DeserializeObject(arrayItem);
DataTable dataTable = JsonConvert.DeserializeObject<DataTable>(arrayItem);
DataTable dataTable = JsonUtil.ToDataTablePreservingComplexValues(arrayItem);
if (dataTable != null && dataTable.Rows.Count > 0)
{
menu.ExecRightMenu(menuModel, dataTable.Select());
@@ -323,10 +321,7 @@ namespace Lskj.Control.BrowserSetting
{
if (!string.IsNullOrWhiteSpace(rowdata) && StaticControl.RightMenuGridView != null)
{
JObject rowObject = JsonConvert.DeserializeObject<JObject>(rowdata);
JArray jArray = new JArray();
jArray.Add(rowObject);
DataTable dataTable = JsonConvert.DeserializeObject<DataTable>(JsonConvert.SerializeObject(jArray));
DataTable dataTable = JsonUtil.ToDataTablePreservingComplexValues(rowdata);
DataTable gridTable = (StaticControl.RightMenuGridView.GridControl.DataSource as DataTable).TrimDeleteRows();
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -28,6 +28,7 @@
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.pl_buttom = new DevExpress.XtraEditors.PanelControl();
this.panelControl1 = new DevExpress.XtraEditors.PanelControl();
this.btnAdd = new DevExpress.XtraEditors.SimpleButton();
@@ -35,7 +36,7 @@
this.btnDel = new DevExpress.XtraEditors.SimpleButton();
this.btnSave = new DevExpress.XtraEditors.SimpleButton();
this.spreadsheetControl1 = new DevExpress.XtraSpreadsheet.SpreadsheetControl();
this.barManager1 = new DevExpress.XtraBars.BarManager();
this.barManager1 = new DevExpress.XtraBars.BarManager(this.components);
this.commonBar1 = new DevExpress.XtraSpreadsheet.UI.CommonBar();
this.spreadsheetCommandBarButtonItem1 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem();
this.spreadsheetCommandBarButtonItem2 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem();
@@ -51,6 +52,7 @@
this.barDockControlLeft = new DevExpress.XtraBars.BarDockControl();
this.barDockControlRight = new DevExpress.XtraBars.BarDockControl();
this.spreadsheetBarController1 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetBarController();
this.components.Add(this.spreadsheetBarController1);
((System.ComponentModel.ISupportInitialize)(this.pl_buttom)).BeginInit();
this.pl_buttom.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.panelControl1)).BeginInit();
+6 -2
View File
@@ -654,13 +654,14 @@ namespace Lskj.Control
if (parametersArray.Length > i)
{
string commandParameter = parametersArray[i];
//string field = commandParameter.Replace("@", "").Replace("{", "").Replace("}", "");
string field = commandParameter.Replace("@", "").Replace("{", "").Replace("}", "");
//string value = focusedRow.Table.Columns.Contains(field) ? focusedRow[field] + "" : commandParameter.Replace("@", "");
//value = SearchObj.ReplaceControlValue(value);
//value = TopControlObj.ReplaceControlValue(value);
//value = ReplaceControlValue(value, MainControlPanel);
//value = value.Replace("@", "").Replace("{", "").Replace("}", "");
//sqlParameter.Value = value;
sqlParameter.Value = field;
}
}
SqlParameter returnValue = new SqlParameter("@return", SqlDbType.Int, 4);
@@ -670,16 +671,19 @@ namespace Lskj.Control
if (!(returnValue.Value + "").Equals("1"))
{
SqlParameter outSqlParameter = sqlParameters.Cast<SqlParameter>().Where(n => n.Direction == ParameterDirection.Output).FirstOrDefault();
string msg = "导入后执行sql失败";
if (outSqlParameter != null)
{
string outMessage = outSqlParameter.Value + "";
if (!string.IsNullOrEmpty(outMessage))
{
MessageUtil.Show("导入后执行sql失败:" + outSqlParameter.Value + "");
msg="导入后执行sql失败:" + outSqlParameter.Value + "";
}
}
MessageUtil.Show(msg);
string deleteSql = string.Format("delete from {0} where {1}='1'", this._tableName, this._importFlag);
SqlHelper.ExecuteNonQuery(deleteSql);
return false;
}
}
else
+17 -10
View File
@@ -1157,7 +1157,10 @@ namespace Lskj.Control
if (groupDataTable.Columns.Count > 0)
{
DataTable orderTable = groupDataTable.Clone();
groupDataTable.Select().OrderBy(n => n[groupDataTable.Columns[0]]).CopyToDataTable(orderTable, LoadOption.PreserveChanges);
// DataTable中的数据库空值是DBNull,不能直接和String等实际类型比较。
// 仅将DBNull作为null参与排序,非空数据仍按字段原始类型排序。
DataColumn orderColumn = groupDataTable.Columns[0];
groupDataTable.Select().OrderBy(n => n.IsNull(orderColumn) ? null : n[orderColumn]).CopyToDataTable(orderTable, LoadOption.PreserveChanges);
InitShowDataGridColumns(orderTable);
try
{
@@ -1331,15 +1334,17 @@ namespace Lskj.Control
/// <returns></returns>
static int CalcIndicatorBestWidth(DevExpress.XtraGrid.Views.Grid.GridView view)
{
Graphics graphics = new System.Windows.Forms.Control().CreateGraphics();
SizeF sizeF = new SizeF();
int count = view.TopRowIndex + ((DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo)view.GetViewInfo()).RowsInfo.Count;
if (count == 0)
{
count = 30;
}
sizeF = graphics.MeasureString(count.ToString(), view.Appearance.Row.Font);
return Convert.ToInt32(sizeF.Width) + 20;
int textWidth = TextRenderer.MeasureText(
count.ToString(),
view.Appearance.Row.Font,
Size.Empty,
TextFormatFlags.NoPadding | TextFormatFlags.SingleLine).Width;
return textWidth + 20;
}
/// <summary>
/// 计算默认的宽度
@@ -1349,16 +1354,18 @@ namespace Lskj.Control
static int CalcIndicatorDefaultWidth(DevExpress.XtraGrid.Views.Grid.GridView view)
{
var grid = view.GridControl;
Graphics graphics = new System.Windows.Forms.Control().CreateGraphics();
SizeF sizeF = new SizeF();
int rowHeight = 22;//22是Row的估计高度
if (view.RowHeight > 0)
{
rowHeight = view.RowHeight;
}
int count = grid != null ? grid.Height / rowHeight : 30;
sizeF = graphics.MeasureString(count.ToString(), view.Appearance.Row.Font);
return Convert.ToInt32(sizeF.Width) + 20;
int textWidth = TextRenderer.MeasureText(
count.ToString(),
view.Appearance.Row.Font,
Size.Empty,
TextFormatFlags.NoPadding | TextFormatFlags.SingleLine).Width;
return textWidth + 20;
}
#endregion
#region
@@ -2156,4 +2163,4 @@ namespace Lskj.Control
}
}
}
}
}
+16 -1
View File
@@ -94,6 +94,11 @@ namespace Lskj.Control
/// 父容器表格
/// </summary>
public GridControlEx ParentGridEx;
/// <summary>
/// 父容器表格条件
/// </summary>
public MyControl SearchObj;
/// <summary>
/// 源表格
@@ -391,6 +396,7 @@ namespace Lskj.Control
//提交到数据库
try
{
WaitForm.ShowForm();
string sql = "select * from " + _tableName + " where 1<>1";
//SqlDataAdapter dat = BaseImpl.GetAdapterResult(sql);
//SqlCommandBuilder scb = new SqlCommandBuilder(dat);
@@ -678,6 +684,10 @@ namespace Lskj.Control
string errorMsg = string.Format("{0}\r\n第{1}行,第{2}列\r\n列名:{3}", mesage, rowNum, colNum, colName);
XtraMessageBox.Show("数据提交错误:\n" + errorMsg + "\r\n", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
WaitForm.HideForm();
}
}
/// <summary>
/// 数字转换时间格式
@@ -954,7 +964,12 @@ namespace Lskj.Control
DataRow SelectTheLine = this.ParentGridEx.GetViewFocusedDataRow();
fieldValue = ReplaceHelper.ReplaceRowParam(SelectTheLine, fieldValue);
}
fieldValue= BaseImpl.GetDefaultValue(fieldValue);
if (this.SearchObj != null)
{
fieldValue = this.SearchObj.ReplaceParentControlValue(fieldValue);
}
fieldValue = BaseImpl.GetDefaultValue(fieldValue);
if (!string.IsNullOrEmpty(fieldValue))
{
rowItem[col.FieldName] = fieldValue;
+3 -4
View File
@@ -31,11 +31,10 @@ namespace Lskj.Control
{
this.SuspendLayout();
//
// FrmWebBrowser
// FrmWebBrowser2
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Name = "FrmWebBrowser";
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.Name = "FrmWebBrowser2";
this.Size = new System.Drawing.Size(800, 450);
this.ResumeLayout(false);
+16 -5
View File
@@ -64,24 +64,35 @@ namespace Lskj.Control
private void bsClient_OnCreated(object sender, EventArgs e)
{
cefBrowserSettings = (CefBrowser)sender;
var handle = cefBrowserSettings.GetHost().GetWindowHandle();
ResizeWindow(handle, this.Width, this.Height);
SyncBrowserBounds();
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
if (cefBrowserSettings != null)
SyncBrowserBounds();
}
/// <summary>
/// 将CEF原生子窗口同步到当前控件的客户区,修正高DPI或父容器布局变化造成的位置偏移。
/// </summary>
public void SyncBrowserBounds()
{
if (cefBrowserSettings == null || IsDisposed || Disposing ||
ClientSize.Width <= 0 || ClientSize.Height <= 0)
{
ResizeWindow(cefBrowserSettings.GetHost().GetWindowHandle(), Width, Height);
return;
}
ResizeWindow(cefBrowserSettings.GetHost().GetWindowHandle(), ClientSize.Width, ClientSize.Height);
}
public void ResizeWindow(IntPtr handle, int width, int height)
{
if (handle != IntPtr.Zero)
{
const uint SWP_NOZORDER = 0x0004;
const uint SWP_NOACTIVATE = 0x0010;
NativeMethod.SetWindowPos(handle, IntPtr.Zero,
0, 0, width, height,
0x0002 | 0x0004
SWP_NOZORDER | SWP_NOACTIVATE
);
}
}
+6 -2
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
DisposeGridResources();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -38,6 +38,8 @@ namespace Lskj.Control
new Dictionary<string, ExtendedReturnPopupContext>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, DataTable> mExtendedReturnSchemas =
new Dictionary<string, DataTable>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, string> mExtendedReturnSchemaSqls =
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, string> mExtendedReturnDisplayFields =
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, ExtendedLookupRequestState> mExtendedReturnQueryStates =
@@ -45,6 +47,7 @@ namespace Lskj.Control
private bool mExtendedReturnDisplayEventAttached;
private bool mExtendedReturnEditEventAttached;
private bool mExtendedReturnDisposeEventAttached;
private volatile bool mExtendedReturnDisposed;
private int mExtendedReturnSchemaGeneration;
private sealed class ExtendedLookupRequestState
@@ -60,6 +63,9 @@ namespace Lskj.Control
{
public GridColumnModel Model;
public ExtendedReturnSearchPopup Popup;
public PopupContainerControl PopupControl;
public RepositoryItemPopupContainerEdit SearchEdit;
public RepositoryItemTextEdit DisplayEdit;
public PopupContainerEdit OwnerEdit;
public DataRow BusinessRow;
}
@@ -70,8 +76,10 @@ namespace Lskj.Control
public DateTime DueTime;
public string FieldName;
public string Keyword;
public string SearchField;
public string SourceSql;
public string ConnectionString;
public bool SchemaOnly;
public GridColumnModel Model;
public PopupContainerEdit Editor;
public ExtendedReturnPopupContext PopupContext;
@@ -80,6 +88,7 @@ namespace Lskj.Control
private sealed class ExtendedLookupQueryResult
{
public DataTable Schema;
public DataTable Table;
public Exception Error;
}
@@ -119,7 +128,7 @@ namespace Lskj.Control
private void GridControlEx_Disposed_ExtendedReturn(object sender, EventArgs e)
{
DisposeExtendedReturnRequestTimers();
DisposeExtendedReturnResources();
}
private void InitExtendedSearchReturn(GridColumn column, GridColumnModel model)
@@ -133,6 +142,8 @@ namespace Lskj.Control
column.ColumnEdit = displayEdit;
column.FilterMode = ColumnFilterMode.DisplayText;
mExtendedReturnSearchEditors[model.FieldName] = searchEdit;
ExtendedReturnPopupContext context = GetExtendedReturnPopupContext(model.FieldName);
context.DisplayEdit = displayEdit;
this.mControlList.Add(model);
if (!mExtendedReturnEditEventAttached)
@@ -145,6 +156,14 @@ namespace Lskj.Control
private RepositoryItemPopupContainerEdit CreateExtendedReturnSearchEdit(GridColumnModel model)
{
ExtendedReturnPopupContext previousContext;
if (mExtendedReturnPopupContexts.TryGetValue(model.FieldName, out previousContext))
{
mExtendedReturnPopupContexts.Remove(model.FieldName);
mExtendedReturnSearchEditors.Remove(model.FieldName);
DisposeExtendedReturnPopupContext(previousContext);
}
Size popupSize = GetExtendedReturnPopupSize(model);
ExtendedReturnSearchPopup popup = new ExtendedReturnSearchPopup();
popup.Dock = DockStyle.Fill;
@@ -180,7 +199,9 @@ namespace Lskj.Control
ExtendedReturnPopupContext context = new ExtendedReturnPopupContext
{
Model = model,
Popup = popup
Popup = popup,
PopupControl = popupControl,
SearchEdit = searchEdit
};
popupControl.Tag = context;
popup.Tag = context;
@@ -340,9 +361,31 @@ namespace Lskj.Control
string actualValueText = GetExtendedReturnBusinessValueText(context);
context.Popup.PrepareForOpen();
string sourceSql = ResolveExtendedReturnSourceSql(model, context.BusinessRow);
DataTable cachedSchema = TryGetExtendedReturnSchema(model.FieldName, sourceSql);
if (cachedSchema != null)
{
ConfigureExtendedReturnSearchColumns(context, cachedSchema);
}
if (actualValueText.Length > 0)
{
StartExtendedReturnSearch(context, actualValueText);
QueueExtendedReturnSearch(
context.OwnerEdit,
context,
sourceSql,
actualValueText,
string.Empty,
false);
}
else if (cachedSchema == null)
{
QueueExtendedReturnSearch(
context.OwnerEdit,
context,
sourceSql,
string.Empty,
string.Empty,
true);
}
else
{
@@ -426,7 +469,7 @@ namespace Lskj.Control
try
{
StartExtendedReturnSearch(context, popup.SearchText);
StartExtendedReturnSearch(context, popup.SearchText, popup.SelectedSearchField);
}
catch (Exception ex)
{
@@ -434,18 +477,27 @@ namespace Lskj.Control
}
}
private void StartExtendedReturnSearch(ExtendedReturnPopupContext context, string keyword)
private void StartExtendedReturnSearch(
ExtendedReturnPopupContext context,
string keyword,
string searchField)
{
if (context == null || context.Model == null || context.OwnerEdit == null) return;
keyword = (keyword ?? string.Empty).Trim();
CancelExtendedReturnSearch(context.Model.FieldName);
context.Popup.ResultGrid.DataSource = null;
context.Popup.ClearResultAndFilter();
if (keyword.Length == 0) return;
ValidateExtendedReturnBusinessConfiguration(context.Model, context.BusinessRow);
string sourceSql = ResolveExtendedReturnSourceSql(context.Model, context.BusinessRow);
QueueExtendedReturnSearch(context.OwnerEdit, context, sourceSql, keyword);
QueueExtendedReturnSearch(
context.OwnerEdit,
context,
sourceSql,
keyword,
searchField,
false);
}
private void ExtendedReturnSearch_ClearRequested(object sender, EventArgs e)
@@ -622,8 +674,12 @@ namespace Lskj.Control
PopupContainerEdit edit,
ExtendedReturnPopupContext context,
string sourceSql,
string keyword)
string keyword,
string searchField,
bool schemaOnly)
{
if (mExtendedReturnDisposed) return;
GridColumnModel model = context.Model;
ExtendedLookupRequest request;
lock (mExtendedReturnSyncRoot)
@@ -636,8 +692,10 @@ namespace Lskj.Control
DueTime = DateTime.UtcNow,
FieldName = model.FieldName,
Keyword = keyword,
SearchField = searchField,
SourceSql = sourceSql,
ConnectionString = SqlHelper._connection.ConnectionString,
SchemaOnly = schemaOnly,
Model = model,
Editor = edit,
PopupContext = context,
@@ -673,6 +731,8 @@ namespace Lskj.Control
private void ExtendedReturnDebounceElapsed(object stateValue)
{
if (mExtendedReturnDisposed) return;
string fieldName = stateValue as string;
if (string.IsNullOrWhiteSpace(fieldName)) return;
@@ -683,6 +743,8 @@ namespace Lskj.Control
private void StartExtendedReturnWorker(string fieldName)
{
if (mExtendedReturnDisposed) return;
ExtendedLookupRequest request;
lock (mExtendedReturnSyncRoot)
{
@@ -710,6 +772,8 @@ namespace Lskj.Control
{
while (request != null)
{
if (mExtendedReturnDisposed) return;
lock (mExtendedReturnSyncRoot)
{
ExtendedLookupRequestState currentState = GetExtendedLookupState(request.FieldName);
@@ -721,6 +785,8 @@ namespace Lskj.Control
}
ExtendedLookupQueryResult result = QueryExtendedReturn(request);
if (mExtendedReturnDisposed) return;
bool deliverResult = false;
ExtendedLookupRequest nextRequest = null;
lock (mExtendedReturnSyncRoot)
@@ -781,13 +847,18 @@ namespace Lskj.Control
try
{
DataTable schema = GetExtendedReturnSchema(request.FieldName, request.SourceSql, request.ConnectionString);
result.Schema = schema;
IList<ExtendedReturnFieldMapping> mappings = ExtendedReturnSupport.ParseResultFields(request.Model.ResultFields);
ValidateExtendedReturnSourceColumns(schema.Columns, request.Model, mappings);
string searchSql = ExtendedReturnSupport.BuildSearchSql(request.SourceSql, schema.Columns, ExtendedLookupMaxRows);
result.Table = ExecuteExtendedReturnQuery(
searchSql,
ExtendedReturnSupport.BuildLikeParameterValue(request.Keyword),
request.ConnectionString);
if (!request.SchemaOnly)
{
string searchSql = ExtendedReturnSupport.BuildSearchSql(
request.SourceSql, schema.Columns, ExtendedLookupMaxRows, request.SearchField);
result.Table = ExecuteExtendedReturnQuery(
searchSql,
ExtendedReturnSupport.BuildLikeParameterValue(request.Keyword),
request.ConnectionString);
}
}
catch (Exception ex)
{
@@ -802,7 +873,13 @@ namespace Lskj.Control
lock (mExtendedReturnSyncRoot)
{
DataTable cachedSchema;
if (mExtendedReturnSchemas.TryGetValue(fieldName, out cachedSchema)) return cachedSchema;
string cachedSql;
if (mExtendedReturnSchemas.TryGetValue(fieldName, out cachedSchema) &&
mExtendedReturnSchemaSqls.TryGetValue(fieldName, out cachedSql) &&
string.Equals(cachedSql, sourceSql, StringComparison.Ordinal))
{
return cachedSchema;
}
schemaGeneration = mExtendedReturnSchemaGeneration;
}
@@ -810,15 +887,38 @@ namespace Lskj.Control
lock (mExtendedReturnSyncRoot)
{
DataTable cachedSchema;
if (mExtendedReturnSchemas.TryGetValue(fieldName, out cachedSchema)) return cachedSchema;
string cachedSql;
if (mExtendedReturnSchemas.TryGetValue(fieldName, out cachedSchema) &&
mExtendedReturnSchemaSqls.TryGetValue(fieldName, out cachedSql) &&
string.Equals(cachedSql, sourceSql, StringComparison.Ordinal))
{
return cachedSchema;
}
if (schemaGeneration == mExtendedReturnSchemaGeneration)
{
mExtendedReturnSchemas[fieldName] = schema;
mExtendedReturnSchemaSqls[fieldName] = sourceSql;
}
}
return schema;
}
private DataTable TryGetExtendedReturnSchema(string fieldName, string sourceSql)
{
lock (mExtendedReturnSyncRoot)
{
DataTable cachedSchema;
string cachedSql;
if (mExtendedReturnSchemas.TryGetValue(fieldName, out cachedSchema) &&
mExtendedReturnSchemaSqls.TryGetValue(fieldName, out cachedSql) &&
string.Equals(cachedSql, sourceSql, StringComparison.Ordinal))
{
return cachedSchema;
}
return null;
}
}
private static DataTable ExecuteExtendedReturnQuery(
string commandText,
string keywordParameterValue,
@@ -854,11 +954,11 @@ namespace Lskj.Control
private void BeginInvokeExtendedReturnResult(ExtendedLookupRequest request, ExtendedLookupQueryResult result)
{
if (this.IsDisposed || !this.IsHandleCreated) return;
if (mExtendedReturnDisposed || this.IsDisposed || !this.IsHandleCreated) return;
MethodInvoker deliver = new MethodInvoker(delegate
{
if (this.IsDisposed || request.Editor == null || request.Editor.IsDisposed) return;
if (mExtendedReturnDisposed || this.IsDisposed || request.Editor == null || request.Editor.IsDisposed) return;
if (!object.ReferenceEquals(this.GridView.ActiveEditor, request.Editor)) return;
if (this.GridView.FocusedColumn == null ||
!string.Equals(this.GridView.FocusedColumn.FieldName, request.FieldName, StringComparison.OrdinalIgnoreCase)) return;
@@ -870,11 +970,13 @@ namespace Lskj.Control
if (state.Version != request.Version) return;
}
ConfigureExtendedReturnSearchColumns(request.PopupContext, result.Schema);
if (result.Error != null)
{
MessageUtil.Show("扩展搜索查询失败:" + result.Error.Message);
return;
}
if (request.SchemaOnly) return;
lock (mExtendedReturnSyncRoot)
{
@@ -904,6 +1006,27 @@ namespace Lskj.Control
}
}
private void ConfigureExtendedReturnSearchColumns(
ExtendedReturnPopupContext context,
DataTable sourceSchema)
{
if (context == null || context.Popup == null || context.Model == null || sourceSchema == null) return;
ExtendedReturnSearchPopup popup = context.Popup;
List<KeyValuePair<string, string>> options = new List<KeyValuePair<string, string>>();
IList<ExtendedReturnFieldMapping> mappings =
ExtendedReturnSupport.ParseResultFields(context.Model.ResultFields);
foreach (DataColumn column in sourceSchema.Columns)
{
if (!ExtendedReturnSupport.IsSearchableColumn(column.ColumnName)) continue;
options.Add(new KeyValuePair<string, string>(
column.ColumnName,
GetExtendedReturnColumnCaption(column.ColumnName, mappings)));
}
popup.SetSearchColumns(options);
}
private void ConfigureExtendedReturnViewColumns(ExtendedReturnPopupContext context, DataTable table)
{
if (context == null || context.Popup == null || table == null || context.Model == null) return;
@@ -918,6 +1041,7 @@ namespace Lskj.Control
column.Name = column.FieldName = dataColumn.ColumnName;
column.Caption = GetExtendedReturnColumnCaption(dataColumn.ColumnName, mappings);
column.Visible = !dataColumn.ColumnName.StartsWith("_", StringComparison.Ordinal);
column.OptionsFilter.AutoFilterCondition = AutoFilterCondition.Contains;
resultView.Columns.Add(column);
}
@@ -972,7 +1096,7 @@ namespace Lskj.Control
}
context.OwnerEdit.EditValue = null;
context.Popup.ResultGrid.DataSource = null;
context.Popup.ClearResultAndFilter();
if (context.OwnerEdit.IsPopupOpen) context.OwnerEdit.ClosePopup();
this.GridView.PostEditor();
this.GridView.UpdateCurrentRow();
@@ -1002,7 +1126,7 @@ namespace Lskj.Control
ExtendedReturnPopupContext context = GetExtendedReturnPopupContext(model.FieldName);
CancelExtendedReturnSearch(model.FieldName);
SetExtendedReturnEditorBusinessValue(context);
context.Popup.ResultGrid.DataSource = null;
context.Popup.ClearResultAndFilter();
this.GridView.RefreshRow(this.GridView.FocusedRowHandle);
}
catch (Exception ex)
@@ -1188,16 +1312,19 @@ namespace Lskj.Control
/// </summary>
private void ResetExtendedReturnState()
{
if (mExtendedReturnDisposed) return;
DisposeExtendedReturnRequestTimers();
lock (mExtendedReturnSyncRoot)
{
mExtendedReturnSchemas.Clear();
mExtendedReturnSchemaSqls.Clear();
mExtendedReturnSchemaGeneration++;
}
foreach (ExtendedReturnPopupContext context in mExtendedReturnPopupContexts.Values)
{
context.Popup.ResultGrid.DataSource = null;
context.Popup.ClearResultAndFilter();
}
}
@@ -1210,6 +1337,7 @@ namespace Lskj.Control
state.Version++;
state.DeliveredVersion = 0;
state.PendingRequest = null;
state.IsRunning = false;
if (state.DebounceTimer != null)
{
state.DebounceTimer.Change(Timeout.Infinite, Timeout.Infinite);
@@ -1219,5 +1347,163 @@ namespace Lskj.Control
}
}
}
/// <summary>
/// 释放扩展返回专用的弹窗控件树和事件订阅。
/// PopupContainerControl 不在 GridControlEx.Controls 树中,不能依赖宿主控件的
/// 默认 Dispose 递归释放;这里必须显式切断事件和 GridView 的本地化器订阅。
/// </summary>
private void DisposeExtendedReturnResources()
{
lock (mExtendedReturnSyncRoot)
{
if (mExtendedReturnDisposed) return;
mExtendedReturnDisposed = true;
}
DisposeExtendedReturnRequestTimers();
try
{
if (mExtendedReturnDisplayEventAttached)
{
this.GridView.CustomColumnDisplayText -= GridView_CustomColumnDisplayText_ExtendedReturn;
mExtendedReturnDisplayEventAttached = false;
}
if (mExtendedReturnEditEventAttached)
{
this.GridView.CustomRowCellEditForEditing -= GridView_CustomRowCellEditForEditing_ExtendedReturn;
this.GridView.RowCellClick -= GridView_RowCellClick_ExtendedReturn;
mExtendedReturnEditEventAttached = false;
}
}
catch
{
// 宿主 GridView 可能已经进入 DevExpress 的销毁流程,释放必须继续。
}
try
{
this.Disposed -= GridControlEx_Disposed_ExtendedReturn;
mExtendedReturnDisposeEventAttached = false;
}
catch
{
}
List<ExtendedReturnPopupContext> contexts =
new List<ExtendedReturnPopupContext>(mExtendedReturnPopupContexts.Values);
List<RepositoryItemPopupContainerEdit> searchEditors =
new List<RepositoryItemPopupContainerEdit>(mExtendedReturnSearchEditors.Values);
mExtendedReturnPopupContexts.Clear();
mExtendedReturnSearchEditors.Clear();
foreach (ExtendedReturnPopupContext context in contexts)
{
DisposeExtendedReturnPopupContext(context);
}
// 防止异常配置导致某个 editor 没有对应 context 时仍然遗留事件订阅。
foreach (RepositoryItemPopupContainerEdit searchEdit in searchEditors)
{
DisposeExtendedReturnSearchEditor(searchEdit);
}
lock (mExtendedReturnSyncRoot)
{
foreach (DataTable schema in mExtendedReturnSchemas.Values)
{
DisposeExtendedReturnDataTable(schema);
}
mExtendedReturnSchemas.Clear();
mExtendedReturnSchemaSqls.Clear();
mExtendedReturnQueryStates.Clear();
mExtendedReturnSchemaGeneration++;
}
mExtendedReturnDisplayFields.Clear();
// 这些字段会在扩展返回弹窗操作中指向当前 GridView,销毁时不能继续保留引用。
CurrentOperGridView = null;
CurrentOperModel = null;
CurrentOperColumnKey = string.Empty;
}
private void DisposeExtendedReturnPopupContext(ExtendedReturnPopupContext context)
{
if (context == null) return;
PopupContainerEdit ownerEdit = context.OwnerEdit;
if (ownerEdit != null)
{
try
{
if (!ownerEdit.IsDisposed && ownerEdit.IsPopupOpen)
{
ownerEdit.ClosePopup();
}
}
catch
{
}
}
ExtendedReturnSearchPopup popup = context.Popup;
if (popup != null)
{
try { popup.SearchRequested -= ExtendedReturnSearch_SearchRequested; } catch { }
try { popup.ClearRequested -= ExtendedReturnSearch_ClearRequested; } catch { }
try { popup.ResultSelected -= ExtendedReturnSearch_ResultSelected; } catch { }
try { popup.ResultGrid.DataSource = null; } catch { }
try { popup.ClearResultAndFilter(); } catch { }
try { popup.Tag = null; } catch { }
}
PopupContainerControl popupControl = context.PopupControl;
if (popupControl != null)
{
try { popupControl.Tag = null; } catch { }
}
DisposeExtendedReturnSearchEditor(context.SearchEdit);
DisposeExtendedReturnComponent(popup == null ? null : popup.ResultView);
DisposeExtendedReturnComponent(popup == null ? null : popup.ResultGrid);
DisposeExtendedReturnComponent(popup);
DisposeExtendedReturnComponent(popupControl);
DisposeExtendedReturnComponent(context.DisplayEdit);
context.Model = null;
context.Popup = null;
context.PopupControl = null;
context.SearchEdit = null;
context.DisplayEdit = null;
context.OwnerEdit = null;
context.BusinessRow = null;
}
private void DisposeExtendedReturnSearchEditor(RepositoryItemPopupContainerEdit searchEdit)
{
if (searchEdit == null) return;
try { searchEdit.QueryPopUp -= ExtendedReturnSearch_QueryPopUp; } catch { }
try { searchEdit.Popup -= ExtendedReturnSearch_Popup; } catch { }
try { searchEdit.Closed -= ExtendedReturnSearch_Closed; } catch { }
try { searchEdit.QueryDisplayText -= ExtendedReturnSearch_QueryDisplayText; } catch { }
try { searchEdit.PopupControl = null; } catch { }
try { searchEdit.Tag = null; } catch { }
DisposeExtendedReturnComponent(searchEdit);
}
private static void DisposeExtendedReturnDataTable(DataTable table)
{
if (table == null) return;
try { table.Dispose(); } catch { }
}
private static void DisposeExtendedReturnComponent(IDisposable component)
{
if (component == null) return;
try { component.Dispose(); } catch { }
}
}
}
File diff suppressed because it is too large Load Diff
@@ -12,10 +12,15 @@ using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Views.Grid.ViewInfo;
// Token: 0x02000003 RID: 3
public class AmountCellRender
public class AmountCellRender : IDisposable
{
public AmountCellRender(GridView gridView_0)
{
if (gridView_0 == null)
{
throw new ArgumentNullException("gridView_0");
}
Class5.gBkiB4AzUqwkh();
this.colorGray = Color.FromArgb(189, 185, 185);
this.colorGreen = Color.Green;
@@ -25,23 +30,58 @@ public class AmountCellRender
this.dictionary_0 = new Dictionary<string, Class2>();
this.list_0 = new List<GridColumn>();
this.object_0 = gridView_0;
this.gridControl_0 = this.object_0.GridControl;
this.object_0.CustomDrawCell += this.object_0_CustomDrawCell;
this.object_0.CustomDrawColumnHeader += this.object_0_CustomDrawColumnHeader;
this.object_0.CustomDrawFooterCell += this.object_0_CustomDrawFooterCell;
this.object_0.GridControl.Paint += this.method_0;
if (this.gridControl_0 != null)
{
this.gridControl_0.Paint += this.method_0;
}
}
private void method_0(object sender, PaintEventArgs e)
{
BaseViewInfo viewInfo = ((sender as GridControl).FocusedView as GridView).GetViewInfo();
if (this.disposed || this.list_0.Count == 0)
{
return;
}
GridControl gridControl = sender as GridControl;
if (gridControl == null || gridControl.IsDisposed || gridControl.Disposing)
{
return;
}
GridView gridView = gridControl.FocusedView as GridView;
if (gridView == null)
{
return;
}
GridViewInfo gridViewInfo = gridView.GetViewInfo() as GridViewInfo;
if (gridViewInfo == null || gridViewInfo.ColumnsInfo == null)
{
return;
}
foreach (GridColumn gridColumn in this.list_0)
{
Class2 @class = this.dictionary_0[gridColumn.Name];
Class2 @class;
if (gridColumn == null ||
!this.dictionary_0.TryGetValue(gridColumn.Name, out @class) ||
@class == null)
{
continue;
}
if (@class.IsCountinuousCell())
{
GridViewInfo gridViewInfo = viewInfo as GridViewInfo;
GridColumnInfoArgs gridColumnInfoArgs = gridViewInfo.ColumnsInfo[gridColumn];
if (gridColumnInfoArgs == null) return;
if (gridColumnInfoArgs == null)
{
continue;
}
int num = 0;
int int_;
if (@class.method_4())
@@ -82,10 +122,16 @@ public class AmountCellRender
private void object_0_CustomDrawCell(object sender, RowCellCustomDrawEventArgs e)
{
if (this.dictionary_0.ContainsKey(e.Column.Name))
if (this.disposed || e.Column == null)
{
return;
}
Class2 @class;
if (this.dictionary_0.TryGetValue(e.Column.Name, out @class) &&
@class != null)
{
e.DisplayText = "";
Class2 @class = this.dictionary_0[e.Column.Name];
Rectangle bounds = e.Bounds;
Rectangle rectangle_ = bounds;
Graphics graphics = e.Graphics;
@@ -98,14 +144,20 @@ public class AmountCellRender
private void object_0_CustomDrawFooterCell(object sender, FooterCellCustomDrawEventArgs e)
{
if (this.dictionary_0.ContainsKey(e.Column.Name))
if (this.disposed || e.Column == null)
{
return;
}
Class2 @class;
if (this.dictionary_0.TryGetValue(e.Column.Name, out @class) &&
@class != null)
{
Class2 @class = this.dictionary_0[e.Column.Name];
if (@class.method_8())
{
e.Info.DisplayText = "";
Rectangle bounds = e.Bounds;
@class.method_17(bounds, e.Graphics, e.Appearance.Font, e.Info.Value.ToString());
@class.method_17(bounds, e.Graphics, e.Appearance.Font, Convert.ToString(e.Info.Value));
e.Handled = true;
}
}
@@ -113,13 +165,15 @@ public class AmountCellRender
private void object_0_CustomDrawColumnHeader(object sender, ColumnHeaderCustomDrawEventArgs e)
{
if (e.Column == null)
if (this.disposed || e.Column == null)
{
return;
}
if (this.dictionary_0.ContainsKey(e.Column.Name))
Class2 @class;
if (this.dictionary_0.TryGetValue(e.Column.Name, out @class) &&
@class != null)
{
Class2 @class = this.dictionary_0[e.Column.Name];
if (@class.method_6())
{
e.Column.Caption = "";
@@ -204,14 +258,44 @@ public class AmountCellRender
public void RemoveAmountColumn(GridColumn gridColumn_0)
{
if (this.dictionary_0.ContainsKey(gridColumn_0.Name))
if (gridColumn_0 != null && this.dictionary_0.ContainsKey(gridColumn_0.Name))
{
this.dictionary_0.Remove(gridColumn_0.Name);
this.list_0.Remove(gridColumn_0);
}
}
public void Dispose()
{
if (this.disposed)
{
return;
}
this.disposed = true;
GridView gridView = this.object_0;
GridControl gridControl = this.gridControl_0;
this.object_0 = null;
this.gridControl_0 = null;
if (gridView != null)
{
gridView.CustomDrawCell -= this.object_0_CustomDrawCell;
gridView.CustomDrawColumnHeader -= this.object_0_CustomDrawColumnHeader;
gridView.CustomDrawFooterCell -= this.object_0_CustomDrawFooterCell;
}
if (gridControl != null)
{
gridControl.Paint -= this.method_0;
}
this.dictionary_0.Clear();
this.list_0.Clear();
}
private GridView object_0;
private GridControl gridControl_0;
private bool disposed;
private Color colorGray;
private Color colorGreen;
+9 -3
View File
@@ -255,7 +255,10 @@ public class Class2
if (color != Color.Empty)
{
Rectangle rect = new Rectangle(rectangle_0.Left + i - 2, int_2, int_1, int_3);
graphics_0.FillRectangle(new SolidBrush(color), rect);
using (SolidBrush solidBrush = new SolidBrush(color))
{
graphics_0.FillRectangle(solidBrush, rect);
}
}
}
else
@@ -265,9 +268,12 @@ public class Class2
num++;
}
Rectangle rect2 = new Rectangle(rectangle_0.Left - 1, int_2, int_1 + 1, int_3);
graphics_0.FillRectangle(new SolidBrush(Color.FromArgb(161, 157, 157)), rect2);
Rectangle rect3 = new Rectangle(rectangle_0.Left + rectangle_0.Width - 1, int_2, int_1 + 1, int_3);
graphics_0.FillRectangle(new SolidBrush(Color.FromArgb(161, 157, 157)), rect3);
using (SolidBrush solidBrush = new SolidBrush(Color.FromArgb(161, 157, 157)))
{
graphics_0.FillRectangle(solidBrush, rect2);
graphics_0.FillRectangle(solidBrush, rect3);
}
}
// Token: 0x06000028 RID: 40 RVA: 0x00002CC8 File Offset: 0x00000EC8
+5 -3
View File
@@ -160,9 +160,11 @@ namespace Lskj.Control
}
else
{
Graphics g = this.lblText.CreateGraphics();
SizeF sizeF = g.MeasureString(value, this.lblText.Font);
this.plLeft.Width = (int)sizeF.Width + PaddingLeft;
this.plLeft.Width = TextRenderer.MeasureText(
value,
this.lblText.Font,
Size.Empty,
TextFormatFlags.NoPadding | TextFormatFlags.SingleLine).Width + PaddingLeft;
}
}
}
+252
View File
@@ -0,0 +1,252 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using DevExpress.XtraEditors;
namespace Lskj.Control
{
/// <summary>
/// 带标题的时间输入控件,使用上下按钮调整时间。
/// </summary>
public class LabelTimeEdit : BaseUserControl
{
private readonly Panel plLeft;
private readonly Panel plRight;
private readonly Label lblText;
private readonly TimeEdit txtEdit;
private string formatString = "HH:mm:ss";
public LabelTimeEdit()
{
plLeft = new Panel();
plRight = new Panel();
lblText = new Label();
txtEdit = new TimeEdit();
SuspendLayout();
plLeft.SuspendLayout();
plRight.SuspendLayout();
((System.ComponentModel.ISupportInitialize)txtEdit.Properties).BeginInit();
plLeft.BackColor = Color.Transparent;
plLeft.Controls.Add(lblText);
plLeft.Dock = DockStyle.Left;
plLeft.Size = new Size(40, 21);
lblText.AutoSize = true;
lblText.Location = new Point(5, 4);
lblText.Text = "名称";
plRight.Controls.Add(txtEdit);
plRight.Dock = DockStyle.Fill;
plRight.Location = new Point(40, 0);
txtEdit.Dock = DockStyle.Fill;
txtEdit.EditValue = null;
txtEdit.Properties.Buttons.Clear();
txtEdit.Properties.Buttons.Add(new DevExpress.XtraEditors.Controls.EditorButton(
DevExpress.XtraEditors.Controls.ButtonPredefines.Combo));
txtEdit.Properties.TimeEditStyle = DevExpress.XtraEditors.Repository.TimeEditStyle.SpinButtons;
AutoScaleMode = AutoScaleMode.None;
BackColor = Color.Transparent;
Controls.Add(plRight);
Controls.Add(plLeft);
Size = new Size(162, 21);
((System.ComponentModel.ISupportInitialize)txtEdit.Properties).EndInit();
plRight.ResumeLayout(false);
plLeft.ResumeLayout(false);
plLeft.PerformLayout();
ResumeLayout(false);
}
/// <summary>
/// 时间编辑器。
/// </summary>
public TimeEdit TextEdit
{
get { return txtEdit; }
}
public override string LabelText
{
get { return lblText.Text; }
set
{
lblText.Text = value;
if (FontSize > 0)
{
plLeft.AutoSize = false;
lblText.AutoSize = false;
lblText.Dock = DockStyle.Fill;
lblText.Location = new Point(0, 0);
lblText.TextAlign = ContentAlignment.MiddleLeft;
txtEdit.Properties.AutoHeight = false;
plLeft.Width = value.Length * GetCharWidth();
GetCharWidthMultilingual(lblText, lblText.Text, plLeft);
}
else
{
plLeft.Width = lblText.Width + PaddingLeft;
}
}
}
public override float FontSize
{
get { return base.FontSize; }
set
{
base.FontSize = value;
if (value > 0)
{
lblText.Font = new Font(lblText.Font.FontFamily, value);
txtEdit.Font = new Font(txtEdit.Font.FontFamily, value);
}
}
}
public override string EditText
{
get { return txtEdit.EditValue == null ? string.Empty : txtEdit.Text; }
set
{
TimeSpan timeValue;
txtEdit.EditValue = TryGetTime(value, out timeValue)
? (object)DateTime.Today.Add(timeValue)
: null;
}
}
public override string NullText
{
get { return txtEdit.Properties.NullValuePrompt; }
set
{
if (!string.IsNullOrEmpty(value))
{
txtEdit.Properties.NullValuePromptShowForEmptyValue = true;
txtEdit.Properties.NullValuePrompt = value;
}
base.NullText = value;
}
}
public override bool ReadOnly
{
get { return base.ReadOnly; }
set
{
base.ReadOnly = value;
txtEdit.Properties.ReadOnly = value;
txtEdit.Enabled = !value;
lblText.ForeColor = value ? ReadOnlyLabelForceColor : Required ? RequiredLabelForceColor : DefaultLabelForceColor;
}
}
public override bool Required
{
get { return base.Required; }
set
{
base.Required = value;
if (value)
{
lblText.ForeColor = RequiredLabelForceColor;
}
}
}
public override Color BackgroundColor
{
get { return txtEdit.Properties.Appearance.BackColor; }
set { txtEdit.Properties.Appearance.BackColor = value; }
}
public override Color ForeColor
{
get { return txtEdit.Properties.Appearance.ForeColor; }
set { txtEdit.Properties.Appearance.ForeColor = value; }
}
public override bool ContentBold
{
get { return txtEdit.Properties.Appearance.Font.Bold; }
set
{
Font oldFont = txtEdit.Properties.Appearance.Font;
txtEdit.Properties.Appearance.Font = new Font(oldFont.FontFamily, oldFont.Size, value ? FontStyle.Bold : FontStyle.Regular);
}
}
/// <summary>
/// 设置时间的显示和输入格式。
/// </summary>
public void TimeFormat(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return;
}
formatString = value;
txtEdit.Properties.DisplayFormat.FormatString = value;
txtEdit.Properties.EditFormat.FormatString = value;
txtEdit.Properties.DisplayFormat.FormatType = DevExpress.Utils.FormatType.Custom;
txtEdit.Properties.EditFormat.FormatType = DevExpress.Utils.FormatType.Custom;
txtEdit.Properties.Mask.EditMask = value;
txtEdit.Properties.Mask.UseMaskAsDisplayFormat = true;
txtEdit.Properties.TimeFormat = value.IndexOf("ss", StringComparison.OrdinalIgnoreCase) >= 0
? DevExpress.XtraEditors.Controls.TimeFormat.HourMinSec
: DevExpress.XtraEditors.Controls.TimeFormat.HourMin;
}
/// <summary>
/// 按控件显示精度比较当前值和原值,避免 DateTime/TimeSpan 字符串格式差异造成误判。
/// </summary>
public bool IsSameTime(string value)
{
TimeSpan oldTime;
TimeSpan currentTime;
bool hasOldTime = TryGetTime(value, out oldTime);
bool hasCurrentTime = TryGetTime(EditText, out currentTime);
if (!hasOldTime || !hasCurrentTime)
{
return !hasOldTime && !hasCurrentTime;
}
if (formatString.IndexOf("ss", StringComparison.OrdinalIgnoreCase) >= 0)
{
return oldTime.Hours == currentTime.Hours &&
oldTime.Minutes == currentTime.Minutes &&
oldTime.Seconds == currentTime.Seconds;
}
return oldTime.Hours == currentTime.Hours && oldTime.Minutes == currentTime.Minutes;
}
private static bool TryGetTime(string value, out TimeSpan timeValue)
{
timeValue = TimeSpan.Zero;
if (string.IsNullOrWhiteSpace(value))
{
return false;
}
if (TimeSpan.TryParse(value, out timeValue))
{
return true;
}
DateTime dateValue;
if (DateTime.TryParse(value, out dateValue))
{
timeValue = dateValue.TimeOfDay;
return true;
}
return false;
}
}
}
+117
View File
@@ -0,0 +1,117 @@
using System;
using System.Threading;
namespace Lskj.Control
{
/// <summary>
/// 串行处理请求,并在繁忙时只保留最后一次请求。
/// 用于输入联想控件,避免每次 TextChanged 都创建独立线程。
/// </summary>
internal sealed class LatestValueWorker<T> : IDisposable
{
private readonly object _syncRoot = new object();
private readonly Action<T, int> _work;
private T _pendingValue;
private bool _hasPendingValue;
private bool _workerRunning;
private bool _disposed;
private int _version;
public LatestValueWorker(Action<T, int> work)
{
if (work == null)
{
throw new ArgumentNullException("work");
}
_work = work;
}
public int Queue(T value)
{
bool startWorker = false;
int version;
lock (_syncRoot)
{
if (_disposed)
{
return -1;
}
version = ++_version;
_pendingValue = value;
_hasPendingValue = true;
if (!_workerRunning)
{
_workerRunning = true;
startWorker = true;
}
}
if (startWorker && !ThreadPool.QueueUserWorkItem(Run))
{
lock (_syncRoot)
{
_workerRunning = false;
}
throw new InvalidOperationException("无法启动输入联想查询任务。");
}
return version;
}
public bool IsCurrent(int version)
{
lock (_syncRoot)
{
return !_disposed && version == _version;
}
}
private void Run(object state)
{
while (true)
{
T value;
int version;
lock (_syncRoot)
{
if (_disposed || !_hasPendingValue)
{
_workerRunning = false;
return;
}
value = _pendingValue;
version = _version;
_pendingValue = default(T);
_hasPendingValue = false;
}
try
{
_work(value, version);
}
catch
{
// 查询异常由控件自身转换为空结果;这里确保工作循环能够继续或退出。
}
}
}
public void Dispose()
{
lock (_syncRoot)
{
_disposed = true;
_hasPendingValue = false;
_pendingValue = default(T);
_version++;
}
}
}
}
@@ -456,6 +456,7 @@
<Compile Include="BlinkBrowser.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="CefBrowserLifetimeCoordinator.cs" />
<Compile Include="BrowserSetting2\BsClient.cs" />
<Compile Include="BrowserSetting2\BsContextMenuHandler.cs" />
<Compile Include="BrowserSetting2\BsDownloadHandler.cs" />
@@ -712,6 +713,7 @@
<SubType>UserControl</SubType>
</Compile>
<Compile Include="AutoGridLookUp\ExtendedReturnModuleSourceResolver.cs" />
<Compile Include="LatestValueWorker.cs" />
<Compile Include="AutoGridLookUp\LabelExtendedReturnSearchEdit.cs">
<SubType>UserControl</SubType>
</Compile>
@@ -926,6 +928,7 @@
<DependentUpon>LabelWeigh.cs</DependentUpon>
</Compile>
<Compile Include="Model\AttachHelper.cs" />
<Compile Include="Model\AltButtonShortcutManager.cs" />
<Compile Include="AuditPanelEx.cs">
<SubType>UserControl</SubType>
</Compile>
@@ -1217,6 +1220,9 @@
<Compile Include="LabelDateEdit.Designer.cs">
<DependentUpon>LabelDateEdit.cs</DependentUpon>
</Compile>
<Compile Include="LabelTimeEdit.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="LabelImageEdit.cs">
<SubType>UserControl</SubType>
</Compile>
@@ -0,0 +1,122 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using DevExpress.XtraEditors;
namespace Lskj.Control.Model
{
/// <summary>
/// 将按钮原有的 &amp; 助记键改为必须按 Alt 才能触发的快捷键。
/// </summary>
public sealed class AltButtonShortcutManager
{
private sealed class ShortcutItem
{
public SimpleButton Button;
public Keys Key;
}
private readonly List<ShortcutItem> mShortcutItems =
new List<ShortcutItem>();
private bool mUpdatingText;
/// <summary>
/// 注册按钮快捷键,并移除标题中的 &amp;,保持界面显示为“按钮名(X)”。
/// </summary>
public void Register(SimpleButton button, Keys defaultKey)
{
if (button == null)
{
return;
}
ShortcutItem item = mShortcutItems.Find(
shortcut => ReferenceEquals(shortcut.Button, button));
if (item == null)
{
item = new ShortcutItem { Button = button, Key = defaultKey };
mShortcutItems.Add(item);
button.TextChanged += OnButtonTextChanged;
}
UpdateShortcut(item, defaultKey);
}
/// <summary>
/// 只响应 Alt+原助记键;未按 Alt、同时按下其他修饰键时均不处理。
/// </summary>
public bool ProcessKey(Keys keyData)
{
if ((keyData & Keys.Modifiers) != Keys.Alt)
{
return false;
}
Keys keyCode = keyData & Keys.KeyCode;
foreach (ShortcutItem item in mShortcutItems)
{
SimpleButton button = item.Button;
if (item.Key == keyCode && button != null &&
!button.IsDisposed && button.Visible && button.Enabled)
{
button.PerformClick();
return true;
}
}
return false;
}
private void OnButtonTextChanged(object sender, EventArgs e)
{
if (mUpdatingText)
{
return;
}
SimpleButton button = sender as SimpleButton;
ShortcutItem item = mShortcutItems.Find(
shortcut => ReferenceEquals(shortcut.Button, button));
if (item != null)
{
UpdateShortcut(item, item.Key);
}
}
private void UpdateShortcut(ShortcutItem item, Keys defaultKey)
{
string text = item.Button.Text ?? string.Empty;
int mnemonicIndex = FindMnemonicIndex(text);
if (mnemonicIndex >= 0)
{
item.Key = (Keys)char.ToUpperInvariant(text[mnemonicIndex + 1]);
mUpdatingText = true;
try
{
item.Button.Text = text.Remove(mnemonicIndex, 1);
}
finally
{
mUpdatingText = false;
}
}
else
{
item.Key = defaultKey;
}
}
private static int FindMnemonicIndex(string text)
{
for (int index = 0; index < text.Length - 1; index++)
{
if (text[index] == '&' && char.IsLetterOrDigit(text[index + 1]))
{
return index;
}
}
return -1;
}
}
}
@@ -182,7 +182,10 @@ namespace Lskj.Control.Model
/// 判断两个值是否相同。
/// 优先按日期、数字进行值比较,最后再按普通字符串比较。
/// </summary>
private static bool IsSameValue(string oldValue, string newValue)
/// <param name="oldValue">原始值</param>
/// <param name="newValue">当前值</param>
/// <returns>两个值在统一格式后是否相同</returns>
public static bool IsSameValue(string oldValue, string newValue)
{
oldValue = NormalizeValue(oldValue);
newValue = NormalizeValue(newValue);
@@ -26,8 +26,68 @@ namespace Lskj.Control.Model
/// <summary>
/// 表格拖拽到表格
/// </summary>
public class BandedGridDragGrid
public class BandedGridDragGrid : IDisposable
{
private bool _disposed;
internal static void DisposeRegistrations(
Dictionary<BandedGridView, List<BandedGridDragGrid>> sourceRegistrations,
Dictionary<GridView, List<BandedGridDragGrid>> targetRegistrations,
BandedGridView sourceGridView,
GridView targetGridView)
{
DisposeSourceRegistrations(sourceRegistrations, sourceGridView);
DisposeTargetRegistrations(targetRegistrations, targetGridView);
}
private static void DisposeSourceRegistrations(
Dictionary<BandedGridView, List<BandedGridDragGrid>> registrations,
BandedGridView gridView)
{
foreach (KeyValuePair<BandedGridView, List<BandedGridDragGrid>> entry in registrations.ToList())
{
bool removeKey = ReferenceEquals(entry.Key, gridView);
foreach (BandedGridDragGrid registration in entry.Value.ToList())
{
if (removeKey || registration == null || registration._disposed || registration.References(gridView))
{
if (registration != null)
registration.Dispose();
entry.Value.Remove(registration);
}
}
if (removeKey || entry.Value.Count == 0)
registrations.Remove(entry.Key);
}
}
private static void DisposeTargetRegistrations(
Dictionary<GridView, List<BandedGridDragGrid>> registrations,
GridView gridView)
{
foreach (KeyValuePair<GridView, List<BandedGridDragGrid>> entry in registrations.ToList())
{
bool removeKey = ReferenceEquals(entry.Key, gridView);
foreach (BandedGridDragGrid registration in entry.Value.ToList())
{
if (removeKey || registration == null || registration._disposed || registration.References(gridView))
{
if (registration != null)
registration.Dispose();
entry.Value.Remove(registration);
}
}
if (removeKey || entry.Value.Count == 0)
registrations.Remove(entry.Key);
}
}
internal bool References(GridView gridView)
{
return gridView != null &&
(ReferenceEquals(_sourceGridView, gridView) ||
ReferenceEquals(_targetGridView, gridView));
}
/// <summary>
/// 是否正在拖拽
/// </summary>
@@ -106,6 +166,99 @@ namespace Lskj.Control.Model
this._targetGridView.GridControl.DragEnter += new System.Windows.Forms.DragEventHandler(gridControl_DragEnter);
this._targetGridView.GridControl.DragDrop += new System.Windows.Forms.DragEventHandler(gridControl_DragDrop);
this._targetGridView.GridControl.DragLeave += new EventHandler(gridControl_DragLeave);
this._sourceGridView.Disposed += OnGridViewDisposed;
if (!ReferenceEquals(this._sourceGridView, this._targetGridView))
{
this._targetGridView.Disposed += OnGridViewDisposed;
}
}
private void OnGridViewDisposed(object sender, EventArgs e)
{
Dispose();
}
public void Dispose()
{
if (_disposed)
{
return;
}
_disposed = true;
BandedGridView sourceGridView = _sourceGridView;
GridView targetGridView = _targetGridView;
if (sourceGridView != null)
{
sourceGridView.MouseDown -= sourceGridView_MouseDown;
sourceGridView.MouseMove -= sourceGridView_MouseMove;
sourceGridView.MouseUp -= sourceGridView_MouseUp;
sourceGridView.RowClick -= OnRowClick;
sourceGridView.Disposed -= OnGridViewDisposed;
}
if (targetGridView != null)
{
if (targetGridView.GridControl != null)
{
targetGridView.GridControl.DragOver -= gridControl_DragOver;
targetGridView.GridControl.DragEnter -= gridControl_DragEnter;
targetGridView.GridControl.DragDrop -= gridControl_DragDrop;
targetGridView.GridControl.DragLeave -= gridControl_DragLeave;
}
if (!ReferenceEquals(sourceGridView, targetGridView))
{
targetGridView.Disposed -= OnGridViewDisposed;
}
}
RemoveRegistration(
StaticBandedControl.BandedGridViewDragGridDic,
sourceGridView,
this);
RemoveRegistration(
StaticBandedControl.BandedTargetViewDragGridDic,
targetGridView,
this);
if (ReferenceEquals(
StaticBandedControl.SourceDragBandedGridView,
sourceGridView))
{
StaticBandedControl.SourceDragBandedGridView = null;
}
OnDragComplete = null;
DragHander.Clear();
_hitInfo = null;
_sourceGridView = null;
_targetGridView = null;
}
private static void RemoveRegistration<TKey>(
Dictionary<TKey, List<BandedGridDragGrid>> registrations,
TKey key,
BandedGridDragGrid registration)
where TKey : class
{
if (key == null)
{
return;
}
List<BandedGridDragGrid> registrationsForView;
if (!registrations.TryGetValue(key, out registrationsForView))
{
return;
}
registrationsForView.Remove(registration);
if (registrationsForView.Count == 0)
{
registrations.Remove(key);
}
}
/// <summary>
/// 点击时候判断位置
+51 -5
View File
@@ -22,6 +22,7 @@ using System.IO;
using System.Data.SqlClient;
using Lskj.Business;
using DevExpress.XtraGrid.Views.Grid;
using Lskj.Core;
namespace Lskj.Control.Model
{
@@ -38,6 +39,12 @@ namespace Lskj.Control.Model
/// </summary>
private MyControl _controlObj;
public bool issuccess = true;
/// <summary>
/// 最初账套版本
/// </summary>
public DataRow AccountItem;
/// <summary>
/// Occurs when [apply before].
/// </summary>
@@ -73,13 +80,12 @@ namespace Lskj.Control.Model
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
public bool Apply(DataRow rowItem)
{
bool resultValue = false;
if (rowItem == null || this._controlObj == null) return resultValue;
GridRightMenuModel model = new GridRightMenuModel(rowItem);
try
{
bool resultValue = false;
if (rowItem == null || this._controlObj == null) return resultValue;
GridRightMenuModel model = new GridRightMenuModel(rowItem);
//if (!string.IsNullOrWhiteSpace(model.MenuCond))
//{
// try
@@ -103,6 +109,18 @@ namespace Lskj.Control.Model
// }
//}
if (!string.IsNullOrEmpty(model.UnionZTid))
{
string UnionZTid = ReplaceHelper.ReplaceRowParam(BaseGridView.GetFocusedDataRow(), model.UnionZTid);
string condition = string.Format("where ShowName ='{0}'", ERPInfo.Instance.AccountBook);
DataTable dt = MainImpl.GetLedgerList(condition);
DataRow RT = BaseImpl.GetDataRowResult($"select * from p_sydbGroupTab where ID={UnionZTid}");
AccountItem = dt.Rows[0];
AccountItem["IP"] = DBConfig.Instance.ServerName;
ToDBatching(RT, AccountItem);
}
if (!string.IsNullOrWhiteSpace(model.BeforeMsg))
{
@@ -186,6 +204,10 @@ namespace Lskj.Control.Model
string Message = ErrorMessage.PromptErrorMessage(ex);
MessageUtil.Show(Message, ex.Message);
}
finally
{
if (!string.IsNullOrEmpty(model.UnionZTid)) ToDBatching(AccountItem, AccountItem);
}
return true;
}
/// <summary>
@@ -507,5 +529,29 @@ namespace Lskj.Control.Model
}
return false;
}
/// <summary>
/// 启动账套数据源刷新
/// </summary>
protected void ToDBatching(DataRow RT, DataRow firstrow)
{
string serverIP = RT["IP"] + "";
string dbName = RT["DBName"] + "";
string dataBook = RT["ShowName"] + "";
bool isInternal = RT.Table.Columns.Contains("IsInternalNetwork") && !string.IsNullOrEmpty(RT["IsInternalNetwork"] + "") ? "1".Equals(RT["IsInternalNetwork"] + "") : false;
DBConfig.Instance.DataBook = dataBook;
DBConfig.Instance.ServerName = serverIP;
DBConfig.Instance.DataBase = dbName;
DBConfig.Instance.IsInternalNetwork = isInternal;
if (!DBConfig.Instance.CreateConnection())
{
ToDBatching(firstrow, firstrow);
}
}
}
}
+18 -1
View File
@@ -161,7 +161,7 @@ namespace Lskj.Control.Model
/// </summary>
public const int LabComboxCheckListText = 19;
/// <summary>
/// Memo控件
/// Memo控件 (备注框A
/// </summary>
public const int LabMemoEdit = 20;
/// <summary>
@@ -501,6 +501,23 @@ namespace Lskj.Control.Model
/// </summary>
public const int LabSearchReturnIdExtended = 174;
///// <summary>
///// 快速搜索框返回id(字典模式)
///// </summary>
//public const int DictionarySearchBoxToId = 181;
///// <summary>
///// 快速搜索框返回text(字典模式)
///// </summary>
//public const int DictionarySearchBoxToText = 182;
///// <summary>
///// 快速搜索框返回id 带参数(字典模式)
///// </summary>
//public const int DictionarySearchBoxToIdParam = 183;
///// <summary>
///// 快速搜索框返回text 带参数(字典模式)
///// </summary>
//public const int DictionarySearchBoxToTextParam = 184;
/// <summary>
/// <para>说明:是否为Value类型</para>
/// <para>创建人:龚宇超</para>
@@ -78,6 +78,11 @@ namespace Lskj.Control.Model
}
public static string BuildSearchSql(string sourceSql, DataColumnCollection columns, int maxRows)
{
return BuildSearchSql(sourceSql, columns, maxRows, string.Empty);
}
public static string BuildSearchSql(string sourceSql, DataColumnCollection columns, int maxRows, string searchField)
{
if (columns == null || columns.Count == 0)
{
@@ -88,17 +93,50 @@ namespace Lskj.Control.Model
throw new ArgumentOutOfRangeException("maxRows", "最大返回行数必须大于零。");
}
List<DataColumn> searchColumns = new List<DataColumn>();
string selectedField = (searchField ?? string.Empty).Trim();
if (selectedField.Length == 0)
{
foreach (DataColumn column in columns)
{
if (IsSearchableColumn(column.ColumnName))
{
searchColumns.Add(column);
}
}
}
else
{
foreach (DataColumn column in columns)
{
if (string.Equals(column.ColumnName, selectedField, StringComparison.OrdinalIgnoreCase) &&
IsSearchableColumn(column.ColumnName))
{
searchColumns.Add(column);
break;
}
}
}
if (searchColumns.Count == 0)
{
if (selectedField.Length > 0)
{
throw new InvalidOperationException(string.Format("搜索字段“{0}”不存在或不允许查询。", selectedField));
}
throw new InvalidOperationException("搜索 SQL 没有返回任何可查询列。");
}
string alias = QuoteIdentifier(SearchAlias);
StringBuilder builder = new StringBuilder();
builder.AppendFormat("select top ({0}) * from ({1}) as {2} where ", maxRows, NormalizeSourceSql(sourceSql), alias);
for (int i = 0; i < columns.Count; i++)
for (int i = 0; i < searchColumns.Count; i++)
{
if (i > 0) builder.Append(" or ");
builder.Append("convert(nvarchar(4000), ");
builder.Append(alias);
builder.Append('.');
builder.Append(QuoteIdentifier(columns[i].ColumnName));
builder.Append(QuoteIdentifier(searchColumns[i].ColumnName));
builder.Append(") like ");
builder.Append(SearchParameterName);
builder.Append(" escape N'\\'");
@@ -106,6 +144,12 @@ namespace Lskj.Control.Model
return builder.ToString();
}
public static bool IsSearchableColumn(string columnName)
{
return !string.IsNullOrWhiteSpace(columnName) &&
!columnName.StartsWith("_", StringComparison.Ordinal);
}
public static string BuildLikeParameterValue(string keyword)
{
string value = keyword ?? string.Empty;
@@ -307,6 +307,11 @@ namespace Lskj.Control.Model
/// </summary>
public bool AddHideBottomPanel;
/// <summary>
/// 禁用条件
/// </summary>
public string VisibleCond;
/// <summary>
/// 主模块编号
/// </summary>
@@ -379,6 +384,7 @@ namespace Lskj.Control.Model
this.IgnoreAssociatedFields = item.Table.Columns.Contains("IgnoreAssociatedFields") ? "1".Equals(item["IgnoreAssociatedFields"] + "") : false;
this.Library = item.Table.Columns.Contains("Library") ? item["Library"] + "" : "";
this.AddHideBottomPanel = item.Table.Columns.Contains("AddHideBottomPanel") ? "1".Equals(item["AddHideBottomPanel"] + "") : false;
this.VisibleCond = item.Table.Columns.Contains("VisibleCond") ? item["VisibleCond"] + "" : "";
}
}
}
+130 -1
View File
@@ -29,8 +29,46 @@ namespace Lskj.Control.Model
/// <summary>
/// 表格拖拽到表格
/// </summary>
public class GridDragGrid
public class GridDragGrid : IDisposable
{
private bool _disposed;
internal static void DisposeRegistrations(
Dictionary<GridView, List<GridDragGrid>> sourceRegistrations,
Dictionary<GridView, List<GridDragGrid>> targetRegistrations,
GridView gridView)
{
DisposeRegistrations(sourceRegistrations, gridView);
DisposeRegistrations(targetRegistrations, gridView);
}
private static void DisposeRegistrations(
Dictionary<GridView, List<GridDragGrid>> registrations,
GridView gridView)
{
foreach (KeyValuePair<GridView, List<GridDragGrid>> entry in registrations.ToList())
{
bool removeKey = ReferenceEquals(entry.Key, gridView);
foreach (GridDragGrid registration in entry.Value.ToList())
{
if (removeKey || registration == null || registration._disposed || registration.References(gridView))
{
if (registration != null)
registration.Dispose();
entry.Value.Remove(registration);
}
}
if (removeKey || entry.Value.Count == 0)
registrations.Remove(entry.Key);
}
}
internal bool References(GridView gridView)
{
return gridView != null &&
(ReferenceEquals(_sourceGridView, gridView) ||
ReferenceEquals(_targetGridView, gridView));
}
/// <summary>
/// 是否正在拖拽
/// </summary>
@@ -119,6 +157,97 @@ namespace Lskj.Control.Model
this._targetGridView.GridControl.DragEnter += new System.Windows.Forms.DragEventHandler(gridControl_DragEnter);
this._targetGridView.GridControl.DragDrop += new System.Windows.Forms.DragEventHandler(gridControl_DragDrop);
this._targetGridView.GridControl.DragLeave += new EventHandler(gridControl_DragLeave);
this._sourceGridView.Disposed += OnGridViewDisposed;
if (!ReferenceEquals(this._sourceGridView, this._targetGridView))
{
this._targetGridView.Disposed += OnGridViewDisposed;
}
}
private void OnGridViewDisposed(object sender, EventArgs e)
{
Dispose();
}
public void Dispose()
{
if (_disposed)
{
return;
}
_disposed = true;
GridView sourceGridView = _sourceGridView;
GridView targetGridView = _targetGridView;
if (sourceGridView != null)
{
sourceGridView.MouseDown -= sourceGridView_MouseDown;
sourceGridView.MouseMove -= sourceGridView_MouseMove;
sourceGridView.MouseUp -= sourceGridView_MouseUp;
sourceGridView.RowClick -= OnRowClick;
sourceGridView.Disposed -= OnGridViewDisposed;
}
if (targetGridView != null)
{
if (targetGridView.GridControl != null)
{
targetGridView.GridControl.DragOver -= gridControl_DragOver;
targetGridView.GridControl.DragEnter -= gridControl_DragEnter;
targetGridView.GridControl.DragDrop -= gridControl_DragDrop;
targetGridView.GridControl.DragLeave -= gridControl_DragLeave;
}
if (!ReferenceEquals(sourceGridView, targetGridView))
{
targetGridView.Disposed -= OnGridViewDisposed;
}
}
RemoveRegistration(
StaticControl.GridViewDragGridDic,
sourceGridView,
this);
RemoveRegistration(
StaticControl.TargetViewDragGridDic,
targetGridView,
this);
if (ReferenceEquals(StaticControl.SourceDragGridView, sourceGridView))
{
StaticControl.SourceDragGridView = null;
}
OnDragComplete = null;
DragHander.Clear();
_hitInfo = null;
_sourceGridView = null;
_targetGridView = null;
}
private static void RemoveRegistration<TKey>(
Dictionary<TKey, List<GridDragGrid>> registrations,
TKey key,
GridDragGrid registration)
where TKey : class
{
if (key == null)
{
return;
}
List<GridDragGrid> registrationsForView;
if (!registrations.TryGetValue(key, out registrationsForView))
{
return;
}
registrationsForView.Remove(registration);
if (registrationsForView.Count == 0)
{
registrations.Remove(key);
}
}
/// <summary>
/// 点击时候判断位置
+42 -2
View File
@@ -24,8 +24,9 @@ namespace Lskj.Control.Model
/// <summary>
/// 表格拖拽到树结构
/// </summary>
public class GridDragTree
public class GridDragTree : IDisposable
{
private bool _disposed;
/// <summary>
/// 拖动位置
/// </summary>
@@ -59,8 +60,47 @@ namespace Lskj.Control.Model
this._treeView.AllowDrop = true;
this._treeView.DragOver += new DragEventHandler(treeView_DragOver);
this._treeView.DragDrop += new DragEventHandler(treeView_DragDrop);
if (this._gridView.GridControl != null)
{
this._gridView.GridControl.Disposed += OnOwnerDisposed;
}
this._treeView.Disposed += OnOwnerDisposed;
}
private void OnOwnerDisposed(object sender, EventArgs e)
{
Dispose();
}
/// <summary>
/// 模块关闭时解除源表格和目标树的拖拽事件。
/// </summary>
public void Dispose()
{
if (_disposed) return;
_disposed = true;
if (_gridView != null)
{
_gridView.MouseDown -= gridView_MouseDown;
_gridView.MouseMove -= gridView_MouseMove;
if (_gridView.GridControl != null)
{
_gridView.GridControl.Disposed -= OnOwnerDisposed;
}
}
if (_treeView != null)
{
_treeView.DragOver -= treeView_DragOver;
_treeView.DragDrop -= treeView_DragDrop;
_treeView.Disposed -= OnOwnerDisposed;
}
OnDragComplete = null;
_hitInfo = null;
_gridView = null;
_treeView = null;
}
/// <summary>
/// <para>说明:获取表格选中行数据</para>
+11 -13
View File
@@ -913,6 +913,14 @@ namespace Lskj.Control.Model
/// <param name="key">The key.</param>
/// <returns>DataTable.</returns>
public static DataTable GetCustomColumnByDatabase(this GridView gridView, string key)
{
return GetCustomColumnByDatabase(key);
}
/// <summary>
/// 获取个性配置列数据,不依赖任何界面控件。
/// </summary>
public static DataTable GetCustomColumnByDatabase(string key)
{
try
{
@@ -950,22 +958,11 @@ namespace Lskj.Control.Model
{
try
{
if (!BaseImpl.HasExistsColumn(ResourceKeys.SettingTableName, ""))
if (!BaseImpl.HasExistsColumn(ResourceKeys.SettingTableName, "IfFixColumn"))
{
BaseImpl.ExecSqlValue("alter table " + ResourceKeys.SettingTableName + " add IfFixColumn bit");
}
// 读取普通用户读取个人配置,没有则读取管理员配置,管理未配置则读取系统默认.逐级上报读取方式.
string sqlValue = string.Format("select * from {0} where formKey='{1}' and operatorid='{2}' order by orderid ", ResourceKeys.SettingTableName, key, ERPInfo.Instance.UserId);
DataTable table = BaseImpl.GetDataTableResult(sqlValue);
//if (table == null || table.Rows.Count == 0)
//{
// sqlValue = string.Format("select * from {0} where formKey='{1}' and operatorid='{2}'", ResourceKeys.SettingTableName, key, ERPInfo.Instance.UserManager);
// table = BaseImpl.GetDataTableResult(sqlValue);
//}
return table;
return GetCustomColumnByDatabase(key);
}
catch (Exception)
{
@@ -1110,6 +1107,7 @@ namespace Lskj.Control.Model
gridControl.gridViewRightMenu = rightMenu;
rightMenu.InitRightMenus(gridControl, table, model, control, menu);
rightMenu.SetRightCallback(handler);
gridControl.SetRightMenuButtonTable(table);
}
/// <summary>
/// <para>说明:设置表格右键菜单</para>
@@ -36,54 +36,62 @@ namespace Lskj.Control.Model.MenuStrip
}
protected override void MenuStripOpening(object sender, System.ComponentModel.CancelEventArgs e)
{
int[] mSelectRows = this._gridView.GetSelectedRows();
if (mSelectRows == null || mSelectRows.Length == 0) return;
int[] mSelectRows = this._gridView.GetSelectedRows() ?? new int[0];
DataRow mSelectRow = this._gridView.GetDataRow(mSelectRows[0]);
DataRow[] dataRows = new DataRow[mSelectRows.Length];
for (int i = 0; i < mSelectRows.Length; i++)
{
dataRows[i] = this._gridView.GetDataRow(mSelectRows[i]);
}
ContextMenuStrip cmsMenu = (ContextMenuStrip)sender;
cmsMenu.Items.Clear();
cmsMenu.Items.AddRange(this.RightMenuItems.ToArray());
// 创建QQ、浏览器右键菜单
List<ToolStripMenuItem> mQQArray = new List<ToolStripMenuItem>();
List<ToolStripMenuItem> mBrowerArray = new List<ToolStripMenuItem>();
foreach (GridColumn column in this._gridView.Columns)
if (mSelectRows.Length > 0)
{
if (!mSelectRow.Table.Columns.Contains(column.Name))
continue;
string rowValue = mSelectRow[column.Name] + "";
if (!string.IsNullOrWhiteSpace(rowValue))
DataRow mSelectRow = this._gridView.GetDataRow(mSelectRows[0]);
// 创建QQ、浏览器右键菜单
List<ToolStripMenuItem> mQQArray = new List<ToolStripMenuItem>();
List<ToolStripMenuItem> mBrowerArray = new List<ToolStripMenuItem>();
foreach (GridColumn column in this._gridView.Columns)
{
GridColumnModel model = column.Tag as GridColumnModel;
if (model == null) continue;
if (model.FieldType == ControlType.LabQQ)
if (!mSelectRow.Table.Columns.Contains(column.Name))
continue;
string rowValue = mSelectRow[column.Name] + "";
if (!string.IsNullOrWhiteSpace(rowValue))
{
ToolStripMenuItem item = new ToolStripMenuItem("(" + column.Caption + ")" + rowValue, Resources.qq);
item.Tag = mSelectRow[column.Name] + "";
item.Click += new EventHandler(QQItemClick);
mQQArray.Add(item);
}
GridColumnModel model = column.Tag as GridColumnModel;
if (model == null) continue;
if (model.FieldType == ControlType.LabWWW ||
rowValue.StartsWith("www.") ||
rowValue.StartsWith("http://") ||
rowValue.StartsWith("https://") ||
rowValue.StartsWith("ftp://") ||
rowValue.StartsWith("file://"))
{
ToolStripMenuItem item = new ToolStripMenuItem("(" + column.Caption + ")" + rowValue, Resources.qq);
item.Tag = mSelectRow[column.Name] + "";
item.Click += new EventHandler(BrowerItemClick);
mBrowerArray.Add(item);
if (model.FieldType == ControlType.LabQQ)
{
ToolStripMenuItem item = new ToolStripMenuItem("(" + column.Caption + ")" + rowValue, Resources.qq);
item.Tag = mSelectRow[column.Name] + "";
item.Click += new EventHandler(QQItemClick);
mQQArray.Add(item);
}
if (model.FieldType == ControlType.LabWWW ||
rowValue.StartsWith("www.") ||
rowValue.StartsWith("http://") ||
rowValue.StartsWith("https://") ||
rowValue.StartsWith("ftp://") ||
rowValue.StartsWith("file://"))
{
ToolStripMenuItem item = new ToolStripMenuItem("(" + column.Caption + ")" + rowValue, Resources.qq);
item.Tag = mSelectRow[column.Name] + "";
item.Click += new EventHandler(BrowerItemClick);
mBrowerArray.Add(item);
}
}
}
}
cmsMenu.Items.AddRange(mQQArray.ToArray());
cmsMenu.Items.AddRange(mBrowerArray.ToArray());
cmsMenu.Items.AddRange(mQQArray.ToArray());
cmsMenu.Items.AddRange(mBrowerArray.ToArray());
}
// 判断右键菜单是否可用
foreach (ToolStripItem cms in cmsMenu.Items)
@@ -95,34 +103,84 @@ namespace Lskj.Control.Model.MenuStrip
{
try
{
string cond = string.Empty;
if (this._control != null)
cond = _control.ReplaceParentControlValue(model.MenuCond);
cond = ReplaceHelper.ReplaceRowParam(mSelectRow, model.MenuCond);
if (this._gridView != null)
bool condResult = false;
StringBuilder condBuilder = new StringBuilder();
StringBuilder sqlCondBuilder = new StringBuilder();
GridCell[] cells = this._gridView.GetSelectedCells();
DataRow focusedRow = this.BaseGridView.GetFocusedDataRow();
DataRow[] conditionRows = dataRows;
if (model.AllowNullExec && conditionRows.Length == 0)
{
GridCell[] cells = this._gridView.GetSelectedCells();
if (cells != null && cells.Length > 0 && cond.Contains("{COLUMN_"))
conditionRows = new DataRow[] { new DataTable().NewRow() };
}
if (conditionRows.Length == 0) continue;
foreach (DataRow selectRow in conditionRows)
{
string cond = ReplaceHelper.ReplaceUserInfo(model.MenuCond);
cond = RaiseBeforeHandleParamsCallback(model.ParamList, conditionRows, model.MenuCond, selectRow, cond);
if (this._control != null)
{
GridCell cell = cells[0];
DataRow focusedRow = this.BaseGridView.GetFocusedDataRow();
string colValue = focusedRow == null || !focusedRow.Table.Columns.Contains(cell.Column.Name) ? "" : focusedRow[cell.Column.Name] + "";
cond = cond.ReplaceColumnParam(cell.Column.Name, cell.Column.Caption, colValue);
cond = _control.ReplaceParentControlValue(cond);
}
//cond = ReplaceHelper.ReplaceRowParam(selectRow, cond);
cond = ReplaceHelper.ReplaceRowParamEmptyWrapQuote(selectRow, cond);
if (model.Mergeexec && cond.StartsWith("@"))
{
//替换[],替换的是多选行中的数据
cond = ReplaceHelper.ReplaceRowParam(conditionRows, cond.Replace("[", "{").Replace("]", "}"), "", "");
}
if (this._gridView != null)
{
if (cells != null && cells.Length > 0 && cond.Contains("{COLUMN_"))
{
GridCell cell = cells[0];
string colValue = focusedRow == null || !focusedRow.Table.Columns.Contains(cell.Column.Name) ? "" : focusedRow[cell.Column.Name] + "";
cond = cond.ReplaceColumnParam(cell.Column.Name, cell.Column.Caption, colValue);
}
}
if (ControlObj != null)
{
cond = ControlObj.ReplaceParentControlValue(cond);
}
if (cond.StartsWith("@"))
{
sqlCondBuilder.Append($"({cond.TrimStart('@')}) = '1' and ");
}
else
{
condBuilder.Append($"({cond}) and ");
}
}
if (ControlObj != null)
cond = ControlObj.ReplaceParentControlValue(cond);
string condStr = model.MenuCond;
if (!string.IsNullOrWhiteSpace(sqlCondBuilder.ToString()) || !string.IsNullOrWhiteSpace(condBuilder.ToString()))
{
if (model.MenuCond.StartsWith("@"))
{
condStr = $"@if({sqlCondBuilder.ToString().TrimEnd().TrimEnd('d', 'n', 'a')}) begin select '1' end else begin select '0' end";
}
else
{
condStr = condBuilder.ToString().TrimEnd().TrimEnd('d', 'n', 'a');
}
}
condResult = ValidateCond(condStr, null);
//cms.Enabled = ReplaceHelper.EvalCond(cond);
if (model.ForbiddenDisplay)
{
cms.Visible = ValidateCond(cond, null); ;
cms.Visible = condResult;
}
cms.Enabled = ValidateCond(cond, null); ;
cms.Enabled = condResult;
}
catch (Exception ex)
{
string Message = ErrorMessage.PromptErrorMessage(ex);
MessageUtil.Show(ResourceKeys.SetRightMenuCondFault + "\r\n" + Message);
e.Cancel = true;
break;
}
}
@@ -50,6 +50,7 @@ namespace Lskj.Control.Model
/// 最初账套版本
/// </summary>
public DataRow AccountItem;
public DataTable MenuTable;
public DynamicModel Model;
public MyControl ControlObj;
@@ -267,7 +268,7 @@ namespace Lskj.Control.Model
public bool ValidateCond(string cond, DataRow dataRow)
{
bool result = false;
cond = ReplaceHelper.ReplaceRowParam(dataRow, cond);
cond = ReplaceHelper.ReplaceRowParamEmptyWrapQuote(dataRow, cond);
if (cond.StartsWith("@") || cond.StartsWith("!"))
{
result = "1".Equals(BaseImpl.GetDefaultValue(cond));
@@ -137,6 +137,7 @@ namespace Lskj.Control.Model
{
conditionRows = new DataRow[] { new DataTable().NewRow() };
}
if (conditionRows.Length == 0) continue;
foreach (DataRow selectRow in conditionRows)
{
@@ -147,8 +148,8 @@ namespace Lskj.Control.Model
{
cond = _control.ReplaceParentControlValue(cond);
}
cond = ReplaceHelper.ReplaceRowParam(selectRow, cond);
//cond = ReplaceHelper.ReplaceRowParam(selectRow, cond);
cond = ReplaceHelper.ReplaceRowParamEmptyWrapQuote(selectRow, cond);
if (model.Mergeexec&& cond.StartsWith("@"))
{
//替换[],替换的是多选行中的数据
@@ -147,6 +147,7 @@ namespace Lskj.Control.Model.MenuStrip
{
conditionRows = new DataRow[] { new DataTable().NewRow() };
}
if (conditionRows.Length == 0) continue;
foreach (DataRow selectRow in conditionRows)
{
@@ -156,8 +157,8 @@ namespace Lskj.Control.Model.MenuStrip
cond = RaiseBeforeHandleParamsCallback(model.ParamList, conditionRows, model.MenuCond, selectRow, cond);
if (this._control != null)
cond = _control.ReplaceParentControlValue(cond);
cond = ReplaceHelper.ReplaceRowParam(selectRow, cond);
//cond = ReplaceHelper.ReplaceRowParam(selectRow, cond);
cond = ReplaceHelper.ReplaceRowParamEmptyWrapQuote(selectRow, cond);
if (model.Mergeexec && cond.StartsWith("@"))
{
//替换[],替换的是多选行中的数据
+354 -77
View File
@@ -32,8 +32,10 @@ namespace Lskj.Control.Model
/// <summary>
/// 查询控件、添加修改界面控件管理类
/// </summary>
public class MyControl
public class MyControl : IDisposable
{
private const long UserSearchCooldownTicks =
TimeSpan.TicksPerMillisecond * 350;
private string _searchSql;
private DataTable _controls;
private DataTable _schemes;
@@ -46,8 +48,12 @@ namespace Lskj.Control.Model
private GridControlEx _gridLeft;
private TreeViewEx _tvLeft;
private MyControl _leftSearch;
private DropDownButton _dropDown = new DropDownButton();
private PopupMenu _popupMenu = new PopupMenu();
private DropDownButton _dropDown;
private PopupMenu _popupMenu;
private bool mDisposed;
private bool mUserSearchInProgress;
private long mLastUserSearchCompletedTicks;
private int mAcceptedUserSearchCount;
/// <summary>
/// 计算字段
/// </summary>
@@ -112,6 +118,10 @@ namespace Lskj.Control.Model
/// </summary>
/// <value>The button object.</value>
public SimpleButton ButtonObj { get { return _button; } }
public int AcceptedUserSearchCount
{
get { return mAcceptedUserSearchCount; }
}
/// <summary>
/// 条件数据源刷新按钮
/// </summary>
@@ -133,6 +143,10 @@ namespace Lskj.Control.Model
public DataRow CurrentData;
public ModuleModel SystemModel;
/// <summary>
/// 外部已查询的MRP操作按钮数据;为空时保持原查询逻辑。
/// </summary>
public DataTable MrpClickMenus;
/// <summary>
/// 下拉框、搜索框控件对象
/// </summary>
public List<ControlModel> mControlList = new List<ControlModel>();
@@ -265,6 +279,12 @@ namespace Lskj.Control.Model
///特殊左侧表
/// </summary>
public GridControlEx SpecialLeftTable;
/// <summary>
///修改前的数据源
/// </summary>
public DataRow beforeData;
/// <summary>
/// 控件Panel对象
/// </summary>
@@ -893,10 +913,13 @@ namespace Lskj.Control.Model
return controlModel;
}));
}
Task<DataTable> rightDtGridRightMenusTask = cachesDic.AddTask(this, "RightDtGridRightMenus", new Task<DataTable>(() =>
if (MrpClickMenus == null)
{
return BaseModuleImpl.GetBaseGridRightMenus(dynamicModel.ModuleCode, ModuleType.MrpClickBtn);
}));
Task<DataTable> rightDtGridRightMenusTask = cachesDic.AddTask(this, "RightDtGridRightMenus", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRightMenus(dynamicModel.ModuleCode, ModuleType.MrpClickBtn);
}));
}
return true;
}));
}
@@ -1018,6 +1041,10 @@ namespace Lskj.Control.Model
// 创建模版搜索
if (_schemes != null && ModuleId > 0 && _schemes.Rows.Count > 0)
{
if (_popupMenu == null)
{
_popupMenu = new PopupMenu();
}
_dropDown = new DropDownButton();
_dropDown.DropDownArrowStyle = DropDownArrowStyle.Show;
_dropDown.DropDownControl = this._popupMenu;
@@ -1036,7 +1063,17 @@ namespace Lskj.Control.Model
}
if (dynamicModel != null && !string.IsNullOrEmpty(dynamicModel.ModuleCode))
{
if (!dataCaches.GetValue(parent, "SysModel", out ModuleModel moduleModel))
ModuleModel moduleModel = null;
if (SystemModel != null && string.Equals(SystemModel.ModeCode, dynamicModel.ModuleCode, StringComparison.OrdinalIgnoreCase))
{
moduleModel = SystemModel;
}
if (moduleModel == null && dataCaches.GetValue(parent, "SysModel", out ModuleModel cacheModuleModel) &&
cacheModuleModel != null && string.Equals(cacheModuleModel.ModeCode, dynamicModel.ModuleCode, StringComparison.OrdinalIgnoreCase))
{
moduleModel = cacheModuleModel;
}
if (moduleModel == null)
{
moduleModel = new ModuleModel(MainImpl.GetSystemdllTab(dynamicModel.ModuleCode));
}
@@ -1054,13 +1091,14 @@ namespace Lskj.Control.Model
btnCondSearch.Click += new EventHandler(OnBtnCondSearchClick);
}
}
DataTable rightDt = null;
if (dynamicModel != null)
DataTable rightDt = MrpClickMenus;
if (rightDt == null && dynamicModel != null)
{
if (!dataCaches.GetValue(parent, "RightDtGridRightMenus", out rightDt))
if (!dataCaches.GetValue(this, "RightDtGridRightMenus", out rightDt))
{
rightDt = BaseModuleImpl.GetBaseGridRightMenus(dynamicModel.ModuleCode, ModuleType.MrpClickBtn);
}
MrpClickMenus = rightDt;
}
if (rightDt != null && rightDt.Rows.Count > 0)
{
@@ -1198,6 +1236,10 @@ namespace Lskj.Control.Model
// 创建模版搜索
if (_schemes != null && ModuleId > 0 && _schemes.Rows.Count > 0)
{
if (_popupMenu == null)
{
_popupMenu = new PopupMenu();
}
_dropDown = new DropDownButton();
_dropDown.DropDownArrowStyle = DropDownArrowStyle.Show;
_dropDown.DropDownControl = this._popupMenu;
@@ -1214,13 +1256,14 @@ namespace Lskj.Control.Model
_popupMenu.Name = "pm_search";
CreateSearchScheme();
}
DataTable rightDt = null;
if (dynamicModel != null)
DataTable rightDt = MrpClickMenus;
if (rightDt == null && dynamicModel != null)
{
if (!dynamicModel.DataCaches.GetValue(parent, "RightDtGridRightMenus", out rightDt))
if (!dynamicModel.DataCaches.GetValue(this, "RightDtGridRightMenus", out rightDt))
{
rightDt = BaseModuleImpl.GetBaseGridRightMenus(dynamicModel.ModuleCode, ModuleType.MrpClickBtn);
}
MrpClickMenus = rightDt;
}
if (rightDt != null && rightDt.Rows.Count > 0)
{
@@ -1289,10 +1332,13 @@ namespace Lskj.Control.Model
return controlModel;
}));
}
Task<DataTable> rightDtGridRightMenusTask = cachesDic.AddTask(this, "RightDtGridRightMenus", new Task<DataTable>(() =>
if (MrpClickMenus == null)
{
return BaseModuleImpl.GetBaseGridRightMenus(dynamicModel.ModuleCode, ModuleType.MrpClickBtn);
}));
Task<DataTable> rightDtGridRightMenusTask = cachesDic.AddTask(this, "RightDtGridRightMenus", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRightMenus(dynamicModel.ModuleCode, ModuleType.MrpClickBtn);
}));
}
return true;
}));
}
@@ -1730,8 +1776,14 @@ namespace Lskj.Control.Model
WaitForm.HideForm();
mControlSourceDic.Clear();
if (this.OnDataSourceBindCallBack != null) this.OnDataSourceBindCallBack(this, null);
this.mTimer.Stop();
this.mTimer.Dispose();
Timer timer = this.mTimer;
this.mTimer = null;
if (timer != null)
{
timer.Tick -= mTimerTick;
timer.Stop();
timer.Dispose();
}
}
}
}
@@ -2043,8 +2095,6 @@ namespace Lskj.Control.Model
case ControlType.LabDate:
case ControlType.LabDateTime:
case ControlType.LabDateTimeShort:
case ControlType.LabTime:
case ControlType.LabShortTime:
// 日期控件
LabelDateEdit dateEdit = ctr as LabelDateEdit;
if (string.IsNullOrWhiteSpace(dateEdit.FormatType))
@@ -2057,6 +2107,12 @@ namespace Lskj.Control.Model
}
//value = dateEdit.TextEdit.EditValue == null ? dateEdit.EditText : dateEdit.TextEdit.EditValue.ToString();
break;
case ControlType.LabTime:
case ControlType.LabShortTime:
// 时间控件只返回时分秒部分,不附带日期。
LabelTimeEdit timeEdit = ctr as LabelTimeEdit;
value = timeEdit == null ? string.Empty : timeEdit.EditText;
break;
case ControlType.LabDateHalfDay:
// 日期半天控件
LabelDateHalfDayEdit dateHalfDayEdit = ctr as LabelDateHalfDayEdit;
@@ -3048,6 +3104,8 @@ namespace Lskj.Control.Model
}
else
{
// 修改记录
foreach (ControlModel model in this.ControlModels)
{
@@ -3064,6 +3122,16 @@ namespace Lskj.Control.Model
if (userControl != null)
{
string fieldValue = this.GetControlValue(model);
if (beforeData != null &&
beforeData.Table != null &&
beforeData.Table.Columns.Contains(model.FieldName) &&
AuditChangeLog.IsSameValue(beforeData[model.FieldName] + "", fieldValue))
{
continue;
}
if (fieldValue == "****") continue;
if (model.FieldType == 7)
{
@@ -4373,6 +4441,8 @@ namespace Lskj.Control.Model
model.FieldType = 161;
model.IsRadio = true;
}
return model;
}
/// <summary>
@@ -4453,11 +4523,20 @@ namespace Lskj.Control.Model
Font mRowFont = new Font("Microsoft YaHei UI", 12);
switch (model.FieldType)
{
case ControlType.LabTime:
case ControlType.LabShortTime:
// 时间控件使用 TimeEdit,避免 DateEdit 显示日期日历。
LabelTimeEdit timeEdit = new LabelTimeEdit();
timeEdit.TextEdit.KeyDown += new KeyEventHandler(OnTextEditKeyDown);
timeEdit.TextEdit.TextChanged += new EventHandler(OnTextEditTextChanged);
// 时间类型固定使用时分或时分秒,避免旧的日期格式配置覆盖为年月日。
timeEdit.TimeFormat(DateFormat.Format(model.FieldType));
if (!isLoadBorder) timeEdit.TextEdit.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
baseControl = timeEdit;
break;
case ControlType.LabDate:
case ControlType.LabDateTime:
case ControlType.LabDateTimeShort:
case ControlType.LabTime:
case ControlType.LabShortTime:
case ControlType.LabShortDate:
// 日期控件
LabelDateEdit dateEdit = new LabelDateEdit();
@@ -4727,7 +4806,11 @@ namespace Lskj.Control.Model
multiAutoEdit.ValueField = model.ValueMember;
multiAutoEdit.TextField = model.TextMember;
multiAutoEdit.ControlObj = this;
multiAutoEdit.CurrentOperColumnKey= Model.ModuleCode + "_" + model.FieldName;
if (Model != null)
{
multiAutoEdit.CurrentOperColumnKey = Model.ModuleCode + "_" + model.FieldName;
}
//multiAutoEdit.SetDataSource(dataSource);
multiAutoEdit.TextBoxProhibition = model.TextBoxProhibition;
multiAutoEdit.TextEdit.KeyDown += new KeyEventHandler(OnTextEditKeyDown);
@@ -6067,6 +6150,61 @@ namespace Lskj.Control.Model
}
}
private bool TryBeginUserSearch()
{
if (mDisposed || mUserSearchInProgress)
{
return false;
}
long now = DateTime.UtcNow.Ticks;
if (mLastUserSearchCompletedTicks > 0 &&
now - mLastUserSearchCompletedTicks < UserSearchCooldownTicks)
{
return false;
}
mUserSearchInProgress = true;
mAcceptedUserSearchCount++;
return true;
}
private void EndUserSearch()
{
mUserSearchInProgress = false;
mLastUserSearchCompletedTicks = DateTime.UtcNow.Ticks;
}
private bool ExecuteUserSearch(object sender, EventArgs e)
{
if (!TryBeginUserSearch())
{
return false;
}
try
{
SearchArgs args = new SearchArgs();
if (OnSearchBeforeCallBack != null)
{
OnSearchBeforeCallBack(sender, args);
}
if (args.Continue)
{
this.SearchGrid(false);
}
if (OnSearchAfterCallBack != null)
{
OnSearchAfterCallBack(sender, e);
}
return true;
}
finally
{
EndUserSearch();
}
}
/// <summary>
/// <para>说明:</para>
/// <para>创建人:龚宇超</para>
@@ -6091,18 +6229,8 @@ namespace Lskj.Control.Model
{
if (baseControl.Model.IsSearchControl)
{
// 搜索控件回车直接搜索
SearchArgs args = new SearchArgs();
// 查询之前
if (OnSearchBeforeCallBack != null)
OnSearchBeforeCallBack(sender, args);
if (args.Continue) this.SearchGrid(false);
// 查询之后
if (OnSearchAfterCallBack != null) OnSearchAfterCallBack(sender, e);
if (baseControl.Model.ScanAfterEmpty)
if (ExecuteUserSearch(sender, e) &&
baseControl.Model.ScanAfterEmpty)
{
baseControl.EditText = string.Empty;
}
@@ -6201,14 +6329,7 @@ namespace Lskj.Control.Model
{
if (baseControl.Model.IsSearchControl)
{
// 搜索控件回车直接搜索
SearchArgs args = new SearchArgs();
// 查询之前
if (OnSearchBeforeCallBack != null)
OnSearchBeforeCallBack(sender, args);
if (args.Continue) this.SearchGrid(false);
// 查询之后
if (OnSearchAfterCallBack != null) OnSearchAfterCallBack(sender, e);
ExecuteUserSearch(sender, e);
}
}
}
@@ -6225,45 +6346,57 @@ namespace Lskj.Control.Model
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
protected void OnSimpleButtonClick(object sender, EventArgs e)
{
if (!TryBeginUserSearch())
{
return;
}
try
{
if (Model != null)
try
{
bool allowBefore = ApiHelper.IsExecEventApi(Interface.Api.OperateEvent.BeforeSearchBtnClick, Model.ModuleCode, 0);
//查询前调用Api接口
if (allowBefore)
if (Model != null)
{
DataRow dataRow = this.GetAllControlValueRow();
ApiHelper apiHelper = new ApiHelper(Model.ModuleCode, 0, dataRow);
apiHelper.OnEvent(Interface.Api.OperateEvent.BeforeSearchBtnClick, Interface.Api.ActionType.None);
if (apiHelper.apiHandlerModels.Count > 0)
bool allowBefore = ApiHelper.IsExecEventApi(Interface.Api.OperateEvent.BeforeSearchBtnClick, Model.ModuleCode, 0);
//查询前调用Api接口
if (allowBefore)
{
Hashtable hashtable = apiHelper.apiHandlerModels[apiHelper.apiHandlerModels.Count - 1].resultPmsHashtables[0];
if (hashtable.ContainsKey("result"))
DataRow dataRow = this.GetAllControlValueRow();
ApiHelper apiHelper = new ApiHelper(Model.ModuleCode, 0, dataRow);
apiHelper.OnEvent(Interface.Api.OperateEvent.BeforeSearchBtnClick, Interface.Api.ActionType.None);
if (apiHelper.apiHandlerModels.Count > 0)
{
string jsonResult = hashtable["result"] + "";
DataTable dataTable = JsonConvert.DeserializeObject<DataTable>(jsonResult);
this._mainGridEx.SetGridViewDataSource(dataTable);
return;
Hashtable hashtable = apiHelper.apiHandlerModels[apiHelper.apiHandlerModels.Count - 1].resultPmsHashtables[0];
if (hashtable.ContainsKey("result"))
{
string jsonResult = hashtable["result"] + "";
DataTable dataTable = JsonConvert.DeserializeObject<DataTable>(jsonResult);
this._mainGridEx.SetGridViewDataSource(dataTable);
return;
}
}
}
}
}
catch (Exception ex)
{
MessageUtil.Show(ex.Message);
}
SearchArgs args = new SearchArgs();
// 查询之前
if (OnSearchBeforeCallBack != null)
OnSearchBeforeCallBack(sender, args);
if (args.Continue) this.SearchGrid(false);
// 查询之后
if (OnSearchAfterCallBack != null) OnSearchAfterCallBack(sender, e);
}
catch (Exception ex)
finally
{
MessageUtil.Show(ex.Message);
EndUserSearch();
}
SearchArgs args = new SearchArgs();
// 查询之前
if (OnSearchBeforeCallBack != null)
OnSearchBeforeCallBack(sender, args);
if (args.Continue) this.SearchGrid(false);
// 查询之后
if (OnSearchAfterCallBack != null) OnSearchAfterCallBack(sender, e);
}
@@ -6298,15 +6431,7 @@ namespace Lskj.Control.Model
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
protected void OnFixButtonClick(object sender, EventArgs e)
{
SearchArgs args = new SearchArgs();
// 查询之前
if (OnSearchBeforeCallBack != null)
OnSearchBeforeCallBack(sender, args);
if (args.Continue) this.SearchGrid(false);
// 查询之后
if (OnSearchAfterCallBack != null) OnSearchAfterCallBack(sender, e);
ExecuteUserSearch(sender, e);
}
/// <summary>
/// <para>说明:高级搜索按钮鼠标离开时</para>
@@ -6587,6 +6712,10 @@ namespace Lskj.Control.Model
LabelDateEdit dateEdit = controlObj as LabelDateEdit;
value = dateEdit.TextEdit.EditValue == null ? dateEdit.EditText : dateEdit.TextEdit.DateTime.ToString("yyyy-MM-dd");
}
else if (controlObj is LabelTimeEdit)
{
value = ((LabelTimeEdit)controlObj).EditText;
}
else if (controlObj is LabelCheckEdit)
{
LabelCheckEdit checkEdit = controlObj as LabelCheckEdit;
@@ -6692,6 +6821,154 @@ namespace Lskj.Control.Model
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposing || mDisposed)
{
return;
}
mDisposed = true;
mUserSearchInProgress = false;
Timer timer = mTimer;
mTimer = null;
if (timer != null)
{
try
{
timer.Tick -= mTimerTick;
timer.Stop();
timer.Dispose();
}
catch
{
// A completed delayed-load timer may already be disposed.
}
}
if (_button != null)
{
_button.Click -= OnSimpleButtonClick;
_button.Tag = null;
}
if (_fixButton != null)
{
_fixButton.Click -= OnFixButtonClick;
}
if (_refreshButton != null)
{
_refreshButton.Click -= OnRefreshButtonClick;
_refreshButton.Tag = null;
}
if (btnCondSearch != null)
{
btnCondSearch.Click -= OnBtnCondSearchClick;
btnCondSearch.Tag = null;
}
if (_dropDown != null)
{
_dropDown.Leave -= OnDropDownLeave;
_dropDown.DropDownControl = null;
}
foreach (SimpleButton button in mrpBtnDic.Values.Distinct())
{
if (button != null)
{
button.Click -= OnModuleClick;
button.Tag = null;
}
}
BarManager searchSchemeManager =
_popupMenu == null ? null : _popupMenu.Manager;
if (_popupMenu != null)
{
_popupMenu.Manager = null;
_popupMenu.ItemLinks.Clear();
_popupMenu.Dispose();
}
if (searchSchemeManager != null)
{
searchSchemeManager.Dispose();
}
if (_mainGridEx != null &&
ReferenceEquals(_mainGridEx.ParentControl, this))
{
_mainGridEx.ParentControl = null;
}
try
{
if (Model != null && Model.DataCaches != null)
{
Model.DataCaches.RemoveCache(this);
}
}
catch
{
// Cache cleanup must not interrupt module disposal.
}
preSearchVerification = null;
OnSearchBeforeCallBack = null;
OnSearchAfterCallBack = null;
OnAddCallBack = null;
ClearDetails = null;
OnLastQueryTriggered = null;
OnSourceRefrshCallBack = null;
OnDataSourceBindCallBack = null;
OnDataFileRefrshCallBack = null;
OpenDocumentSource = null;
_calcControls.Clear();
_models.Clear();
mControlList.Clear();
mExtendedReturnSearchControls.Clear();
mExtendedReturnPendingChanges.Clear();
mControlSourceDic.Clear();
mCacheDictionary.Clear();
DetailSelection.Clear();
changeLabelAutoGridLooks.Clear();
mrpBtnDic.Clear();
ModuleResultDic.Clear();
ParaContrlsDic.Clear();
_controls = null;
_schemes = null;
_fixField = null;
_fixKey = null;
_button = null;
_fixButton = null;
_refreshButton = null;
_dropDown = null;
_popupMenu = null;
btnCondSearch = null;
_gridControl = null;
_mainGridEx = null;
_gridLeft = null;
_tvLeft = null;
_leftSearch = null;
_parentPanel = null;
CurrentData = null;
SystemModel = null;
SaveCondTab = null;
mrpDyncModel = null;
Model = null;
popUpDyncModel = null;
rightItemLinks = null;
SpecialLeftTable = null;
beforeData = null;
OtherParams = null;
}
}
}
@@ -7,11 +7,94 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WinFormsControl = System.Windows.Forms.Control;
namespace Lskj.Control.Model
{
public static class StaticBandedControl
{
public static void ReleaseModuleReferences(WinFormsControl moduleRoot, XtraTabPage modulePage, string moduleCode)
{
try
{
List<BandedGridView> bandedViews = CollectBandedGridViews(moduleRoot);
List<GridView> targetViews = CollectTargetGridViews(moduleRoot);
foreach (BandedGridView view in bandedViews)
BandedGridDragGrid.DisposeRegistrations(
BandedGridViewDragGridDic,
BandedTargetViewDragGridDic,
view,
null);
foreach (GridView view in targetViews)
BandedGridDragGrid.DisposeRegistrations(
BandedGridViewDragGridDic,
BandedTargetViewDragGridDic,
null,
view);
if (SourceDragBandedGridView != null &&
(bandedViews.Contains(SourceDragBandedGridView) ||
(SourceDragBandedGridView.GridControl != null && SourceDragBandedGridView.GridControl.IsDisposed)))
SourceDragBandedGridView = null;
RemoveConditionPanels(moduleCode);
while (modulePage != null && DogVerifyModuleForms.Remove(modulePage))
{
}
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine("释放旧 Banded 模块引用失败:" + exception);
}
}
private static List<BandedGridView> CollectBandedGridViews(WinFormsControl root)
{
List<BandedGridView> result = new List<BandedGridView>();
if (root == null)
return result;
foreach (WinFormsControl control in EnumerateControls(root))
{
DevExpress.XtraGrid.GridControl grid = control as DevExpress.XtraGrid.GridControl;
BandedGridView view = grid == null ? null : grid.MainView as BandedGridView;
if (view != null && !result.Contains(view))
result.Add(view);
}
return result;
}
private static List<GridView> CollectTargetGridViews(WinFormsControl root)
{
List<GridView> result = new List<GridView>();
if (root == null)
return result;
foreach (WinFormsControl control in EnumerateControls(root))
{
DevExpress.XtraGrid.GridControl grid = control as DevExpress.XtraGrid.GridControl;
GridView view = grid == null ? null : grid.MainView as GridView;
if (view != null && !result.Contains(view))
result.Add(view);
}
return result;
}
private static IEnumerable<WinFormsControl> EnumerateControls(WinFormsControl root)
{
yield return root;
foreach (WinFormsControl child in root.Controls)
foreach (WinFormsControl nested in EnumerateControls(child))
yield return nested;
}
private static void RemoveConditionPanels(string moduleCode)
{
foreach (string key in ConditionsPanelDic.Keys.ToList())
{
ModuleConditionsPanelEx panel;
if (string.Equals(key, moduleCode, StringComparison.OrdinalIgnoreCase) ||
!ConditionsPanelDic.TryGetValue(key, out panel) || panel == null || panel.IsDisposed)
ConditionsPanelDic.Remove(key);
}
}
/// <summary>
/// 记录当前U盾权限窗口
/// </summary>
@@ -44,4 +127,4 @@ namespace Lskj.Control.Model
/// </summary>
public static FrmProgressBar frmProgressBar;
}
}
}
+199 -1
View File
@@ -3,17 +3,215 @@ using DevExpress.XtraTab;
using Lskj.Control.ZKFinger;
using Lskj.Util;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Lskj.Model;
using System.Reflection;
using WinFormsControl = System.Windows.Forms.Control;
namespace Lskj.Control.Model
{
public static class StaticControl
{
/// <summary>
/// Releases static references owned by a closed legacy module. Cleanup is
/// best-effort so it cannot change the module close result.
/// </summary>
public static void ReleaseModuleReferences(WinFormsControl moduleRoot, XtraTabPage modulePage, string moduleCode)
{
List<GridView> gridViews = new List<GridView>();
try
{
gridViews = CollectGridViews(moduleRoot);
}
catch (Exception exception)
{
TraceCleanupFailure("收集表格引用", exception);
}
try
{
foreach (GridView gridView in gridViews)
{
try
{
RemoveGridReferences(gridView);
}
catch (Exception exception)
{
TraceCleanupFailure("释放表格拖拽引用", exception);
}
}
TryCleanup(() => RemoveConditionPanels(moduleCode), "释放条件面板引用");
TryCleanup(() => RemoveProtectedReferences(moduleRoot, modulePage), "释放权限保护引用");
TryCleanup(() => ClearRightMenuReferences(moduleRoot, gridViews), "释放右键菜单引用");
TryCleanup(
() => StaticBandedControl.ReleaseModuleReferences(moduleRoot, modulePage, moduleCode),
"释放带状表格引用");
}
finally
{
// DynamicModel caches retain completed tasks, result tables and
// their closures. Always release them after other references.
TryCleanup(() => ClearDataCaches(moduleRoot), "释放动态数据缓存");
}
}
private static void TryCleanup(Action cleanup, string operation)
{
try
{
cleanup();
}
catch (Exception exception)
{
TraceCleanupFailure(operation, exception);
}
}
private static void TraceCleanupFailure(string operation, Exception exception)
{
Debug.WriteLine("释放旧模块引用失败[" + operation + "]" + exception);
}
private static List<GridView> CollectGridViews(WinFormsControl root)
{
List<GridView> result = new List<GridView>();
if (root == null)
return result;
foreach (WinFormsControl control in EnumerateControls(root))
{
DevExpress.XtraGrid.GridControl grid = control as DevExpress.XtraGrid.GridControl;
GridView view = grid == null ? null : grid.MainView as GridView;
if (view != null && !result.Contains(view))
result.Add(view);
}
return result;
}
private static IEnumerable<WinFormsControl> EnumerateControls(WinFormsControl root)
{
yield return root;
foreach (WinFormsControl child in root.Controls)
foreach (WinFormsControl nested in EnumerateControls(child))
yield return nested;
}
private static void RemoveGridReferences(GridView gridView)
{
GridDragGrid.DisposeRegistrations(GridViewDragGridDic, TargetViewDragGridDic, gridView);
if (ReferenceEquals(SourceDragGridView, gridView) ||
(SourceDragGridView != null && SourceDragGridView.GridControl != null && SourceDragGridView.GridControl.IsDisposed))
SourceDragGridView = null;
}
private static void RemoveConditionPanels(string moduleCode)
{
foreach (string key in ConditionsPanelDic.Keys.ToList())
{
ModuleConditionsPanelEx panel;
if (string.Equals(key, moduleCode, StringComparison.OrdinalIgnoreCase) ||
!ConditionsPanelDic.TryGetValue(key, out panel) || panel == null || panel.IsDisposed)
ConditionsPanelDic.Remove(key);
}
}
private static void RemoveProtectedReferences(WinFormsControl root, XtraTabPage page)
{
while (page != null && DogVerifyModuleForms.Remove(page))
{
}
foreach (XtraTabPage item in DogVerifyModuleForms.ToList())
if (item == null || item.IsDisposed || IsContained(root, item))
DogVerifyModuleForms.Remove(item);
foreach (IForm item in DogVerifyNoPageForms.ToList())
if (item == null || item.SubForm == null || item.SubForm.IsDisposed || IsContained(root, item.SubForm))
DogVerifyNoPageForms.Remove(item);
}
private static bool IsContained(WinFormsControl root, WinFormsControl value)
{
if (root == null || value == null)
return false;
if (ReferenceEquals(root, value))
return true;
foreach (WinFormsControl child in root.Controls)
if (IsContained(child, value))
return true;
return false;
}
private static void ClearRightMenuReferences(WinFormsControl root, List<GridView> gridViews)
{
if (_RightMenuGridView != null && (gridViews.Contains(_RightMenuGridView) ||
(_RightMenuGridView.GridControl != null && _RightMenuGridView.GridControl.IsDisposed)))
RightMenuGridView = null;
if (RightMenuMyControl != null && RightMenuMyControl.MainGridEx != null &&
(RightMenuMyControl.MainGridEx.IsDisposed || IsContained(root, RightMenuMyControl.MainGridEx)))
RightMenuMyControl = null;
if (BomUnionPage != null && (BomUnionPage.IsDisposed || IsContained(root, BomUnionPage)))
BomUnionPage = null;
if (AddParentGrid.Value != null && (AddParentGrid.Value.IsDisposed || IsContained(root, AddParentGrid.Value)))
AddParentGrid = new KeyValuePair<string, GridControlEx>();
}
private static void ClearDataCaches(WinFormsControl root)
{
if (root == null)
return;
// Clear the root first because child enumeration can fail while a
// DevExpress control is disposing its child collection.
ClearDynamicModels(root);
try
{
foreach (WinFormsControl control in EnumerateControls(root).Skip(1).ToList())
ClearDynamicModels(control);
}
catch (Exception exception)
{
TraceCleanupFailure("遍历动态数据缓存", exception);
}
}
private static void ClearDynamicModels(object instance)
{
if (instance == null)
return;
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
for (Type type = instance.GetType(); type != null; type = type.BaseType)
foreach (FieldInfo field in type.GetFields(flags | BindingFlags.DeclaredOnly))
try
{
ClearDynamicModel(field.GetValue(instance));
}
catch (Exception exception)
{
Debug.WriteLine("清理动态缓存字段失败:" + exception);
}
}
private static void ClearDynamicModel(object value)
{
DynamicModel model = value as DynamicModel;
if (model == null || model.DataCaches == null)
return;
Dictionary<object, Hashtable> caches = model.DataCaches;
foreach (Hashtable cache in caches.Values.OfType<Hashtable>().ToList())
{
foreach (IDisposable item in cache.Values.OfType<IDisposable>().ToList())
try { item.Dispose(); } catch { }
cache.Clear();
}
caches.Clear();
model.DataCaches = null;
}
/// <summary>
/// 记录当前U盾权限窗口
/// </summary>
@@ -84,4 +282,4 @@ namespace Lskj.Control.Model
}
}
}
+16 -3
View File
@@ -73,10 +73,23 @@ namespace Lskj.Control.Model
/// </summary>
public static void HideForm()
{
bool isSplashFormVisible = LoadForm.IsSplashFormVisible;
if (isSplashFormVisible)
SplashScreenManager manager = _loadForm;
if (manager == null)
return;
try
{
_loadForm.CloseWaitForm();
if (manager.IsSplashFormVisible)
{
manager.CloseWaitForm();
manager.WaitForSplashFormClose();
}
}
finally
{
manager.Dispose();
if (ReferenceEquals(_loadForm, manager))
_loadForm = null;
}
}
}
+7 -191
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -28,6 +32,7 @@
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.scc_container = new DevExpress.XtraEditors.SplitContainerControl();
this.pl_left = new DevExpress.XtraEditors.PanelControl();
this.pl_left_main = new System.Windows.Forms.Panel();
@@ -38,25 +43,8 @@
this.pl_left_top = new DevExpress.XtraEditors.PanelControl();
this.pl_right = new DevExpress.XtraEditors.PanelControl();
this.moduleGridDetailEx1 = new Lskj.Control.ModuleGridDetailEx();
this.excelControlEx1 = new Lskj.Control.ExcelControlEx();
this.repModelDetailEx = new Lskj.Control.ReplacementDetailEx();
this.MainBodyTab = new DevExpress.XtraTab.XtraTabControl();
this.barManager1 = new DevExpress.XtraBars.BarManager();
this.barDockControlTop = new DevExpress.XtraBars.BarDockControl();
this.barDockControlBottom = new DevExpress.XtraBars.BarDockControl();
this.barDockControlLeft = new DevExpress.XtraBars.BarDockControl();
this.barDockControlRight = new DevExpress.XtraBars.BarDockControl();
this.commonBar1 = new DevExpress.XtraSpreadsheet.UI.CommonBar();
this.spreadsheetCommandBarButtonItem1 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem();
this.spreadsheetCommandBarButtonItem2 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem();
this.spreadsheetCommandBarButtonItem3 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem();
this.spreadsheetCommandBarButtonItem4 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem();
this.spreadsheetCommandBarButtonItem5 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem();
this.spreadsheetCommandBarButtonItem6 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem();
this.spreadsheetCommandBarButtonItem7 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem();
this.spreadsheetCommandBarButtonItem8 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem();
this.spreadsheetCommandBarButtonItem9 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem();
this.spreadsheetBarController1 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetBarController();
((System.ComponentModel.ISupportInitialize)(this.scc_container)).BeginInit();
this.scc_container.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pl_left)).BeginInit();
@@ -68,8 +56,6 @@
((System.ComponentModel.ISupportInitialize)(this.pl_right)).BeginInit();
this.pl_right.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.MainBodyTab)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.barManager1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.spreadsheetBarController1)).BeginInit();
this.SuspendLayout();
//
// scc_container
@@ -172,7 +158,6 @@
//
this.pl_right.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
this.pl_right.Controls.Add(this.moduleGridDetailEx1);
this.pl_right.Controls.Add(this.excelControlEx1);
this.pl_right.Controls.Add(this.repModelDetailEx);
this.pl_right.Controls.Add(this.MainBodyTab);
this.pl_right.Dock = System.Windows.Forms.DockStyle.Fill;
@@ -190,20 +175,6 @@
this.moduleGridDetailEx1.TabIndex = 0;
this.moduleGridDetailEx1.VisibleDetailPanel = true;
//
// excelControlEx1
//
this.excelControlEx1.AddEnabled = true;
this.excelControlEx1.DeleteEnabled = true;
this.excelControlEx1.Dock = System.Windows.Forms.DockStyle.Fill;
this.excelControlEx1.Location = new System.Drawing.Point(0, 0);
this.excelControlEx1.Margin = new System.Windows.Forms.Padding(6);
this.excelControlEx1.Name = "excelControlEx1";
this.excelControlEx1.PrintEnabled = true;
this.excelControlEx1.SaveEnabled = true;
this.excelControlEx1.Size = new System.Drawing.Size(712, 610);
this.excelControlEx1.TabIndex = 1;
this.excelControlEx1.Visible = false;
//
// repModelDetailEx
//
this.repModelDetailEx.Dock = System.Windows.Forms.DockStyle.Fill;
@@ -224,147 +195,11 @@
this.MainBodyTab.TabIndex = 6;
this.MainBodyTab.Visible = false;
//
// barManager1
//
this.barManager1.DockControls.Add(this.barDockControlTop);
this.barManager1.DockControls.Add(this.barDockControlBottom);
this.barManager1.DockControls.Add(this.barDockControlLeft);
this.barManager1.DockControls.Add(this.barDockControlRight);
this.barManager1.Form = this;
this.barManager1.MaxItemId = 9;
//
// barDockControlTop
//
this.barDockControlTop.CausesValidation = false;
this.barDockControlTop.Dock = System.Windows.Forms.DockStyle.Top;
this.barDockControlTop.Location = new System.Drawing.Point(0, 0);
this.barDockControlTop.Size = new System.Drawing.Size(915, 0);
//
// barDockControlBottom
//
this.barDockControlBottom.CausesValidation = false;
this.barDockControlBottom.Dock = System.Windows.Forms.DockStyle.Bottom;
this.barDockControlBottom.Location = new System.Drawing.Point(0, 610);
this.barDockControlBottom.Size = new System.Drawing.Size(915, 0);
//
// barDockControlLeft
//
this.barDockControlLeft.CausesValidation = false;
this.barDockControlLeft.Dock = System.Windows.Forms.DockStyle.Left;
this.barDockControlLeft.Location = new System.Drawing.Point(0, 0);
this.barDockControlLeft.Size = new System.Drawing.Size(0, 610);
//
// barDockControlRight
//
this.barDockControlRight.CausesValidation = false;
this.barDockControlRight.Dock = System.Windows.Forms.DockStyle.Right;
this.barDockControlRight.Location = new System.Drawing.Point(915, 0);
this.barDockControlRight.Size = new System.Drawing.Size(0, 610);
//
// commonBar1
//
this.commonBar1.BarName = "";
this.commonBar1.Control = null;
this.commonBar1.DockCol = 0;
this.commonBar1.DockRow = 0;
this.commonBar1.FloatLocation = new System.Drawing.Point(339, 195);
this.commonBar1.FloatSize = new System.Drawing.Size(244, 31);
this.commonBar1.Offset = 44;
this.commonBar1.Text = "";
//
// spreadsheetCommandBarButtonItem1
//
this.spreadsheetCommandBarButtonItem1.Caption = "New";
this.spreadsheetCommandBarButtonItem1.CommandName = "FileNew";
this.spreadsheetCommandBarButtonItem1.Enabled = false;
this.spreadsheetCommandBarButtonItem1.Id = 8;
this.spreadsheetCommandBarButtonItem1.Name = "spreadsheetCommandBarButtonItem1";
//
// spreadsheetCommandBarButtonItem2
//
this.spreadsheetCommandBarButtonItem2.Caption = "Open";
this.spreadsheetCommandBarButtonItem2.CommandName = "FileOpen";
this.spreadsheetCommandBarButtonItem2.Enabled = false;
this.spreadsheetCommandBarButtonItem2.Id = 7;
this.spreadsheetCommandBarButtonItem2.Name = "spreadsheetCommandBarButtonItem2";
//
// spreadsheetCommandBarButtonItem3
//
this.spreadsheetCommandBarButtonItem3.Caption = "Save";
this.spreadsheetCommandBarButtonItem3.CommandName = "FileSave";
this.spreadsheetCommandBarButtonItem3.Enabled = false;
this.spreadsheetCommandBarButtonItem3.Id = 6;
this.spreadsheetCommandBarButtonItem3.Name = "spreadsheetCommandBarButtonItem3";
//
// spreadsheetCommandBarButtonItem4
//
this.spreadsheetCommandBarButtonItem4.Caption = "Save As";
this.spreadsheetCommandBarButtonItem4.CommandName = "FileSaveAs";
this.spreadsheetCommandBarButtonItem4.Enabled = false;
this.spreadsheetCommandBarButtonItem4.Id = 5;
this.spreadsheetCommandBarButtonItem4.Name = "spreadsheetCommandBarButtonItem4";
//
// spreadsheetCommandBarButtonItem5
//
this.spreadsheetCommandBarButtonItem5.Caption = "&Quick Print";
this.spreadsheetCommandBarButtonItem5.CommandName = "FileQuickPrint";
this.spreadsheetCommandBarButtonItem5.Enabled = false;
this.spreadsheetCommandBarButtonItem5.Id = 4;
this.spreadsheetCommandBarButtonItem5.Name = "spreadsheetCommandBarButtonItem5";
//
// spreadsheetCommandBarButtonItem6
//
this.spreadsheetCommandBarButtonItem6.Caption = "&Print";
this.spreadsheetCommandBarButtonItem6.CommandName = "FilePrint";
this.spreadsheetCommandBarButtonItem6.Enabled = false;
this.spreadsheetCommandBarButtonItem6.Id = 3;
this.spreadsheetCommandBarButtonItem6.Name = "spreadsheetCommandBarButtonItem6";
//
// spreadsheetCommandBarButtonItem7
//
this.spreadsheetCommandBarButtonItem7.Caption = "Print Pre&view";
this.spreadsheetCommandBarButtonItem7.CommandName = "FilePrintPreview";
this.spreadsheetCommandBarButtonItem7.Enabled = false;
this.spreadsheetCommandBarButtonItem7.Id = 2;
this.spreadsheetCommandBarButtonItem7.Name = "spreadsheetCommandBarButtonItem7";
//
// spreadsheetCommandBarButtonItem8
//
this.spreadsheetCommandBarButtonItem8.Caption = "Undo";
this.spreadsheetCommandBarButtonItem8.CommandName = "FileUndo";
this.spreadsheetCommandBarButtonItem8.Enabled = false;
this.spreadsheetCommandBarButtonItem8.Id = 1;
this.spreadsheetCommandBarButtonItem8.Name = "spreadsheetCommandBarButtonItem8";
//
// spreadsheetCommandBarButtonItem9
//
this.spreadsheetCommandBarButtonItem9.Caption = "Redo";
this.spreadsheetCommandBarButtonItem9.CommandName = "FileRedo";
this.spreadsheetCommandBarButtonItem9.Enabled = false;
this.spreadsheetCommandBarButtonItem9.Id = 0;
this.spreadsheetCommandBarButtonItem9.Name = "spreadsheetCommandBarButtonItem9";
//
// spreadsheetBarController1
//
this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem1);
this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem2);
this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem3);
this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem4);
this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem5);
this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem6);
this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem7);
this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem8);
this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem9);
//
// ModuleEx
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.BackColor = System.Drawing.SystemColors.Control;
this.Controls.Add(this.scc_container);
this.Controls.Add(this.barDockControlLeft);
this.Controls.Add(this.barDockControlRight);
this.Controls.Add(this.barDockControlBottom);
this.Controls.Add(this.barDockControlTop);
this.Name = "ModuleEx";
this.Size = new System.Drawing.Size(915, 610);
((System.ComponentModel.ISupportInitialize)(this.scc_container)).EndInit();
@@ -378,10 +213,7 @@
((System.ComponentModel.ISupportInitialize)(this.pl_right)).EndInit();
this.pl_right.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.MainBodyTab)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.barManager1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.spreadsheetBarController1)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
@@ -389,22 +221,6 @@
private DevExpress.XtraEditors.SplitContainerControl scc_container;
private DevExpress.XtraEditors.PanelControl pl_right;
private DevExpress.XtraBars.BarManager barManager1;
private DevExpress.XtraBars.BarDockControl barDockControlTop;
private DevExpress.XtraBars.BarDockControl barDockControlBottom;
private DevExpress.XtraBars.BarDockControl barDockControlLeft;
private DevExpress.XtraBars.BarDockControl barDockControlRight;
private DevExpress.XtraSpreadsheet.UI.CommonBar commonBar1;
private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem1;
private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem2;
private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem3;
private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem4;
private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem5;
private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem6;
private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem7;
private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem8;
private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem9;
private DevExpress.XtraSpreadsheet.UI.SpreadsheetBarController spreadsheetBarController1;
private DevExpress.XtraEditors.PanelControl pl_left;
private System.Windows.Forms.Panel pl_left_main;
private DevExpress.XtraEditors.PanelControl pl_gridandtree_container;
+219 -29
View File
@@ -62,6 +62,10 @@ namespace Lskj.Control
/// 左侧表格查询条件
/// </summary>
private MyControl _leftGridSearchObj;
private GridDragTree _gridDragTree;
private bool mModuleResourcesReleased;
private GridDragGrid _gridDragGrid;
private BandedGridDragGrid _bandedGridDragGrid;
public bool IsExcel { get { return Model is DynamicExcelModel; } }
/// <summary>
@@ -150,6 +154,179 @@ namespace Lskj.Control
public ModuleEx()
{
InitializeComponent();
this.Disposed += OnModuleExDisposed;
}
public void ReleaseResourcesForDispose()
{
if (mModuleResourcesReleased)
{
return;
}
mModuleResourcesReleased = true;
HashSet<ModuleGridDetailEx> details =
new HashSet<ModuleGridDetailEx>();
HashSet<ModuleGridEx> grids = new HashSet<ModuleGridEx>();
foreach (System.Windows.Forms.Control control in
EnumerateModuleControls(this))
{
ModuleGridDetailEx detail = control as ModuleGridDetailEx;
if (detail != null)
{
details.Add(detail);
}
ModuleGridEx grid = control as ModuleGridEx;
if (grid != null)
{
grids.Add(grid);
}
}
foreach (ModuleGridDetailEx detail in details)
{
detail.ReleaseResourcesForDispose();
}
foreach (ModuleGridEx grid in grids)
{
grid.SaveEvent -= SetDetailGridView;
grid.OnExportCallBack -= SetExportGridView;
grid.ReleaseResourcesForDispose();
}
MyControl leftSearch = _leftGridSearchObj;
_leftGridSearchObj = null;
if (leftSearch != null)
{
leftSearch.OnDataSourceBindCallBack -= OnLeftControlObjDataSourceBindCallBack;
leftSearch.Dispose();
}
GridDragTree dragTree = _gridDragTree;
_gridDragTree = null;
if (dragTree != null)
{
dragTree.OnDragComplete -= OnDragTreeCompleted;
dragTree.Dispose();
}
GridDragGrid dragGrid = _gridDragGrid;
_gridDragGrid = null;
if (dragGrid != null)
{
dragGrid.OnDragComplete -= OnDragGridCompleted;
dragGrid.Dispose();
}
BandedGridDragGrid bandedDragGrid = _bandedGridDragGrid;
_bandedGridDragGrid = null;
if (bandedDragGrid != null)
{
bandedDragGrid.OnDragComplete -= OnDragBandedGridCompleted;
bandedDragGrid.Dispose();
}
try
{
if (treeLeft != null)
{
treeLeft.TreeNodeSelectAfter -= OnTreeLeftTreeNodeSelected;
treeLeft.OnTreeNodeMouseDoubleClick -= TreeLeft_OnTreeNodeMouseDoubleClick;
}
if (gridLeft != null && gridLeft.GridView != null)
{
gridLeft.GridView.RowClick -= OnGridViewRowClick;
}
if (treeGridLeft != null && treeGridLeft.TreeListObj != null)
{
treeGridLeft.TreeListObj.Click -= TreeListObj_Click;
treeGridLeft.TreeListObj.BeforeExpand -= TreeListObj_BeforeExpand;
treeGridLeft.TreeListObj.BeforeCollapse -= TreeListObj_BeforeCollapse;
}
if (MainBodyTab != null)
{
MainBodyTab.SelectedPageChanged -= MainBodyTab_SelectedPageChanged;
}
if (excelControlEx1 != null)
{
excelControlEx1.SaveCallBack -= OnExcelSaveClick;
}
}
catch
{
// A partially disposed child control must not stop cleanup.
}
try
{
if (Model != null && Model.DataCaches != null)
{
Model.DataCaches.RemoveCache(this);
}
}
catch
{
// Cache cleanup must not interrupt module disposal.
}
OnLeftGridViewRowClickCallBack = null;
OnLeftTreeViewRowClickCallBack = null;
if (Details != null)
{
Details.Clear();
}
LeftRowObj = null;
ColumnNameTable = null;
_currentRow = null;
ExcelControlObj = null;
Model = null;
SysModel = null;
}
private static IEnumerable<System.Windows.Forms.Control>
EnumerateModuleControls(System.Windows.Forms.Control parent)
{
if (parent == null)
{
yield break;
}
foreach (System.Windows.Forms.Control child in parent.Controls)
{
yield return child;
foreach (System.Windows.Forms.Control nested in
EnumerateModuleControls(child))
{
yield return nested;
}
}
}
/// <summary>
/// Excel 控件包含 SpreadsheetControl、BarManager 和命令注册项,
/// 普通表格模块不应在设计器初始化阶段创建这些重型资源。
/// </summary>
private ExcelControlEx EnsureExcelControl()
{
if (this.excelControlEx1 != null && !this.excelControlEx1.IsDisposed)
{
return this.excelControlEx1;
}
this.excelControlEx1 = new ExcelControlEx
{
AddEnabled = true,
DeleteEnabled = true,
Dock = DockStyle.Fill,
Margin = new Padding(6),
Name = "excelControlEx1",
PrintEnabled = true,
SaveEnabled = true,
TabIndex = 1,
Visible = false
};
this.pl_right.Controls.Add(this.excelControlEx1);
this.ExcelControlObj = this.excelControlEx1;
return this.excelControlEx1;
}
/// <summary>
@@ -221,9 +398,14 @@ namespace Lskj.Control
if (Model.HasOperPrivilege() && model.IsBaseModule)
{
// 有权限则允许拖拽
GridDragTree dragTree = new GridDragTree(this.ModuleGridObj.GridControlObj.GridView, this.treeLeft.TreeView);
dragTree.CanDragParentNode = true;
dragTree.OnDragComplete += new GridDragTreeCompleteEventHandler(OnDragTreeCompleted);
if (_gridDragTree != null)
{
_gridDragTree.OnDragComplete -= OnDragTreeCompleted;
_gridDragTree.Dispose();
}
_gridDragTree = new GridDragTree(this.ModuleGridObj.GridControlObj.GridView, this.treeLeft.TreeView);
_gridDragTree.CanDragParentNode = true;
_gridDragTree.OnDragComplete += new GridDragTreeCompleteEventHandler(OnDragTreeCompleted);
}
if (this.SysModel.TreeDoubleClick)
{
@@ -270,10 +452,11 @@ namespace Lskj.Control
if (Model.HasOperPrivilege() && model.IsBaseModule && !this.SysModel.IsTreeTable)
{
// 有权限则允许拖拽
GridDragGrid dragGrid = new GridDragGrid(this.ModuleGridObj.GridControlObj.GridView, this.gridLeft.GridView);
dragGrid.OnDragComplete += new GridFragGridCompleteEventHandler(OnDragGridCompleted);
_gridDragGrid?.Dispose();
_gridDragGrid = new GridDragGrid(this.ModuleGridObj.GridControlObj.GridView, this.gridLeft.GridView);
_gridDragGrid.OnDragComplete += new GridFragGridCompleteEventHandler(OnDragGridCompleted);
//配置了拖拽条件后,在点击时判断条件
dragGrid.DragConditions = this.SysModel.DragConditions;
_gridDragGrid.DragConditions = this.SysModel.DragConditions;
}
break;
@@ -284,20 +467,22 @@ namespace Lskj.Control
}
if (this.IsExcel)
{
//由于创建对象时候要注册,所以动态构造这控件不在设计器进行否则表格模式也会弹出注册
// 只有 Excel 模式才创建 Spreadsheet/Bar 相关资源。
ExcelControlEx excelControl = EnsureExcelControl();
this.ModuleGridDetailObj.Visible = false;
this.repModelDetailEx.Visible = false;
this.excelControlEx1.Visible = true;
excelControl.Visible = true;
excelControl.BringToFront();
if (!Model.DataCaches.GetValue(this, "BasePrimaryKey", out SysModel.ParmaryKey))
{
SysModel.ParmaryKey = BaseImpl.GetBasePrimaryKey(this.Model.ModuleCode);
}
this.excelControlEx1.AddEnabled = this.SysModel.AddEnable;
this.excelControlEx1.DeleteEnabled = this.SysModel.DeleteEnable;
this.excelControlEx1.PrintEnabled = !string.IsNullOrWhiteSpace(this.SysModel.PrintFile);
this.excelControlEx1.SaveEnabled = this.SysModel.ModifyEnable;
this.excelControlEx1.CreateFile();
this.excelControlEx1.SaveCallBack += new EventHandler(OnExcelSaveClick);
excelControl.AddEnabled = this.SysModel.AddEnable;
excelControl.DeleteEnabled = this.SysModel.DeleteEnable;
excelControl.PrintEnabled = !string.IsNullOrWhiteSpace(this.SysModel.PrintFile);
excelControl.SaveEnabled = this.SysModel.ModifyEnable;
excelControl.CreateFile();
excelControl.SaveCallBack += new EventHandler(OnExcelSaveClick);
if (!Model.DataCaches.GetValue(this, "BaseGridColumns", out DataTable dtGridColumns))
{
dtGridColumns = BaseModuleImpl.GetBaseGridColumns(this.Model.ModuleCode);
@@ -314,8 +499,10 @@ namespace Lskj.Control
}
else
{
this.excelControlEx1.Visible = false;
if (this.excelControlEx1 != null)
{
this.excelControlEx1.Visible = false;
}
if (SysModel.isReplacMainDetail == "1")
{
this.ModuleGridDetailObj.Visible = false;
@@ -342,8 +529,9 @@ namespace Lskj.Control
if (Model.HasOperPrivilege() && model.IsBaseModule && !this.SysModel.IsTreeTable && this.ModuleGridObj.GridControlObj.GridView is BandedGridView&&(this.SysModel.MenuType==2 || this.SysModel.MenuType==5))
{
// 有权限则允许拖拽
BandedGridDragGrid BandedDragGrid = new BandedGridDragGrid(this.ModuleGridObj.GridControlObj.GridView as BandedGridView, this.gridLeft.GridView);
BandedDragGrid.OnDragComplete += new BandedGridFragGridCompleteEventHandler(OnDragBandedGridCompleted);
_bandedGridDragGrid?.Dispose();
_bandedGridDragGrid = new BandedGridDragGrid(this.ModuleGridObj.GridControlObj.GridView as BandedGridView, this.gridLeft.GridView);
_bandedGridDragGrid.OnDragComplete += new BandedGridFragGridCompleteEventHandler(OnDragBandedGridCompleted);
}
}
@@ -445,7 +633,6 @@ namespace Lskj.Control
{
case 1:
case 4://左侧为树节点
this.ModuleGridObj.LeftTreeViewEx = this.treeLeft;
Task<DataRow> baseLeftTreeFieldTask = cachesDic.AddTask(this, "BaseLeftTreeField", new Task<DataRow>(() =>
{
return BaseModuleImpl.GetBaseLeftTreeField(dynamicModel.ModuleCode);//获取表格左侧树字段
@@ -499,12 +686,7 @@ namespace Lskj.Control
DataTable customQueryFieldsTab = customQueryFieldsTask.Result;
if (customQueryFieldsTab != null && customQueryFieldsTab.Rows.Count > 0)
{
Task<MyControl> leftGridSearchObjTask = cachesDic.AddTask(this, "LeftGridSearchObj", new Task<MyControl>(() =>
{
string searchSql = baseLeftTreeFieldTask.Result["fieldsql"] + "";
return new MyControl(searchSql, sysModel.IsTreeTable ? this.treeGridLeft as GridControlEx : this.gridLeft);
}));
ModuleGridDetailObj._leftGridSearchObj = leftGridSearchObjTask.Result;
// MyControl 必须由后续 UI 初始化阶段创建。
}
else
{
@@ -526,7 +708,7 @@ namespace Lskj.Control
Task<DataTable> customColumnByDatabaseTask = cachesDic.AddTask(gridLeft, "CustomColumnByDatabase", new Task<DataTable>(() =>
{
string customColumKey = GridCustomColumnStruct.BaseLeftGridView + dynamicModel.ModuleCode;
return gridLeft.GridView.GetCustomColumnByDatabase(customColumKey);
return GridExtend.GetCustomColumnByDatabase(customColumKey);
}));
}
else
@@ -534,12 +716,11 @@ namespace Lskj.Control
Task<DataTable> customColumnByDatabaseTask = cachesDic.AddTask(treeGridLeft, "CustomColumnByDatabase", new Task<DataTable>(() =>
{
string customColumKey = GridCustomColumnStruct.BaseLeftGridView + dynamicModel.ModuleCode;
return treeGridLeft.GridView.GetCustomColumnByDatabase(customColumKey);
return GridExtend.GetCustomColumnByDatabase(customColumKey);
}));
}
}
}
ModuleGridObj.LeftGridEx = sysModel.IsTreeTable ? this.treeGridLeft : this.gridLeft;
break;
}
if (dynamicModel is DynamicExcelModel)//isExcel
@@ -1967,6 +2148,15 @@ namespace Lskj.Control
}
}
/// <summary>
/// 控件销毁后释放拖拽辅助对象;关闭被取消时不会触发,不影响模块继续使用。
/// </summary>
private void OnModuleExDisposed(object sender, EventArgs e)
{
this.Disposed -= OnModuleExDisposed;
ReleaseResourcesForDispose();
}
/// <summary>
/// 初始化页签
@@ -2081,7 +2271,7 @@ namespace Lskj.Control
{
if (this.gridLeft.Visible) this.OnGridViewRowClick(null, null);
if (this.treeGridLeft.Visible) this.TreeListObj_Click(null, null);
if (this.treeLeft.Visible)
if (this.treeLeft.Visible&& this.treeLeft.TreeView.SelectedNode!=null)
{
TreeViewEventArgs treeViewEventArgs = new TreeViewEventArgs(this.treeLeft.TreeView.SelectedNode);
this.OnTreeLeftTreeNodeSelected(null, treeViewEventArgs);
+6 -2
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
+141 -12
View File
@@ -39,6 +39,8 @@ namespace Lskj.Control
/// </summary>
public partial class ModuleGridDetailEx : UserControl
{
private bool mModuleResourcesReleased;
private bool mDetailPageCachesPrepared;
/// <summary>
/// 系统模块实体对象
@@ -147,6 +149,68 @@ namespace Lskj.Control
{
InitializeComponent();
}
internal void ReleaseResourcesForDispose()
{
if (mModuleResourcesReleased)
{
return;
}
mModuleResourcesReleased = true;
MyControl searchObj = SearchObj;
if (searchObj != null)
{
searchObj.OnSearchAfterCallBack -= SearchObj_ClearDetails_DoubleMode;
searchObj.OnLastQueryTriggered -= SearchObj_ClearDetails_DoubleMode;
searchObj.OnSearchAfterCallBack -= SearchObj_ClearDetails;
searchObj.OnLastQueryTriggered -= SearchObj_ClearDetails;
}
if (ModuleGridObj != null)
{
ModuleGridObj.AfterRefreshingCallBack -= ModuleGridObj_AfterRefreshingCallBack;
try
{
GridControlEx grid = ModuleGridObj.GridControlObj;
if (grid != null && grid.GridView != null)
{
grid.GridView.DoubleClick -= GridView_DoubleClick;
grid.GridView.DoubleClick -= OnGridViewDoubleClick;
grid.GridView.Click -= OnGridViewDoubleClick;
grid.GridView.MouseDown -= GridView_MouseDown;
grid.GridView.FocusedRowObjectChanged -= OnGridViewFocusedRowObjectChanged;
}
}
catch
{
// A partially disposed DevExpress view must not stop cleanup.
}
ModuleGridObj.ReleaseResourcesForDispose();
}
try
{
if (Model != null && Model.DataCaches != null)
{
Model.DataCaches.RemoveCache(this);
}
}
catch
{
// Cache cleanup must not interrupt control disposal.
}
OnGridViewRowClickCallBack = null;
if (GridDetailList != null)
{
GridDetailList.Clear();
}
datamodel.Clear();
_leftGridSearchObj = null;
Model = null;
SysModel = null;
}
/// <summary>
/// <para>说明:初始化控件</para>
/// <para>创建人:龚宇超</para>
@@ -189,6 +253,7 @@ namespace Lskj.Control
}
else
{
PrepareDetailPageCaches(dataCaches);
// 初始化底部多标签
this.InitializePages();
}
@@ -220,7 +285,6 @@ namespace Lskj.Control
//获取通用数据
Task<ModuleModel> sysModelTask = cachesDic.GetTask<ModuleModel>(this, "SysModel");
Task<DynamicModel> dynamicModelTask = cachesDic.GetTask<DynamicModel>(this, "DynamicModel");
Task<List<GridDetailModel>> detailsTask = cachesDic.GetTask<List<GridDetailModel>>(this, "Details");
ModuleGridObj._leftGridSearchObj = _leftGridSearchObj;
Task<bool> getDataCachesTask = cachesDic.AddTask(this, "DataCaches", new Task<bool>(() =>
{
@@ -231,23 +295,42 @@ namespace Lskj.Control
cachesDic.AddTask(ModuleGridObj, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(ModuleGridObj, "SysModel", sysModelTask);
this.ModuleGridObj.GetDataCaches(cachesDic);
if (!string.IsNullOrEmpty(sysModel.MainModuleCodeField) && this.ModuleGridObj.GridControlObj.GridView.Columns.ColumnByFieldName(sysModel.MainModuleCodeField) != null)
// 下方模块都使用当前主表的主键,共享主表已经创建的查询任务,避免每个明细重复查询。
Task<string> parentPrimaryKeyTask = cachesDic.GetTask<string>(ModuleGridObj, "BasePrimaryKey");
if (parentPrimaryKeyTask != null)
{
//InitializeDynamicPages();
}
else
{
//添加数据到mControl
cachesDic.AddTask(tcButtom, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(tcButtom, "Details", detailsTask);
// 初始化底部多标签
this.tcButtom.GetDataCaches(cachesDic);
cachesDic.AddTask(tcButtom, "ParentPrimaryKey", parentPrimaryKeyTask);
}
}
return true;
}));
}
private void PrepareDetailPageCaches(
Dictionary<object, Hashtable> cachesDic)
{
if (mDetailPageCachesPrepared || cachesDic == null)
{
return;
}
Task<DynamicModel> dynamicModelTask =
cachesDic.GetTask<DynamicModel>(this, "DynamicModel");
Task<List<GridDetailModel>> detailsTask =
cachesDic.GetTask<List<GridDetailModel>>(this, "Details");
// 未启用预加载缓存时,InitializePages 会按原有同步方式创建明细页签。
if (dynamicModelTask == null || detailsTask == null)
{
return;
}
mDetailPageCachesPrepared = true;
cachesDic.AddTask(tcButtom, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(tcButtom, "Details", detailsTask);
this.tcButtom.GetDataCaches(cachesDic);
}
/// <summary>
/// <para>说明:初始化底部多标签数据</para>
@@ -707,6 +790,13 @@ namespace Lskj.Control
}
}
if (model!=null&& !string.IsNullOrWhiteSpace(model.VisibleCond))
{
tabPage.PageVisible = !ValidateCond(model.VisibleCond, rowItem);
if (!tabPage.PageVisible) return;
}
if (IsDynamicDetailType)
{
@@ -1464,9 +1554,48 @@ namespace Lskj.Control
}
/// <summary>
/// <para>说明:检查可用条件</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2017-11-09 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="cond">The cond.</param>
/// <param name="dataRow">The data row.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
private bool ValidateCond(string cond, DataRow dataRow)
{
bool result = false;
string condition = cond;
try
{
if (string.IsNullOrWhiteSpace(cond)) return true;//如果值是空格或者空行,默认正确
cond = ReplaceHelper.ReplaceRowParamEmptyWrapQuote(dataRow, cond);
if (cond.StartsWith("@") || cond.StartsWith("!"))
{
result = "1".Equals(BaseImpl.GetDefaultValue(cond));
}
else if (dataRow == null)
{
result = ReplaceHelper.EvalCond(cond);
}
else
{
result = ReplaceHelper.ReplaceRowParamCond(dataRow, cond);
}
return result;
}
catch (Exception ex)
{
}
return result;
}
}
}
}
+16 -10
View File
@@ -13,9 +13,15 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
Lskj.Control.Model.PrintUtil.OnAfterPrint -=
new System.EventHandler(OnReportPrintAfter);
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -337,7 +343,7 @@
this.btnFixSearch.Name = "btnFixSearch";
this.btnFixSearch.Size = new System.Drawing.Size(63, 24);
this.btnFixSearch.TabIndex = 33;
this.btnFixSearch.Text = "查询(&Q)";
this.btnFixSearch.Text = "查询(Q)";
//
// txtFixKey
//
@@ -433,7 +439,7 @@
this.btnSave.Name = "btnSave";
this.btnSave.Size = new System.Drawing.Size(72, 26);
this.btnSave.TabIndex = 37;
this.btnSave.Text = "保存(&S)";
this.btnSave.Text = "保存(S)";
this.btnSave.Click += new System.EventHandler(this.OnSaveClick);
//
// btnUpdate
@@ -445,7 +451,7 @@
this.btnUpdate.Name = "btnUpdate";
this.btnUpdate.Size = new System.Drawing.Size(72, 26);
this.btnUpdate.TabIndex = 38;
this.btnUpdate.Text = "修改(&U)";
this.btnUpdate.Text = "修改(U)";
this.btnUpdate.Visible = false;
this.btnUpdate.Click += new System.EventHandler(this.OnUpdateClick);
//
@@ -458,7 +464,7 @@
this.btnPrint.Name = "btnPrint";
this.btnPrint.Size = new System.Drawing.Size(72, 26);
this.btnPrint.TabIndex = 37;
this.btnPrint.Text = "打印(&P)";
this.btnPrint.Text = "打印(P)";
this.btnPrint.Visible = false;
this.btnPrint.Click += new System.EventHandler(this.OnPrintClick);
//
@@ -471,7 +477,7 @@
this.btnExport.Name = "btnExport";
this.btnExport.Size = new System.Drawing.Size(72, 26);
this.btnExport.TabIndex = 37;
this.btnExport.Text = "导出(&E)";
this.btnExport.Text = "导出(E)";
this.btnExport.Visible = false;
this.btnExport.Click += new System.EventHandler(this.OnExportClick);
//
@@ -484,7 +490,7 @@
this.btnImport.Name = "btnImport";
this.btnImport.Size = new System.Drawing.Size(72, 26);
this.btnImport.TabIndex = 37;
this.btnImport.Text = "导入(&I)";
this.btnImport.Text = "导入(I)";
this.btnImport.Visible = false;
this.btnImport.Click += new System.EventHandler(this.OnImportClick);
//
@@ -497,7 +503,7 @@
this.btnDel.Name = "btnDel";
this.btnDel.Size = new System.Drawing.Size(72, 26);
this.btnDel.TabIndex = 36;
this.btnDel.Text = "删除(&D)";
this.btnDel.Text = "删除(D)";
this.btnDel.Click += new System.EventHandler(this.OnDelClick);
//
// btnAdd
@@ -509,7 +515,7 @@
this.btnAdd.Name = "btnAdd";
this.btnAdd.Size = new System.Drawing.Size(72, 26);
this.btnAdd.TabIndex = 35;
this.btnAdd.Text = "增加(&A)";
this.btnAdd.Text = "增加(A)";
this.btnAdd.Click += new System.EventHandler(this.OnAddClick);
//
// ModuleGridEx
+215 -78
View File
@@ -53,6 +53,9 @@ namespace Lskj.Control
/// </summary>
public partial class ModuleGridEx : UserControl
{
private readonly AltButtonShortcutManager mAltButtonShortcuts =
new AltButtonShortcutManager();
#region private property
/// <summary>
@@ -77,6 +80,10 @@ namespace Lskj.Control
/// </summary>
private bool _visibleMrpSearchPanel;
/// <summary>
/// 外部已查询的MRP操作按钮数据,供搜索区域复用。
/// </summary>
public DataTable MrpClickMenus;
/// <summary>
/// 底部操作按钮是否显示简短模式,默认为简短模式
/// </summary>
private bool _operShortMode = true;
@@ -424,6 +431,7 @@ namespace Lskj.Control
/// 自定义查询条件
/// </summary>
public MyControl SearchObj { get; private set; }
private bool mModuleResourcesReleased;
/// <summary>
/// 左查询条件
/// </summary>
@@ -516,8 +524,29 @@ namespace Lskj.Control
searchObj = new MyControl(ReplaceBmpField(this.SysModel.MenuSql), gcMain, LeftTreeViewEx, LeftGridEx, _leftGridSearchObj);//替换sql语句中的bmp字段
searchObj.SpecialLeftTable = this.SpecialLeftTable;
searchObj.Model = Model;
if (!fixedQuery && Model.DataCaches != null)
{
searchObj.OtherParams = Model.OtherParams();
DynamicModel searchModel = Model;
DataTable searchControls = _queryTable;
Model.DataCaches.AddTask(searchObj, "DynamicModel",
new Task<DynamicModel>(() => searchModel));
Model.DataCaches.AddTask(searchObj, "ControlsTable",
new Task<DataTable>(() => searchControls));
searchObj.GetSearchDataCaches(Model.DataCaches);
}
}
if (this.MrpClickMenus == null && Model.DataCaches != null)
{
Model.DataCaches.GetValue(
this,
"UnionBaseGridRightMenus",
out this.MrpClickMenus);
}
this.SearchObj = searchObj;
// 搜索区域复用当前模块配置,MyControl 内部会校验模块号,不一致时仍按原逻辑查询。
this.SearchObj.SystemModel = this.SysModel;
this.SearchObj.MrpClickMenus = this.MrpClickMenus;
if (this._leftGridField != null)
{
@@ -538,6 +567,7 @@ namespace Lskj.Control
if (fixedQuery)
{
this.pl_top_fix_search.Visible = true;
// 加载固定查询条件
@@ -550,7 +580,12 @@ namespace Lskj.Control
{
table = Business.Impl.LanguageTranslation.TranslationTableColumn(table, "fieldText");
}
//固定条件不显示,隐藏上方。(只显示表格)
if (SystemInfo.Instance.HideFixedConditions)
{
this.pl_top.Visible = false;
table = new DataTable();
}
// DataTable
this.cbField.DisplayMember = "fieldText";
@@ -560,11 +595,7 @@ namespace Lskj.Control
this.SearchObj.InitDefaultSearchControl(table, this.pl_top_fix_search, false);
else
this.SearchObj.InitDefaultSearchControl(table, this.pl_top_fix_search);
//固定条件不显示,隐藏上方。(只显示表格)
if (SystemInfo.Instance.HideFixedConditions)
{
this.pl_top.Visible = false;
}
}
else
{
@@ -1680,7 +1711,8 @@ namespace Lskj.Control
}
else
{
cond = ReplaceHelper.ReplaceRowParam(dataRow, cond);
//cond = ReplaceHelper.ReplaceRowParam(dataRow, cond);
cond = ReplaceHelper.ReplaceRowParamEmptyWrapQuote(dataRow, cond);
if (cond.StartsWith("@") || cond.StartsWith("!"))
{
result = "1".Equals(BaseImpl.GetDefaultValue(cond));
@@ -2454,8 +2486,6 @@ namespace Lskj.Control
form.SubForm.Dispose();
form = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
catch (Exception ex)
@@ -3465,6 +3495,12 @@ namespace Lskj.Control
// 刷新数据
if (ImportResults)
{
if (!string.IsNullOrWhiteSpace(this.SysModel.afterimportSql))
{
string sql = this.SearchObj.ReplaceControlValue(this.SysModel.afterimportSql);
string newResult = SqlHelper.ExecuteScalar(sql) + "";
}
if (ImportReturnName.Count > 0)
{
this.SearchObj.SearchGrid();
@@ -3473,11 +3509,7 @@ namespace Lskj.Control
{
this.SearchObj.SearchLastGrid();
}
if (!string.IsNullOrWhiteSpace(this.SysModel.afterimportSql))
{
string sql = this.SearchObj.ReplaceControlValue(this.SysModel.afterimportSql);
string newResult = SqlHelper.ExecuteScalar(sql) + "";
}
}
//GridColumnCollection gridColumns = this.gcMain.GridView.Columns;
@@ -3512,11 +3544,20 @@ namespace Lskj.Control
FrmImport import = new FrmImport(this.SysModel.MenuTable, this.Model.ModuleCode, _parmaryKey, this.gcMain, this.SysModel.PrefixKey, leftField, leftValue, this.Model.FormText, this.SysModel.ConcatenatedPrefix);
import.ParentGridEx = this.ParentGridEx;
import.SearchObj = this.SearchObj;
import.ImportReturnName = ImportReturnName;
import.ImportReturnValue = ImportReturnValue;
DialogResult result = import.ShowDialog();
if (result == DialogResult.OK)
{
if (!string.IsNullOrWhiteSpace(this.SysModel.afterimportSql))
{
string sql = this.SearchObj.ReplaceControlValue(this.SysModel.afterimportSql);
string newResult = SqlHelper.ExecuteScalar(sql) + "";
//if (!string.IsNullOrEmpty(newResult)) MessageUtil.Show(newResult);
}
// 刷新数据
if (ImportReturnName.Count > 0)
{
@@ -3527,14 +3568,6 @@ namespace Lskj.Control
this.SearchObj.SearchLastGrid();
}
if (!string.IsNullOrWhiteSpace(this.SysModel.afterimportSql))
{
string sql = this.SearchObj.ReplaceControlValue(this.SysModel.afterimportSql);
string newResult = SqlHelper.ExecuteScalar(sql) + "";
//if (!string.IsNullOrEmpty(newResult)) MessageUtil.Show(newResult);
}
}
}
@@ -3672,7 +3705,141 @@ namespace Lskj.Control
public ModuleGridEx()
{
InitializeComponent();
InitializeAltButtonShortcuts();
this.OperShortMode = true;
this.Disposed += OnModuleGridExDisposed;
}
private void InitializeAltButtonShortcuts()
{
mAltButtonShortcuts.Register(btnFixSearch, Keys.Q);
mAltButtonShortcuts.Register(btnSave, Keys.S);
mAltButtonShortcuts.Register(btnUpdate, Keys.U);
mAltButtonShortcuts.Register(btnPrint, Keys.P);
mAltButtonShortcuts.Register(btnExport, Keys.E);
mAltButtonShortcuts.Register(btnImport, Keys.I);
mAltButtonShortcuts.Register(btnDel, Keys.D);
mAltButtonShortcuts.Register(btnAdd, Keys.A);
}
protected override bool ProcessCmdKey(
ref System.Windows.Forms.Message msg, Keys keyData)
{
return mAltButtonShortcuts.ProcessKey(keyData) ||
base.ProcessCmdKey(ref msg, keyData);
}
/// <summary>
/// 清理公共事件和全局右键引用,避免模块关闭后仍保留当前表格。
/// </summary>
private void OnModuleGridExDisposed(object sender, EventArgs e)
{
this.Disposed -= OnModuleGridExDisposed;
ReleaseResourcesForDispose();
}
internal void ReleaseResourcesForDispose()
{
if (mModuleResourcesReleased)
{
return;
}
mModuleResourcesReleased = true;
PrintUtil.OnAfterPrint -= OnReportPrintAfter;
MyControl searchObj = SearchObj;
SearchObj = null;
if (searchObj != null)
{
searchObj.OnSearchBeforeCallBack -= OnSearchBeforeCallBack;
searchObj.OnSearchAfterCallBack -= OnSearchAfterCallBack;
searchObj.OnDataSourceBindCallBack -= OnMainSearchDataSourceBindCallBack;
if (ReferenceEquals(StaticControl.RightMenuMyControl, searchObj))
{
StaticControl.RightMenuMyControl = null;
}
searchObj.Dispose();
}
try
{
if (gcMain != null)
{
if (ReferenceEquals(StaticControl.RightMenuGridView, gcMain.GridView))
{
StaticControl.RightMenuGridView = null;
}
if (gcMain.GridView != null)
{
gcMain.GridView.FocusedRowObjectChanged -= OnGridViewFocusedRowObjectChanged;
gcMain.GridView.ShowingEditor -= OnGridViewShowingEditor;
gcMain.GridView.DoubleClick -= OnGridViewDoubleClick;
gcMain.GridView.MouseDown -= OnGridViewMouseDown;
gcMain.GridView.MouseDown -= OnGridMouseDown;
gcMain.GridView.MouseMove -= OnGridMouseMove;
gcMain.GridView.MouseUp -= OnGridMouseUp;
}
if (gcMain.CustomGroupBandEx != null)
{
gcMain.CustomGroupBandEx.GridView.FocusedRowObjectChanged -= OnGridViewFocusedRowObjectChanged;
gcMain.CustomGroupBandEx.GridView.ShowingEditor -= OnGridViewShowingEditor;
}
if (gcMain.ParentControl != null &&
ReferenceEquals(gcMain.ParentControl, searchObj))
{
gcMain.ParentControl = null;
}
gcMain.Model = null;
gcMain.SysModel = null;
}
}
catch
{
// A partially disposed DevExpress view must not stop module cleanup.
}
try
{
if (Model != null && Model.DataCaches != null)
{
Model.DataCaches.RemoveCache(this);
}
}
catch
{
// Cache cleanup must not interrupt control disposal.
}
OnSaveGridCallBack = null;
AfterDeleteGridCallBack = null;
RightGridCallBack = null;
DetailRightGridCallBack = null;
OnCloseCallback = null;
AfterRefreshingCallBack = null;
SaveEvent = null;
OnExportCallBack = null;
verifyDetailsTab = null;
if (m_dragRowShadow != null)
{
m_dragRowShadow.Dispose();
m_dragRowShadow = null;
}
ButtonModeRightMenus.Clear();
RightButtons.Clear();
itemCommonList.Clear();
LineStatus.Clear();
_leftGridSearchObj = null;
LeftTreeViewEx = null;
LeftGridEx = null;
SpecialLeftTable = null;
ParentGridEx = null;
ParentControlEx = null;
ParentControlObj = null;
TabObj = null;
Model = null;
SysModel = null;
}
/// <summary>
@@ -3784,13 +3951,10 @@ namespace Lskj.Control
}
if (this.SearchObj != null)
{
this.SearchObj.SystemModel = sysModel;
}
//if (this.SearchObj != null)
//{
// this.SearchObj.SystemModel = sysModel;
//}
//禁用条件
if (this.SysModel.ForbiddenCondition)
@@ -3957,33 +4121,12 @@ namespace Lskj.Control
{
return BaseModuleImpl.GetSchemesList(dynamicModel.ModuleId);//获取高级查询条件模版
}));
//InitializeQueryCondition
Task<MyControl> searchObjTask = cachesDic.AddTask(this, "SearchObj", new Task<MyControl>(() =>
{
DataTable queryTable = customQueryFieldsTask.Result;
bool fixedQuery = queryTable == null || queryTable.Rows.Count == 0;
MyControl myControl = new MyControl(sysModel.MenuSql, gcMain, LeftTreeViewEx, LeftGridEx, _leftGridSearchObj)
{
SpecialLeftTable = this.SpecialLeftTable,
Model = dynamicModel
};
if (!fixedQuery)
{
myControl.OtherParams = dynamicModel.OtherParams();
cachesDic.AddTask(myControl, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(myControl, "ControlsTable", customQueryFieldsTask);
myControl.GetSearchDataCaches(cachesDic);
}
return myControl;
}));
Task<ModuleModel> searchSysModelTask = cachesDic.AddTask(pl_top_search, "SysModel", new Task<ModuleModel>(() =>
{
return new ModuleModel(MainImpl.GetSystemdllTab(dynamicModel.ModuleCode));
}));
Task<DataTable> searchBaseGridRightMenusTask = cachesDic.AddTask(pl_top_search, "BaseGridRightMenus", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRightMenus(dynamicModel.ModuleCode, ModuleType.MrpClickBtn);
}));
// 搜索区域与当前模块共享同一个模块配置任务,避免再次查询模块信息。
cachesDic.AddTask(pl_top_search, "SysModel", sysModelTask);
//Task<DataTable> searchBaseGridRightMenusTask = cachesDic.AddTask(pl_top_search, "BaseGridRightMenus", new Task<DataTable>(() =>
//{
// return BaseModuleImpl.GetBaseGridRightMenus(dynamicModel.ModuleCode, ModuleType.MrpClickBtn);
//}));
Task<DataTable> fixedQueryFieldsTask = cachesDic.AddTask(this, "FixedQueryFields", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetFixedQueryFields(dynamicModel.ModuleCode);//加载固定查询条件
@@ -5171,28 +5314,6 @@ namespace Lskj.Control
if (!gridView.FocusedColumn.FieldName.Equals("RightMenuBtnEdit"))//操作列可点击
{
e.Cancel = !btnSave.Enabled;
//如果是备注框,显示编辑框,但不能修改(编辑框弹出和取消编辑冲突,只能改变只读状态后,开始编辑)
if (gridColumnModel != null && gridColumnModel.FieldType == ControlType.LabMemoEdit)
{
RepositoryItemMemoExEdit memoEdit = gridColumn.ColumnEdit as RepositoryItemMemoExEdit;
if (e.Cancel)
{
//设置只读
memoEdit.ReadOnly = true;
//只读状态允许下拉列表
memoEdit.AllowDropDownWhenReadOnly = DevExpress.Utils.DefaultBoolean.True;
//允许编辑(编辑框弹出)
e.Cancel = false;
}
else
{
if (gridColumn.OptionsColumn.AllowEdit && memoEdit.ReadOnly)
{
memoEdit.ReadOnly = false;
}
}
}
}
if (!string.IsNullOrEmpty(this.SysModel.RowAllowEditCond) && focusedRow != null)
{
@@ -5204,6 +5325,22 @@ namespace Lskj.Control
//e.Cancel = !ReplaceHelper.EvalCond(ReplaceHelper.ReplaceRowParam(focusedRow, gridColumnModel.DisableCond));
e.Cancel = !ValidateCond(gridColumnModel.DisableCond, focusedRow);
}
// 备注框在禁编状态下仍允许打开弹窗查看内容,但不能修改。
if (gridColumnModel != null && gridColumnModel.FieldType == ControlType.LabMemoEdit)
{
RepositoryItemMemoExEdit memoEdit = gridColumn.ColumnEdit as RepositoryItemMemoExEdit;
if (memoEdit != null)
{
bool readOnly = !btnSave.Enabled || e.Cancel || gridColumn.OptionsColumn.ReadOnly;
memoEdit.ReadOnly = readOnly;
if (readOnly)
{
memoEdit.AllowDropDownWhenReadOnly = DevExpress.Utils.DefaultBoolean.True;
e.Cancel = false;
}
}
}
}
catch (Exception ex)
{
+12 -7
View File
@@ -14,9 +14,14 @@ namespace Lskj.Control
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
Lskj.Control.Model.PrintUtil.OnAfterPrint -=
new EventHandler(OnReportPrintAfter);
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -305,7 +310,7 @@ namespace Lskj.Control
this.btnAttach.Size = new System.Drawing.Size(80, 28);
this.btnAttach.TabIndex = 6;
this.btnAttach.TabStop = false;
this.btnAttach.Text = "附件管理(&F)";
this.btnAttach.Text = "附件管理(F)";
//
// btnUpdate
//
@@ -316,7 +321,7 @@ namespace Lskj.Control
this.btnUpdate.Size = new System.Drawing.Size(80, 28);
this.btnUpdate.TabIndex = 4;
this.btnUpdate.TabStop = false;
this.btnUpdate.Text = "修改保存(&E)";
this.btnUpdate.Text = "修改保存(E)";
//
// ddb_common
//
@@ -337,7 +342,7 @@ namespace Lskj.Control
this.btnApply.Name = "btnApply";
this.btnApply.Size = new System.Drawing.Size(80, 28);
this.btnApply.TabIndex = 5;
this.btnApply.Text = "提交审核(&R)";
this.btnApply.Text = "提交审核(R)";
//
// btnAdd
//
@@ -348,7 +353,7 @@ namespace Lskj.Control
this.btnAdd.Size = new System.Drawing.Size(80, 28);
this.btnAdd.TabIndex = 3;
this.btnAdd.TabStop = false;
this.btnAdd.Text = "添加保存(&A)";
this.btnAdd.Text = "添加保存(A)";
//
// btnClose
//
@@ -359,7 +364,7 @@ namespace Lskj.Control
this.btnClose.Size = new System.Drawing.Size(80, 28);
this.btnClose.TabIndex = 10;
this.btnClose.TabStop = false;
this.btnClose.Text = "退出(&C)";
this.btnClose.Text = "退出(C)";
//
// simpleButton1
//
+29 -5
View File
@@ -47,6 +47,9 @@ namespace Lskj.Control
/// </summary>
public partial class ModulePanelEx : UserControl
{
private readonly AltButtonShortcutManager mAltButtonShortcuts =
new AltButtonShortcutManager();
public LabelTextEdit ScanEdit { get { return this._scanEdit; } }
#region private property
@@ -228,6 +231,7 @@ namespace Lskj.Control
{
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.Selectable | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.SupportsTransparentBackColor, true);
InitializeComponent();
InitializeAltButtonShortcuts();
this.scc_container.PanelVisibility = SplitPanelVisibility.Panel1;
this.simpleButton1.Click += simpleButton1_Click;
this.btnClear.Click += OnBtnClearClick;
@@ -241,6 +245,22 @@ namespace Lskj.Control
this.BtnMesClose.Click += OnBtnMesCloseClick;
}
private void InitializeAltButtonShortcuts()
{
mAltButtonShortcuts.Register(btnAttach, Keys.F);
mAltButtonShortcuts.Register(btnUpdate, Keys.E);
mAltButtonShortcuts.Register(btnApply, Keys.R);
mAltButtonShortcuts.Register(btnAdd, Keys.A);
mAltButtonShortcuts.Register(btnClose, Keys.C);
}
protected override bool ProcessCmdKey(
ref System.Windows.Forms.Message msg, Keys keyData)
{
return mAltButtonShortcuts.ProcessKey(keyData) ||
base.ProcessCmdKey(ref msg, keyData);
}
#region private method
/// <summary>
/// <para>说明:控制滚动条是否存在横向的</para>
@@ -360,9 +380,9 @@ namespace Lskj.Control
this.btnUpdate.Location = this.btnApply.Location;
}
// 设置文本
btnAdd.Text = !string.IsNullOrWhiteSpace(this.SysModel.AddCaption) ? this.SysModel.AddCaption : "添加保存(&A)";
btnUpdate.Text = !string.IsNullOrWhiteSpace(this.SysModel.ModifyCaption) ? this.SysModel.ModifyCaption : "修改保存(&E)";
btnApply.Text = !string.IsNullOrWhiteSpace(this.SysModel.ApplyCaption) ? this.SysModel.ApplyCaption : "提交审核(&R)";
btnAdd.Text = !string.IsNullOrWhiteSpace(this.SysModel.AddCaption) ? this.SysModel.AddCaption : "添加保存(A)";
btnUpdate.Text = !string.IsNullOrWhiteSpace(this.SysModel.ModifyCaption) ? this.SysModel.ModifyCaption : "修改保存(E)";
btnApply.Text = !string.IsNullOrWhiteSpace(this.SysModel.ApplyCaption) ? this.SysModel.ApplyCaption : "提交审核(R)";
//隐藏帮助文档按钮
if (SystemInfo.Instance.HideHelpDocument) this.simpleButton1.Visible = false;
@@ -1814,7 +1834,11 @@ namespace Lskj.Control
{
// 提交数据
this.PrimaryValue = this.SysModel.NewVer == 0 ? this.ControlObj.GetControlValue(this.PrimaryKey) : this.PrimaryValue;
if (string.IsNullOrEmpty(PrimaryValue) || SavaState) this.AddControlRecord(true, false);
if (string.IsNullOrEmpty(PrimaryValue) || SavaState)
{
isApply=this.AddControlRecord(true, false);
if (!isApply) return;//保存失败不执行提交
}
DialogResult result = MessageUtil.Show(ResourceKeys.BillApply, MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
@@ -2739,7 +2763,7 @@ namespace Lskj.Control
BaseUserControl baseControl = this.ControlObj.FindControl(PrimaryKey);
if (baseControl != null)
{
this.ControlObj.CopyControlValue();
this.ControlObj.CopyControlValue(this.SysModel.CancelCopyAssociation);
baseControl.EditText = BaseImpl.GetDefaultValue(baseControl.Model.Default, ParentKey);
lteSpeciesNo.TextEdit.EditValue = this.ParentKey;
@@ -247,11 +247,10 @@ namespace Lskj.Control.MultiModelLookUp
{
try
{
string width = IniHelper.Read(string.Format("base_width_{0}", this.UnionModuleCodel));//通过Key获取Value值
string width = IniHelper.Read(string.Format("FrmModelLookUp_width_{0}", this.UnionModuleCodel));//通过Key获取Value值
if (!string.IsNullOrEmpty(width))
{
this.splitMain.SplitterPosition = Convert.ToInt32(width);
}
}
catch (Exception ex)
@@ -777,6 +776,7 @@ namespace Lskj.Control.MultiModelLookUp
private void PositionChange(object sender, EventArgs e)
{
PositionSplitter = this.splitMain_Right.SplitterPosition;
IniHelper.Write(string.Format("FrmModelLookUp_height_{0}", this.UnionModuleCodel), PositionSplitter + "");
}
#endregion
#region
@@ -1034,6 +1034,17 @@ namespace Lskj.Control.MultiModelLookUp
this.Width = this.SysModel.ModuleFrameWidth;
}
string height = IniHelper.Read(string.Format("FrmModelLookUp_height_{0}", this.UnionModuleCodel));//通过Key获取Value值
if (!string.IsNullOrEmpty(height))
{
this.splitMain_Right.SplitterPosition = Convert.ToInt32(height);
}
else if (this.SysModel.BottomHeight > 0)
{
this.splitMain_Right.SplitterPosition = Convert.ToInt32(this.splitMain_Right.Height - this.SysModel.BottomHeight);
}
switch (this.SysModel.MenuType)
{
case 1: // 左侧为树节点
@@ -1057,7 +1068,7 @@ namespace Lskj.Control.MultiModelLookUp
this.splitMain.PanelVisibility = SplitPanelVisibility.Panel2;
break;
}
this.splitMain.SplitterPositionChanged += SplitMain_SplitterPositionChanged;
}
else
{
@@ -1067,6 +1078,12 @@ namespace Lskj.Control.MultiModelLookUp
}
return false;
}
private void SplitMain_SplitterPositionChanged(object sender, EventArgs e)
{
IniHelper.Write(string.Format("FrmModelLookUp_width_{0}", this.UnionModuleCodel), this.splitMain.SplitterPosition + "");
}
#endregion
@@ -28,11 +28,11 @@
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.splitMain = new DevExpress.XtraEditors.SplitContainerControl();
this.pl_left = new DevExpress.XtraEditors.PanelControl();
this.pl_left_main = new System.Windows.Forms.Panel();
this.pl_gridandtree_container = new DevExpress.XtraEditors.PanelControl();
this.treeLeft = new Lskj.Control.TreeViewEx();
this.gridLeft = new Lskj.Control.GridControlEx();
this.pl_left_top = new DevExpress.XtraEditors.PanelControl();
this.splitMain_Right = new DevExpress.XtraEditors.SplitContainerControl();
@@ -44,12 +44,11 @@
this.btn_selectAll = new DevExpress.XtraEditors.SimpleButton();
this.btn_cancelAll = new DevExpress.XtraEditors.SimpleButton();
this.btnOk = new DevExpress.XtraEditors.SimpleButton();
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip();
this.tsmi_all = new System.Windows.Forms.ToolStripMenuItem();
this.tsmi_reserve = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
this.tsmi_cancel = new System.Windows.Forms.ToolStripMenuItem();
this.treeLeft = new Lskj.Control.TreeViewEx();
((System.ComponentModel.ISupportInitialize)(this.splitMain)).BeginInit();
this.splitMain.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pl_left)).BeginInit();
@@ -118,6 +117,16 @@
this.pl_gridandtree_container.Size = new System.Drawing.Size(260, 454);
this.pl_gridandtree_container.TabIndex = 9;
//
// treeLeft
//
this.treeLeft.Dock = System.Windows.Forms.DockStyle.Fill;
this.treeLeft.Location = new System.Drawing.Point(0, 0);
this.treeLeft.Margin = new System.Windows.Forms.Padding(4);
this.treeLeft.Name = "treeLeft";
this.treeLeft.Size = new System.Drawing.Size(260, 454);
this.treeLeft.TabIndex = 7;
this.treeLeft.Visible = false;
//
// gridLeft
//
this.gridLeft.AdapterObj = null;
@@ -218,7 +227,7 @@
this.btnCancel.Location = new System.Drawing.Point(772, 5);
this.btnCancel.Margin = new System.Windows.Forms.Padding(4);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(79, 35);
this.btnCancel.Size = new System.Drawing.Size(76, 35);
this.btnCancel.TabIndex = 24;
this.btnCancel.Text = "取消(&C)";
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
@@ -297,16 +306,6 @@
this.tsmi_cancel.Size = new System.Drawing.Size(100, 22);
this.tsmi_cancel.Text = "取消";
//
// treeLeft
//
this.treeLeft.Dock = System.Windows.Forms.DockStyle.Fill;
this.treeLeft.Location = new System.Drawing.Point(0, 0);
this.treeLeft.Margin = new System.Windows.Forms.Padding(4);
this.treeLeft.Name = "treeLeft";
this.treeLeft.Size = new System.Drawing.Size(260, 454);
this.treeLeft.TabIndex = 7;
this.treeLeft.Visible = false;
//
// FrmModelLookUp2
//
this.Appearance.BackColor = System.Drawing.SystemColors.Control;
@@ -266,12 +266,12 @@ namespace Lskj.Control.MultiModelLookUp
{
try
{
string width = IniHelper.Read(string.Format("base_width_{0}", this.UnionModuleCodel));//通过Key获取Value值
string width = IniHelper.Read(string.Format("FrmModelLookUp2_width_{0}", this.UnionModuleCodel));//通过Key获取Value值
if (!string.IsNullOrEmpty(width))
{
this.splitMain.SplitterPosition = Convert.ToInt32(width);
}
}
catch (Exception ex)
{
@@ -466,7 +466,8 @@ namespace Lskj.Control.MultiModelLookUp
}
}
}
SetCustomColumns();
//SetCustomColumns();
}
#endregion
#region
@@ -481,7 +482,7 @@ namespace Lskj.Control.MultiModelLookUp
/// </summary>
private void SetCustomColumns()
{
if (string.IsNullOrEmpty(this.CurrentOperColumnKey) || !BaseImpl.HasExistsTable(ResourceKeys.SettingTableName)) return;
if (string.IsNullOrEmpty(this.CurrentOperColumnKey)) return;
DataTable customTable = this.gcMain.GridView.GetCustomColumnByDatabase(this.CurrentOperColumnKey);
if (customTable != null && customTable.Rows.Count > 0)
@@ -805,6 +806,7 @@ namespace Lskj.Control.MultiModelLookUp
private void PositionChange(object sender, EventArgs e)
{
PositionSplitter = this.splitMain_Right.SplitterPosition;
IniHelper.Write(string.Format("FrmModelLookUp2_height_{0}", this.UnionModuleCodel), PositionSplitter + "");
}
#endregion
#region
@@ -1137,7 +1139,15 @@ namespace Lskj.Control.MultiModelLookUp
this.Width = this.SysModel.ModuleFrameWidth;
}
string height = IniHelper.Read(string.Format("FrmModelLookUp2_height_{0}", this.UnionModuleCodel));//通过Key获取Value值
if (!string.IsNullOrEmpty(height))
{
this.splitMain_Right.SplitterPosition = Convert.ToInt32(height);
}
else if (this.SysModel.BottomHeight > 0)
{
this.splitMain_Right.SplitterPosition = Convert.ToInt32(this.splitMain_Right.Height - this.SysModel.BottomHeight);
}
switch (this.SysModel.MenuType)
{
@@ -1162,7 +1172,7 @@ namespace Lskj.Control.MultiModelLookUp
this.splitMain.PanelVisibility = SplitPanelVisibility.Panel2;
break;
}
this.splitMain.SplitterPositionChanged += SplitMain_SplitterPositionChanged;
}
else
{
@@ -1172,6 +1182,11 @@ namespace Lskj.Control.MultiModelLookUp
}
return false;
}
private void SplitMain_SplitterPositionChanged(object sender, EventArgs e)
{
IniHelper.Write(string.Format("FrmModelLookUp2_width_{0}", this.UnionModuleCodel), this.splitMain.SplitterPosition + "");
}
#endregion
//设置选中框的值
+6 -2
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
+54 -6
View File
@@ -37,6 +37,8 @@ namespace Lskj.Control
/// </summary>
public partial class ReplacementDetailEx : UserControl
{
private bool mResourcesReleased;
private bool mDetailPageCachesPrepared;
/// <summary>
/// 系统模块实体对象
/// </summary>
@@ -102,6 +104,39 @@ namespace Lskj.Control
{
InitializeComponent();
}
internal void ReleaseResourcesForDispose()
{
if (mResourcesReleased)
{
return;
}
mResourcesReleased = true;
if (ModuleGridObj != null)
{
ModuleGridObj.ReleaseResourcesForDispose();
}
try
{
if (Model != null && Model.DataCaches != null)
{
Model.DataCaches.RemoveCache(this);
}
}
catch
{
// Cache cleanup must not interrupt control disposal.
}
if (GridDetailList != null)
{
GridDetailList.Clear();
}
_leftGridSearchObj = null;
Model = null;
SysModel = null;
}
/// <summary>
/// <para>说明:初始化控件</para>
/// <para>创建人:龚宇超</para>
@@ -128,6 +163,7 @@ namespace Lskj.Control
this.ModuleGridObj.InitializeControl(sysModel, dyncModel);
RefreshDetail = this.SysModel.RefreshDetail == "0";
Console.WriteLine(DateTime.Now);
PrepareDetailPageCaches(dyncModel.DataCaches);
// 初始化底部多标签
this.InitializePages();
Console.WriteLine(DateTime.Now);
@@ -162,15 +198,27 @@ namespace Lskj.Control
//获取通用数据
Task<ModuleModel> sysModelTask = cachesDic.GetTask<ModuleModel>(this, "SysModel");
Task<DynamicModel> dynamicModelTask = cachesDic.GetTask<DynamicModel>(this, "DynamicModel");
Task<List<GridDetailModel>> detailsTask = cachesDic.GetTask<List<GridDetailModel>>(this, "Details");
cachesDic.AddTask(ModuleGridObj, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(ModuleGridObj, "SysModel", sysModelTask);
cachesDic.AddTask(ModuleGridObj, "Details", detailsTask);
cachesDic.AddTask(tcButtom, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(tcButtom, "Details", detailsTask);
//初始化顶部表格
ModuleGridObj.GetDataCaches(cachesDic);
// 初始化底部多标签
}
private void PrepareDetailPageCaches(
Dictionary<object, Hashtable> cachesDic)
{
if (mDetailPageCachesPrepared || cachesDic == null)
{
return;
}
mDetailPageCachesPrepared = true;
Task<DynamicModel> dynamicModelTask =
cachesDic.GetTask<DynamicModel>(this, "DynamicModel");
Task<List<GridDetailModel>> detailsTask =
cachesDic.GetTask<List<GridDetailModel>>(this, "Details");
cachesDic.AddTask(tcButtom, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(tcButtom, "Details", detailsTask);
tcButtom.GetDataCaches(cachesDic);
}
@@ -650,4 +698,4 @@ namespace Lskj.Control
}
}
}
}
@@ -111,15 +111,17 @@ namespace Lskj.Control.SiftColControl
/// <returns></returns>
static int CalcIndicatorBestWidth(DevExpress.XtraGrid.Views.Grid.GridView view)
{
Graphics graphics = new System.Windows.Forms.Control().CreateGraphics();
SizeF sizeF = new SizeF();
int count = view.TopRowIndex + ((DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo)view.GetViewInfo()).RowsInfo.Count;
if (count == 0)
{
count = 30;
}
sizeF = graphics.MeasureString(count.ToString(), view.Appearance.Row.Font);
return Convert.ToInt32(sizeF.Width) + 20;
int textWidth = TextRenderer.MeasureText(
count.ToString(),
view.Appearance.Row.Font,
Size.Empty,
TextFormatFlags.NoPadding | TextFormatFlags.SingleLine).Width;
return textWidth + 20;
}
/// <summary>
/// 计算默认的宽度
@@ -129,16 +131,18 @@ namespace Lskj.Control.SiftColControl
static int CalcIndicatorDefaultWidth(DevExpress.XtraGrid.Views.Grid.GridView view)
{
var grid = view.GridControl;
Graphics graphics = new System.Windows.Forms.Control().CreateGraphics();
SizeF sizeF = new SizeF();
int rowHeight = 22;//22是Row的估计高度
if (view.RowHeight > 0)
{
rowHeight = view.RowHeight;
}
int count = grid != null ? grid.Height / rowHeight : 30;
sizeF = graphics.MeasureString(count.ToString(), view.Appearance.Row.Font);
return Convert.ToInt32(sizeF.Width) + 20;
int textWidth = TextRenderer.MeasureText(
count.ToString(),
view.Appearance.Row.Font,
Size.Empty,
TextFormatFlags.NoPadding | TextFormatFlags.SingleLine).Width;
return textWidth + 20;
}
#endregion
}
+4 -1
View File
@@ -211,7 +211,10 @@ namespace Lskj.Control
private void btnClear_Click(object sender, EventArgs e)
{
try {
pictureEdit1.CreateGraphics().Clear(Color.White);
using (Graphics graphics = pictureEdit1.CreateGraphics())
{
graphics.Clear(Color.White);
}
_mousePath.Reset();
}
catch (Exception ex)
+48 -15
View File
@@ -211,17 +211,17 @@ namespace Lskj.Control
g.SetGridViewDataSource(table);
break;
/* ③ Tag 是面板/其它容器,递归找内部网格 ------------------------ */
/* ③ 图表控件:需先于通用容器判断,避免绑定到图表内部隐藏网格 -- */
case ChartControlEx chartEx:
chartEx.CreateChart(table);
break;
/* ④ Tag 是面板/其它容器,递归找内部网格 ------------------------ */
case System.Windows.Forms.Control container when FindGridControlEx(container) is GridControlEx g2:
g2.LastSearchSql = lastSql ?? g2.LastSearchSql;
g2.SetGridViewDataSource(table);
break;
/* ④ 图表控件 ---------------------------------------------------- */
case ChartControlEx chartEx:
chartEx.CreateChart(table);
break;
/* ⑤ 其它控件无需绑定 ------------------------------------------- */
default:
break;
@@ -501,6 +501,14 @@ namespace Lskj.Control
Dictionary<object, Hashtable> dataCaches = Model?.DataCaches;
// 普通 ModuleGridEx 明细使用同一个父模块主键,避免同步加载时每个明细重复查询。
bool hasModuleGridDetail = Model != null && gridDetail.Any(model => IsModuleGridDetail(model, gridDetail, isGridmerge));
string parentPrimaryKey = null;
if (hasModuleGridDetail && !dataCaches.GetValue(this, "ParentPrimaryKey", out parentPrimaryKey))
{
parentPrimaryKey = BaseImpl.GetBasePrimaryKey(Model.ModuleCode);
}
this.DetaiName = string.Empty;
foreach (GridDetailModel model in gridDetail)
@@ -520,7 +528,7 @@ namespace Lskj.Control
page.SizeChanged += OnPageSizeChanged;
// 2️⃣ 先生成“左侧”父明细控件
System.Windows.Forms.Control leftCtrl = CreateDetailControl(page, model, dataCaches);
System.Windows.Forms.Control leftCtrl = CreateDetailControl(page, model, dataCaches, true, null, hasModuleGridDetail, parentPrimaryKey);
int position = int.TryParse(IniHelper.Read($"base_TabPageMain_{model.Id}"), out int value) ? value : 0; // 0 是转换失败时的默认值
if (hasRight && isGridmerge)
{
@@ -559,7 +567,7 @@ namespace Lskj.Control
foreach (var child in rightChildren.OrderBy(c => c.Orderid))
{
XtraTabPage childPage = new XtraTabPage { Text = child.DetailName };
System.Windows.Forms.Control childCtrl = CreateDetailControl(childPage, child, dataCaches, true, leftControl);
System.Windows.Forms.Control childCtrl = CreateDetailControl(childPage, child, dataCaches, true, leftControl, hasModuleGridDetail, parentPrimaryKey);
childPage.Controls.Add(childCtrl);
rightTab.TabPages.Add(childPage);
_rightSideTabPages.Add(childPage);
@@ -605,6 +613,21 @@ namespace Lskj.Control
}
}
/// <summary>
/// 判断明细配置是否会创建普通 ModuleGridEx 控件。
/// </summary>
private static bool IsModuleGridDetail(GridDetailModel model, List<GridDetailModel> gridDetail, bool isGridmerge)
{
if (model == null || model.IsChart || model.IsExcel || model.IsWebView || model.IsWebView2 || model.IsWebView3 ||
model.IsSched || (model.IsAddPanel && isGridmerge) || model.IsDetailView)
{
return false;
}
int sameDetailCount = gridDetail.Count(item => item.DetailName.Equals(model.DetailName));
return !(model.IsReadOnly && sameDetailCount == 1) && !(sameDetailCount > 1 && isGridmerge);
}
@@ -989,6 +1012,7 @@ namespace Lskj.Control
this.isMrpDetail = true;
gridEx.VisibleMrpSearchPanel = true;
}
gridEx.MrpClickMenus = rightDt;
gridEx.VisibleOperPanel = !model.IsReadOnly;
gridEx.InitializeControl(model.SystemModel, dyncModel);
gridEx.GridControlObj.Tag = model;
@@ -1106,7 +1130,7 @@ namespace Lskj.Control
/// <param name="dataCaches"></param>
/// <param name="isGridmerge"></param>
/// <returns></returns>
private System.Windows.Forms.Control CreateDetailControl(System.Windows.Forms.Control parentControl, GridDetailModel model, Dictionary<object, Hashtable> dataCaches, bool isGridmerge = true, GridControlEx leftGridControlEx =null)
private System.Windows.Forms.Control CreateDetailControl(System.Windows.Forms.Control parentControl, GridDetailModel model, Dictionary<object, Hashtable> dataCaches, bool isGridmerge = true, GridControlEx leftGridControlEx = null, bool hasParentPrimaryKey = false, string parentPrimaryKey = null)
{
GridDetailModel[] isMeage = _gridDetail.Cast<GridDetailModel>().Where(x => x.DetailName.Equals(model.DetailName)).ToArray();
@@ -1441,8 +1465,11 @@ namespace Lskj.Control
if (Model != null)
{
if (!dataCaches.GetValue(gridEx, "ParentPrimaryKey", out string primaryKey))
string primaryKey = parentPrimaryKey;
if (!hasParentPrimaryKey && !dataCaches.GetValue(gridEx, "ParentPrimaryKey", out primaryKey))
{
primaryKey = BaseImpl.GetBasePrimaryKey(Model.ModuleCode);
}
model.SystemModel.ParmaryKey = primaryKey;
}
@@ -1465,6 +1492,7 @@ namespace Lskj.Control
isMrpDetail = true;
gridEx.VisibleMrpSearchPanel = true;
}
gridEx.MrpClickMenus = rightDt;
gridEx.VisibleOperPanel = !model.IsReadOnly;
if (model.HideBottomPanel|| model.Library.Equals("Lskj.Report.dll", StringComparison.OrdinalIgnoreCase))
@@ -1600,6 +1628,15 @@ namespace Lskj.Control
Task<List<GridDetailModel>> detailsTask = cachesDic.GetTask<List<GridDetailModel>>(this, "Details");
DynamicModel dynamicModel = dynamicModelTask.Result;
List<GridDetailModel> details = detailsTask.Result;
// 所有子模块使用同一个父模块主键。优先复用外部主表的查询任务,其他入口只补查一次。
Task<string> parentPrimaryKeyTask = cachesDic.GetTask<string>(this, "ParentPrimaryKey");
if (parentPrimaryKeyTask == null)
{
parentPrimaryKeyTask = cachesDic.AddTask(this, "ParentPrimaryKey", new Task<string>(() =>
{
return BaseImpl.GetBasePrimaryKey(dynamicModel.ModuleCode);
}));
}
string DetaiName = string.Empty;
PageControlsDic.Clear();
foreach (GridDetailModel model in details)
@@ -1778,11 +1815,7 @@ namespace Lskj.Control
}));
if (dynamicModel != null)
{
Task<string> basePrimaryKeyTask = cachesDic.AddTask(gridEx, "ParentPrimaryKey", new Task<string>(() =>
{
string basePrimaryKey = BaseImpl.GetBasePrimaryKey(dynamicModel.ModuleCode);
return basePrimaryKey;
}));
cachesDic.AddTask(gridEx, "ParentPrimaryKey", parentPrimaryKeyTask);
}
Task<DataTable> baseGridRightMenusTask = cachesDic.AddTask(gridEx, "UnionBaseGridRightMenus", new Task<DataTable>(() =>
{
@@ -2112,6 +2112,7 @@ namespace Lskj.Control
public override int SetGridViewDataSource(DbDataAdapter adapter, bool selectRowHandler = true)
{
if (adapter == null) return 0;
DbDataAdapter previousAdapter = this.AdapterObj;
if (this.ColumnList == null || this.ColumnList.Count == 0)
{
this.gcMain.Bands.Clear();
@@ -2122,53 +2123,74 @@ namespace Lskj.Control
lastNodeIndex = 0;
if (selectRowHandler) lastNodeIndex = this.TreeListObj.GetVisibleIndexByNode(this.TreeListObj.FocusedNode);
this.AdapterObj = adapter;
DataSet dataSet = new DataSet();
//adapter.Fill(dataSet, "SetGridViewDataSource");
// 重连配置
int maxRetryCount = 2; // 次数
int retryDelay = 1000; // 等待时间
for (int i = 0; i < maxRetryCount; i++)
try
{
try
for (int i = 0; i < maxRetryCount; i++)
{
adapter.Fill(dataSet, "SetGridViewDataSource");
break;//连接成功
}
catch (SqlException ex)
{
// 判断是否是连接相关错误
if (IsConnectionError(ex.Number) ||
ex.Message.Contains("物理连接不可用") ||
ex.Message.Contains("传输级错误"))
try
{
if (i < maxRetryCount - 1)
adapter.Fill(dataSet, "SetGridViewDataSource");
break;//连接成功
}
catch (SqlException ex)
{
// 判断是否是连接相关错误
if (IsConnectionError(ex.Number) ||
ex.Message.Contains("物理连接不可用") ||
ex.Message.Contains("传输级错误"))
{
SqlConnection.ClearAllPools();
System.Threading.Thread.Sleep(retryDelay);
continue; // 重试
if (i < maxRetryCount - 1)
{
SqlConnection.ClearAllPools();
System.Threading.Thread.Sleep(retryDelay);
continue; // 重试
}
else
{
// 最后一次重试失败,抛出错误
throw new Exception($"经过 {maxRetryCount} 次重试后仍无法连接到数据库: {ex.Message}", ex);
}
}
else
{
// 最后一次重试失败,抛出错误
throw new Exception($"经过 {maxRetryCount} 次重试后仍无法连接到数据库: {ex.Message}", ex);
// 其他SQL错误直接抛出
throw;
}
}
else
{
// 其他SQL错误直接抛出
throw;
}
}
}
catch
{
dataSet.Dispose();
DisposeDataAdapter(adapter);
throw;
}
DataTable resultTable = dataSet.Tables.Count > 0 ? dataSet.Tables[0] : null;
int rowCount = resultTable == null ? 0 : resultTable.Rows.Count;
if (resultTable != null)
{
dataSet.Tables.Remove(resultTable);
}
dataSet.Dispose();
DbCommandBuilder cb = SqlHelper.dbFactory.CreateCommandBuilder();
cb.DataAdapter = this.AdapterObj;
DisposeAdapterCommandBuilder();
if (previousAdapter != null && !ReferenceEquals(previousAdapter, adapter))
{
DisposeDataAdapter(previousAdapter);
}
this.AdapterObj = adapter;
SetAdapterCommandBuilder(this.AdapterObj);
//SqlCommandBuilder cb = new SqlCommandBuilder(this.AdapterObj);
GetTreeExpanded();
this.gcMain.DataSource = dataSet.Tables[0];
this.gcMain.DataSource = resultTable;
this.SetAutoColumns();
//根据记录展开对应节点
foreach (TreeListNode treeListNode in treeListNodes)
@@ -2193,7 +2215,7 @@ namespace Lskj.Control
{
this.TreeListObj.FocusedNode = lastNode;
}
return dataSet.Tables[0] != null ? dataSet.Tables[0].Rows.Count : 0;
return rowCount;
}
+56 -31
View File
@@ -396,7 +396,8 @@ namespace Lskj.Control
DataRow gridRow = dataRowView != null ? dataRowView.Row : null;
foreach (DataRow item in this.GridRowColorsTable.Rows)
{
string cond = ReplaceHelper.ReplaceRowParam(gridRow, item["condition"] + "");
//string cond = ReplaceHelper.ReplaceRowParam(gridRow, item["condition"] + "");
string cond = ReplaceHelper.ReplaceRowParamEmptyWrapQuote(gridRow, item["condition"] + "");
try
{
if (!string.IsNullOrWhiteSpace(cond) && ReplaceHelper.EvalCond(cond))
@@ -417,7 +418,7 @@ namespace Lskj.Control
if (model.IsStrickOut) fontStyle = fontStyle | FontStyle.Strikeout;
if (model.IsUnderLine) fontStyle = fontStyle | FontStyle.Underline;
e.Appearance.Font = new Font(e.Appearance.Font, fontStyle);
e.Appearance.FontStyleDelta = fontStyle;
}
}
catch (Exception)
@@ -448,7 +449,8 @@ namespace Lskj.Control
DataRow gridRow = dataRowView != null ? dataRowView.Row : null;
foreach (DataRow item in this.GridRowColorsTable.Rows)
{
string cond = ReplaceHelper.ReplaceRowParam(gridRow, item["condition"] + "").ReplaceColumnParam(e.Column.Name, e.Column.Caption, e.CellValue + "");
//string cond = ReplaceHelper.ReplaceRowParam(gridRow, item["condition"] + "").ReplaceColumnParam(e.Column.Name, e.Column.Caption, e.CellValue + "");
string cond = ReplaceHelper.ReplaceRowParamEmptyWrapQuote(gridRow, item["condition"] + "").ReplaceColumnParam(e.Column.Name, e.Column.Caption, e.CellValue + "");
try
{
if (!string.IsNullOrWhiteSpace(cond) && ReplaceHelper.EvalCond(cond))
@@ -469,7 +471,7 @@ namespace Lskj.Control
if (model.IsStrickOut) fontStyle = fontStyle | FontStyle.Strikeout;
if (model.IsUnderLine) fontStyle = fontStyle | FontStyle.Underline;
e.Appearance.Font = new Font(e.Appearance.Font, fontStyle);
e.Appearance.FontStyleDelta = fontStyle;
}
}
catch (Exception)
@@ -2538,60 +2540,83 @@ namespace Lskj.Control
public override int SetGridViewDataSource(DbDataAdapter adapter, bool selectRowHandler = true)
{
if (adapter == null) return 0;
DbDataAdapter previousAdapter = this.AdapterObj;
if (this.ColumnList == null || this.ColumnList.Count == 0)
{
this.TreeListObj.Columns.Clear();
}
lastNodeIndex = 0;
if (selectRowHandler) lastNodeIndex = this.TreeListObj.GetVisibleIndexByNode(this.TreeListObj.FocusedNode);
this.AdapterObj = adapter;
DataSet dataSet = new DataSet();
//adapter.Fill(dataSet, "SetGridViewDataSource");
// 重连配置
int maxRetryCount = 2; // 次数
int retryDelay = 1000; // 等待时间
for (int i = 0; i < maxRetryCount; i++)
try
{
try
for (int i = 0; i < maxRetryCount; i++)
{
adapter.Fill(dataSet, "SetGridViewDataSource");
break;//连接成功
}
catch (SqlException ex)
{
// 判断是否是连接相关错误
if (IsConnectionError(ex.Number) ||
ex.Message.Contains("物理连接不可用") ||
ex.Message.Contains("传输级错误"))
try
{
if (i < maxRetryCount - 1)
adapter.Fill(dataSet, "SetGridViewDataSource");
break;//连接成功
}
catch (SqlException ex)
{
// 判断是否是连接相关错误
if (IsConnectionError(ex.Number) ||
ex.Message.Contains("物理连接不可用") ||
ex.Message.Contains("传输级错误"))
{
SqlConnection.ClearAllPools();
System.Threading.Thread.Sleep(retryDelay);
continue; // 重试
if (i < maxRetryCount - 1)
{
SqlConnection.ClearAllPools();
System.Threading.Thread.Sleep(retryDelay);
continue; // 重试
}
else
{
// 最后一次重试失败,抛出错误
throw new Exception($"经过 {maxRetryCount} 次重试后仍无法连接到数据库: {ex.Message}", ex);
}
}
else
{
// 最后一次重试失败,抛出错误
throw new Exception($"经过 {maxRetryCount} 次重试后仍无法连接到数据库: {ex.Message}", ex);
// 其他SQL错误直接抛出
throw;
}
}
else
{
// 其他SQL错误直接抛出
throw;
}
}
}
DbCommandBuilder cb = SqlHelper.dbFactory.CreateCommandBuilder();
cb.DataAdapter = this.AdapterObj;
catch
{
dataSet.Dispose();
DisposeDataAdapter(adapter);
throw;
}
DataTable resultTable = dataSet.Tables.Count > 0 ? dataSet.Tables[0] : null;
int rowCount = resultTable == null ? 0 : resultTable.Rows.Count;
if (resultTable != null)
{
dataSet.Tables.Remove(resultTable);
}
dataSet.Dispose();
DisposeAdapterCommandBuilder();
if (previousAdapter != null && !ReferenceEquals(previousAdapter, adapter))
{
DisposeDataAdapter(previousAdapter);
}
this.AdapterObj = adapter;
SetAdapterCommandBuilder(this.AdapterObj);
//SqlCommandBuilder cb = new SqlCommandBuilder(this.AdapterObj);
GetTreeExpanded();
this.TreeListObj.DataSource = dataSet.Tables[0];
this.TreeListObj.DataSource = resultTable;
this.AdjustIndicatorWidthSmart();
this.SetAutoColumns();
@@ -2607,7 +2632,7 @@ namespace Lskj.Control
{
this.TreeListObj.CollapseAll();
}
return dataSet.Tables[0] != null ? dataSet.Tables[0].Rows.Count : 0;
return rowCount;
}
+13
View File
@@ -381,6 +381,15 @@ namespace Lskj.Core
{
return Internet ? AESUtil.Decrypt(Connection3) : AESUtil.Decrypt(Connection4);
}
private static string EnableSqlServerIdleConnectionResilience(string connectionString)
{
SqlConnectionStringBuilder builder =
new SqlConnectionStringBuilder(connectionString);
builder["ConnectRetryCount"] = 1;
return builder.ConnectionString;
}
/// <summary>
/// <para>说明:创建数据库连接</para>
/// <para>创建人:龚宇超</para>
@@ -420,6 +429,10 @@ namespace Lskj.Core
providerName = "Dm";
SqlHelper.ConnectionType = ConnectionType.DmServer;
}
if (connectionType == ConnectionType.SqlServer)
{
connStr = EnableSqlServerIdleConnectionResilience(connStr);
}
SqlHelper.dbFactory = DbProviderFactories.GetFactory(providerName);
if (SqlHelper._connection != null)
{
+263 -113
View File
@@ -11,6 +11,9 @@ using DevExpress.LookAndFeel;
using DevExpress.XtraEditors;
using DevExpress.XtraTab;
using DevExpress.XtraTab.ViewInfo;
using DevExpress.XtraTreeList;
using DevExpress.XtraTreeList.Columns;
using DevExpress.XtraTreeList.Nodes;
using Lskj.Business;
using Lskj.Business.Impl;
using Lskj.Control;
@@ -129,12 +132,20 @@ namespace Lskj.Main.Control
/// 缓存分组控件
/// </summary>
private Dictionary<string, Panel> _groupItems = new Dictionary<string, Panel>();
private TreeView _leftGroupTreeView;
private ImageList _leftGroupTreeIcons;
private TreeList _leftGroupTreeView;
private TreeListNode _leftGroupHotNode;
private TreeListNode _leftGroupSelectedNode;
private ImageList _leftGroupTreeImageList;
private Panel _leftGroupSeparator;
private const string LeftGroupTreeNodeTypeMenu = "menu";
private const string LeftGroupTreeNodeTypeGroup = "group";
private const int GroupControlTopPadding = 8;
private static readonly Color LeftGroupTreeBackgroundColor = Color.FromArgb(39, 45, 81);
private static readonly Color LeftGroupTreeActiveColor = Color.FromArgb(52, 142, 216);
private static readonly Color LeftGroupTreeHoverColor = Color.FromArgb(79, 101, 132);
private static readonly Color LeftGroupTreeTextColor = Color.FromArgb(235, 255, 255, 255);
private static readonly Color LeftGroupTreeArrowColor = Color.FromArgb(173, 255, 255, 255);
/// <summary>
/// 缓存右上菜单控件
/// </summary>
@@ -741,32 +752,198 @@ namespace Lskj.Main.Control
return groupCaption.Length > 2 ? groupCaption.Remove(0, 2) : groupCaption;
}
private TreeView GetLeftGroupTreeView()
private TreeList GetLeftGroupTreeView()
{
if (_leftGroupTreeView != null) return _leftGroupTreeView;
_leftGroupTreeView = new TreeView
_leftGroupTreeView = new TreeList
{
Dock = DockStyle.Fill,
BorderStyle = BorderStyle.None,
BackColor = Color.FromArgb(250, 253, 255),
DrawMode = TreeViewDrawMode.Normal,
Font = new Font("微软雅黑", 10F),
ForeColor = Color.FromArgb(38, 73, 98),
HideSelection = false,
Indent = 20,
ImageList = GetLeftGroupTreeIcons(),
ItemHeight = 29,
LineColor = Color.FromArgb(198, 214, 226),
ShowLines = false,
ShowPlusMinus = false,
ShowRootLines = false
BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder,
RowHeight = ScaleLeftGroupTreeMetric(44),
TreeLevelWidth = ScaleLeftGroupTreeMetric(18)
};
_leftGroupTreeView.NodeMouseClick += OnLeftGroupTreeViewNodeMouseClick;
TreeListColumn textColumn = new TreeListColumn
{
Caption = "功能导航",
FieldName = "nodetext",
Visible = true,
VisibleIndex = 0
};
textColumn.OptionsColumn.AllowEdit = false;
_leftGroupTreeView.Columns.Add(textColumn);
_leftGroupTreeView.OptionsBehavior.Editable = false;
_leftGroupTreeView.OptionsBehavior.AutoNodeHeight = false;
_leftGroupTreeView.OptionsSelection.EnableAppearanceFocusedCell = false;
_leftGroupTreeView.OptionsSelection.EnableAppearanceFocusedRow = true;
_leftGroupTreeView.OptionsSelection.MultiSelect = true;
_leftGroupTreeView.OptionsView.AutoWidth = true;
_leftGroupTreeView.OptionsView.ExpandButtonCentered = true;
_leftGroupTreeView.OptionsView.ShowButtons = false;
_leftGroupTreeView.OptionsView.ShowColumns = false;
_leftGroupTreeView.OptionsView.ShowFocusedFrame = false;
_leftGroupTreeView.OptionsView.ShowHorzLines = false;
_leftGroupTreeView.OptionsView.ShowIndentAsRowStyle = true;
_leftGroupTreeView.OptionsView.ShowIndicator = false;
_leftGroupTreeView.OptionsView.ShowVertLines = false;
_leftGroupTreeView.Appearance.Empty.BackColor = LeftGroupTreeBackgroundColor;
_leftGroupTreeView.Appearance.Empty.Options.UseBackColor = true;
_leftGroupTreeView.Appearance.Row.BackColor = LeftGroupTreeBackgroundColor;
_leftGroupTreeView.Appearance.Row.ForeColor = LeftGroupTreeTextColor;
_leftGroupTreeView.Appearance.Row.Font = new Font("微软雅黑", 10F);
_leftGroupTreeView.Appearance.Row.Options.UseBackColor = true;
_leftGroupTreeView.Appearance.Row.Options.UseForeColor = true;
_leftGroupTreeView.Appearance.Row.Options.UseFont = true;
_leftGroupTreeView.Appearance.FocusedRow.BackColor = LeftGroupTreeActiveColor;
_leftGroupTreeView.Appearance.FocusedRow.ForeColor = Color.White;
_leftGroupTreeView.Appearance.FocusedRow.Options.UseBackColor = true;
_leftGroupTreeView.Appearance.FocusedRow.Options.UseForeColor = true;
_leftGroupTreeView.Appearance.HideSelectionRow.BackColor = LeftGroupTreeActiveColor;
_leftGroupTreeView.Appearance.HideSelectionRow.ForeColor = Color.White;
_leftGroupTreeView.Appearance.HideSelectionRow.Options.UseBackColor = true;
_leftGroupTreeView.Appearance.HideSelectionRow.Options.UseForeColor = true;
_leftGroupTreeView.Appearance.SelectedRow.BackColor = LeftGroupTreeHoverColor;
_leftGroupTreeView.Appearance.SelectedRow.ForeColor = Color.White;
_leftGroupTreeView.Appearance.SelectedRow.Options.UseBackColor = true;
_leftGroupTreeView.Appearance.SelectedRow.Options.UseForeColor = true;
_leftGroupTreeView.SelectImageList = GetLeftGroupTreeImageList();
_leftGroupTreeView.AfterCollapse += OnLeftGroupTreeListAfterExpandOrCollapse;
_leftGroupTreeView.AfterExpand += OnLeftGroupTreeListAfterExpandOrCollapse;
_leftGroupTreeView.CalcNodeHeight += OnLeftGroupTreeListCalcNodeHeight;
_leftGroupTreeView.MouseClick += OnLeftGroupTreeListMouseClick;
_leftGroupTreeView.MouseLeave += OnLeftGroupTreeListMouseLeave;
_leftGroupTreeView.MouseMove += OnLeftGroupTreeListMouseMove;
return _leftGroupTreeView;
}
private ImageList GetLeftGroupTreeImageList()
{
if (_leftGroupTreeImageList != null) return _leftGroupTreeImageList;
_leftGroupTreeImageList = new ImageList
{
ColorDepth = ColorDepth.Depth32Bit,
ImageSize = new Size(ScaleLeftGroupTreeMetric(14), ScaleLeftGroupTreeMetric(14)),
TransparentColor = Color.Transparent
};
_leftGroupTreeImageList.Images.Add(CreateLeftGroupTreeArrowImage(false, LeftGroupTreeArrowColor));
_leftGroupTreeImageList.Images.Add(CreateLeftGroupTreeArrowImage(true, LeftGroupTreeArrowColor));
_leftGroupTreeImageList.Images.Add(CreateLeftGroupTreeArrowImage(false, Color.White));
_leftGroupTreeImageList.Images.Add(CreateLeftGroupTreeArrowImage(true, Color.White));
return _leftGroupTreeImageList;
}
private Bitmap CreateLeftGroupTreeArrowImage(bool expanded, Color color)
{
Size imageSize = _leftGroupTreeImageList.ImageSize;
Bitmap bitmap = new Bitmap(imageSize.Width, imageSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.Transparent);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
int centerX = imageSize.Width / 2;
int centerY = imageSize.Height / 2;
Point[] points;
if (expanded)
{
int width = ScaleLeftGroupTreeMetric(8);
int height = ScaleLeftGroupTreeMetric(6);
points = new[]
{
new Point(centerX - width / 2, centerY - height / 2),
new Point(centerX + width / 2, centerY - height / 2),
new Point(centerX, centerY + height / 2)
};
}
else
{
int width = ScaleLeftGroupTreeMetric(6);
int height = ScaleLeftGroupTreeMetric(8);
points = new[]
{
new Point(centerX - width / 2, centerY - height / 2),
new Point(centerX - width / 2, centerY + height / 2),
new Point(centerX + width / 2, centerY)
};
}
using (SolidBrush arrowBrush = new SolidBrush(color))
{
graphics.FillPolygon(arrowBrush, points);
}
}
return bitmap;
}
private int ScaleLeftGroupTreeMetric(int value)
{
float dpi = DpiX > 0 ? DpiX : 96F;
return Math.Max(1, Convert.ToInt32(value * dpi / 96F));
}
private void OnLeftGroupTreeListAfterExpandOrCollapse(object sender, NodeEventArgs e)
{
UpdateLeftGroupTreeNodeArrow(e == null ? null : e.Node);
}
private void OnLeftGroupTreeListCalcNodeHeight(object sender, CalcNodeHeightEventArgs e)
{
if (e == null || e.Node == null) return;
e.NodeHeight = ScaleLeftGroupTreeMetric(e.Node.Level == 0 ? 44 : 36);
}
private void UpdateLeftGroupTreeNodeArrow(TreeListNode node)
{
if (node == null || node.Level != 0) return;
node.ImageIndex = node.Expanded ? 1 : 0;
node.SelectImageIndex = node.Expanded ? 3 : 2;
}
private void OnLeftGroupTreeListMouseMove(object sender, MouseEventArgs e)
{
TreeList treeList = sender as TreeList;
if (treeList == null) return;
TreeListHitInfo hitInfo = treeList.CalcHitInfo(e.Location);
TreeListNode hotNode = hitInfo == null ? null : hitInfo.Node;
if (hotNode == _leftGroupHotNode) return;
if (_leftGroupHotNode != null && _leftGroupHotNode != _leftGroupSelectedNode)
{
_leftGroupHotNode.Selected = false;
}
_leftGroupHotNode = hotNode;
if (_leftGroupHotNode != null && _leftGroupHotNode != _leftGroupSelectedNode)
{
_leftGroupHotNode.Selected = true;
}
treeList.Invalidate();
}
private void OnLeftGroupTreeListMouseLeave(object sender, EventArgs e)
{
TreeList treeList = sender as TreeList;
if (treeList == null) return;
if (_leftGroupHotNode != null && _leftGroupHotNode != _leftGroupSelectedNode)
{
_leftGroupHotNode.Selected = false;
}
_leftGroupHotNode = null;
if (_leftGroupSelectedNode != null)
{
_leftGroupSelectedNode.Selected = true;
treeList.FocusedNode = _leftGroupSelectedNode;
}
treeList.Invalidate();
}
private Panel GetLeftGroupSeparator()
{
if (_leftGroupSeparator != null) return _leftGroupSeparator;
@@ -823,118 +1000,83 @@ namespace Lskj.Main.Control
}
}
private ImageList GetLeftGroupTreeIcons()
{
if (_leftGroupTreeIcons != null) return _leftGroupTreeIcons;
_leftGroupTreeIcons = new ImageList();
_leftGroupTreeIcons.ColorDepth = ColorDepth.Depth32Bit;
_leftGroupTreeIcons.ImageSize = new Size(18, 18);
string iconPath = PubUtil.MainTreeviewImagePath;
if (Directory.Exists(iconPath))
{
string[] files = Directory.GetFiles(iconPath, "*.png").OrderBy(n => n).ToArray();
foreach (string file in files)
{
using (Image image = ImageHelper.ReadImage(file))
{
if (image != null)
{
_leftGroupTreeIcons.Images.Add(new Bitmap(image));
}
}
}
}
if (_leftGroupTreeIcons.Images.Count == 0)
{
_leftGroupTreeIcons.Images.Add(new Bitmap(18, 18));
}
return _leftGroupTreeIcons;
}
private void BindLeftGroupTreeView(DataTable treeTable, string defaultNode)
{
TreeView treeView = GetLeftGroupTreeView();
treeView.BeginUpdate();
treeView.Nodes.Clear();
Dictionary<string, TreeNode> nodeMap = new Dictionary<string, TreeNode>();
List<DataRow> rows = treeTable.Rows.Cast<DataRow>()
.OrderBy(n => Convert.ToInt32(n["sortno"]))
.ToList();
int iconCount = GetLeftGroupTreeIcons().Images.Count;
foreach (DataRow row in rows)
TreeList treeList = GetLeftGroupTreeView();
treeList.BeginUpdate();
try
{
TreeNode node = new TreeNode(row["nodetext"] + "");
int iconIndex = 0;
int.TryParse(row["iconindex"] + "", out iconIndex);
iconIndex = Math.Abs(iconIndex) % iconCount;
node.ImageIndex = iconIndex;
node.SelectedImageIndex = iconIndex;
node.Name = row["nodekey"] + "";
node.Tag = row;
nodeMap[node.Name] = node;
}
treeList.Nodes.Clear();
_leftGroupHotNode = null;
_leftGroupSelectedNode = null;
foreach (DataRow row in rows)
{
string nodeKey = row["nodekey"] + "";
string parentKey = row["parentkey"] + "";
TreeNode node = nodeMap[nodeKey];
if (!string.IsNullOrEmpty(parentKey) && nodeMap.ContainsKey(parentKey))
Dictionary<string, TreeListNode> nodeMap = new Dictionary<string, TreeListNode>();
List<DataRow> rows = treeTable.Rows.Cast<DataRow>()
.OrderBy(n => Convert.ToInt32(n["sortno"]))
.ToList();
foreach (DataRow row in rows)
{
nodeMap[parentKey].Nodes.Add(node);
string nodeKey = row["nodekey"] + "";
string parentKey = row["parentkey"] + "";
TreeListNode parentNode = !string.IsNullOrEmpty(parentKey) && nodeMap.ContainsKey(parentKey)
? nodeMap[parentKey]
: null;
TreeListNode node = treeList.AppendNode(new object[] { row["nodetext"] + "" }, parentNode);
node.Tag = row;
if (parentNode == null)
{
UpdateLeftGroupTreeNodeArrow(node);
}
else
{
node.ImageIndex = -1;
node.SelectImageIndex = -1;
}
nodeMap[nodeKey] = node;
}
else
treeList.CollapseAll();
if (!string.IsNullOrEmpty(defaultNode) && nodeMap.ContainsKey(defaultNode))
{
treeView.Nodes.Add(node);
_leftGroupSelectedNode = nodeMap[defaultNode];
_leftGroupSelectedNode.Selected = true;
treeList.FocusedNode = _leftGroupSelectedNode;
}
}
treeView.CollapseAll();
FocusLeftGroupTreeNode(defaultNode);
treeView.EndUpdate();
}
private void FocusLeftGroupTreeNode(string nodeKey)
{
if (_leftGroupTreeView == null || string.IsNullOrEmpty(nodeKey)) return;
TreeNode node = FindLeftGroupTreeNode(_leftGroupTreeView.Nodes, nodeKey);
if (node == null) return;
_leftGroupTreeView.SelectedNode = node;
}
private TreeNode FindLeftGroupTreeNode(TreeNodeCollection nodes, string nodeKey)
{
foreach (TreeNode node in nodes)
finally
{
if (node.Name.Equals(nodeKey)) return node;
TreeNode childNode = FindLeftGroupTreeNode(node.Nodes, nodeKey);
if (childNode != null) return childNode;
treeList.EndUpdate();
}
return null;
}
private void OnLeftGroupTreeViewNodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
private void OnLeftGroupTreeListMouseClick(object sender, MouseEventArgs e)
{
try
{
TreeView treeView = sender as TreeView;
if (treeView == null || e.Node == null || e.Button != MouseButtons.Left) return;
TreeList treeList = sender as TreeList;
if (treeList == null || e.Button != MouseButtons.Left) return;
treeView.SelectedNode = e.Node;
if (e.Node.Nodes.Count > 0)
TreeListHitInfo hitInfo = treeList.CalcHitInfo(e.Location);
if (hitInfo == null || hitInfo.Node == null) return;
if (_leftGroupHotNode != null && _leftGroupHotNode != hitInfo.Node)
{
e.Node.Toggle();
_leftGroupHotNode.Selected = false;
}
OnLeftGroupTreeRowClick(e.Node.Tag as DataRow);
if (_leftGroupSelectedNode != null && _leftGroupSelectedNode != hitInfo.Node)
{
_leftGroupSelectedNode.Selected = false;
}
_leftGroupSelectedNode = hitInfo.Node;
_leftGroupHotNode = hitInfo.Node;
_leftGroupSelectedNode.Selected = true;
treeList.FocusedNode = _leftGroupSelectedNode;
treeList.Invalidate();
if (hitInfo.Node.HasChildren && hitInfo.HitInfoType != HitInfoType.Button)
{
hitInfo.Node.Expanded = !hitInfo.Node.Expanded;
}
OnLeftGroupTreeRowClick(hitInfo.Node.Tag as DataRow);
}
catch (Exception ex)
{
@@ -950,11 +1092,11 @@ namespace Lskj.Main.Control
string expandNode = GetLeftGroupTreeDefaultNode(treeTable, defaultParentMenu);
this.pl_center_left.Controls.Clear();
this.pl_center_left.Padding = Padding.Empty;
this.pl_center_left.BackColor = Color.FromArgb(250, 253, 255);
this.pl_center_left.BackColor = LeftGroupTreeBackgroundColor;
this.pl_center_main.Padding = Padding.Empty;
this.pl_center_main.BackColor = Color.FromArgb(240, 240, 240);
SetLeftGroupSeparatorVisible(true);
TreeView treeView = GetLeftGroupTreeView();
TreeList treeView = GetLeftGroupTreeView();
this.pl_center_left.Controls.Add(treeView);
BindLeftGroupTreeView(treeTable, expandNode);
@@ -4836,6 +4978,14 @@ namespace Lskj.Main.Control
tabPage.Controls.Add(this.FirstMain);
this.webBrowser.Show();
this.webBrowser.BringToFront();
// 等待页签和FirstMain完成布局后,再同步CEF原生子窗口的位置和尺寸。
this.webBrowser.BeginInvoke(new MethodInvoker(delegate
{
if (!this.webBrowser.IsDisposed && !this.webBrowser.Disposing)
{
this.webBrowser.SyncBrowserBounds();
}
}));
//if (this.webBrowser.cefBrowserSettings != null) this.webBrowser.cefBrowserSettings.Reload();
int MemuEventType = 1;
//左侧二级目录菜单设置为单击切换模式
+3
View File
@@ -681,6 +681,9 @@ namespace Lskj.Main
ERPInfo.Instance.LoginAccount = LoginAccount;
ERPInfo.Instance.InPassWord = password;
ERPInfo.Instance.PrimitiveBrowser = SystemInfo.Instance.PrimitiveBrowser;
if (BaseImpl.HasExistsColumn("p_formmenuconfigtab", "SingleOpenMode")) ERPInfo.Instance.SingleOpenMode = true;
DBConfig.Instance.LoginName = isLoginByAd ? lueUserName.Text.Trim() : lueUserName.Text;
DBConfig.Instance.NoticeUserID = userId;
DBConfig.Instance.NoticeUserName = userName;
+12 -3
View File
@@ -428,10 +428,19 @@ namespace Lskj.Main
ERPInfo.Instance.UserId = userId;
ERPInfo.Instance.UserName = userName;
this.Close();
IniHelper.Write("isRefresh", "1");
Manager.ReStartMain(true);
//this.DialogResult = System.Windows.Forms.DialogResult.OK;
if (Manager.ExternalMainShell == null)
{
this.Close();
Manager.ReStartMain(true);
}
else
{
// WPF 已接管主窗口生命周期:只返回切换成功,
// 由 WPF 在当前模态窗体关闭后重建主框架。
this.DialogResult = System.Windows.Forms.DialogResult.OK;
this.Close();
}
break;
case 1: // 密码不正确
MessageUtil.Show(ResourceKeys.NameOrPasswordError);
+4 -1
View File
@@ -73,6 +73,9 @@
<Reference Include="DevExpress.XtraGrid.v15.2, Version=15.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="DevExpress.XtraTreeList.v15.2, Version=15.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="libzkfpcsharp, Version=1.0.0.1, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\引用DLL\libzkfpcsharp.dll</HintPath>
@@ -584,4 +587,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>
+159 -21
View File
@@ -63,6 +63,9 @@ namespace Lskj.Main.Model
private static CancellationTokenSource _sessionMonitorCancellation;
private static readonly List<Thread> SessionMonitorThreads =
new List<Thread>();
private static readonly object OpeningModuleSync = new object();
private static readonly HashSet<string> OpeningModuleKeys =
new HashSet<string>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// 默认下载地址
/// </summary>
@@ -285,6 +288,8 @@ namespace Lskj.Main.Model
/// Params">The URL parameters.</param>
public static void OpenModule(string menuId, string menuName, string dllName, string modelFlag, string urlParams)
{
string openingModuleKey = null;
bool ownsOpeningGate = false;
try
{
// 验证参数
@@ -293,6 +298,14 @@ namespace Lskj.Main.Model
MessageUtil.Show(ResourceKeys.NotFoundMenu);
return;
}
openingModuleKey = BuildOpeningModuleKey(menuId, dllName, modelFlag);
ownsOpeningGate = TryBeginOpenModule(openingModuleKey);
if (!ownsOpeningGate)
{
// 列数据源初始化期间可能会处理 WinForms 消息。
// 快速重复点击必须在页签注册前就被拦截,否则会构建多份重型控件树。
return;
}
// 验证权限
int purview = MainImpl.GetUserPurviewsByMenuId(menuId);
if (purview == 0)
@@ -302,7 +315,12 @@ namespace Lskj.Main.Model
}
//验证是否设置不能打开多个相同模块
bool SingleOpenMode = MainImpl.GetOpenRestrictions(menuId);
bool openInBsMode = MainImpl.GetBsOpenMode(menuId) == 1;
string configuredDllName = dllName;
if (openInBsMode)
{
dllName = "Lskj.PubBrower2.dll";
}
LogUtil.WriteDebug(modelFlag.ToString(), "操作模块", menuName, menuName, menuId.ToString());
DllModule module = new DllModule
@@ -320,6 +338,21 @@ namespace Lskj.Main.Model
urlParams,
menuId
};
if (openInBsMode)
{
string bsUrl = BuildBsMenuUrl(configuredDllName, modelFlag);
args = new string[]
{
menuName,
ERPInfo.Instance.UserId,
ERPInfo.Instance.UserName,
purview + "",
"",
menuId,
"",
bsUrl
};
}
dllName = MainImpl.GetDefaultValue(dllName);
if (SystemInfo.Instance.SoftOpenMode || SingleOpenMode)
{
@@ -416,8 +449,62 @@ namespace Lskj.Main.Model
string Message = ErrorMessage.PromptErrorMessage(ex);
MessageUtil.Show(Message, ex.Message);
}
finally
{
if (ownsOpeningGate)
{
EndOpenModule(openingModuleKey);
}
}
}
private static string BuildBsMenuUrl(string dllName, string dllCoid)
{
return string.Format(
"pages/app/app.html?xtype={0}&dllcoid={1}&username={2}&password={3}",
dllName,
dllCoid,
ERPInfo.Instance.UserName,
ERPInfo.Instance.Password);
}
private static string BuildOpeningModuleKey(
string menuId,
string dllName,
string modelFlag)
{
return string.Join(
"|",
new[]
{
(menuId ?? string.Empty).Trim(),
(dllName ?? string.Empty).Trim(),
(modelFlag ?? string.Empty).Trim()
});
}
private static bool TryBeginOpenModule(string openingModuleKey)
{
lock (OpeningModuleSync)
{
if (OpeningModuleKeys.Contains(openingModuleKey))
{
return false;
}
OpeningModuleKeys.Add(openingModuleKey);
return true;
}
}
private static void EndOpenModule(string openingModuleKey)
{
lock (OpeningModuleSync)
{
OpeningModuleKeys.Remove(openingModuleKey);
}
}
/// <summary>
/// <para>说明:添加模块到tab中</para>
/// <para>创建人:龚宇超</para>
@@ -432,6 +519,10 @@ namespace Lskj.Main.Model
/// <param name="args">The arguments.</param>
public static void AddModuleToTab(DllModule module, string[] args)
{
string guid = null;
XtraTabPage tp = null;
Form form = null;
bool trackDogVerifiedModule = false;
try
{
bool isQuickLoad = (args[5] + "").Equals(SystemInfo.Instance.QuickMenuId);
@@ -441,8 +532,6 @@ namespace Lskj.Main.Model
// //QuickMenuForm.BringToFront();
// return;
//}
string guid = Guid.NewGuid().ToString();
XtraTabPage tp = new XtraTabPage();
if (SystemInfo.Instance.IsDogVerify)
{
if (!CheckPrivateTable())
@@ -497,7 +586,7 @@ namespace Lskj.Main.Model
}
else
{
StaticControl.DogVerifyModuleForms.Add(tp);
trackDogVerifiedModule = true;
}
}
else
@@ -532,12 +621,21 @@ namespace Lskj.Main.Model
return;
}
guid = Guid.NewGuid().ToString();
tp = new XtraTabPage();
if (trackDogVerifiedModule)
{
StaticControl.DogVerifyModuleForms.Add(tp);
}
ERPInfo.Instance.selectFormModleId = module.Id;
// 每次打开顶层模块时重新记录本次初始化使用的表、字段参数。
InitialParamCache.Clear();
IForm iform = FormHelper.LoadDllForm(module.DllName, args);
// 菜单打开的模块默认最大化,界面FormState设置为Normal模式,否则会出现界面不是全屏,会显示默认阴影界面
//iform.SubForm.WindowState = _frmMain.WindowState;
iform.SubForm.WindowState = FormWindowState.Normal; ;
Form form = iform.SubForm; // 表示组成应用程序的用户界面的窗口或对话框。
form = iform.SubForm; // 表示组成应用程序的用户界面的窗口或对话框。
form.Tag = guid;
// 这个必须有不然会提示:"不能向tabControl中添加顶级控件"
form.TopLevel = isQuickLoad;
@@ -571,22 +669,23 @@ namespace Lskj.Main.Model
form.Show();
if (args != null && !string.IsNullOrEmpty(args[4] + ""))
{
ModuleModel moduleModel = new ModuleModel(MainImpl.GetSystemdllTab(args[4] + ""));
if (!string.IsNullOrEmpty(moduleModel.SearchCondFormModuleCode))
{
ModuleConditionsPanelEx mcpex = new ModuleConditionsPanelEx();
mcpex.InitializeControl(new ModuleModel(MainImpl.GetSystemdllTab(moduleModel.SearchCondFormModuleCode)), null, null, true);
if (StaticControl.ConditionsPanelDic.ContainsKey(args[4] + ""))
{
StaticControl.ConditionsPanelDic[args[4] + ""].Dispose();
StaticControl.ConditionsPanelDic[args[4] + ""] = mcpex;
}
else
{
StaticControl.ConditionsPanelDic.Add(args[4] + "", mcpex);
}
DialogResult dialogResult = mcpex.ShowDialog();
}
//2026-08-08 pz说把SearchCondFormModuleCode判断去掉,不要这个功能
//ModuleModel moduleModel = new ModuleModel(MainImpl.GetSystemdllTab(args[4] + ""));
//if (!string.IsNullOrEmpty(moduleModel.SearchCondFormModuleCode))
//{
// ModuleConditionsPanelEx mcpex = new ModuleConditionsPanelEx();
// mcpex.InitializeControl(new ModuleModel(MainImpl.GetSystemdllTab(moduleModel.SearchCondFormModuleCode)), null, null, true);
// if (StaticControl.ConditionsPanelDic.ContainsKey(args[4] + ""))
// {
// StaticControl.ConditionsPanelDic[args[4] + ""].Dispose();
// StaticControl.ConditionsPanelDic[args[4] + ""] = mcpex;
// }
// else
// {
// StaticControl.ConditionsPanelDic.Add(args[4] + "", mcpex);
// }
// DialogResult dialogResult = mcpex.ShowDialog();
//}
}
TabMain.TabPages.Add(tp);
@@ -598,6 +697,7 @@ namespace Lskj.Main.Model
}
catch (Exception ex)
{
CleanupFailedModuleOpen(guid, tp, form);
string Message = ErrorMessage.PromptErrorMessage(ex);
MessageUtil.Show(ex.InnerException != null ? ex.InnerException.Message : ex.Message);
LogHelper.Instance.WriteError(ex);
@@ -605,6 +705,44 @@ namespace Lskj.Main.Model
}
}
private static void CleanupFailedModuleOpen(
string guid,
XtraTabPage tabPage,
Form form)
{
try
{
if (!string.IsNullOrWhiteSpace(guid))
{
ModuleForms.Remove(guid);
}
if (tabPage != null)
{
StaticControl.DogVerifyModuleForms.Remove(tabPage);
if (TabMain != null && TabMain.TabPages.Contains(tabPage))
{
TabMain.TabPages.Remove(tabPage);
}
}
if (form != null && !form.IsDisposed)
{
form.Close();
form.Dispose();
}
if (tabPage != null && !tabPage.IsDisposed)
{
tabPage.Dispose();
}
}
catch (Exception cleanupException)
{
LogHelper.Instance.WriteError(cleanupException);
}
}
/// <summary>
/// 快速菜单关闭时,清除记录
/// </summary>
+36 -9
View File
@@ -185,7 +185,18 @@ namespace Lskj.Main
{
if (_cefInitialized)
{
CefRuntime.Shutdown();
bool browsersClosed =
CefBrowserRuntimeLifetime.CloseAllBrowsersAndWait(5000);
if (browsersClosed)
{
CefRuntime.Shutdown();
}
else
{
LogHelper.Instance.WriteLog(
"[CEF_LIFECYCLE] CefRuntime.Shutdown skipped " +
"because browser close callbacks are incomplete.");
}
_cefInitialized = false;
}
_mainProcessInitialized = false;
@@ -234,14 +245,18 @@ namespace Lskj.Main
commandLine.AppendSwitch("ignore-certificate-errors", "1");
commandLine.AppendSwitch("allow-running-insecure-content", "1");
//如果注册表中CefMultithreading不为1,并且根目录中不存在BrowserMultithreading.txt"文件,就是单线程模式
//只要有一个条件满足就是多线程模式
if (!BrowserMultithreading() && !File.Exists(PubUtil.AbsolutelyPath + "BrowserMultithreading.txt"))
{
commandLine.AppendSwitch("single-process", "1");//单线程模式,默认开启。(开启单线程模式后会影响浏览器的性能)
}
// CEF's single-process switch is unsupported and is unrelated
// to MultiThreadedMessageLoop. Keep renderer and utility work
// in CEF's normal child processes, as in the official sample.
commandLine.AppendSwitch("no-proxy-server");
// CEF 87 can terminate the host with STATUS_WX86_BREAKPOINT
// while creating the first browser on machines whose GPU
// driver does not support the legacy compositor path. Keep
// software rendering enabled, but bypass GPU initialization.
commandLine.AppendSwitch("disable-gpu");
commandLine.AppendSwitch("disable-gpu-compositing");
commandLine.AppendSwitch("disable-features", "VizDisplayCompositor");
commandLine.AppendSwitch("ppapi-flash-version", "99.0.0.999");
commandLine.AppendSwitch("ppapi-flash-path", @"PepperFlash\pepflashplayer.dll");
//}
@@ -284,8 +299,20 @@ namespace Lskj.Main
/// <param name="e">The <see cref="ThreadExceptionEventArgs"/> instance containing the event data.</param>
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine(e.ExceptionObject.ToString());
MessageUtil.Show(e.ExceptionObject.ToString());
Exception exception = e == null
? null
: e.ExceptionObject as Exception;
if (exception == null)
{
exception = new Exception(
e == null || e.ExceptionObject == null
? "AppDomain 未处理异常对象为空。"
: e.ExceptionObject.ToString());
}
Console.WriteLine(exception);
LogHelper.Instance.WriteError(exception);
MessageUtil.Show(exception);
}
+5 -1
View File
@@ -108,7 +108,11 @@ namespace Lskj.Model
/// 是否阻止回车事件
/// </summary>
public bool IsExecute = false;
/// <summary>
/// 是否根据模块id判断是否设置不能同时打开多个相同模块
/// </summary>
public bool SingleOpenMode = false;
/// <summary>
/// 登录IP
+10 -1
View File
@@ -1058,7 +1058,14 @@ namespace Lskj.Model
/// 模块弹出框宽度
/// </summary>
public int ModuleFrameWidth;
/// <summary>
/// 下方高
/// </summary>
public int BottomHeight;
/// <summary>
/// 取消复制新增时触发关联(默认触发,设置为1不触发。ModulePanelEx的复制新增按钮)
/// </summary>
public bool CancelCopyAssociation;
#endregion
/// <summary>
@@ -1254,6 +1261,8 @@ namespace Lskj.Model
this.ModuleFrameHeight = rowItem.Table.Columns.Contains("ModuleFrameHeight") && !string.IsNullOrEmpty(rowItem["ModuleFrameHeight"] + "") ? Convert.ToInt32(rowItem["ModuleFrameHeight"] + "") : 0;
this.ModuleFrameWidth = rowItem.Table.Columns.Contains("ModuleFrameWidth") && !string.IsNullOrEmpty(rowItem["ModuleFrameWidth"] + "") ? Convert.ToInt32(rowItem["ModuleFrameWidth"] + "") : 0;
this.BottomHeight = rowItem.Table.Columns.Contains("BottomHeight") && !string.IsNullOrEmpty(rowItem["BottomHeight"] + "") ? Convert.ToInt32(rowItem["BottomHeight"] + "") : 0;
this.CancelCopyAssociation = rowItem.Table.Columns.Contains("CancelCopyAssociation") ? !"1".Equals(rowItem["CancelCopyAssociation"] + "") : true;
}
}
}
+12 -8
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -428,7 +432,7 @@
this.btnSave.Name = "btnSave";
this.btnSave.Size = new System.Drawing.Size(67, 23);
this.btnSave.TabIndex = 17;
this.btnSave.Text = "保存(&S)";
this.btnSave.Text = "保存(S)";
this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
//
// dpb_Tools
@@ -477,7 +481,7 @@
this.btnSpare.Name = "btnSpare";
this.btnSpare.Size = new System.Drawing.Size(67, 23);
this.btnSpare.TabIndex = 19;
this.btnSpare.Text = "分单(&P)";
this.btnSpare.Text = "分单(P)";
this.btnSpare.Click += new System.EventHandler(this.btnSpare_Click);
//
// btnPrint
@@ -504,7 +508,7 @@
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(75, 23);
this.btnClose.TabIndex = 5;
this.btnClose.Text = "关闭(&Q)";
this.btnClose.Text = "关闭(Q)";
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// btnRemindBack
@@ -529,7 +533,7 @@
this.btnBack.Name = "btnBack";
this.btnBack.Size = new System.Drawing.Size(75, 23);
this.btnBack.TabIndex = 4;
this.btnBack.Text = "返退(&N)";
this.btnBack.Text = "返退(N)";
this.btnBack.Click += new System.EventHandler(this.btnReturn_Click);
//
// btnRemindAccradit
@@ -554,7 +558,7 @@
this.btnAccradit.Name = "btnAccradit";
this.btnAccradit.Size = new System.Drawing.Size(75, 23);
this.btnAccradit.TabIndex = 3;
this.btnAccradit.Text = "审核(&Y)";
this.btnAccradit.Text = "审核(Y)";
this.btnAccradit.Click += new System.EventHandler(this.btnAccradit_Click);
//
// label_date
@@ -767,4 +771,4 @@
private DevExpress.XtraBars.PopupMenu pmFP;
private DevExpress.XtraBars.BarManager barManager2;
}
}
}
@@ -44,9 +44,78 @@ namespace Lskj.PubAccraditation
/// </summary>
public partial class FrmAccraditation : BaseForm
{
private readonly AltButtonShortcutManager mAltButtonShortcuts =
new AltButtonShortcutManager();
public FrmAccraditation()
{
InitializeComponent();
InitializeAltButtonShortcuts();
}
private void InitializeAltButtonShortcuts()
{
mAltButtonShortcuts.Register(btnSave, Keys.S);
mAltButtonShortcuts.Register(btnSpare, Keys.P);
mAltButtonShortcuts.Register(btnClose, Keys.Q);
mAltButtonShortcuts.Register(btnBack, Keys.N);
mAltButtonShortcuts.Register(btnAccradit, Keys.Y);
}
protected override bool ProcessCmdKey(
ref System.Windows.Forms.Message msg, Keys keyData)
{
return mAltButtonShortcuts.ProcessKey(keyData) ||
base.ProcessCmdKey(ref msg, keyData);
}
private void ReleaseResourcesForDispose()
{
if (mResourcesReleased)
{
return;
}
mResourcesReleased = true;
PrintUtil.OnAfterPrint -= OnReportPrintAfter;
MyControl control = ControlObj;
ControlObj = null;
if (control != null)
{
control.OnDataSourceBindCallBack -=
OnControlObjOnDataSourceBindCallBack;
control.OnDataFileRefrshCallBack -= OnDataFileRefrshFile;
control.Dispose();
}
try
{
if (gridBillInfo != null)
{
TreeGridControlEx treeGrid =
gridBillInfo as TreeGridControlEx;
if (treeGrid != null)
{
treeGrid.OnDataSourceBindCallBack -=
OnGridBillInfoOnDataSourceBindCallBack;
}
else
{
gridBillInfo.OnDataSourceBindCallBack -=
OnGridBillInfoOnDataSourceBindCallBack;
}
gridBillInfo.ParentControl = null;
}
if (SysModel != null && SysModel.DataCaches != null)
{
SysModel.DataCaches.RemoveCache(this);
}
}
catch
{
// A partially disposed child must not stop form cleanup.
}
}
#region
@@ -70,6 +139,7 @@ namespace Lskj.PubAccraditation
/// 主表控件
/// </summary>
public MyControl ControlObj;
private bool mResourcesReleased;
/// <summary>
/// 是否是Brp模块加载审核明细
/// </summary>
@@ -385,16 +455,6 @@ namespace Lskj.PubAccraditation
{
return BaseModuleImpl.GetControlLocation(billAuditModelTask.Result.FormKey, dynamicModel.ModuleCode);
}));
Task<MyControl> controlObjTask = cachesDic.AddTask(this, "ControlObj", new Task<MyControl>(() =>
{
MyControl myControl = new MyControl();
myControl.Model = SysModel;
myControl.PrimaryValue = dynamicModel.BillDocumentId;
cachesDic.AddTask(myControl, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(myControl, "ControlsTable", controlLocationTask);
myControl.GetControlDataCaches(cachesDic);
return myControl;
}));
Task<DataTable> detailColumnsTask = cachesDic.AddTask(gridBillInfo, "DetailColumns", new Task<DataTable>(() =>
{
return BillImpl.GetDetailColumns(dynamicModel.ModuleCode);
@@ -980,14 +1040,26 @@ namespace Lskj.PubAccraditation
{
Dictionary<object, Hashtable> dataCaches = SysModel != null ? SysModel.DataCaches : null;
// 初始化表头
bool controlCreated = false;
if (!dataCaches.GetValue(this, "ControlObj", out this.ControlObj))
{
this.ControlObj = new MyControl();
controlCreated = true;
}
if (!dataCaches.GetValue(this, "ControlLocation", out DataTable dtControlLocation))
{
dtControlLocation = BaseModuleImpl.GetControlLocation(this.BillModelObj.FormKey, this.SysModel.ModuleCode);
}
if (controlCreated && dataCaches != null)
{
DynamicModel controlModel = SysModel;
DataTable controlsTable = dtControlLocation;
dataCaches.AddTask(ControlObj, "DynamicModel",
new Task<DynamicModel>(() => controlModel));
dataCaches.AddTask(ControlObj, "ControlsTable",
new Task<DataTable>(() => controlsTable));
ControlObj.GetControlDataCaches(dataCaches);
}
this.ControlObj.PrimaryValue = this.SysModel.BillDocumentId;
this.ControlObj.isAuditMain = true;
this.ControlObj.InitControl(dtControlLocation, this.pl_left_top);
@@ -2151,8 +2223,8 @@ namespace Lskj.PubAccraditation
{
this.btnAccradit.Enabled = true;
this.btnRemindAccradit.Visible = this.btnRemindBack.Visible = this.btnSave.Visible = this.btnClose.Visible = this.btnSpare.Visible = this.btnBack.Visible = false;
this.btnAccradit.Text = "确认(&Y)";
this.btnAccradit.Text = "确认(&Y)";
this.btnAccradit.Text = "确认(Y)";
this.btnAccradit.Text = "确认(Y)";
this.label_auditPerson.Text = "确认意见";
this.label_date.EditText = "会签人";
this.txtRemark.Text = "确认";
@@ -3665,6 +3737,15 @@ namespace Lskj.PubAccraditation
string newfieldValue = fieldValue;
if (fieldValue == "****") continue;
if (SystemInfo.Instance.IsSpecialAuditSave &&
this._drBillInfoMsg != null &&
this._drBillInfoMsg.Table != null &&
this._drBillInfoMsg.Table.Columns.Contains(model.FieldName) &&
AuditChangeLog.IsSameValue(this._drBillInfoMsg[model.FieldName] + "", fieldValue))
{
continue;
}
if ((model.FieldType == ControlType.LabDate ||
model.FieldType == ControlType.LabDate ||
model.FieldType == ControlType.LabDate ||
@@ -3683,7 +3764,12 @@ namespace Lskj.PubAccraditation
}
}
SaveErrorMessage = errorMessage;
return string.Format("update {0} set {1} where {2}='{3}'", this.BillModelObj.MasterTable, updateBuilder.ToString().TrimEnd(','), BillModelObj.PrimaryKey, this.SysModel.BillDocumentId);
string updateFields = updateBuilder.ToString().TrimEnd(',');
if (string.IsNullOrEmpty(updateFields))
{
return string.Empty;
}
return string.Format("update {0} set {1} where {2}='{3}'", this.BillModelObj.MasterTable, updateFields, BillModelObj.PrimaryKey, this.SysModel.BillDocumentId);
}
#endregion
+467 -29
View File
@@ -26,6 +26,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
@@ -89,6 +90,7 @@ namespace Lskj.PubBill
/// </summary>
private DataTable _detailColumns;
private bool IsCopying = false;
private bool _moduleResourcesReleased;
protected DataRow BillRowItem;
@@ -249,7 +251,10 @@ namespace Lskj.PubBill
/// 保存验证条件表
/// </summary>
public DataTable SaveCondTab = new DataTable();
/// <summary>
/// 明细对应字段(参数9中的明细sql对应的主表明细字段) Dictionary<sql中本身的字段名称, as 后对应明细的字段>
/// </summary>
public Dictionary<string, string> DetailMappingField = new Dictionary<string, string>();
public BillModule()
@@ -257,6 +262,155 @@ namespace Lskj.PubBill
InitializeComponent();
}
/// <summary>
/// Releases runtime objects created by the bill module. Cleanup is
/// idempotent and best-effort so it cannot change the close result.
/// </summary>
public void ReleaseModuleResources()
{
if (_moduleResourcesReleased)
return;
_moduleResourcesReleased = true;
TryRelease(() => PrintUtil.OnAfterPrint -= new EventHandler(OnReportPrintAfter), "打印回调");
TryRelease(ReleaseModuleEvents, "模块事件");
TryRelease(ReleaseModuleDataSources, "模块数据源");
TryRelease(ReleaseRuntimeCollections, "运行时集合");
BillRowItem = null;
ControlObj = null;
BillModel = null;
SysModel = null;
SumGridColumn = null;
ScanCodeTextEdit = null;
InitialSelectionTab = null;
_imageEdit = null;
_waterMark = null;
_itemImport = null;
_itemImportUpdate = null;
}
private void ReleaseModuleEvents()
{
if (ScanCodeTextEdit != null)
ScanCodeTextEdit.KeyDown -= Text_KeyDown;
if (gcMain != null)
{
gcMain.OnAfterLinkCilk -= OnAfterLinkCilkCall;
gcMain.OnAllAfterParseCallBack -= OnAllAfterParseCallBack;
if (gcMain.GridControl != null)
gcMain.GridControl.DataSourceChanged -= OnGcMainDataSourceChanged;
if (gcMain.GridView != null)
{
gcMain.GridView.KeyDown -= OnToWithdraw;
gcMain.GridView.ShowingEditor -= OnGridViewShowingEditor;
gcMain.GridView.MouseDown -= GridView_MouseDown;
gcMain.GridView.FocusedRowChanged -= GridView_FocusedRowChanged;
gcMain.GridView.InitNewRow -= OnGridViewInitNewRow;
gcMain.GridView.CellValueChanged -= OnGridViewCellValueChanged;
gcMain.GridView.RowCellClick -= OngcMainRowCellClick;
}
}
if (tb_buttom != null)
{
tb_buttom.OnDetailSaveGridCallBack -= Tab_OnDetailSaveGridCallBack;
tb_buttom.BillDetailRightGridCallBack -= Tab_OnDetailSaveGridCallBack;
tb_buttom.OnRightCallback -= OnButtomRightCallBack;
if (tb_buttom.TabControlObj != null)
tb_buttom.TabControlObj.SelectedPageChanged -= TabControlObj_SelectedPageChanged;
}
}
private void ReleaseModuleDataSources()
{
foreach (System.Windows.Forms.Control control in EnumerateChildControls(this).ToList())
{
GridControlEx grid = control as GridControlEx;
if (grid != null)
{
TreeGridControlEx treeGrid = grid as TreeGridControlEx;
if (treeGrid != null && treeGrid.TreeListObj != null)
treeGrid.TreeListObj.DataSource = null;
if (grid.GridControl != null)
grid.GridControl.DataSource = null;
}
XtraTabPage tabPage = control as XtraTabPage;
if (tabPage != null)
tabPage.Tag = null;
}
if (_imageEdit != null && _imageEdit.TextEdit != null)
_imageEdit.TextEdit.Image = null;
if (cb_input != null)
cb_input.Properties.Items.Clear();
if (cb_templete != null)
cb_templete.Properties.Items.Clear();
}
private static IEnumerable<System.Windows.Forms.Control> EnumerateChildControls(
System.Windows.Forms.Control root)
{
if (root == null)
yield break;
yield return root;
foreach (System.Windows.Forms.Control child in root.Controls)
foreach (System.Windows.Forms.Control nested in EnumerateChildControls(child))
yield return nested;
}
private void ReleaseRuntimeCollections()
{
foreach (BillModuleModel model in BillModuleModelDic.Values.ToList())
{
if (model == null)
continue;
model.SourceControl = null;
model.SourceDetailControl = null;
model.SourceDetailDetailControl = null;
model.SourceModel = null;
}
BillModuleModelDic.Clear();
pageNumKey.Clear();
foreach (Dictionary<int, DataRow> rows in ToWithdrawRows)
if (rows != null)
rows.Clear();
ToWithdrawRows.Clear();
ChangeColorRow.Clear();
DateColumnList.Clear();
itemCommonList.Clear();
ColorHandles.Clear();
if (DetailMappingField != null)
DetailMappingField.Clear();
if (_printSaveParams != null)
_printSaveParams.Clear();
if (_detailColumns != null)
{
_detailColumns.Dispose();
_detailColumns = null;
}
if (SaveCondTab != null)
{
SaveCondTab.Dispose();
SaveCondTab = null;
}
}
private static void TryRelease(Action release, string operation)
{
try
{
release();
}
catch (Exception exception)
{
Debug.WriteLine("释放单据模块资源失败[" + operation + "]" + exception);
}
}
#region
/// <summary>
/// <para>说明:窗口加载</para>
@@ -470,6 +624,7 @@ namespace Lskj.PubBill
Task<MyControl> controlObjTask = cachesDic.AddTask(this, "ControlObj", new Task<MyControl>(() =>
{
MyControl myControl = new MyControl() { Model = dynamicModel };
myControl.MrpClickMenus = new DataTable();
myControl.OtherParams = dynamicModel.OtherParams();
cachesDic.AddTask(myControl, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(myControl, "ControlsTable", controlLocationTask);
@@ -685,6 +840,7 @@ namespace Lskj.PubBill
string searchSql = model.SourceType == 1 ? Regex.Replace(model.DetailSql, "{speciesno}", "", RegexOptions.IgnoreCase) : model.SourceSql;
searchControl = new MyControl(searchSql, gridControl == null ? gridDetail : gridControl, treeView);
searchControl.Model = dynamicModel;
searchControl.MrpClickMenus = new DataTable();
searchControl.OtherParams = dynamicModel.OtherParams();
cachesDic.AddTask(searchControl, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(searchControl, "ControlsTable", customQueryFieldsTask);
@@ -972,7 +1128,7 @@ namespace Lskj.PubBill
}
if (this.BillModel.CanImport)
{
this.pmBillExp.AddItems(new BarItem[] { _itemImport, _itemImportUpdate });
this.pmBillExp.AddItems(new BarItem[] { _itemImport });//_itemImportUpdate
}
//分配
this.pmFP.AddItems(new BarItem[] { itemFPBatch });
@@ -1363,7 +1519,11 @@ namespace Lskj.PubBill
if (!string.IsNullOrEmpty(this.SysModel.BillMasterSql))
{
// 处理单据明细数据
if (!this.SysModel.BillDetailSql.StartsWith("*")) this.AddMultiRowToGridView(BillImpl.GetDataTableResult(this.SysModel.BillDetailSql));
if (!this.SysModel.BillDetailSql.StartsWith("*"))
{
this.AddMultiRowToGridView(BillImpl.GetDataTableResult(this.SysModel.BillDetailSql));
this.DetailMappingField = GetFieldAliasMap(this.SysModel.BillDetailSql);
}
}
}
}
@@ -1378,7 +1538,16 @@ namespace Lskj.PubBill
BaseUserControl baseUserControl = ControlObj.FindControl("bom_rdm_tianshu");
if (baseUserControl != null)
{
int.TryParse(baseUserControl.EditText, out dayCount);
//int.TryParse(baseUserControl.EditText, out dayCount);
decimal value;
if (decimal.TryParse(baseUserControl.EditText, out value) &&
value == decimal.Truncate(value) &&
value > 0 &&
value <= int.MaxValue)
{
dayCount = (int)value;
}
}
if (dayCount <= 0)
{
@@ -1455,7 +1624,16 @@ namespace Lskj.PubBill
BaseUserControl baseUserControl = ControlObj.FindControl("bom_rdm_tianshu");
if (baseUserControl != null)
{
int.TryParse(baseUserControl.EditText, out dayCount);
//int.TryParse(baseUserControl.EditText, out dayCount);
decimal value;
if (decimal.TryParse(baseUserControl.EditText, out value) &&
value == decimal.Truncate(value) &&
value > 0 &&
value <= int.MaxValue)
{
dayCount = (int)value;
}
}
if (dayCount <= 0)
{
@@ -4607,6 +4785,9 @@ namespace Lskj.PubBill
int position = this.gcMain.GridView.FocusedRowHandle;
bool isLastRow = this.gcMain.GridView.IsLastVisibleRow;
bool onlyOne = true;
dataTable = CreateDetailMappingTable(dataTable);
foreach (DataRow rowItem in dataTable.Rows)
{
if (unionModel == null || ValidateDetailCond(rowItem, unionModel))
@@ -4615,18 +4796,6 @@ namespace Lskj.PubBill
AssociatedField = repeatProduct;
if ("1".Equals(this.BillModel.DetailDoubleClickTip) && this.gcMain.GridView.Columns[repeatProduct] != null && dataTable.Columns.Contains(repeatProduct))
{
// 需要提示编码重复
//GridView view = this.gcMain.GridView;
//bool result = (view.LocateByValue(repeatProduct, rowItem[repeatProduct], null) >= 0) |
// (view.LocateByValue(repeatProduct, rowItem[repeatProduct], null) >= 0) |
// (view.LocateByValue(repeatProduct, rowItem[repeatProduct], null) >= 0) |
// (view.LocateByValue(repeatProduct, rowItem[repeatProduct], null) >= 0);
//if (result)
//{
// DialogResult dialog = MessageUtil.Show(ResourceKeys.ProductIsRepet, MessageBoxButtons.YesNo);
// if (dialog != DialogResult.Yes)
// return;
//}
//上面方法无法处理大小写,改成搜索的形式
DataTable dt = this.gcMain.gridControl.DataSourceTable();
@@ -4732,22 +4901,13 @@ namespace Lskj.PubBill
{
// 插入数据行
gridTable.Rows.InsertAt(newRow, position);
//this.gcMain.GridView.ClearSelection();
//this.gcMain.GridView.SelectRowHandler(position);
}
else
{
// 添加数据行
gridTable.Rows.Add(newRow);
// this.gcMain.GridView.ClearSelection();
// this.gcMain.GridView.SelectRowHandler(gridTable.Rows.Count - 1);
}
position++;
//if (isLastRow)
//{
// this.gcMain.GridView.ClearSelection();
// this.gcMain.GridView.SelectRowHandler(position + 1);
//}
if (!string.IsNullOrEmpty(NumberMc) && gridTable.Columns.Contains(mRecordPrimaryField))
{
DataRow[] rt = gridTable.Rows.Cast<DataRow>().Where(x => (newRow[BillModel.DetailPreFix + "ProductId"] + "").Equals(x[BillModel.DetailPreFix + "ProductId"] + "") && !string.IsNullOrEmpty(x[mRecordPrimaryField] + "")).ToArray();
@@ -4906,13 +5066,18 @@ namespace Lskj.PubBill
if (unionModel != null)
{
bool onlyOne = true;
DataRow[] mappingRows = CreateDetailMappingRows(rowItems);
for (int i = 0; i < rowItems.Length; i++)
{
DataRow rowItem = rowItems[i]; //unionModel.GridDetailControlObj.GridView.GetDataRow(selectedRows[i]);
DataRow mappingRow = mappingRows[i];
// 检查当前记录是否满足条件
if (ValidateDetailCond(rowItem, unionModel))
{
this.AddRowToGridView(rowItem);
this.AddRowToGridView(mappingRow);
if (!string.IsNullOrWhiteSpace(this.BillModel.ChangeColColor))
{
if (rowItem.Table.Columns.Contains(this.BillModel.ChangeColColor))
@@ -6502,7 +6667,15 @@ namespace Lskj.PubBill
BaseUserControl baseUserControl = ControlObj.FindControl("bom_rdm_tianshu");
if (baseUserControl != null)
{
int.TryParse(baseUserControl.EditText, out dayCount);
decimal value;
if (decimal.TryParse(baseUserControl.EditText, out value) &&
value == decimal.Truncate(value) &&
value > 0 &&
value <= int.MaxValue)
{
dayCount = (int)value;
}
}
if (dayCount <= 0)
{
@@ -9698,7 +9871,8 @@ namespace Lskj.PubBill
try
{
if (string.IsNullOrWhiteSpace(cond)) return true;//如果值是空格或者空行,默认正确
cond = ReplaceHelper.ReplaceRowParam(dataRow, cond);
//cond = ReplaceHelper.ReplaceRowParam(dataRow, cond);
cond = ReplaceHelper.ReplaceRowParamEmptyWrapQuote(dataRow, cond);
if (cond.StartsWith("@") || cond.StartsWith("!"))
{
result = "1".Equals(BaseImpl.GetDefaultValue(cond));
@@ -10472,5 +10646,269 @@ namespace Lskj.PubBill
/// <summary>
/// 获取明细sql对应的字段
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public static Dictionary<string, string> GetFieldAliasMap(string sql)
{
Dictionary<string, string> result =
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
try
{
if (string.IsNullOrWhiteSpace(sql))
return result;
string cleanSql = Regex.Replace(
sql,
@"/\*.*?\*/|--[^\r\n]*",
string.Empty,
RegexOptions.Singleline);
Match selectMatch = Regex.Match(
cleanSql,
@"\bSELECT\b(?<columns>.*?)\bFROM\b",
RegexOptions.IgnoreCase | RegexOptions.Singleline);
if (!selectMatch.Success)
return result;
string columns = selectMatch.Groups["columns"].Value;
const string identifier =
@"(?:\[[^\]]+\]|""[^""]+""|[\p{L}_@#][\p{L}\p{N}_@$#]*)";
string pattern =
@"(?:^|,)\s*" +
@"(?:(?:" + identifier + @")\s*\.\s*)*" +
@"(?<field>" + identifier + @")\s+" +
@"AS\s+" +
@"(?<alias>" + identifier + @")\s*" +
@"(?=,|$)";
MatchCollection matches = Regex.Matches(
columns,
pattern,
RegexOptions.IgnoreCase | RegexOptions.Multiline);
foreach (Match match in matches)
{
try
{
string fieldName = UnwrapSqlIdentifier(
match.Groups["field"].Value);
string aliasName = UnwrapSqlIdentifier(
match.Groups["alias"].Value);
if (string.IsNullOrWhiteSpace(fieldName) ||
string.IsNullOrWhiteSpace(aliasName))
{
continue;
}
// 相同字段重复配置时,以最后一个别名为准。
result[fieldName] = aliasName;
}
catch (Exception ex)
{
LogHelper.Instance.WriteError(ex);
continue;
}
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteError(ex);
}
return result;
}
/// <summary>
/// 获取明细sql对应的字段
/// </summary>
private static string UnwrapSqlIdentifier(string value)
{
value = (value ?? string.Empty).Trim();
if (value.Length >= 2 &&
value[0] == '[' &&
value[value.Length - 1] == ']')
{
return value.Substring(1, value.Length - 2)
.Replace("]]", "]");
}
if (value.Length >= 2 &&
value[0] == '"' &&
value[value.Length - 1] == '"')
{
return value.Substring(1, value.Length - 2)
.Replace("\"\"", "\"");
}
return value;
}
/// <summary>
/// 根据参数9的字段映射转换DataTable。
/// 保留原字段,并添加AS后的目标字段。
/// </summary>
private DataTable CreateDetailMappingTable(DataTable sourceTable)
{
if (sourceTable == null ||
DetailMappingField == null ||
DetailMappingField.Count == 0)
{
return sourceTable;
}
DataTable result;
try
{
result = sourceTable.Copy();
}
catch (Exception ex)
{
LogHelper.Instance.WriteError(ex);
return sourceTable;
}
foreach (KeyValuePair<string, string> mapping in DetailMappingField)
{
try
{
string sourceField = mapping.Key;
string targetField = mapping.Value;
if (string.IsNullOrWhiteSpace(sourceField) ||
string.IsNullOrWhiteSpace(targetField) ||
sourceField.Equals(targetField, StringComparison.OrdinalIgnoreCase))
{
continue;
}
if (!result.Columns.Contains(sourceField))
continue;
// 已经存在目标字段时保留原值,兼容原来的SQL配置。
if (result.Columns.Contains(targetField))
continue;
DataColumn sourceColumn = result.Columns[sourceField];
result.Columns.Add(targetField, sourceColumn.DataType);
foreach (DataRow row in result.Rows)
{
try
{
if (row.RowState != DataRowState.Deleted)
row[targetField] = row[sourceField];
}
catch (Exception ex)
{
LogHelper.Instance.WriteError(ex);
}
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteError(ex);
}
}
return result;
}
/// <summary>
/// 根据参数9的字段映射转换选中的DataRow数组。
/// 返回的行是临时副本,原始行仍用于变色、删除等来源操作。
/// </summary>
private DataRow[] CreateDetailMappingRows(DataRow[] sourceRows)
{
if (sourceRows == null ||
sourceRows.Length == 0 ||
DetailMappingField == null ||
DetailMappingField.Count == 0)
{
return sourceRows;
}
DataRow[] result = new DataRow[sourceRows.Length];
try
{
DataRow schemaRow = sourceRows.FirstOrDefault(
row => row != null && row.Table != null);
if (schemaRow == null)
return result;
DataTable temporaryTable = schemaRow.Table.Clone();
List<int> sourceIndexes = new List<int>();
for (int i = 0; i < sourceRows.Length; i++)
{
DataRow sourceRow = sourceRows[i];
if (sourceRow == null ||
sourceRow.Table == null ||
sourceRow.RowState == DataRowState.Deleted ||
sourceRow.RowState == DataRowState.Detached)
{
continue;
}
try
{
DataRow newRow = temporaryTable.NewRow();
foreach (DataColumn column in temporaryTable.Columns)
{
try
{
if (sourceRow.Table.Columns.Contains(column.ColumnName))
newRow[column.ColumnName] = sourceRow[column.ColumnName];
}
catch (Exception ex)
{
LogHelper.Instance.WriteError(ex);
}
}
temporaryTable.Rows.Add(newRow);
sourceIndexes.Add(i);
}
catch (Exception ex)
{
LogHelper.Instance.WriteError(ex);
}
}
DataTable mappingTable = CreateDetailMappingTable(temporaryTable);
for (int i = 0; i < mappingTable.Rows.Count &&
i < sourceIndexes.Count; i++)
{
result[sourceIndexes[i]] = mappingTable.Rows[i];
}
}
catch (Exception ex)
{
LogHelper.Instance.WriteError(ex);
}
return result;
}
}
}
+17 -1
View File
@@ -209,5 +209,21 @@ namespace Lskj.PubBill
}
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
this.FormClosing -= OnClose;
this.Activated -= FrmMain_Activated;
try
{
if (billModule1 != null)
billModule1.ReleaseModuleResources();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("释放单据窗口资源失败:" + ex);
}
}
}
}
}
+12 -2
View File
@@ -13,9 +13,19 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
if (cellHelper != null)
{
cellHelper.Dispose();
cellHelper = null;
}
class2_0 = null;
class2_1 = null;
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
+26 -14
View File
@@ -3911,8 +3911,6 @@ namespace Lskj.PubBomImport
string suffix = Path.GetExtension(File);
string name = fileInfo.Name;
DateTime creationTime = fileInfo.CreationTime;
byte[] fileBytes = ConvertFileToBytes(File);
string fileStream = Convert.ToBase64String(fileBytes);
string userId = ERPInfo.Instance.UserId;
DateTime uploadTime = DateTime.Now;
string code = "";
@@ -3925,7 +3923,7 @@ namespace Lskj.PubBomImport
//上传文件到服务器目录
//postUrl = "{0}Api/FileUploadApi.ashx?moduleId={1}&idValue={2}&speciesno={8}&folder={3}&totsize={4}&position={5}&filename={6}&method={7}&confirm=1";
postUrl = "{0}Api/FileUploadApi.ashx?moduleId={1}&idValue={2}&speciesno={8}&folder={3}&totsize={4}&position={5}&filename={6}&method={7}&comfirm={9}&encode={10}&gzip=true&uploadToken={11}&__tsp={12}";
postUrl = "{0}Api/FileUploadApi.ashx?moduleId={1}&idValue={2}&speciesno={8}&folder={3}&totsize={4}&position={5}&filename={6}&uname=false&method={7}&comfirm={9}&relPath=&encode={10}&gzip=true&uploadToken={11}&__tsp={12}";
if (!string.IsNullOrEmpty(idValue))
{
@@ -3937,24 +3935,34 @@ namespace Lskj.PubBomImport
loginPmsDic.Add("username", System.Web.HttpUtility.UrlEncode(ERPInfo.Instance.UserName));
loginPmsDic.Add("password", System.Web.HttpUtility.UrlEncode(ERPInfo.Instance.InPassWord));
HttpWebResponse loginResponse = HttpHelper.Post(loginUrl, "", loginPmsDic, null, out string loginResult);
if (loginResponse != null && !string.IsNullOrEmpty(loginResult))
try
{
JObject jObject = JsonConvert.DeserializeObject<JObject>(loginResult);
if (jObject.ContainsKey("success"))
if (loginResponse != null && !string.IsNullOrEmpty(loginResult))
{
if ((jObject["success"] + "").Equals("True"))
JObject jObject = JsonConvert.DeserializeObject<JObject>(loginResult);
if (jObject.ContainsKey("success"))
{
if (jObject.ContainsKey("token"))
if ((jObject["success"] + "").Equals("True"))
{
token = jObject["token"] + "";
if (jObject.ContainsKey("token"))
{
token = jObject["token"] + "";
}
}
}
}
}
finally
{
loginResponse?.Close();
}
if (!string.IsNullOrEmpty(token))
{
int pageSize = 1 * 1024 * 1024;
long totalSize = fileInfo.Length;
// Web 前端上传器同样提示:经过防火墙的环境需要将分片
// 从 1MB 降到约 0.3MB。所有文件统一使用安全分片,兼容
// 内网网关、透明代理及防火墙对 multipart 请求体的限制。
int pageSize = 320 * 1024;
long position = 0;
int confirm = 1;
int encode = 4;
@@ -3963,7 +3971,7 @@ namespace Lskj.PubBomImport
string uploadToken = Guid.NewGuid().ToString("N").Substring(0, 24);
string uploadFileName = name;
string uploadMethod = "DoWebUpload";
string uploadMethod = "DoWebUploadSafe";
Dictionary<string, string> headerDic = new Dictionary<string, string>();
headerDic.Add("Authorization", $"Bearer {token}");
@@ -3993,7 +4001,7 @@ namespace Lskj.PubBomImport
string uploadUrl = string.Format(
postUrl,
SystemInfo.Instance.OAUrl,
"1000202",
"1000202-1",
System.Web.HttpUtility.UrlEncode(idValue),
"file",
totalSize,
@@ -4009,8 +4017,10 @@ namespace Lskj.PubBomImport
string result = "";
HttpWebResponse webResponse = HttpHelper.PostFileChunk(uploadUrl, buffer, uploadFileName, headerDic, out result);
bool hasResponse = webResponse != null;
webResponse?.Close();
if (webResponse != null && !string.IsNullOrEmpty(result))
if (hasResponse && !string.IsNullOrEmpty(result))
{
JObject jsonObject = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(result);
string isSuccess = jsonObject["success"] + "";
@@ -4079,7 +4089,9 @@ namespace Lskj.PubBomImport
}
else
{
returnMsg = $"上传请求失败,{result}";
long chunkIndex = position / pageSize + 1;
long chunkCount = (totalSize + pageSize - 1) / pageSize;
returnMsg = $"上传请求失败(分片{chunkIndex}/{chunkCount},位置{position},分片大小{pageSize / 1024}KB),{result}";
hasFail = true;
isUpload = false;
break;
+6 -2
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -25,6 +25,24 @@ namespace Lskj.PubModelAdd
{
InitializeComponent();
}
private void ReleaseResourcesForDispose()
{
if (mResourcesReleased)
{
return;
}
mResourcesReleased = true;
MyControl search = _leftGridSearchObj;
_leftGridSearchObj = null;
if (search != null)
{
search.OnDataSourceBindCallBack -=
OnLeftControlObjDataSourceBindCallBack;
search.Dispose();
}
}
#region
/// <summary>
/// 模块初始化完成
@@ -42,6 +60,7 @@ namespace Lskj.PubModelAdd
/// 左侧表格查询条件
/// </summary>
private MyControl _leftGridSearchObj;
private bool mResourcesReleased;
#endregion
#region
/// <summary>

Some files were not shown because too many files have changed in this diff Show More