完成从TIA变量表导入变量

This commit is contained in:
2025-07-04 13:40:14 +08:00
parent fdaaf50c1d
commit 02eab6ecf0
8 changed files with 353 additions and 182 deletions

View File

@@ -10,6 +10,80 @@ namespace PMSWPF.Data.Entities;
[SugarTable("VarData")] [SugarTable("VarData")]
public class DbVariableData public class DbVariableData
{ {
/// <summary>
/// 变量唯一标识符。
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)] //数据库是自增才配自增
public int Id { get; set; }
/// <summary>
/// 变量名称。
/// </summary>
public string Name { get; set; }
/// <summary>
/// 节点ID用于标识变量在设备或系统中的唯一路径。
/// </summary>
public string NodeId { get; set; } = String.Empty;
/// <summary>
/// 节点ID用于标识变量在设备或系统中的唯一路径。
/// </summary>
public string S7Address { get; set; } = String.Empty;
/// <summary>
/// 变量描述。
/// </summary>
[SugarColumn(IsNullable = true)]
public string? Description { get; set; }
/// <summary>
/// 协议类型例如Modbus、OPC UA等。
/// </summary>
[SugarColumn(ColumnDataType = "varchar(20)", SqlParameterDbType = typeof(EnumToStringConvert))]
public ProtocolType ProtocolType { get; set; }
/// <summary>
/// 信号类型,例如模拟量、数字量等。
/// </summary>
[SugarColumn(ColumnDataType = "varchar(20)", IsNullable = true, SqlParameterDbType = typeof(EnumToStringConvert))]
public SignalType SignalType { get; set; }
/// <summary>
/// 数据类型例如Int、Float、String等。
/// </summary>
public string DataType { get; set; } = String.Empty;
/// <summary>
/// 变量当前原始数据值。
/// </summary>
public string DataValue { get; set; } = String.Empty;
/// <summary>
/// 变量经过转换或格式化后的显示值。
/// </summary>
public string DisplayValue { get; set; } = String.Empty;
/// <summary>
/// 指示变量是否处于激活状态。
/// </summary>
public bool IsActive { get; set; }
/// <summary>
/// 指示是否需要保存变量数据。
/// </summary>
public bool IsSave { get; set; }
/// <summary>
/// 指示是否需要对变量进行报警监测。
/// </summary>
public bool IsAlarm { get; set; }
/// <summary>
/// 指示变量是否已被逻辑删除。
/// </summary>
public bool IsDeleted { get; set; }
/// <summary> /// <summary>
/// 报警的最大值阈值。 /// 报警的最大值阈值。
/// </summary> /// </summary>
@@ -25,85 +99,15 @@ public class DbVariableData
/// </summary> /// </summary>
public string Converstion { get; set; } = String.Empty; public string Converstion { get; set; } = String.Empty;
/// <summary>
/// 数据类型例如Int、Float、String等。
/// </summary>
public string DataType { get; set; } = String.Empty;
/// <summary>
/// 变量当前原始数据值。
/// </summary>
public string DataValue { get; set; } = String.Empty;
/// <summary>
/// 变量描述。
/// </summary>
[SugarColumn(IsNullable = true)]
public string? Description { get; set; }
/// <summary>
/// 变量经过转换或格式化后的显示值。
/// </summary>
public string DisplayValue { get; set; } = String.Empty;
/// <summary>
/// 变量唯一标识符。
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)] //数据库是自增才配自增
public int Id { get; set; }
/// <summary>
/// 指示是否需要对变量进行报警监测。
/// </summary>
public bool IsAlarm { get; set; }
/// <summary>
/// 指示变量是否处于激活状态。
/// </summary>
public bool IsActive { get; set; }
/// <summary>
/// 指示变量是否已被逻辑删除。
/// </summary>
public bool IsDeleted { get; set; }
/// <summary>
/// 指示是否需要保存变量数据。
/// </summary>
public bool IsSave { get; set; }
/// <summary>
/// 关联的MQTT配置列表。
/// </summary>
[SugarColumn(IsNullable = true)]
public List<DbMqtt>? Mqtts { get; set; }
/// <summary>
/// 变量名称。
/// </summary>
public string Name { get; set; }
/// <summary>
/// 节点ID用于标识变量在设备或系统中的唯一路径。
/// </summary>
public string NodeId { get; set; } = String.Empty;
/// <summary>
/// 协议类型例如Modbus、OPC UA等。
/// </summary>
[SugarColumn(ColumnDataType = "varchar(20)", SqlParameterDbType = typeof(EnumToStringConvert))]
public ProtocolType ProtocolType { get; set; }
/// <summary> /// <summary>
/// 数据保存的范围或阈值。 /// 数据保存的范围或阈值。
/// </summary> /// </summary>
public double SaveRange { get; set; } public double SaveRange { get; set; }
/// <summary> /// <summary>
/// 信号类型,例如模拟量、数字量等 /// 变量数据最后更新时间
/// </summary> /// </summary>
[SugarColumn(ColumnDataType = "varchar(20)", IsNullable = true, SqlParameterDbType = typeof(EnumToStringConvert))] [SugarColumn(IsNullable = true)]
public SignalType SignalType { get; set; } public DateTime CreateTime { get; set; }
/// <summary> /// <summary>
/// 变量数据最后更新时间。 /// 变量数据最后更新时间。
@@ -116,6 +120,11 @@ public class DbVariableData
[SugarColumn(IsNullable = true)] [SugarColumn(IsNullable = true)]
public DbUser? UpdateUser { get; set; } public DbUser? UpdateUser { get; set; }
/// <summary>
/// 关联的变量表ID。
/// </summary>
public int VariableTableId { get; set; }
/// <summary> /// <summary>
/// 关联的变量表实体。 /// 关联的变量表实体。
/// </summary> /// </summary>
@@ -123,7 +132,8 @@ public class DbVariableData
public DbVariableTable? VariableTable { get; set; } public DbVariableTable? VariableTable { get; set; }
/// <summary> /// <summary>
/// 关联的变量表ID /// 关联的MQTT配置列表
/// </summary> /// </summary>
public int VariableTableId { get; set; } [SugarColumn(IsNullable = true)]
public List<DbMqtt>? Mqtts { get; set; }
} }

View File

@@ -69,6 +69,32 @@ public class VarDataRepository
} }
} }
/// <summary>
/// 新增VariableData
/// </summary>
/// <param name="variableData">VariableData实体</param>
/// <returns></returns>
public async Task<List<VariableData>> AddAsync(List<VariableData> variableDatas)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
List<VariableData> variableDataList = new List<VariableData>();
using (var _db = DbContext.GetInstance())
{
List<DbVariableData> dbVarDataList = variableDatas.Select(varData=>varData.CopyTo<DbVariableData>()).ToList();
foreach (var dbVariableData in dbVarDataList)
{
var resVarData = await _db.Insertable(dbVariableData).ExecuteReturnEntityAsync();
variableDataList.Add(resVarData.CopyTo<VariableData>());
}
stopwatch.Stop();
Logger.Info($"新增VariableData{dbVarDataList.Count}个, 耗时:{stopwatch.ElapsedMilliseconds}ms");
return variableDataList;
}
}
/// <summary> /// <summary>
/// 更新VariableData /// 更新VariableData
/// </summary> /// </summary>

View File

@@ -8,10 +8,90 @@ namespace PMSWPF.Models;
/// </summary> /// </summary>
public partial class VariableData : ObservableObject public partial class VariableData : ObservableObject
{ {
/// <summary>
/// 变量唯一标识符。
/// </summary>
public int Id { get; set; }
/// <summary>
/// 变量名称。
/// </summary>
[ObservableProperty]
private string name;
/// <summary>
/// 节点ID用于标识变量在设备或系统中的唯一路径。
/// </summary>
public string NodeId { get; set; }
/// <summary>
/// 节点ID用于标识变量在设备或系统中的唯一路径。
/// </summary>
public string S7Address { get; set; }
/// <summary>
/// 变量描述。
/// </summary>
[ObservableProperty]
private string description = String.Empty;
/// <summary>
/// 协议类型例如Modbus、OPC UA等。
/// </summary>
public ProtocolType ProtocolType { get; set; }
/// <summary>
/// 信号类型,例如模拟量、数字量等。
/// </summary>
public SignalType SignalType { get; set; }
/// <summary>
/// 数据类型例如Int、Float、String等。
/// </summary>
public string DataType { get; set; }
/// <summary>
/// 变量当前原始数据值。
/// </summary>
[ObservableProperty]
private string dataValue = String.Empty;
/// <summary>
/// 变量经过转换或格式化后的显示值。
/// </summary>
[ObservableProperty]
private string displayValue = String.Empty;
/// <summary>
/// 指示变量是否处于激活状态。
/// </summary>
public bool IsActive { get; set; }
/// <summary>
/// 指示是否需要保存变量数据。
/// </summary>
public bool IsSave { get; set; }
/// <summary>
/// 指示是否需要对变量进行报警监测。
/// </summary>
public bool IsAlarm { get; set; }
/// <summary>
/// 指示变量是否已被逻辑删除。
/// </summary>
public bool IsDeleted { get; set; }
/// <summary>
/// 指示变量是否已被修改了。
/// </summary>
[ObservableProperty]
private bool isModified;
/// <summary> /// <summary>
/// 报警的最大值阈值。 /// 报警的最大值阈值。
/// </summary> /// </summary>
public double AlarmMax { get; set; } public double AlarmMax { get; set; }
/// <summary> /// <summary>
@@ -25,90 +105,17 @@ public partial class VariableData : ObservableObject
[ObservableProperty] [ObservableProperty]
private string converstion = String.Empty; private string converstion = String.Empty;
/// <summary>
/// 数据类型例如Int、Float、String等。
/// </summary>
public string DataType { get; set; }
/// <summary>
/// 变量当前原始数据值。
/// </summary>
[ObservableProperty]
private string dataValue = String.Empty;
/// <summary>
/// 变量描述。
/// </summary>
[ObservableProperty]
private string description = String.Empty;
/// <summary>
/// 变量唯一标识符。
/// </summary>
public int Id { get; set; }
/// <summary>
/// 变量经过转换或格式化后的显示值。
/// </summary>
[ObservableProperty]
private string displayValue = String.Empty;
/// <summary>
/// 指示是否需要对变量进行报警监测。
/// </summary>
public bool IsAlarm { get; set; }
/// <summary>
/// 指示变量是否处于激活状态。
/// </summary>
public bool IsActive { get; set; }
/// <summary>
/// 指示变量是否已被逻辑删除。
/// </summary>
public bool IsDeleted { get; set; }
/// <summary>
/// 指示变量是否已被修改了。
/// </summary>
[ObservableProperty]
private bool isModified;
/// <summary>
/// 指示是否需要保存变量数据。
/// </summary>
public bool IsSave { get; set; }
/// <summary>
/// 关联的MQTT配置列表。
/// </summary>
public List<Mqtt> Mqtts { get; set; }
/// <summary>
/// 变量名称。
/// </summary>
[ObservableProperty]
private string name;
/// <summary>
/// 节点ID用于标识变量在设备或系统中的唯一路径。
/// </summary>
public string NodeId { get; set; }
/// <summary>
/// 协议类型例如Modbus、OPC UA等。
/// </summary>
public ProtocolType ProtocolType { get; set; }
/// <summary> /// <summary>
/// 数据保存的范围或阈值。 /// 数据保存的范围或阈值。
/// </summary> /// </summary>
public double SaveRange { get; set; } public double SaveRange { get; set; }
/// <summary> /// <summary>
/// 信号类型,例如模拟量、数字量等 /// 变量数据创建时间
/// </summary> /// </summary>
public SignalType SignalType { get; set; } [ObservableProperty]
private DateTime createTime;
/// <summary> /// <summary>
/// 变量数据最后更新时间。 /// 变量数据最后更新时间。
@@ -126,4 +133,9 @@ public partial class VariableData : ObservableObject
/// </summary> /// </summary>
public int VariableTableId { get; set; } public int VariableTableId { get; set; }
/// <summary>
/// 关联的MQTT配置列表。
/// </summary>
public List<Mqtt> Mqtts { get; set; }
} }

View File

@@ -1,9 +1,10 @@
using NUnit.Framework; using NUnit.Framework;
using PMSWPF.Helper; using PMSWPF.Helper;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.IO; using System.IO;
using PMSWPF.Enums;
using PMSWPF.Models;
namespace PMSWPF.Tests namespace PMSWPF.Tests
{ {
@@ -17,7 +18,7 @@ namespace PMSWPF.Tests
{ {
// Create a temporary file for testing // Create a temporary file for testing
// _testFilePath = Path.Combine(Path.GetTempPath(), "test.xlsx"); // _testFilePath = Path.Combine(Path.GetTempPath(), "test.xlsx");
_testFilePath = "e:/test.xlsx"; _testFilePath = "e:/test.xlsx";
} }
[TearDown] [TearDown]
@@ -35,10 +36,10 @@ namespace PMSWPF.Tests
{ {
// Arrange // Arrange
var data = new List<TestData> var data = new List<TestData>
{ {
new TestData { Id = 1, Name = "Test1" }, new TestData { Id = 1, Name = "Test1" },
new TestData { Id = 2, Name = "Test2" } new TestData { Id = 2, Name = "Test2" }
}; };
// Act // Act
ExcelHelper.ExportToExcel(data, _testFilePath); ExcelHelper.ExportToExcel(data, _testFilePath);
@@ -84,15 +85,51 @@ namespace PMSWPF.Tests
Assert.AreEqual("Test1", result.Rows[0]["Name"]); Assert.AreEqual("Test1", result.Rows[0]["Name"]);
} }
[Test]
public void ImportVarDataFormExcel()
{
// Act
_testFilePath = "C:\\Users\\Administrator\\Desktop\\浓度变量.xlsx";
var dataTable = ExcelHelper.ImportFromExcel(_testFilePath);
// 判断表头的名字
if (dataTable.Columns[0].ColumnName != "Name" || dataTable.Columns[2].ColumnName != "Data Type" &&
dataTable.Columns[3].ColumnName != "Logical Address")
throw new AggregateException(
"Excel表格式不正确第一列的名字是Name,第三列的名字是Data Type,Data Type,第四列的名字是Logical Address,请检查");
List<VariableData> variableDatas = new List<VariableData>();
foreach (DataRow dataRow in dataTable.Rows)
{
VariableData variableData = new VariableData();
variableData.Name=dataRow["Name"].ToString();
variableData.DataType=SiemensHelper.S7ToCSharpTypeString(dataRow["Data Type"].ToString()) ;
var exS7Addr=dataRow["Logical Address"].ToString();
if (exS7Addr.StartsWith("%"))
{
variableData.S7Address = exS7Addr.Substring(1);
}
variableData.ProtocolType = ProtocolType.S7;
variableData.SignalType = SignalType.OtherASignal;
variableDatas.Add(variableData);
}
Assert.Greater(variableDatas.Count, 0);
// Assert
// Assert.AreEqual(2, result.Rows.Count);FDFD
// Assert.AreEqual("1", result.Rows[0]["Id"]);
// Assert.AreEqual("Test1", result.Rows[0]["Name"]);
}
[Test] [Test]
public void ImportFromExcel_ToListOfObjects_ReturnsCorrectData() public void ImportFromExcel_ToListOfObjects_ReturnsCorrectData()
{ {
// Arrange // Arrange
var data = new List<TestData> var data = new List<TestData>
{ {
new TestData { Id = 1, Name = "Test1" }, new TestData { Id = 1, Name = "Test1" },
new TestData { Id = 2, Name = "Test2" } new TestData { Id = 2, Name = "Test2" }
}; };
ExcelHelper.ExportToExcel(data, _testFilePath); ExcelHelper.ExportToExcel(data, _testFilePath);
// Act // Act

View File

@@ -107,4 +107,16 @@ public class DialogService :IDialogService
} }
return null; return null;
} }
public async Task<string> ShowImportExcelDialog()
{
var vm = new ImportExcelDialogViewModel();
var dialog = new ImportExcelDialog(vm);
var result = await dialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
return vm.FilePath;
}
return null;
}
} }

View File

@@ -15,4 +15,5 @@ public interface IDialogService
void ShowMessageDialog(string title, string message); void ShowMessageDialog(string title, string message);
Task<VariableData> ShowEditVarDataDialog(VariableData variableData); Task<VariableData> ShowEditVarDataDialog(VariableData variableData);
Task<string> ShowImportExcelDialog();
} }

View File

@@ -63,6 +63,7 @@ partial class VariableTableViewModel : ViewModelBase
IsLoadCompletion = true; IsLoadCompletion = true;
} }
/// <summary> /// <summary>
/// 退出当前实体时调用 /// 退出当前实体时调用
/// </summary> /// </summary>
@@ -80,13 +81,12 @@ partial class VariableTableViewModel : ViewModelBase
// 不保存数据,还原原来的数据 // 不保存数据,还原原来的数据
foreach (var modifiedData in modifiedDatas) foreach (var modifiedData in modifiedDatas)
{ {
var oldData = _originalDataVariables.First(od=>od.Id ==modifiedData.Id); var oldData = _originalDataVariables.First(od => od.Id == modifiedData.Id);
oldData.CopyTo( modifiedData); oldData.CopyTo(modifiedData);
modifiedData.IsModified = false; modifiedData.IsModified = false;
} }
return false; return false;
} }
return true; return true;
@@ -107,11 +107,12 @@ partial class VariableTableViewModel : ViewModelBase
{ {
modifiedData.IsModified = false; modifiedData.IsModified = false;
} }
NotificationHelper.ShowMessage($"修改的{modifiedDatas.Count}变量保存成功.", NotificationType.Success); NotificationHelper.ShowMessage($"修改的{modifiedDatas.Count}变量保存成功.", NotificationType.Success);
} }
[RelayCommand] [RelayCommand]
public async void EditVarData(VariableTable variableTable) private async void EditVarData(VariableTable variableTable)
{ {
try try
{ {
@@ -138,9 +139,53 @@ partial class VariableTableViewModel : ViewModelBase
} }
} }
[RelayCommand]
private async void ImprotFromTiaVarTable()
{
try
{
// 让用户选择导入的Excel文件
var filePath = await _dialogService.ShowImportExcelDialog();
if (string.IsNullOrEmpty(filePath))
return;
// 读取Excel转换成VariableData列表
var importVarDataList = ExcelHelper.ImprotFromTiaVariableTable(filePath);
if (importVarDataList.Count == 0)
return;
foreach (var variableData in importVarDataList)
{
variableData.CreateTime=DateTime.Now;
variableData.VariableTableId = VariableTable.Id;
}
// 插入数据库
var resVarDataList= await _varDataRepository.AddAsync(importVarDataList);
//更新界面
// variableTable.DataVariables.AddRange(resVarDataList);
foreach (var variableData in resVarDataList)
{
variableTable.DataVariables.Add(variableData);
}
DataVariables=new ObservableCollection<VariableData>(resVarDataList);
string msgSuccess = $"成功导入变量:{resVarDataList.Count}个。";
Logger.Info(msgSuccess);
NotificationHelper.ShowMessage(msgSuccess, NotificationType.Success);
}
catch (Exception e)
{
string msg = $"从TIA导入变量的过程中发生了不可预期的错误";
Logger.Error(msg + e);
NotificationHelper.ShowMessage(msg + e.Message, NotificationType.Error);
}
}
[RelayCommand] [RelayCommand]
public async void AddVarData(VariableTable variableTable) private async void AddVarData(VariableTable variableTable)
{ {
try try
{ {
@@ -154,6 +199,7 @@ partial class VariableTableViewModel : ViewModelBase
// 更新数据库 // 更新数据库
await _varDataRepository.UpdateAsync(varData); await _varDataRepository.UpdateAsync(varData);
// 更新当前页面的 // 更新当前页面的
DataVariables.Add(varData);
var index = variableTable.DataVariables.IndexOf(SelectedVariableData); var index = variableTable.DataVariables.IndexOf(SelectedVariableData);
// 更新变量表中的 // 更新变量表中的
if (index >= 0 && index < variableTable.DataVariables.Count) if (index >= 0 && index < variableTable.DataVariables.Count)
@@ -168,13 +214,17 @@ partial class VariableTableViewModel : ViewModelBase
} }
} }
public void OnVarTableDataChanged(VariableData varData) // [RelayCommand]
{ // private async void ImportFromExcel()
var originelData = _originalDataVariables.FirstOrDefault(d => d.Id == varData.Id); // {
// var filePath = await _dialogService.ShowImportExcelDialog();
// if (!string.IsNullOrEmpty(filePath))
// {
// // TODO: Implement Excel import logic using the filePath
// NotificationHelper.ShowMessage($"Successfully imported from {filePath}", NotificationType.Success);
// }
// }
// varData.IsModified = originelData.Equals(varData);
// varData.IsModified = originelData.ValueEquals(varData);
}
public async Task OnIsActiveChanged(bool active) public async Task OnIsActiveChanged(bool active)
{ {

View File

@@ -70,13 +70,24 @@
</ui:AppBarButton.Icon> </ui:AppBarButton.Icon>
</ui:AppBarButton> </ui:AppBarButton>
<ui:AppBarButton Command="{Binding SaveModifiedVarDataCommand}" <ui:AppBarButton Command="{Binding SaveModifiedVarDataCommand}"
Label="保存变量"> Label="保存变量">
<ui:AppBarButton.Icon> <ui:AppBarButton.Icon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Save}" /> <ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Save}" />
</ui:AppBarButton.Icon> </ui:AppBarButton.Icon>
</ui:AppBarButton> </ui:AppBarButton>
<ui:AppBarButton
Command="{Binding ImprotFromTiaVarTableCommand}"
Label="从TIA变量表导入">
<ui:AppBarButton.Icon>
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Import}" />
</ui:AppBarButton.Icon>
</ui:AppBarButton>
<ui:AppBarButton x:Name="ShareButton" <ui:AppBarButton x:Name="ShareButton"
Label="Share"> Label="Share">
<ui:AppBarButton.Icon> <ui:AppBarButton.Icon>
@@ -88,6 +99,7 @@
Icon="Setting" Icon="Setting"
Label="Settings" /> Label="Settings" />
</ui:CommandBar.SecondaryCommands> </ui:CommandBar.SecondaryCommands>
</controls:CommandBar> </controls:CommandBar>
<!-- 变量表的名称描述等信息 --> <!-- 变量表的名称描述等信息 -->
<ikw:SimpleStackPanel Margin="5" <ikw:SimpleStackPanel Margin="5"
@@ -110,6 +122,10 @@
Text="所属设备:" /> Text="所属设备:" />
<TextBlock Style="{StaticResource VarTableValueStyle}" <TextBlock Style="{StaticResource VarTableValueStyle}"
Text="{Binding VariableTable.Device.Name}" /> Text="{Binding VariableTable.Device.Name}" />
<TextBlock Style="{StaticResource VarTableLabelStyle}"
Text="协议:" />
<TextBlock Style="{StaticResource VarTableValueStyle}"
Text="{Binding VariableTable.ProtocolType}" />
</ikw:SimpleStackPanel> </ikw:SimpleStackPanel>
@@ -163,9 +179,9 @@
<DataGridTextColumn IsReadOnly="True" <DataGridTextColumn IsReadOnly="True"
Header="节点ID" Header="节点ID"
Binding="{Binding NodeId}" /> Binding="{Binding NodeId}" />
<DataGridTextColumn IsReadOnly="True" <!-- <DataGridTextColumn IsReadOnly="True" -->
Header="协议类型" <!-- Header="协议类型" -->
Binding="{Binding ProtocolType}" /> <!-- Binding="{Binding ProtocolType}" /> -->
<DataGridTextColumn IsReadOnly="True" <DataGridTextColumn IsReadOnly="True"
Header="数据类型" Header="数据类型"
Binding="{Binding DataType}" /> Binding="{Binding DataType}" />
@@ -181,19 +197,26 @@
SelectedItem="{Binding SignalType}"> SelectedItem="{Binding SignalType}">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/> <TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}" />
</DataTemplate> </DataTemplate>
</ComboBox.ItemTemplate> </ComboBox.ItemTemplate>
</ComboBox> </ComboBox>
</DataTemplate> </DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn> </DataGridTemplateColumn>
<DataGridTextColumn IsReadOnly="True"
Header="S7地址"
Binding="{Binding S7Address}" />
<DataGridTextColumn IsReadOnly="True" <DataGridTextColumn IsReadOnly="True"
Header="当前值" Header="当前值"
Binding="{Binding DataValue}" /> Binding="{Binding DataValue}" />
<DataGridTextColumn IsReadOnly="True" <DataGridTextColumn IsReadOnly="True"
Header="显示值" Header="显示值"
Binding="{Binding DisplayValue}" /> Binding="{Binding DisplayValue}" />
<DataGridTextColumn IsReadOnly="True"
Header="创建时间"
Binding="{Binding CreateTime}" />
<DataGridTextColumn IsReadOnly="True" <DataGridTextColumn IsReadOnly="True"
Header="更新时间" Header="更新时间"
Binding="{Binding UpdateTime}" /> Binding="{Binding UpdateTime}" />