|
@@ -0,0 +1,238 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.ComponentModel;
|
|
|
+using System.Linq;
|
|
|
+using System.Windows.Controls;
|
|
|
+using System.Windows.Threading;
|
|
|
+using InABox.Configuration;
|
|
|
+using InABox.Core;
|
|
|
+using InABox.DynamicGrid;
|
|
|
+
|
|
|
+namespace InABox.Wpf;
|
|
|
+
|
|
|
+public abstract class MasterDetailPanel<TMaster, TMasterGrid, TSettings> : MasterDetailPanel, IPanel<TMaster>
|
|
|
+ where TMaster : Entity, IRemotable, IPersistent, new()
|
|
|
+ where TMasterGrid : DynamicDataGrid<TMaster>, new()
|
|
|
+ where TSettings : BaseObject, IUserConfigurationSettings, IMasterDetailSettings, new()
|
|
|
+{
|
|
|
+
|
|
|
+ private DispatcherTimer? timer;
|
|
|
+ private readonly List<IMasterDetailPage<TMaster>> _pages = new();
|
|
|
+ private DateTime _lastselection = DateTime.MaxValue;
|
|
|
+ private int _currentPage = -1;
|
|
|
+ private readonly TMasterGrid _masterGrid;
|
|
|
+ private IDataModelSource? _modelsource;
|
|
|
+
|
|
|
+ protected TSettings Settings { get; private set; } = new();
|
|
|
+
|
|
|
+ private void LoadSettings()
|
|
|
+ {
|
|
|
+ Settings = new UserConfiguration<TSettings>().Load();
|
|
|
+ _splitPanel.AnchorWidth = Settings.AnchorWidth;
|
|
|
+ _splitPanel.View = Settings.ViewType;
|
|
|
+ AfterLoadSettings(Settings);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected void SaveSettings()
|
|
|
+ {
|
|
|
+ BeforeSaveSettings(Settings);
|
|
|
+ Settings.AnchorWidth = _splitPanel.AnchorWidth;
|
|
|
+ Settings.ViewType = _splitPanel.View;
|
|
|
+ Settings.MasterID = _masterGrid.SelectedRows.FirstOrDefault()?.Get<TMaster, Guid>(x => x.ID) ?? Guid.Empty;
|
|
|
+ new UserConfiguration<TSettings>().Save(Settings);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected abstract string MasterCaption { get; }
|
|
|
+ protected abstract string DetailCaption { get; }
|
|
|
+ protected abstract void CreatePages();
|
|
|
+ protected abstract void AfterLoadSettings(TSettings settings);
|
|
|
+ protected abstract void BeforeSaveSettings(TSettings settings);
|
|
|
+ protected abstract string MasterColumnsTag { get; }
|
|
|
+ public abstract string SectionName { get; }
|
|
|
+ public abstract void CreateToolbarButtons(IPanelHost host);
|
|
|
+
|
|
|
+ protected override void DoSplitPanelChanged()
|
|
|
+ {
|
|
|
+ SaveSettings();
|
|
|
+ var newTag = GetMasterColumnsTag();
|
|
|
+ if (!String.Equals(_masterGrid.ColumnsTag, newTag))
|
|
|
+ {
|
|
|
+ _masterGrid.ColumnsTag = newTag;
|
|
|
+ _masterGrid.Refresh(true, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private string GetMasterColumnsTag()
|
|
|
+ {
|
|
|
+ var newTag = Settings.ViewType == DynamicSplitPanelView.Master
|
|
|
+ ? $"{MasterColumnsTag}:Master"
|
|
|
+ : $"{MasterColumnsTag}:Combined";
|
|
|
+ return newTag;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected MasterDetailPanel()
|
|
|
+ {
|
|
|
+ _masterGrid = new TMasterGrid();
|
|
|
+ _masterGrid.OnSelectItem += MasterGrid_OnSelectItem;
|
|
|
+ _masterGrid.BeforeRefresh += MasterGrid_BeforeRefresh;
|
|
|
+ _masterGrid.AfterRefresh += MasterGrid_AfterRefresh;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Setup()
|
|
|
+ {
|
|
|
+ LoadSettings();
|
|
|
+
|
|
|
+ _masterGrid.ColumnsTag = GetMasterColumnsTag();
|
|
|
+
|
|
|
+ _splitPanel.Master = _masterGrid;
|
|
|
+ _splitPanel.MasterCaption = MasterCaption;
|
|
|
+ _splitPanel.DetailCaption = DetailCaption;
|
|
|
+
|
|
|
+ _header.Content = MasterCaption;
|
|
|
+
|
|
|
+ CreatePages();
|
|
|
+
|
|
|
+ timer = new DispatcherTimer();
|
|
|
+ timer.Tick += Timer_Tick;
|
|
|
+ timer.Interval = new TimeSpan(0, 0, 0, 0, 100);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ protected void CreatePage<TPage>(Func<bool> isAllowed, string caption)
|
|
|
+ where TPage : class, IMasterDetailPage<TMaster>
|
|
|
+ {
|
|
|
+ if (isAllowed())
|
|
|
+ {
|
|
|
+ var header = new DynamicTabItem() { Header = caption };
|
|
|
+ _tabControl.Items.Add(header);
|
|
|
+ if (Activator.CreateInstance(typeof(TPage), header) is TPage page)
|
|
|
+ _pages.Add(page);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ protected void CreatePage<TPage>(string caption)
|
|
|
+ where TPage : class, IMasterDetailPage<TMaster>
|
|
|
+ {
|
|
|
+ CreatePage<TPage>(() => true, caption);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Shutdown(CancelEventArgs? cancel)
|
|
|
+ {
|
|
|
+ if (timer != null)
|
|
|
+ timer.IsEnabled = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Refresh()
|
|
|
+ {
|
|
|
+ _masterGrid.Refresh(timer?.IsEnabled == false, true);
|
|
|
+ _lastselection = DateTime.MinValue;
|
|
|
+ if (timer != null)
|
|
|
+ timer.IsEnabled = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public DataModel DataModel(Selection selection)
|
|
|
+ {
|
|
|
+ if (_modelsource == null)
|
|
|
+ {
|
|
|
+ var row = _masterGrid.SelectedRows.FirstOrDefault();
|
|
|
+ var filter = row != null
|
|
|
+ ? new Filter<TMaster>(x => x.ID).IsEqualTo(row.Get<TMaster, Guid>(x => x.ID))
|
|
|
+ : new Filter<TMaster>().None();
|
|
|
+ return new AutoDataModel<TMaster>(filter);
|
|
|
+ }
|
|
|
+
|
|
|
+ return _modelsource.DataModel(selection);
|
|
|
+ }
|
|
|
+
|
|
|
+ public event DataModelUpdateEvent? OnUpdateDataModel;
|
|
|
+
|
|
|
+ public bool IsReady { get; set; }
|
|
|
+
|
|
|
+ private IMasterDetailPage<TMaster>? SelectedPage => _pages.FirstOrDefault(x => x.Tab == _tabControl.SelectedTab);
|
|
|
+
|
|
|
+ public Dictionary<string, object[]> Selected()
|
|
|
+ {
|
|
|
+ return SelectedPage != null
|
|
|
+ ? SelectedPage.Selected()
|
|
|
+ : new Dictionary<string, object[]> { { typeof(TMaster).EntityName(), _masterGrid.SelectedRows } };
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Heartbeat(TimeSpan time)
|
|
|
+ {
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override void DoPagesChanged()
|
|
|
+ {
|
|
|
+ _lastselection = DateTime.MinValue;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private void Timer_Tick(object? sender, EventArgs e)
|
|
|
+ {
|
|
|
+ if (_lastselection < DateTime.Now.AddMilliseconds(-500) && !_masterGridRefreshing)
|
|
|
+ {
|
|
|
+ _lastselection = DateTime.MaxValue;
|
|
|
+ var master = _masterGrid.SelectedRows.FirstOrDefault()?.ToObject<TMaster>() ?? new TMaster();
|
|
|
+ var dataModelSource = SelectedPage?.Refresh(master);
|
|
|
+ if (_tabControl.SelectedIndex != _currentPage)
|
|
|
+ {
|
|
|
+ if(dataModelSource is not null)
|
|
|
+ {
|
|
|
+ _modelsource = dataModelSource;
|
|
|
+ OnUpdateDataModel?.Invoke(dataModelSource.SectionName, dataModelSource.DataModel(Selection.None));
|
|
|
+ }
|
|
|
+ _currentPage = _tabControl.SelectedIndex;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool _masterGridRefreshing;
|
|
|
+
|
|
|
+ private void MasterGrid_BeforeRefresh(object sender, BeforeRefreshEventArgs args)
|
|
|
+ {
|
|
|
+ _masterGridRefreshing = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void MasterGrid_AfterRefresh(object sender, AfterRefreshEventArgs args)
|
|
|
+ {
|
|
|
+
|
|
|
+ _masterGrid.SelectedRows = Settings.MasterID == Guid.Empty
|
|
|
+ ? Array.Empty<CoreRow>()
|
|
|
+ : _masterGrid.Data.Rows.Where(r => r.Get<TMaster, Guid>(c => c.ID) == Settings.MasterID).ToArray();
|
|
|
+ _masterGridRefreshing = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void MasterGrid_OnSelectItem(object sender, DynamicGridSelectionEventArgs e)
|
|
|
+ {
|
|
|
+ if (!_masterGridRefreshing)
|
|
|
+ {
|
|
|
+ _lastselection = DateTime.Now;
|
|
|
+ SaveSettings();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+public abstract partial class MasterDetailPanel : UserControl
|
|
|
+{
|
|
|
+
|
|
|
+ protected MasterDetailPanel()
|
|
|
+ {
|
|
|
+ InitializeComponent();
|
|
|
+ }
|
|
|
+
|
|
|
+ protected abstract void DoSplitPanelChanged();
|
|
|
+
|
|
|
+ private void SplitPanel_OnChanged(object sender, DynamicSplitPanelSettings e)
|
|
|
+ {
|
|
|
+ DoSplitPanelChanged();
|
|
|
+ }
|
|
|
+
|
|
|
+ protected abstract void DoPagesChanged();
|
|
|
+
|
|
|
+ private void Pages_OnChanged(object sender, SelectionChangedEventArgs e)
|
|
|
+ {
|
|
|
+ if (Equals(e.Source, _tabControl))
|
|
|
+ DoPagesChanged();
|
|
|
+ }
|
|
|
+}
|