From 5680c38fa9e484225ab5d3d39596f5795340f90b Mon Sep 17 00:00:00 2001 From: "David P.G" Date: Thu, 11 Sep 2025 18:09:35 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8E=86=E5=8F=B2=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=8A=9F=E8=83=BD=EF=BC=88=E6=9C=AA=E5=AE=8C=E6=88=90?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DMS.Application/DTOs/VariableHistoryDto.cs | 1 + .../Interfaces/IHistoryAppService.cs | 41 +++ .../Interfaces/IVariableAppService.cs | 7 - DMS.Application/Profiles/MappingProfile.cs | 4 +- .../Services/AppDataStorageService.cs | 7 + DMS.Application/Services/HistoryAppService.cs | 74 +++++ .../Services/VariableAppService.cs | 11 - .../IVariableHistoryRepository.cs | 19 ++ DMS.Core/Models/VariableHistory.cs | 1 + .../Repositories/VariableHistoryRepository.cs | 60 ++++ DMS.WPF/App.xaml.cs | 1 + .../ViewModels/VariableHistoryViewModel.cs | 274 ++++++++---------- DMS.WPF/Views/VariableHistoryView.xaml | 38 +-- 13 files changed, 343 insertions(+), 195 deletions(-) create mode 100644 DMS.Application/Interfaces/IHistoryAppService.cs create mode 100644 DMS.Application/Services/HistoryAppService.cs diff --git a/DMS.Application/DTOs/VariableHistoryDto.cs b/DMS.Application/DTOs/VariableHistoryDto.cs index 77573fd..f8bd630 100644 --- a/DMS.Application/DTOs/VariableHistoryDto.cs +++ b/DMS.Application/DTOs/VariableHistoryDto.cs @@ -9,6 +9,7 @@ public class VariableHistoryDto { public long Id { get; set; } public int VariableId { get; set; } + public string VariableName { get; set; } public string Value { get; set; } public DateTime Timestamp { get; set; } } \ No newline at end of file diff --git a/DMS.Application/Interfaces/IHistoryAppService.cs b/DMS.Application/Interfaces/IHistoryAppService.cs new file mode 100644 index 0000000..5441baf --- /dev/null +++ b/DMS.Application/Interfaces/IHistoryAppService.cs @@ -0,0 +1,41 @@ +using DMS.Application.DTOs; + +namespace DMS.Application.Interfaces; + +/// +/// 定义历史记录管理相关的应用服务操作。 +/// +public interface IHistoryAppService +{ + /// + /// 异步获取指定变量的历史记录。 + /// + /// 变量ID + /// 变量历史记录列表 + Task> GetVariableHistoriesAsync(int variableId); + + /// + /// 异步获取指定变量的历史记录,支持条数限制和时间范围筛选。 + /// + /// 变量ID + /// 返回记录的最大数量,null表示无限制 + /// 开始时间,null表示无限制 + /// 结束时间,null表示无限制 + /// 变量历史记录列表 + Task> GetVariableHistoriesAsync(int variableId, int? limit = null, DateTime? startTime = null, DateTime? endTime = null); + + /// + /// 异步获取所有变量的历史记录。 + /// + /// 所有变量历史记录列表 + Task> GetAllVariableHistoriesAsync(); + + /// + /// 异步获取所有变量的历史记录,支持条数限制和时间范围筛选。 + /// + /// 返回记录的最大数量,null表示无限制 + /// 开始时间,null表示无限制 + /// 结束时间,null表示无限制 + /// 所有变量历史记录列表 + Task> GetAllVariableHistoriesAsync(int? limit = null, DateTime? startTime = null, DateTime? endTime = null); +} \ No newline at end of file diff --git a/DMS.Application/Interfaces/IVariableAppService.cs b/DMS.Application/Interfaces/IVariableAppService.cs index 900e9d5..2411d61 100644 --- a/DMS.Application/Interfaces/IVariableAppService.cs +++ b/DMS.Application/Interfaces/IVariableAppService.cs @@ -70,11 +70,4 @@ public interface IVariableAppService /// 要检查的变量。 /// 如果变量已存在则返回该变量,否则返回null。 Task FindExistingVariableAsync(VariableDto variableToCheck); - - /// - /// 异步获取指定变量的历史记录。 - /// - /// 变量ID - /// 变量历史记录列表 - Task> GetVariableHistoriesAsync(int variableId); } \ No newline at end of file diff --git a/DMS.Application/Profiles/MappingProfile.cs b/DMS.Application/Profiles/MappingProfile.cs index 55ef82f..d42d71d 100644 --- a/DMS.Application/Profiles/MappingProfile.cs +++ b/DMS.Application/Profiles/MappingProfile.cs @@ -40,7 +40,9 @@ public class MappingProfile : Profile .ReverseMap(); // VariableHistory 映射 - CreateMap().ReverseMap(); + CreateMap() + .ForMember(dest => dest.VariableName, opt => opt.MapFrom(src => src.Variable.Name)) + .ReverseMap(); // MenuBean 映射 CreateMap().ReverseMap(); diff --git a/DMS.Application/Services/AppDataStorageService.cs b/DMS.Application/Services/AppDataStorageService.cs index 09d6a9f..8c9d3c7 100644 --- a/DMS.Application/Services/AppDataStorageService.cs +++ b/DMS.Application/Services/AppDataStorageService.cs @@ -41,6 +41,13 @@ public class AppDataStorageService : IAppDataStorageService /// 安全字典,用于存储所有MQTT变量别名的数据 /// public ConcurrentDictionary VariableMqttAliases { get; } = new(); + + + + /// + /// 安全字典,用于存储所有历史记录 + /// + public ConcurrentDictionary VariableHistories { get; } = new(); /// /// 安全字典,用于存储所有日志数据 diff --git a/DMS.Application/Services/HistoryAppService.cs b/DMS.Application/Services/HistoryAppService.cs new file mode 100644 index 0000000..7a97165 --- /dev/null +++ b/DMS.Application/Services/HistoryAppService.cs @@ -0,0 +1,74 @@ +using AutoMapper; +using DMS.Application.DTOs; +using DMS.Application.Interfaces; +using DMS.Core.Interfaces; + +namespace DMS.Application.Services; + +/// +/// 历史记录应用服务实现类,负责处理变量历史记录相关的业务逻辑。 +/// +public class HistoryAppService : IHistoryAppService +{ + private readonly IRepositoryManager _repoManager; + private readonly IMapper _mapper; + + /// + /// 构造函数,注入仓储管理器和AutoMapper。 + /// + /// 仓储管理器实例。 + /// AutoMapper实例。 + public HistoryAppService(IRepositoryManager repoManager, IMapper mapper) + { + _repoManager = repoManager; + _mapper = mapper; + } + + /// + /// 异步获取指定变量的历史记录。 + /// + /// 变量ID + /// 变量历史记录列表 + public async Task> GetVariableHistoriesAsync(int variableId) + { + var histories = await _repoManager.VariableHistories.GetByVariableIdAsync(variableId); + return _mapper.Map>(histories); + } + + /// + /// 异步获取指定变量的历史记录,支持条数限制和时间范围筛选。 + /// + /// 变量ID + /// 返回记录的最大数量,null表示无限制 + /// 开始时间,null表示无限制 + /// 结束时间,null表示无限制 + /// 变量历史记录列表 + public async Task> GetVariableHistoriesAsync(int variableId, int? limit = null, DateTime? startTime = null, DateTime? endTime = null) + { + var histories = await _repoManager.VariableHistories.GetByVariableIdAsync(variableId, limit, startTime, endTime); + return _mapper.Map>(histories); + } + + /// + /// 异步获取所有变量的历史记录。 + /// + /// 所有变量历史记录列表 + public async Task> GetAllVariableHistoriesAsync() + { + var histories = await _repoManager.VariableHistories.GetAllAsync(); + return _mapper.Map>(histories); + } + + /// + /// 异步获取所有变量的历史记录,支持条数限制和时间范围筛选。 + /// + /// 返回记录的最大数量,null表示无限制 + /// 开始时间,null表示无限制 + /// 结束时间,null表示无限制 + /// 所有变量历史记录列表 + public async Task> GetAllVariableHistoriesAsync(int? limit = null, DateTime? startTime = null, DateTime? endTime = null) + { + var histories = await _repoManager.VariableHistories.GetAllAsync(limit, startTime, endTime); + return _mapper.Map>(histories); + } +} \ No newline at end of file diff --git a/DMS.Application/Services/VariableAppService.cs b/DMS.Application/Services/VariableAppService.cs index 71e34e0..7cc15f0 100644 --- a/DMS.Application/Services/VariableAppService.cs +++ b/DMS.Application/Services/VariableAppService.cs @@ -285,15 +285,4 @@ public class VariableAppService : IVariableAppService // 如果找到了匹配的变量,返回第一个(也是唯一一个) return existingVariables.FirstOrDefault(); } - - /// - /// 异步获取指定变量的历史记录。 - /// - /// 变量ID - /// 变量历史记录列表 - public async Task> GetVariableHistoriesAsync(int variableId) - { - var histories = await _repoManager.VariableHistories.GetByVariableIdAsync(variableId); - return _mapper.Map>(histories); - } } \ No newline at end of file diff --git a/DMS.Core/Interfaces/Repositories/IVariableHistoryRepository.cs b/DMS.Core/Interfaces/Repositories/IVariableHistoryRepository.cs index 528708e..e7f9a3d 100644 --- a/DMS.Core/Interfaces/Repositories/IVariableHistoryRepository.cs +++ b/DMS.Core/Interfaces/Repositories/IVariableHistoryRepository.cs @@ -10,4 +10,23 @@ public interface IVariableHistoryRepository:IBaseRepository /// 变量ID /// 变量历史记录列表 Task> GetByVariableIdAsync(int variableId); + + /// + /// 根据变量ID获取历史记录,支持条数限制和时间范围筛选 + /// + /// 变量ID + /// 返回记录的最大数量,null表示无限制 + /// 开始时间,null表示无限制 + /// 结束时间,null表示无限制 + /// 变量历史记录列表 + Task> GetByVariableIdAsync(int variableId, int? limit = null, DateTime? startTime = null, DateTime? endTime = null); + + /// + /// 获取所有历史记录,支持条数限制和时间范围筛选 + /// + /// 返回记录的最大数量,null表示无限制 + /// 开始时间,null表示无限制 + /// 结束时间,null表示无限制 + /// 所有历史记录列表 + Task> GetAllAsync(int? limit = null, DateTime? startTime = null, DateTime? endTime = null); } \ No newline at end of file diff --git a/DMS.Core/Models/VariableHistory.cs b/DMS.Core/Models/VariableHistory.cs index 2e2a59c..b7ac7c6 100644 --- a/DMS.Core/Models/VariableHistory.cs +++ b/DMS.Core/Models/VariableHistory.cs @@ -7,6 +7,7 @@ public class VariableHistory { public long Id { get; set; } public int VariableId { get; set; } + public Variable Variable { get; set; } public string Value { get; set; } // 以字符串形式存储,便于通用性 public DateTime Timestamp { get; set; } } \ No newline at end of file diff --git a/DMS.Infrastructure/Repositories/VariableHistoryRepository.cs b/DMS.Infrastructure/Repositories/VariableHistoryRepository.cs index 273ce30..68ee3ac 100644 --- a/DMS.Infrastructure/Repositories/VariableHistoryRepository.cs +++ b/DMS.Infrastructure/Repositories/VariableHistoryRepository.cs @@ -123,4 +123,64 @@ public class VariableHistoryRepository : BaseRepository, IVar .ToListAsync(); return _mapper.Map>(dbList); } + + /// + /// 根据变量ID获取历史记录,支持条数限制和时间范围筛选 + /// + /// 变量ID + /// 返回记录的最大数量,null表示无限制 + /// 开始时间,null表示无限制 + /// 结束时间,null表示无限制 + /// 变量历史记录列表 + public async Task> GetByVariableIdAsync(int variableId, int? limit = null, DateTime? startTime = null, DateTime? endTime = null) + { + var query = Db.Queryable() + .Where(h => h.VariableId == variableId); + + // 添加时间范围筛选 + if (startTime.HasValue) + query = query.Where(h => h.Timestamp >= startTime.Value); + + if (endTime.HasValue) + query = query.Where(h => h.Timestamp <= endTime.Value); + + // 按时间倒序排列 + query = query.OrderBy(h => h.Timestamp, SqlSugar.OrderByType.Desc); + + // 添加条数限制 + if (limit.HasValue) + query = query.Take(limit.Value); + + var dbList = await query.ToListAsync(); + return _mapper.Map>(dbList); + } + + /// + /// 获取所有历史记录,支持条数限制和时间范围筛选 + /// + /// 返回记录的最大数量,null表示无限制 + /// 开始时间,null表示无限制 + /// 结束时间,null表示无限制 + /// 所有历史记录列表 + public new async Task> GetAllAsync(int? limit = null, DateTime? startTime = null, DateTime? endTime = null) + { + var query = Db.Queryable(); + + // 添加时间范围筛选 + if (startTime.HasValue) + query = query.Where(h => h.Timestamp >= startTime.Value); + + if (endTime.HasValue) + query = query.Where(h => h.Timestamp <= endTime.Value); + + // 按时间倒序排列 + query = query.OrderBy(h => h.Timestamp, SqlSugar.OrderByType.Desc); + + // 添加条数限制 + if (limit.HasValue) + query = query.Take(limit.Value); + + var dbList = await query.ToListAsync(); + return _mapper.Map>(dbList); + } } \ No newline at end of file diff --git a/DMS.WPF/App.xaml.cs b/DMS.WPF/App.xaml.cs index 3ee7e41..7848d09 100644 --- a/DMS.WPF/App.xaml.cs +++ b/DMS.WPF/App.xaml.cs @@ -216,6 +216,7 @@ public partial class App : System.Windows.Application services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/DMS.WPF/ViewModels/VariableHistoryViewModel.cs b/DMS.WPF/ViewModels/VariableHistoryViewModel.cs index a1d6fb8..9e7859c 100644 --- a/DMS.WPF/ViewModels/VariableHistoryViewModel.cs +++ b/DMS.WPF/ViewModels/VariableHistoryViewModel.cs @@ -9,36 +9,19 @@ using DMS.WPF.Interfaces; using DMS.WPF.ViewModels.Items; using Microsoft.Extensions.DependencyInjection; using ObservableCollections; +using System.Linq; namespace DMS.WPF.ViewModels; -partial class VariableHistoryViewModel : ViewModelBase,INavigatable +partial class VariableHistoryViewModel : ViewModelBase, INavigatable { private readonly IMapper _mapper; private readonly IDialogService _dialogService; - private readonly IVariableAppService _variableAppService; + private readonly IHistoryAppService _historyAppService; private readonly IWPFDataService _wpfDataService; private readonly IDataStorageService _dataStorageService; private readonly INotificationService _notificationService; - /// - /// 当前选中的设备 - /// - [ObservableProperty] - private DeviceItemViewModel _selectedDevice; - - /// - /// 当前选中的变量表 - /// - [ObservableProperty] - private VariableTableItemViewModel _selectedVariableTable; - - /// - /// 当前选中的变量 - /// - [ObservableProperty] - private VariableItemViewModel _selectedVariable; - /// /// 用于过滤变量的搜索文本 /// @@ -46,142 +29,87 @@ partial class VariableHistoryViewModel : ViewModelBase,INavigatable private string _searchText; /// - /// 所有设备列表 + /// 是否打开建议列表 /// - public NotifyCollectionChangedSynchronizedViewList Devices { get; } + [ObservableProperty] + private bool _isSuggestionListOpen; /// - /// 当前设备下的变量表列表 + /// 建议的变量列表 /// - public NotifyCollectionChangedSynchronizedViewList VariableTables { get; } - + [ObservableProperty] + private List _suggestedVariables; + /// - /// 当前变量表下的变量列表 + /// 历史记录条数限制 /// - public NotifyCollectionChangedSynchronizedViewList Variables { get; } + [ObservableProperty] + private int? _historyLimit; + + /// + /// 历史记录开始时间 + /// + [ObservableProperty] + private DateTime? _startTime; + + /// + /// 历史记录结束时间 + /// + [ObservableProperty] + private DateTime? _endTime; /// /// 变量历史记录列表 /// public NotifyCollectionChangedSynchronizedViewList VariableHistories { get; } - private readonly ObservableList _deviceItemList; - private readonly ObservableList _variableTableItemList; - private readonly ObservableList _variableItemList; private readonly ObservableList _variableHistoryList; - - private readonly ISynchronizedView _deviceSynchronizedView; - private readonly ISynchronizedView _variableTableSynchronizedView; - private readonly ISynchronizedView _variableSynchronizedView; private readonly ISynchronizedView _variableHistorySynchronizedView; - public VariableHistoryViewModel(IMapper mapper, IDialogService dialogService, IVariableAppService variableAppService, + /// + /// 所有变量的缓存列表,用于搜索 + /// + private List _allVariableHistories; + + public VariableHistoryViewModel(IMapper mapper, IDialogService dialogService, IHistoryAppService historyAppService, IWPFDataService wpfDataService, IDataStorageService dataStorageService, INotificationService notificationService) { _mapper = mapper; _dialogService = dialogService; - _variableAppService = variableAppService; + _historyAppService = historyAppService; _wpfDataService = wpfDataService; _dataStorageService = dataStorageService; _notificationService = notificationService; - _deviceItemList = new ObservableList(); - _variableTableItemList = new ObservableList(); - _variableItemList = new ObservableList(); _variableHistoryList = new ObservableList(); - - _deviceSynchronizedView = _deviceItemList.CreateView(v => v); - _variableTableSynchronizedView = _variableTableItemList.CreateView(v => v); - _variableSynchronizedView = _variableItemList.CreateView(v => v); _variableHistorySynchronizedView = _variableHistoryList.CreateView(v => v); - - Devices = _deviceSynchronizedView.ToNotifyCollectionChanged(); - VariableTables = _variableTableSynchronizedView.ToNotifyCollectionChanged(); - Variables = _variableSynchronizedView.ToNotifyCollectionChanged(); VariableHistories = _variableHistorySynchronizedView.ToNotifyCollectionChanged(); - } - - - - /// - /// 加载所有设备 - /// - private void LoadDevices() - { - _deviceItemList.Clear(); - _deviceItemList.AddRange(_dataStorageService.Devices); + _allVariableHistories = new List(); + _suggestedVariables = new List(); + + // 初始化默认值 + _historyLimit = 1000; // 默认限制1000条记录 + _startTime = null; + _endTime = null; } /// - /// 当选中的设备发生变化时 + /// 加载所有变量的历史记录 /// - /// - partial void OnSelectedDeviceChanged(DeviceItemViewModel value) - { - if (value != null) - { - // 清空变量表和变量列表 - _variableTableItemList.Clear(); - _variableItemList.Clear(); - _variableHistoryList.Clear(); - - // 加载选中设备下的变量表 - _variableTableItemList.AddRange(value.VariableTables); - - // 清空选中项 - SelectedVariableTable = null; - SelectedVariable = null; - } - } - - /// - /// 当选中的变量表发生变化时 - /// - /// - partial void OnSelectedVariableTableChanged(VariableTableItemViewModel value) - { - if (value != null) - { - // 清空变量列表和历史记录 - _variableItemList.Clear(); - _variableHistoryList.Clear(); - - // 加载选中变量表下的变量 - _variableItemList.AddRange(value.Variables); - - // 清空选中项 - SelectedVariable = null; - } - } - - /// - /// 当选中的变量发生变化时 - /// - /// - partial void OnSelectedVariableChanged(VariableItemViewModel value) - { - // if (value != null) - // { - // // 加载选中变量的历史记录 - // LoadVariableHistories(value.Id); - // } - // else - // { - // _variableHistoryList.Clear(); - // } - } - - /// - /// 加载变量的历史记录 - /// - /// - private async void LoadVariableHistories(int variableId) + /// 返回记录的最大数量,null表示无限制 + /// 开始时间,null表示无限制 + /// 结束时间,null表示无限制 + private async void LoadAllVariableHistories(int? limit = null, DateTime? startTime = null, DateTime? endTime = null) { try { _variableHistoryList.Clear(); - var histories = await _variableAppService.GetVariableHistoriesAsync(variableId); - _variableHistoryList.AddRange(histories); + var allHistories = await _historyAppService.GetAllVariableHistoriesAsync(limit, startTime, endTime); + _allVariableHistories = allHistories.ToList(); + _variableHistoryList.AddRange(_allVariableHistories); + + // 更新建议列表 + UpdateSuggestedVariables(); } catch (Exception ex) { @@ -191,49 +119,99 @@ partial class VariableHistoryViewModel : ViewModelBase,INavigatable } /// - /// 搜索变量 + /// 更新建议的变量列表 + /// + private void UpdateSuggestedVariables() + { + if (string.IsNullOrWhiteSpace(SearchText)) + { + // 如果搜索文本为空,显示所有唯一的变量名 + _suggestedVariables = _allVariableHistories + .GroupBy(h => h.VariableName) + .Select(g => g.First()) + .Take(10) + .ToList(); + } + else + { + // 根据搜索文本过滤建议列表 + _suggestedVariables = _allVariableHistories + .Where(h => + h.VariableName?.Contains(SearchText, StringComparison.OrdinalIgnoreCase) == + true) + .GroupBy(h => h.VariableName) + .Select(g => g.First()) + .Take(10) + .ToList(); + } + + } + + /// + /// 搜索变量历史记录 /// /// partial void OnSearchTextChanged(string value) { - if (SelectedVariableTable == null) return; + // 更新建议列表 + UpdateSuggestedVariables(); if (string.IsNullOrWhiteSpace(SearchText)) { - _variableSynchronizedView.ResetFilter(); + // 如果搜索文本为空,显示所有历史记录 + _variableHistoryList.Clear(); + _variableHistoryList.AddRange(_allVariableHistories); } else { - _variableSynchronizedView.AttachFilter(FilterVariables); - } - } + // 根据搜索文本过滤历史记录 + var filteredHistories = _allVariableHistories + .Where(h => + h.VariableName?.Contains( + SearchText, StringComparison.OrdinalIgnoreCase) == true) + .ToList(); - /// - /// 过滤变量 - /// - /// - /// - private bool FilterVariables(VariableItemViewModel item) - { - var searchTextLower = SearchText.ToLower(); - return item.Name?.ToLower().Contains(searchTextLower) == true || - item.Description?.ToLower().Contains(searchTextLower) == true || - item.OpcUaNodeId?.ToLower().Contains(searchTextLower) == true || - item.S7Address?.ToLower().Contains(searchTextLower) == true; + _variableHistoryList.Clear(); + _variableHistoryList.AddRange(filteredHistories); + } } public async Task OnNavigatedToAsync(MenuItemViewModel menu) { - - VariableItemViewModel variable =_dataStorageService.Variables.FirstOrDefault(v => v.Id == menu.TargetId); - if (variable!=null) + // 加载所有变量的历史记录 + LoadAllVariableHistories(HistoryLimit, StartTime, EndTime); + } + + /// + /// 重新加载历史记录,使用当前设置的限制和时间范围 + /// + public void ReloadHistories() + { + LoadAllVariableHistories(HistoryLimit, StartTime, EndTime); + } + + /// + /// 根据变量ID加载历史记录 + /// + /// 变量ID + /// 返回记录的最大数量,null表示无限制 + /// 开始时间,null表示无限制 + /// 结束时间,null表示无限制 + public async Task LoadVariableHistoriesAsync(int variableId, int? limit = null, DateTime? startTime = null, DateTime? endTime = null) + { + try { - // 直接设置选中的变量 - SelectedVariable = variable; - + _variableHistoryList.Clear(); + var histories = await _historyAppService.GetVariableHistoriesAsync(variableId, limit, startTime, endTime); + _variableHistoryList.AddRange(histories); - // 加载历史记录 - LoadVariableHistories(variable.Id); + // 更新建议列表 + UpdateSuggestedVariables(); + } + catch (Exception ex) + { + // 记录更详细的错误信息 + _notificationService.ShowError($"加载变量历史记录失败: {ex.Message}", ex); } } } \ No newline at end of file diff --git a/DMS.WPF/Views/VariableHistoryView.xaml b/DMS.WPF/Views/VariableHistoryView.xaml index 5ef7b63..26e91ea 100644 --- a/DMS.WPF/Views/VariableHistoryView.xaml +++ b/DMS.WPF/Views/VariableHistoryView.xaml @@ -39,41 +39,22 @@ - - + + - - - - - - - - - - - - + Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" + ItemsSource="{Binding SuggestedVariables}" + DisplayMemberPath="VariableName" + IsSuggestionListOpen="{Binding IsSuggestionListOpen, Mode=TwoWay}" + TextMemberPath="VariableName" /> @@ -89,6 +70,7 @@ SelectionMode="Single" Style="{StaticResource DataGridBaseStyle}"> +