DynamicGrid.cs 152 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Collections.ObjectModel;
  5. using System.ComponentModel;
  6. using System.Data;
  7. using System.Diagnostics;
  8. using System.Globalization;
  9. using System.Linq;
  10. using System.Linq.Expressions;
  11. using System.Threading.Tasks;
  12. using System.Windows;
  13. using System.Windows.Controls;
  14. using System.Windows.Data;
  15. using System.Windows.Forms.VisualStyles;
  16. using System.Windows.Input;
  17. using System.Windows.Media;
  18. using System.Windows.Media.Animation;
  19. using System.Windows.Media.Imaging;
  20. using System.Windows.Threading;
  21. using InABox.Clients;
  22. using InABox.Core;
  23. using InABox.Wpf;
  24. using InABox.WPF;
  25. using Microsoft.CodeAnalysis.CSharp.Syntax;
  26. using Microsoft.Xaml.Behaviors;
  27. using Syncfusion.Data;
  28. using Syncfusion.DocIO.ReaderWriter.DataStreamParser.Escher;
  29. using Syncfusion.UI.Xaml.Grid;
  30. using Syncfusion.UI.Xaml.Grid.Cells;
  31. using Syncfusion.UI.Xaml.Grid.Helpers;
  32. using Syncfusion.Windows.Shared;
  33. using Brush = System.Windows.Media.Brush;
  34. using Color = System.Drawing.Color;
  35. using Columns = InABox.Core.Columns;
  36. using DataColumn = System.Data.DataColumn;
  37. using DataRow = System.Data.DataRow;
  38. using FilterElement = Syncfusion.UI.Xaml.Grid.FilterElement;
  39. using FontStyle = System.Windows.FontStyle;
  40. using GridCellToolTipOpeningEventArgs = Syncfusion.UI.Xaml.Grid.GridCellToolTipOpeningEventArgs;
  41. using GridFilterEventArgs = Syncfusion.UI.Xaml.Grid.GridFilterEventArgs;
  42. using GridSelectionMode = Syncfusion.UI.Xaml.Grid.GridSelectionMode;
  43. using Image = System.Windows.Controls.Image;
  44. using RowColumnIndex = Syncfusion.UI.Xaml.ScrollAxis.RowColumnIndex;
  45. using SolidColorBrush = System.Windows.Media.SolidColorBrush;
  46. using String = System.String;
  47. using VerticalAlignment = System.Windows.VerticalAlignment;
  48. using VirtualizingCellsControl = Syncfusion.UI.Xaml.Grid.VirtualizingCellsControl;
  49. namespace InABox.DynamicGrid
  50. {
  51. public class DynamicGridRowStyle : DynamicGridStyle<VirtualizingCellsControl>
  52. {
  53. public DynamicGridRowStyle() : base(null)
  54. {
  55. }
  56. public DynamicGridRowStyle(IDynamicGridStyle source) : base(source)
  57. {
  58. }
  59. public override DependencyProperty FontSizeProperty => Control.FontSizeProperty;
  60. public override DependencyProperty FontStyleProperty => Control.FontStyleProperty;
  61. public override DependencyProperty FontWeightProperty => Control.FontWeightProperty;
  62. public override DependencyProperty BackgroundProperty => Control.BackgroundProperty;
  63. public override DependencyProperty ForegroundProperty => Control.ForegroundProperty;
  64. }
  65. public class DynamicGridCellStyle : DynamicGridStyle<Control>
  66. {
  67. public DynamicGridCellStyle() : base(null)
  68. {
  69. }
  70. public DynamicGridCellStyle(IDynamicGridStyle source) : base(source)
  71. {
  72. }
  73. public override DependencyProperty FontSizeProperty => Control.FontSizeProperty;
  74. public override DependencyProperty FontStyleProperty => Control.FontStyleProperty;
  75. public override DependencyProperty FontWeightProperty => Control.FontWeightProperty;
  76. public override DependencyProperty BackgroundProperty => Control.BackgroundProperty;
  77. public override DependencyProperty ForegroundProperty => Control.ForegroundProperty;
  78. }
  79. public class GridSelectionControllerExt : GridSelectionController
  80. {
  81. public GridSelectionControllerExt(SfDataGrid datagrid)
  82. : base(datagrid)
  83. {
  84. }
  85. protected override void ProcessSelectedItemChanged(SelectionPropertyChangedHandlerArgs handle)
  86. {
  87. base.ProcessSelectedItemChanged(handle);
  88. if (handle.NewValue != null)
  89. {
  90. //this.DataGrid.ScrollInView(this.CurrentCellManager.CurrentRowColumnIndex);
  91. //int rowIndex = this.CurrentCellManager.CurrentRowColumnIndex.RowIndex;
  92. var columnIndex = CurrentCellManager.CurrentRowColumnIndex.ColumnIndex;
  93. var scrollRowIndex = DataGrid.GetVisualContainer().ScrollRows.LastBodyVisibleLineIndex;
  94. DataGrid.ScrollInView(new RowColumnIndex(scrollRowIndex, columnIndex));
  95. }
  96. }
  97. }
  98. public class DynamicGridSummaryStyleSelector : StyleSelector
  99. {
  100. private readonly IDynamicGrid _grid;
  101. public DynamicGridSummaryStyleSelector(IDynamicGrid grid)
  102. {
  103. _grid = grid;
  104. }
  105. public override Style SelectStyle(object item, DependencyObject container)
  106. {
  107. var vcol = ((GridTableSummaryCell)container).ColumnBase.ColumnIndex;
  108. var col = vcol > -1 && vcol < _grid.VisibleColumns.Count ? _grid.VisibleColumns[vcol] : null;
  109. var style = new Style(typeof(GridTableSummaryCell));
  110. style.Setters.Add(new Setter(Control.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  111. style.Setters.Add(new Setter(Control.ForegroundProperty, new SolidColorBrush(Colors.Black)));
  112. style.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty,
  113. col != null ? col.HorizontalAlignment(typeof(double)) : HorizontalAlignment.Right));
  114. style.Setters.Add(new Setter(Control.BorderBrushProperty, new SolidColorBrush(Colors.Gray)));
  115. style.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0, 0, 0.75, 0)));
  116. style.Setters.Add(new Setter(Control.FontSizeProperty, 12D));
  117. style.Setters.Add(new Setter(Control.FontWeightProperty, FontWeights.DemiBold));
  118. return style;
  119. }
  120. }
  121. // Used to render boolean columns (the default "false" value shows what appears to be an intermediate state, which is ugly
  122. // This should show nothing for false, and a tick in a box for true
  123. public class BoolToImageConverter : UtilityConverter<bool,ImageSource>
  124. {
  125. public ImageSource TrueValue { get; set; }
  126. public ImageSource FalseValue { get; set; }
  127. public BoolToImageConverter()
  128. {
  129. TrueValue = Wpf.Resources.Bullet_Tick.AsBitmapImage();
  130. }
  131. public override ImageSource Convert(bool value)
  132. {
  133. return value ? TrueValue : FalseValue;
  134. }
  135. public override bool Deconvert(ImageSource value)
  136. {
  137. return ImageUtils.IsEqual(value as BitmapImage,TrueValue as BitmapImage);
  138. }
  139. }
  140. public class StringToColorImageConverter : IValueConverter
  141. {
  142. private readonly int _height = 50;
  143. private readonly int _width = 25;
  144. private readonly Dictionary<string, BitmapImage> cache = new();
  145. public StringToColorImageConverter(int width, int height)
  146. {
  147. _width = width;
  148. _height = height;
  149. }
  150. public object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
  151. {
  152. var str = value?.ToString();
  153. if (str is null)
  154. return null;
  155. var colorcode = str.TrimStart('#');
  156. if (!cache.ContainsKey(colorcode))
  157. {
  158. var col = ImageUtils.StringToColor(colorcode);
  159. var bmp = ImageUtils.BitmapFromColor(col, _width, _height, Color.Black);
  160. cache[colorcode] = bmp.AsBitmapImage();
  161. }
  162. var result = cache[colorcode];
  163. return result;
  164. }
  165. public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  166. {
  167. return null;
  168. }
  169. }
  170. public class StringArrayConverter : IValueConverter
  171. {
  172. object? IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
  173. {
  174. if (value is string[] strArray)
  175. {
  176. return string.Join("\n", strArray);
  177. }
  178. Logger.Send(LogType.Error, "", $"Attempt to convert an object which is not a string array: {value}.");
  179. return null;
  180. }
  181. object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  182. {
  183. return value;
  184. }
  185. }
  186. [Serializable]
  187. class DynamicGridDragFormat
  188. {
  189. private string entity;
  190. public DataTable Table { get; set; }
  191. public Type Entity { get => CoreUtils.GetEntity(entity); set => entity = value.EntityName(); }
  192. public DynamicGridDragFormat(DataTable table, Type entity)
  193. {
  194. Table = table;
  195. Entity = entity;
  196. }
  197. }
  198. public abstract class DynamicGrid<T> : BaseDynamicGrid<T> where T : BaseObject, new()
  199. {
  200. private readonly Dictionary<string, string> _filterpredicates = new();
  201. private UIElement? _header;
  202. private readonly Button Add;
  203. private bool bChanged;
  204. public bool bRefreshing;
  205. private readonly Label ClipboardSpacer;
  206. private readonly ContextMenu ColumnsMenu;
  207. private readonly Button Copy;
  208. private readonly Label Count;
  209. private readonly Button Cut;
  210. private readonly SfDataGrid DataGrid;
  211. private readonly Border Disabler;
  212. private readonly Button Delete;
  213. private readonly DockPanel Docker;
  214. private readonly DynamicRowMovementColumn? down;
  215. private readonly Button Edit;
  216. private readonly Label EditSpacer;
  217. private readonly Button Export;
  218. private readonly Label ExportSpacer;
  219. private readonly Button DuplicateBtn;
  220. private readonly Button SwitchViewBtn;
  221. private readonly GridRowSizingOptions gridRowResizingOptions = new() { CanIncludeHiddenColumns = false, AutoFitMode = AutoFitMode.SmartFit };
  222. private readonly Button Help;
  223. private readonly Button Import;
  224. private T? inplaceeditor;
  225. private readonly Grid Layout;
  226. private readonly Label Loading;
  227. private DoubleAnimation LoadingFader = new DoubleAnimation(1d, 0.2d, new Duration(TimeSpan.FromSeconds(2))) { AutoReverse = true };
  228. protected Dictionary<string, CoreTable> Lookups = new();
  229. //private readonly Button MultiEdit;
  230. private readonly Button Paste;
  231. private readonly Button Print;
  232. private readonly Label PrintSpacer;
  233. private readonly StackPanel LeftButtonStack;
  234. private readonly StackPanel RightButtonStack;
  235. private readonly DynamicRowMovementColumn? up;
  236. /// <summary>
  237. /// <see langword="null"/> when <see cref="DataGrid.ItemsSource"/> is <see langword="null"/>, generally while the grid is refreshing its columns.
  238. /// </summary>
  239. private DataTable? DataGridItems => (DataGrid.ItemsSource as DataTable);
  240. #region Events
  241. public event SelectItemHandler? OnSelectItem;
  242. public event OnCellDoubleClick? OnCellDoubleClick;
  243. public event EventHandler? OnChanged;
  244. public delegate void BeforeSelectionEvent(CancelEventArgs cancel);
  245. public event BeforeSelectionEvent? OnBeforeSelection;
  246. public void DoChanged() => OnChanged?.Invoke(this, EventArgs.Empty);
  247. public event EditorValueChangedHandler? OnEditorValueChanged;
  248. public override event OnCustomiseEditor<T>? OnCustomiseEditor;
  249. public override event OnCustomiseColumns? OnCustomiseColumns;
  250. public override event OnFilterRecord? OnFilterRecord;
  251. public override event OnDoubleClick? OnDoubleClick;
  252. public override event EntitySaveEvent? OnBeforeSave;
  253. public override event EntitySaveEvent? OnAfterSave;
  254. public delegate void EditorLoaded(IDynamicEditorForm editor, T[] items);
  255. public event EditorLoaded OnEditorLoaded;
  256. #endregion
  257. private DynamicGridCellStyleConverter<System.Windows.Media.Brush?> CellBackgroundConverter;
  258. private DynamicGridCellStyleConverter<System.Windows.Media.Brush?> CellForegroundConverter;
  259. private DynamicGridCellStyleConverter<double?> CellFontSizeConverter;
  260. private DynamicGridCellStyleConverter<System.Windows.FontStyle?> CellFontStyleConverter;
  261. private DynamicGridCellStyleConverter<System.Windows.FontWeight?> CellFontWeightConverter;
  262. protected virtual Brush? GetCellBackground(CoreRow row, String columnname) => null;
  263. protected virtual Brush? GetCellForeground(CoreRow row, String columnname) => null;
  264. protected virtual double? GetCellFontSize(CoreRow row, String columnname) => null;
  265. protected virtual FontStyle? GetCellFontStyle(CoreRow row, String columnname) => null;
  266. protected virtual FontWeight? GetCellFontWeight(CoreRow row, String columnname) => null;
  267. protected DynamicGridSettings Settings { get; set; }
  268. public DynamicGrid() : base()
  269. {
  270. IsReady = false;
  271. Data = new CoreTable();
  272. ColumnsMenu = new ContextMenu();
  273. ColumnsMenu.Opened += ColumnsMenu_ContextMenuOpening;
  274. MasterColumns = new DynamicGridColumns();
  275. MasterColumns.ExtractColumns(typeof(T));
  276. foreach (var column in LookupFactory.RequiredColumns<T>().ColumnNames())
  277. {
  278. AddHiddenColumn(column);
  279. }
  280. ActionColumns = new DynamicActionColumns();
  281. if (IsSequenced)
  282. {
  283. up = new DynamicRowMovementColumn(DynamicRowMovement.Up, SwapRows);
  284. ActionColumns.Add(up);
  285. down = new DynamicRowMovementColumn(DynamicRowMovement.Down, SwapRows);
  286. ActionColumns.Add(down);
  287. HiddenColumns.Add(x => (x as ISequenceable)!.Sequence);
  288. }
  289. CellBackgroundConverter = new DynamicGridCellStyleConverter<System.Windows.Media.Brush?>(this, GetCellBackground);
  290. CellForegroundConverter = new DynamicGridCellStyleConverter<System.Windows.Media.Brush?>(this, GetCellForeground);
  291. CellFontSizeConverter = new DynamicGridCellStyleConverter<double?>(this, GetCellFontSize);
  292. CellFontStyleConverter = new DynamicGridCellStyleConverter<System.Windows.FontStyle?>(this, GetCellFontStyle);
  293. CellFontWeightConverter = new DynamicGridCellStyleConverter<System.Windows.FontWeight?>(this, GetCellFontWeight);
  294. VisibleColumns = new DynamicGridColumns();
  295. DataGrid = new SfDataGrid();
  296. DataGrid.VerticalAlignment = VerticalAlignment.Stretch;
  297. DataGrid.HorizontalAlignment = HorizontalAlignment.Stretch;
  298. DataGrid.HeaderContextMenu = ColumnsMenu;
  299. DataGrid.CellTapped += DataGrid_CellTapped;
  300. DataGrid.CellDoubleTapped += DataGrid_CellDoubleTapped;
  301. DataGrid.SelectionChanging += DataGrid_SelectionChanging;
  302. DataGrid.SelectionChanged += DataGrid_SelectionChanged;
  303. DataGrid.SelectionMode = GridSelectionMode.Extended;
  304. DataGrid.SelectionUnit = GridSelectionUnit.Row;
  305. DataGrid.CanMaintainScrollPosition = true;
  306. DataGrid.SummaryCalculationUnit = SummaryCalculationUnit.AllRows;
  307. DataGrid.LiveDataUpdateMode = LiveDataUpdateMode.AllowSummaryUpdate;
  308. DataGrid.NavigationMode = NavigationMode.Row;
  309. DataGrid.AllowEditing = false;
  310. DataGrid.EditTrigger = EditTrigger.OnTap;
  311. DataGrid.CurrentCellBeginEdit += DataGrid_CurrentCellBeginEdit;
  312. DataGrid.CurrentCellEndEdit += DataGrid_CurrentCellEndEdit;
  313. DataGrid.CurrentCellValueChanged += DataGrid_CurrentCellValueChanged;
  314. DataGrid.CurrentCellDropDownSelectionChanged += DataGrid_CurrentCellDropDownSelectionChanged;
  315. DataGrid.CurrentCellRequestNavigate += DataGrid_CurrentCellRequestNavigate;
  316. DataGrid.PreviewKeyUp += DataGrid_PreviewKeyUp;
  317. DataGrid.CurrentCellActivated += DataGrid_CurrentCellActivated;
  318. DataGrid.BorderBrush = new SolidColorBrush(Colors.Gray);
  319. DataGrid.BorderThickness = new Thickness(0.75F);
  320. DataGrid.Background = new SolidColorBrush(Colors.DimGray);
  321. DataGrid.AutoGenerateColumns = false;
  322. DataGrid.ColumnSizer = GridLengthUnitType.AutoLastColumnFill;
  323. DataGrid.SelectionForegroundBrush = BaseDynamicGrid.SelectionForeground;
  324. DataGrid.RowSelectionBrush = BaseDynamicGrid.SelectionBackground;
  325. DataGrid.AllowDraggingRows = false;
  326. DataGrid.Drop += DataGrid_Drop;
  327. DataGrid.DragOver += DataGrid_DragOver;
  328. DataGrid.RowDragDropTemplate = TemplateGenerator.CreateDataTemplate(() =>
  329. {
  330. var border = new Border();
  331. border.Width = 100;
  332. border.Height = 100;
  333. border.BorderBrush = new SolidColorBrush(Colors.Firebrick);
  334. border.Background = new SolidColorBrush(Colors.Red);
  335. border.CornerRadius = new CornerRadius(5);
  336. return border;
  337. });
  338. DataGrid.CurrentCellBorderThickness = new Thickness(0);
  339. DataGrid.AllowFiltering = false;
  340. DataGrid.EnableDataVirtualization = true;
  341. DataGrid.RowHeight = 30;
  342. DataGrid.QueryRowHeight += DataGrid_QueryRowHeight;
  343. DataGrid.HeaderRowHeight = 30;
  344. DataGrid.MouseLeftButtonUp += DataGrid_MouseLeftButtonUp;
  345. DataGrid.MouseRightButtonUp += DataGrid_MouseRightButtonUp;
  346. DataGrid.KeyUp += DataGrid_KeyUp;
  347. DataGrid.PreviewGotKeyboardFocus += DataGrid_PreviewGotKeyboardFocus;
  348. //DataGrid.SelectionController = new GridSelectionControllerExt(DataGrid);
  349. DataGrid.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Visible);
  350. DataGrid.FilterChanged += DataGrid_FilterChanged;
  351. DataGrid.FilterItemsPopulating += DataGrid_FilterItemsPopulating;
  352. var fltstyle = new Style(typeof(GridFilterControl));
  353. fltstyle.Setters.Add(new Setter(GridFilterControl.FilterModeProperty, FilterMode.Both));
  354. fltstyle.Setters.Add(new Setter(GridFilterControl.SortOptionVisibilityProperty, Visibility.Collapsed));
  355. DataGrid.FilterPopupStyle = fltstyle;
  356. DataGrid.RowStyleSelector = RowStyleSelector;
  357. DataGrid.TableSummaryCellStyleSelector = new DynamicGridSummaryStyleSelector(this);
  358. //DataGrid.MouseMove += DataGrid_MouseMove;
  359. DataGrid.CellToolTipOpening += DataGrid_CellToolTipOpening;
  360. //var headstyle = new Style(typeof(GridHeaderCellControl));
  361. //headstyle.Setters.Add(new Setter(GridHeaderCellControl.BackgroundProperty, new SolidColorBrush(Colors.WhiteSmoke)));
  362. //headstyle.Setters.Add(new Setter(GridHeaderCellControl.ForegroundProperty, new SolidColorBrush(Colors.Green)));
  363. //headstyle.Setters.Add(new Setter(GridHeaderCellControl.FontSizeProperty, 12.0F));
  364. //DataGrid.HeaderStyle = headstyle;
  365. DataGrid.SizeChanged += DataGrid_SizeChanged;
  366. DataGrid.SetValue(Grid.RowProperty, 1);
  367. Loading = new Label();
  368. Loading.Content = "Loading...";
  369. Loading.Foreground = new SolidColorBrush(Colors.White);
  370. Loading.VerticalContentAlignment = VerticalAlignment.Center;
  371. Loading.HorizontalContentAlignment = HorizontalAlignment.Center;
  372. Loading.Visibility = Visibility.Collapsed;
  373. Loading.SetValue(Panel.ZIndexProperty, 999);
  374. Loading.SetValue(Grid.RowProperty, 1);
  375. Loading.FontSize = 14.0F;
  376. LoadingFader.Completed += (sender, args) =>
  377. {
  378. if (Loading.Visibility == Visibility.Visible)
  379. {
  380. //Logger.Send(LogType.Information, this.GetType().EntityName().Split(".").Last(), "Loading Fader Restarting");
  381. Loading.BeginAnimation(Label.OpacityProperty, LoadingFader);
  382. }
  383. };
  384. Help = CreateButton(Wpf.Resources.help.AsBitmapImage(Color.White));
  385. Help.Margin = new Thickness(0, 2, 2, 0);
  386. Help.SetValue(DockPanel.DockProperty, Dock.Right);
  387. Help.Click += (o, e) => ShowHelp(typeof(T).Name.Split('.').Last().SplitCamelCase().Replace(" ", "_"));
  388. Add = CreateButton(Wpf.Resources.add.AsBitmapImage(Color.White));
  389. Add.Margin = new Thickness(0, 2, 2, 0);
  390. Add.Click += Add_Click;
  391. Edit = CreateButton(Wpf.Resources.pencil.AsBitmapImage(Color.White));
  392. Edit.Margin = new Thickness(0, 2, 2, 0);
  393. Edit.Click += Edit_Click;
  394. SwitchViewBtn = CreateButton(Wpf.Resources.alter.AsBitmapImage());
  395. SwitchViewBtn.Margin = new Thickness(0, 2, 2, 0);
  396. SwitchViewBtn.Click += SwitchView_Click;
  397. EditSpacer = new Label { Width = 5 };
  398. Print = CreateButton(Wpf.Resources.print.AsBitmapImage(Color.White));
  399. Print.Margin = new Thickness(0, 2, 2, 0);
  400. Print.Click += (o, e) => DoPrint(o);
  401. PrintSpacer = new Label { Width = 5 };
  402. Cut = CreateButton(Wpf.Resources.cut.AsBitmapImage(Color.White));
  403. Cut.Margin = new Thickness(0, 2, 2, 0);
  404. Cut.Click += Cut_Click;
  405. Copy = CreateButton(Wpf.Resources.copy.AsBitmapImage(Color.White));
  406. Copy.Margin = new Thickness(0, 2, 2, 0);
  407. Copy.Click += Copy_Click;
  408. Paste = CreateButton(Wpf.Resources.paste.AsBitmapImage(Color.White));
  409. Paste.Margin = new Thickness(0, 2, 2, 0);
  410. Paste.Click += Paste_Click;
  411. ClipboardSpacer = new Label { Width = 5 };
  412. Export = CreateButton(Wpf.Resources.doc_xls.AsBitmapImage(Color.White), "Export");
  413. Export.Margin = new Thickness(0, 2, 2, 0);
  414. Export.Click += Export_Click;
  415. Import = CreateButton(Wpf.Resources.doc_xls.AsBitmapImage(Color.White), "Import");
  416. Import.Margin = new Thickness(0, 2, 2, 0);
  417. Import.Click += Import_Click;
  418. ExportSpacer = new Label { Width = 5 };
  419. LeftButtonStack = new StackPanel();
  420. LeftButtonStack.Orientation = Orientation.Horizontal;
  421. LeftButtonStack.SetValue(DockPanel.DockProperty, Dock.Left);
  422. LeftButtonStack.Children.Add(Help);
  423. LeftButtonStack.Children.Add(Add);
  424. LeftButtonStack.Children.Add(Edit);
  425. LeftButtonStack.Children.Add(SwitchViewBtn);
  426. //Stack.Children.Add(MultiEdit);
  427. LeftButtonStack.Children.Add(EditSpacer);
  428. LeftButtonStack.Children.Add(Print);
  429. LeftButtonStack.Children.Add(PrintSpacer);
  430. LeftButtonStack.Children.Add(Cut);
  431. LeftButtonStack.Children.Add(Copy);
  432. LeftButtonStack.Children.Add(Paste);
  433. LeftButtonStack.Children.Add(ClipboardSpacer);
  434. LeftButtonStack.Children.Add(Export);
  435. LeftButtonStack.Children.Add(Import);
  436. LeftButtonStack.Children.Add(ExportSpacer);
  437. RightButtonStack = new StackPanel();
  438. RightButtonStack.Orientation = Orientation.Horizontal;
  439. RightButtonStack.SetValue(DockPanel.DockProperty, Dock.Right);
  440. Delete = CreateButton(Wpf.Resources.delete.AsBitmapImage(Color.White));
  441. Delete.Margin = new Thickness(2, 2, 0, 0);
  442. Delete.SetValue(DockPanel.DockProperty, Dock.Right);
  443. Delete.Click += Delete_Click;
  444. DuplicateBtn = AddButton("Duplicate", Wpf.Resources.paste.AsBitmapImage(Color.White), DoDuplicate);
  445. Count = new Label();
  446. Count.Height = 30;
  447. Count.Margin = new Thickness(0, 2, 0, 0);
  448. Count.VerticalContentAlignment = VerticalAlignment.Center;
  449. Count.HorizontalContentAlignment = HorizontalAlignment.Center;
  450. Count.SetValue(DockPanel.DockProperty, Dock.Left);
  451. Docker = new DockPanel();
  452. Docker.SetValue(Grid.RowProperty, 2);
  453. Docker.SetValue(Grid.ColumnProperty, 0);
  454. Docker.Children.Add(LeftButtonStack);
  455. Docker.Children.Add(Delete);
  456. Docker.Children.Add(RightButtonStack);
  457. Docker.Children.Add(Count);
  458. Layout = new Grid();
  459. Layout.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
  460. Layout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
  461. Layout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
  462. Layout.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
  463. Layout.Children.Add(DataGrid);
  464. Layout.Children.Add(Loading);
  465. Layout.Children.Add(Docker);
  466. Disabler = new Border()
  467. {
  468. BorderBrush = new SolidColorBrush(Colors.Transparent),
  469. Background = new SolidColorBrush(Colors.DimGray) { Opacity = 0.2 },
  470. Visibility = Visibility.Collapsed,
  471. };
  472. Disabler.SetValue(Canvas.ZIndexProperty, 99);
  473. Disabler.SetValue(Grid.RowSpanProperty, 3);
  474. Layout.Children.Add(Disabler);
  475. //Scroll.ApplyTemplate();
  476. Content = Layout;
  477. IsEnabledChanged += (sender, args) =>
  478. {
  479. Disabler.Visibility = Equals(args.NewValue, true)
  480. ? Visibility.Collapsed
  481. : Visibility.Visible;
  482. };
  483. Settings = LoadSettings();
  484. Init();
  485. Reconfigure();
  486. }
  487. protected virtual void BeforeSelection(CancelEventArgs cancel)
  488. {
  489. OnBeforeSelection?.Invoke(cancel);
  490. }
  491. private void DataGrid_SelectionChanging(object? sender, Syncfusion.UI.Xaml.Grid.GridSelectionChangingEventArgs e)
  492. {
  493. var cancel = new CancelEventArgs();
  494. BeforeSelection(cancel);
  495. if (cancel.Cancel)
  496. {
  497. e.Cancel = true;
  498. }
  499. }
  500. private void DataGrid_SelectionChanged(object? sender, GridSelectionChangedEventArgs e)
  501. {
  502. }
  503. public bool IsReady { get; private set; }
  504. public UIElement? Header
  505. {
  506. get => _header;
  507. set
  508. {
  509. if (_header is not null && Layout.Children.Contains(_header))
  510. Layout.Children.Remove(_header);
  511. _header = value;
  512. if (_header is not null)
  513. {
  514. _header.SetValue(Grid.RowProperty, 0);
  515. _header.SetValue(Grid.ColumnProperty, 0);
  516. _header.SetValue(Grid.ColumnSpanProperty, 2);
  517. Layout.Children.Add(_header);
  518. }
  519. }
  520. }
  521. /// <summary>
  522. /// Represents the data in the grid. This is <see langword="null"/> until <see cref="Refresh(bool, bool)"/> is called.
  523. /// </summary>
  524. public CoreTable? MasterData { get; set; }
  525. public DynamicActionColumns ActionColumns { get; }
  526. private bool IsSequenced => typeof(T).GetInterfaces().Any(x => x.Equals(typeof(ISequenceable)));
  527. public override double RowHeight
  528. {
  529. get => DataGrid.RowHeight;
  530. set => DataGrid.RowHeight = value;
  531. }
  532. public override double HeaderHeight
  533. {
  534. get => DataGrid.HeaderRowHeight;
  535. set => DataGrid.HeaderRowHeight = value;
  536. }
  537. protected override void OptionsChanged()
  538. {
  539. var reloadColumns = false;
  540. ColumnsMenu.Visibility = HasOption(DynamicGridOption.SelectColumns) ? Visibility.Visible : Visibility.Hidden;
  541. Help.Visibility = HasOption(DynamicGridOption.ShowHelp) ? Visibility.Visible : Visibility.Collapsed;
  542. Add.Visibility = HasOption(DynamicGridOption.AddRows) ? Visibility.Visible : Visibility.Collapsed;
  543. Edit.Visibility = HasOption(DynamicGridOption.EditRows) ? Visibility.Visible : Visibility.Collapsed;
  544. EditSpacer.Visibility = HasOption(DynamicGridOption.AddRows) || HasOption(DynamicGridOption.EditRows)
  545. ? Visibility.Visible
  546. : Visibility.Collapsed;
  547. Print.Visibility = HasOption(DynamicGridOption.Print) ? Visibility.Visible : Visibility.Collapsed;
  548. PrintSpacer.Visibility = HasOption(DynamicGridOption.Print) ? Visibility.Visible : Visibility.Collapsed;
  549. Cut.Visibility = IsSequenced && HasOption(DynamicGridOption.EditRows) ? Visibility.Visible : Visibility.Collapsed;
  550. Copy.Visibility = IsSequenced && HasOption(DynamicGridOption.EditRows) ? Visibility.Visible : Visibility.Collapsed;
  551. Paste.Visibility = IsSequenced && HasOption(DynamicGridOption.EditRows) ? Visibility.Visible : Visibility.Collapsed;
  552. ClipboardSpacer.Visibility = IsSequenced && HasOption(DynamicGridOption.EditRows) ? Visibility.Visible : Visibility.Collapsed;
  553. Export.Visibility = HasOption(DynamicGridOption.ExportData) ? Visibility.Visible : Visibility.Collapsed;
  554. Import.Visibility = HasOption(DynamicGridOption.ImportData) ? Visibility.Visible : Visibility.Collapsed;
  555. ExportSpacer.Visibility = HasOption(DynamicGridOption.ExportData) || HasOption(DynamicGridOption.ImportData)
  556. ? Visibility.Visible
  557. : Visibility.Collapsed;
  558. SwitchViewBtn.Visibility = HasOption(DynamicGridOption.DirectEdit) ? Visibility.Visible : Visibility.Collapsed;
  559. var allowEditing = IsDirectEditMode();
  560. if (DataGrid.AllowEditing != allowEditing)
  561. {
  562. DataGrid.NavigationMode = allowEditing ? NavigationMode.Cell : NavigationMode.Row;
  563. DataGrid.AllowEditing = allowEditing;
  564. reloadColumns = true;
  565. }
  566. Count.Visibility = HasOption(DynamicGridOption.RecordCount) ? Visibility.Visible : Visibility.Collapsed;
  567. Delete.Visibility = HasOption(DynamicGridOption.DeleteRows) ? Visibility.Visible : Visibility.Collapsed;
  568. DataGrid.AllowFiltering = HasOption(DynamicGridOption.FilterRows);
  569. DataGrid.FilterRowPosition = HasOption(DynamicGridOption.FilterRows) ? FilterRowPosition.FixedTop : FilterRowPosition.None;
  570. if (HasOption(DynamicGridOption.DragSource))
  571. {
  572. if (!DataGrid.AllowDraggingRows)
  573. {
  574. DataGrid.AllowDraggingRows = true;
  575. DataGrid.RowDragDropController.DragStart += RowDragDropController_DragStart;
  576. }
  577. }
  578. else
  579. {
  580. if (DataGrid.AllowDraggingRows)
  581. {
  582. DataGrid.AllowDraggingRows = false;
  583. DataGrid.RowDragDropController.DragStart -= RowDragDropController_DragStart;
  584. }
  585. }
  586. DataGrid.AllowDrop = HasOption(DynamicGridOption.DragTarget);
  587. DataGrid.SelectionMode = HasOption(DynamicGridOption.MultiSelect) ? GridSelectionMode.Extended : GridSelectionMode.Single;
  588. if (up != null)
  589. up.Position = HasOption(DynamicGridOption.EditRows) ? DynamicActionColumnPosition.Start : DynamicActionColumnPosition.Hidden;
  590. if (down != null)
  591. down.Position = HasOption(DynamicGridOption.EditRows) ? DynamicActionColumnPosition.Start : DynamicActionColumnPosition.Hidden;
  592. if (DuplicateBtn != null)
  593. DuplicateBtn.Visibility = Visibility.Collapsed;
  594. if(reloadColumns && DataGrid.Columns.Count > 0)
  595. {
  596. Refresh(true, false);
  597. }
  598. }
  599. protected virtual DynamicGridSettings LoadSettings()
  600. {
  601. return new DynamicGridSettings();
  602. }
  603. protected virtual void SaveSettings(DynamicGridSettings settings)
  604. {
  605. }
  606. public bool IsDirectEditMode(IEnumerable<DynamicGridOption>? options = null)
  607. {
  608. return HasOption(DynamicGridOption.DirectEdit, options)
  609. && (Settings.ViewMode == DynamicGridSettings.DynamicGridViewMode.DirectEdit
  610. || Settings.ViewMode == DynamicGridSettings.DynamicGridViewMode.Default);
  611. }
  612. private void SwitchView_Click(object sender, RoutedEventArgs e)
  613. {
  614. Settings.ViewMode = Settings.ViewMode switch
  615. {
  616. DynamicGridSettings.DynamicGridViewMode.Default => DynamicGridSettings.DynamicGridViewMode.Normal,
  617. DynamicGridSettings.DynamicGridViewMode.Normal => DynamicGridSettings.DynamicGridViewMode.DirectEdit,
  618. DynamicGridSettings.DynamicGridViewMode.DirectEdit or _ => DynamicGridSettings.DynamicGridViewMode.Normal
  619. };
  620. SaveSettings(Settings);
  621. Reconfigure();
  622. }
  623. protected override DynamicGridRowStyleSelector<T> GetRowStyleSelector()
  624. {
  625. return new DynamicGridRowStyleSelector<T, DynamicGridRowStyle>();
  626. }
  627. protected override DynamicGridStyle GetRowStyle(CoreRow row, DynamicGridStyle style)
  628. {
  629. var result = base.GetRowStyle(row, style);
  630. if (ClipBuffer != null)
  631. if (ClipBuffer.Item2.Contains(row))
  632. {
  633. var bgbrush = style.Background as SolidColorBrush;
  634. var bgcolor = bgbrush != null ? bgbrush.Color : Colors.Transparent;
  635. result = new DynamicGridRowStyle(style);
  636. result.Background = ClipBuffer.Item1 == ClipAction.Cut
  637. ? new SolidColorBrush(bgcolor.MixColors(0.5, Colors.Orchid))
  638. : new SolidColorBrush(bgcolor.MixColors(0.5, Colors.LightGreen));
  639. result.Foreground = new SolidColorBrush(Colors.Gray);
  640. result.FontStyle = FontStyles.Italic;
  641. }
  642. return result;
  643. }
  644. private void DataGrid_CurrentCellActivated(object? sender, CurrentCellActivatedEventArgs e)
  645. {
  646. // if (!IsDirectEditMode())
  647. // return;
  648. // if ((DataGrid.SelectionController.CurrentCellManager.CurrentCell?.IsEditing != true) &&
  649. // e.ActivationTrigger == ActivationTrigger.Keyboard)
  650. // {
  651. // var result = DataGrid.SelectionController.CurrentCellManager.BeginEdit();
  652. // }
  653. }
  654. private void DataGrid_PreviewKeyUp(object sender, KeyEventArgs e)
  655. {
  656. if (e.Key == Key.OemPeriod)
  657. {
  658. var editor = e.OriginalSource as TimeSpanEdit;
  659. if (editor != null && editor.SelectionStart < 2) editor.SelectionStart = 3;
  660. }
  661. else if (e.Key == Key.Tab)
  662. {
  663. if (IsDirectEditMode())
  664. {
  665. DataGrid.SelectionController.CurrentCellManager.EndEdit();
  666. DataGrid.MoveFocus(new TraversalRequest(FocusNavigationDirection.Right));
  667. DataGrid.SelectionController.CurrentCellManager.BeginEdit();
  668. e.Handled = true;
  669. }
  670. }
  671. //throw new NotImplementedException();
  672. }
  673. private void DataGrid_CurrentCellRequestNavigate(object? sender, CurrentCellRequestNavigateEventArgs e)
  674. {
  675. //throw new NotImplementedException();
  676. }
  677. private void DataGrid_FilterChanged(object? o, GridFilterEventArgs e)
  678. {
  679. var col = DataGrid.Columns.IndexOf(e.Column);
  680. if (ColumnList[col] is DynamicActionColumn column)
  681. {
  682. if (e.FilterPredicates != null)
  683. {
  684. var filter = e.FilterPredicates.Select(x => x.FilterValue.ToString()!).ToArray();
  685. bool include = e.FilterPredicates.Any(x => x.FilterType == FilterType.Equals);
  686. column.SelectedFilters = include ? filter : (column.Filters ?? Enumerable.Empty<string>()).Except(filter).ToArray();
  687. }
  688. else
  689. column.SelectedFilters = Array.Empty<string>();
  690. DataGrid.ClearFilter(e.Column);
  691. //e.FilterPredicates?.Clear();
  692. //e.FilterPredicates?.Add(new FilterPredicate() { PredicateType = PredicateType.Or, FilterBehavior = Syncfusion.Data.FilterBehavior.StringTyped, FilterMode = ColumnFilter.DisplayText, FilterType = Syncfusion.Data.FilterType.NotEquals, FilterValue = "" });
  693. //e.FilterPredicates?.Add(new FilterPredicate() { PredicateType = PredicateType.Or, FilterBehavior = Syncfusion.Data.FilterBehavior.StringTyped, FilterMode = ColumnFilter.DisplayText, FilterType = Syncfusion.Data.FilterType.Equals, FilterValue = "" });
  694. Refresh(false, false);
  695. e.Handled = true;
  696. }
  697. if (e.FilterPredicates == null)
  698. {
  699. if (_filterpredicates.ContainsKey(e.Column.MappingName))
  700. _filterpredicates.Remove(e.Column.MappingName);
  701. }
  702. else
  703. {
  704. _filterpredicates[e.Column.MappingName] = Serialization.Serialize(e.FilterPredicates, true);
  705. }
  706. UpdateRecordCount();
  707. }
  708. private void DataGrid_FilterItemsPopulating(object? sender, GridFilterItemsPopulatingEventArgs e)
  709. {
  710. var col = DataGrid.Columns.IndexOf(e.Column);
  711. if (ColumnList[col] is DynamicActionColumn column && column.Filters is not null)
  712. e.ItemsSource = column.Filters.Select(x => new FilterElement
  713. { DisplayText = x, ActualValue = x, IsSelected = column.SelectedFilters is null || column.SelectedFilters.Contains(x) });
  714. }
  715. private CoreRow? GetRowFromIndex(int rowIndex)
  716. {
  717. var row = rowIndex - (HasOption(DynamicGridOption.FilterRows) ? 2 : 1);
  718. if (row < 0 || DataGridItems is null)
  719. return null;
  720. row = DataGridItems.Rows.IndexOf((DataGrid.View.Records[row].Data as DataRowView)!.Row);
  721. if (row < 0)
  722. return null;
  723. return Data.Rows[row];
  724. }
  725. private void DataGrid_CellToolTipOpening(object? sender, GridCellToolTipOpeningEventArgs e)
  726. {
  727. if (ColumnList[e.RowColumnIndex.ColumnIndex] is not DynamicActionColumn col)
  728. return;
  729. var toolTip = col.ToolTip;
  730. if (toolTip is null)
  731. return;
  732. var row = GetRowFromIndex(e.RowColumnIndex.RowIndex);
  733. e.ToolTip.Template = TemplateGenerator.CreateControlTemplate(
  734. typeof(ToolTip),
  735. () => toolTip.Invoke(col, row)
  736. );
  737. }
  738. //private void DataGrid_MouseMove(object sender, MouseEventArgs e)
  739. //{
  740. // var visualcontainer = DataGrid.GetVisualContainer();
  741. // var point = e.GetPosition(visualcontainer);
  742. // var rowColumnIndex = visualcontainer.PointToCellRowColumnIndex(point);
  743. // var recordIndex = DataGrid.ResolveToRecordIndex(rowColumnIndex.RowIndex);
  744. // if (recordIndex < 0)
  745. // return;
  746. // if (!rowColumnIndex.IsEmpty)
  747. // {
  748. // if (DataGrid.View.TopLevelGroup != null)
  749. // {
  750. // // Get the current row record while grouping
  751. // var record = DataGrid.View.TopLevelGroup.DisplayElements[recordIndex];
  752. // if (record.GetType() == typeof(RecordEntry))
  753. // {
  754. // var data = (record as RecordEntry).Data as CoreRow;
  755. // }
  756. // }
  757. // else
  758. // {
  759. // //For getting the record, need to resolve the corresponding record index from row index                     
  760. // var record1 = DataGrid.View.Records[DataGrid.ResolveToRecordIndex(rowColumnIndex.RowIndex)].Data;
  761. // }
  762. // //Gets the column from ColumnsCollection by resolving the corresponding column index from  GridVisibleColumnIndex                      
  763. // var gridColumn = DataGrid.Columns[DataGrid.ResolveToGridVisibleColumnIndex(rowColumnIndex.ColumnIndex)];
  764. // if (gridColumn is GridImageColumn)
  765. // {
  766. // }
  767. // }
  768. //}
  769. protected virtual void LoadColumnsMenu(ContextMenu menu)
  770. {
  771. }
  772. private void DataGrid_CurrentCellBeginEdit(object? sender, CurrentCellBeginEditEventArgs e)
  773. {
  774. var headerrows = HasOption(DynamicGridOption.FilterRows) ? 2 : 1;
  775. if (e.RowColumnIndex.RowIndex < headerrows || DataGridItems is null)
  776. return;
  777. inplaceeditor ??= LoadItem(Data.Rows[e.RowColumnIndex.RowIndex - headerrows]);
  778. var column = DataGrid.Columns[e.RowColumnIndex.ColumnIndex] as GridComboBoxColumn;
  779. if (column != null && column.ItemsSource == null)
  780. {
  781. var colname = column.MappingName;
  782. var colno = DataGridItems.Columns.IndexOf(colname);
  783. var property = Data.Columns[colno].ColumnName;
  784. var prop = CoreUtils.GetProperty(typeof(T), property);
  785. var editor = prop.GetEditor();
  786. if (editor is ILookupEditor)
  787. {
  788. if (!Lookups.ContainsKey(property))
  789. Lookups[property] = ((ILookupEditor)editor).Values(property);
  790. var combo = column;
  791. combo.ItemsSource = Lookups[property].ToDictionary(Lookups[property].Columns[0].ColumnName, "Display");
  792. combo.SelectedValuePath = "Key";
  793. combo.DisplayMemberPath = "Value";
  794. }
  795. }
  796. bChanged = false;
  797. }
  798. private void DataGrid_CurrentCellValueChanged(object? sender, CurrentCellValueChangedEventArgs e)
  799. {
  800. // Are we sure that this function is ever useful? It seems that since the data in the grid hasn't been updated by this point, this function is essentially useless (the data is updated in EndEdit). Probably need to check the GridCheckBoxColumn
  801. var headerrows = HasOption(DynamicGridOption.FilterRows) ? 2 : 1;
  802. if (e.RowColumnIndex.RowIndex < headerrows)
  803. return;
  804. if (e.Column is GridCheckBoxColumn)
  805. inplaceeditor = LoadItem(Data.Rows[e.RowColumnIndex.RowIndex - headerrows]);
  806. if (inplaceeditor is not null)
  807. UpdateData(e.RowColumnIndex.ColumnIndex);
  808. if (e.Column is GridCheckBoxColumn)
  809. inplaceeditor = null;
  810. if (inplaceeditor is not null)
  811. bChanged = true;
  812. }
  813. private void DataGrid_CurrentCellDropDownSelectionChanged(object? sender,
  814. CurrentCellDropDownSelectionChangedEventArgs e)
  815. {
  816. var headerrows = HasOption(DynamicGridOption.FilterRows) ? 2 : 1;
  817. if (e.RowColumnIndex.RowIndex < headerrows)
  818. return;
  819. inplaceeditor ??= LoadItem(Data.Rows[e.RowColumnIndex.RowIndex - headerrows]);
  820. if ((inplaceeditor is not null) && (e.SelectedItem is Tuple<object?, string> tuple))
  821. {
  822. var iRow = SelectedRows.First().Index;
  823. var mappedname = DataGrid.Columns[e.RowColumnIndex.ColumnIndex].MappingName;
  824. var colno = DataGridItems.Columns.IndexOf(mappedname);
  825. var corecol = Data.Columns[colno].ColumnName;
  826. var updates = new Dictionary<CoreColumn, object?>();
  827. var prefix = String.Join(".", corecol.Split(".").Reverse().Skip(1).Reverse());
  828. var field = corecol.Split(".").Last();
  829. var prop = CoreUtils.GetProperty(typeof(T), corecol);
  830. if (prop.GetEditor() is ILookupEditor editor)
  831. {
  832. var data = editor.Values(corecol);
  833. var lookuprow = data.Rows.FirstOrDefault(r => Equals(r[field], tuple.Item1))
  834. ?? data.NewRow(true);
  835. foreach (CoreColumn lookupcol in data.Columns)
  836. {
  837. var columnname = String.IsNullOrWhiteSpace(prefix)
  838. ? lookupcol.ColumnName
  839. : String.Join(".", prefix, lookupcol.ColumnName);
  840. var updatecol = Data.Columns.FirstOrDefault(x => String.Equals(x.ColumnName, columnname));
  841. if (updatecol != null)
  842. updates[updatecol] = lookuprow[lookupcol.ColumnName];
  843. }
  844. var changes = UpdateData(updates);
  845. DoEntityChanged(this, new DynamicColumnEntityChangedEventArgs(corecol, changes));
  846. bChanged = true;
  847. }
  848. }
  849. }
  850. protected void UpdateCell(int row, string colname, object? value)
  851. {
  852. var datacolname = colname.Replace(".", "_");
  853. var table = DataGridItems;
  854. if (table is null) return;
  855. var colno = table.Columns.IndexOf(datacolname);
  856. if (colno < 0)
  857. {
  858. // This column is not in the list. Because of linked properties, a single lookup change can cause a cascade of updates,
  859. // many of which are likely unnecessary; hence, we shall ignore any which are unnecessary.
  860. return;
  861. }
  862. var corecol = Data.Columns[colno].ColumnName;
  863. var corerow = Data.Rows[row];
  864. corerow[corecol] = value;
  865. var datarow = table.Rows[row];
  866. datarow[datacolname] = value ?? DBNull.Value;
  867. }
  868. private void DataGrid_CurrentCellEndEdit(object? sender, CurrentCellEndEditEventArgs e)
  869. {
  870. var headerrows = HasOption(DynamicGridOption.FilterRows) ? 2 : 1;
  871. if (e.RowColumnIndex.RowIndex < headerrows)
  872. return;
  873. if (inplaceeditor is not null && bChanged)
  874. {
  875. UpdateData(e.RowColumnIndex.ColumnIndex);
  876. }
  877. if (bChanged)
  878. DoChanged();
  879. bChanged = false;
  880. inplaceeditor = null;
  881. DataGridItems?.AcceptChanges();
  882. }
  883. private void UpdateRow(Dictionary<string, object?> changes)
  884. {
  885. if (!SelectedRows.Any())
  886. return;
  887. var iRow = SelectedRows.First().Index;
  888. var corerow = Data.Rows[iRow];
  889. var row = DataGridItems.Rows[iRow];
  890. foreach (var key in changes.Keys)
  891. UpdateCell(iRow, key, changes[key]);
  892. for (var i = 0; i < ActionColumns.Count; i++)
  893. row[$"ActionColumn{i}"] = ActionColumns[i].Data(corerow);
  894. }
  895. private Dictionary<string,object?> UpdateData(Dictionary<CoreColumn, object?> updates)
  896. {
  897. var result = new Dictionary<string, object?>();
  898. if (!SelectedRows.Any())
  899. return result;
  900. var iRow = SelectedRows.First().Index;
  901. var corerow = Data.Rows[iRow];
  902. var row = DataGridItems.Rows[iRow];
  903. foreach (var (col, value) in updates)
  904. {
  905. UpdateRow(corerow, col.ColumnName, value, refresh: false);
  906. DynamicGridUtils.UpdateEditorValue(new BaseObject[] { inplaceeditor }, col.ColumnName, value, result);
  907. }
  908. SaveItem(inplaceeditor);
  909. foreach (var key in result.Keys)
  910. UpdateCell(iRow, key, result[key]);
  911. // foreach (var c in Data.Columns.Where(x => !string.Equals(column.ColumnName, x.ColumnName)))
  912. // {
  913. // var scol = c.ColumnName.Replace('.', '_');
  914. // row[scol] = corerow[c.ColumnName] ?? DBNull.Value;
  915. // }
  916. for (var i = 0; i < ActionColumns.Count; i++)
  917. row[string.Format("ActionColumn{0}", i)] = ActionColumns[i].Data(corerow);
  918. return result;
  919. }
  920. private void UpdateData(int columnindex)
  921. {
  922. if (!SelectedRows.Any())
  923. return;
  924. var iRow = SelectedRows.First().Index; //e.RowColumnIndex.RowIndex - (HasOption(DynamicGridOptions.FilterRows) ? 2 : 1);
  925. if (DataGridItems is null || iRow > DataGridItems.Rows.Count)
  926. return;
  927. var gridcol = ColumnList[columnindex] as DynamicGridColumn;
  928. if (gridcol != null)
  929. {
  930. var datacol = Data.Columns.FirstOrDefault(x => x.ColumnName.Equals(gridcol.ColumnName));
  931. if (datacol != null)
  932. {
  933. var datacolindex = Data.Columns.IndexOf(datacol);
  934. //var colno = DataGridItems.Columns.IndexOf(mappedname);
  935. //var column = Data.Columns.FirstOrDefault(x => x.ColumnName.Equals(gridcol.ColumnName));
  936. //if (column != null)
  937. //{
  938. var value = DataGridItems.Rows[iRow][datacolindex];
  939. if (value is DBNull)
  940. value = CoreUtils.GetDefault(datacol.DataType);
  941. var changes = UpdateData(new Dictionary<CoreColumn, object?>() { { datacol, value } });
  942. DoEntityChanged(gridcol, new DynamicColumnEntityChangedEventArgs(datacol.ColumnName,changes));
  943. }
  944. }
  945. }
  946. private void DataGrid_QueryRowHeight(object? sender, QueryRowHeightEventArgs e)
  947. {
  948. if (e.RowIndex > 0)
  949. {
  950. e.Height = DataGrid.RowHeight;
  951. if (DataGrid.GridColumnSizer.GetAutoRowHeight(e.RowIndex, gridRowResizingOptions, out var autoHeight))
  952. if (autoHeight > DataGrid.RowHeight)
  953. e.Height = autoHeight;
  954. e.Handled = true;
  955. }
  956. }
  957. private void DataGrid_SizeChanged(object sender, SizeChangedEventArgs e)
  958. {
  959. if (IsReady && !bRefreshing) ResizeColumns(DataGrid, e.NewSize.Width - 2, e.NewSize.Height - 2);
  960. }
  961. #region Row Selections
  962. protected CoreRow[] GetVisibleRows()
  963. {
  964. var items = DataGrid.ItemsSource;
  965. var result = new List<CoreRow>();
  966. var table = DataGridItems;
  967. if (table is null) return Array.Empty<CoreRow>();
  968. var rows = DataGrid.View.Records.Select(x => (x.Data as DataRowView)!).ToList();
  969. foreach (var row in rows)
  970. {
  971. var iRow = table.Rows.IndexOf(row.Row);
  972. result.Add(Data.Rows[iRow]);
  973. }
  974. //foreach (var item in DataGrid.SelectedItems)
  975. //{
  976. // if (item is CoreRow)
  977. // {
  978. // //result.Add(item as CoreRow);
  979. // }
  980. // else
  981. // {
  982. // var datarow = item as System.Data.DataRowView;
  983. // int row = datarow.Row.Table.Rows.IndexOf(datarow.Row);
  984. // result.Add(Data.Rows[row]);
  985. // }
  986. //}
  987. return result.ToArray();
  988. }
  989. private CoreRow[] GetSelectedRows()
  990. {
  991. //Logger.Send(LogType.Information, ClientFactory.UserID, String.Format("{0}: GetSelectedRows({1})", this.GetType().EntityName(), DataGrid.SelectedItems.Count));
  992. var result = new List<CoreRow>();
  993. foreach (var item in DataGrid.SelectedItems)
  994. if (item is CoreRow)
  995. {
  996. //result.Add(item as CoreRow);
  997. }
  998. else
  999. {
  1000. var datarow = item as DataRowView;
  1001. if (datarow != null)
  1002. {
  1003. var row = datarow.Row.Table.Rows.IndexOf(datarow.Row);
  1004. result.Add(Data.Rows[row]);
  1005. }
  1006. }
  1007. return result.ToArray();
  1008. }
  1009. private void SetSelectedRows(CoreRow[] rows)
  1010. {
  1011. //Logger.Send(LogType.Information, ClientFactory.UserID, String.Format("{0}: SetSelectedRows({1})", this.GetType().EntityName(), rows.Length));
  1012. // CoreTableAdapter<T> adapter = (CoreTableAdapter<T>)DataGrid.ItemsSource;
  1013. DataGrid.SelectedItems.Clear();
  1014. var bFirst = true;
  1015. foreach (var row in rows.Where(x => x.Index > -1))
  1016. {
  1017. //DataTable table = (DataTable)DataGrid.ItemsSource;
  1018. if (bFirst || HasOption(DynamicGridOption.MultiSelect))
  1019. DataGrid.SelectedItems.Add(DataGrid.GetRecordAtRowIndex(row.Index + (HasOption(DynamicGridOption.FilterRows) ? 2 : 1)));
  1020. bFirst = false;
  1021. }
  1022. }
  1023. public override CoreRow[] SelectedRows
  1024. {
  1025. get => GetSelectedRows();
  1026. set => SetSelectedRows(value);
  1027. }
  1028. protected virtual void SelectItems(CoreRow[]? rows)
  1029. {
  1030. if (IsReady)
  1031. OnSelectItem?.Invoke(this, new DynamicGridSelectionEventArgs(rows));
  1032. DuplicateBtn.Visibility =
  1033. typeof(T).IsAssignableTo(typeof(IDuplicatable)) && rows != null && rows.Length >= 1 ? Visibility.Visible : Visibility.Collapsed;
  1034. }
  1035. private bool bFilterVisible;
  1036. private bool bSwallowKey;
  1037. private void DataGrid_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
  1038. {
  1039. var bOld = bFilterVisible;
  1040. if (e.NewFocus is GridFilterControl)
  1041. bFilterVisible = true;
  1042. else if (e.NewFocus is ScrollViewer || e.NewFocus is SfDataGrid)
  1043. bFilterVisible = false;
  1044. if (bOld && !bFilterVisible)
  1045. {
  1046. //Logger.Send(LogType.Information, "", String.Format("{0}: PreviewGotKeyboardFocus -> {1}", this.GetType().EntityName(), e.NewFocus.GetType().EntityName()));
  1047. SelectItems(SelectedRows);
  1048. bSwallowKey = true;
  1049. }
  1050. }
  1051. private void DataGrid_KeyUp(object sender, KeyEventArgs e)
  1052. {
  1053. if (sender != DataGrid) return;
  1054. if (!bFilterVisible && !bSwallowKey && DataGrid.SelectedIndex > -1)
  1055. {
  1056. //Logger.Send(LogType.Information, "", String.Format("{0}: KeyUp -> {1}", this.GetType().EntityName(), SelectedRows.Length));
  1057. SelectItems(SelectedRows);
  1058. }
  1059. bSwallowKey = false;
  1060. if (IsSequenced)
  1061. {
  1062. if (e.Key == Key.X && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
  1063. {
  1064. CutToClipBuffer();
  1065. }
  1066. else if (e.Key == Key.C && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
  1067. {
  1068. CopyToClipBuffer();
  1069. }
  1070. else if (e.Key == Key.V && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
  1071. {
  1072. PasteFromClipBuffer();
  1073. }
  1074. else if (e.Key == Key.Escape)
  1075. {
  1076. ResetClipBuffer();
  1077. InvalidateGrid();
  1078. }
  1079. }
  1080. }
  1081. private DispatcherTimer? clicktimer;
  1082. private void StartTimer()
  1083. {
  1084. if (clicktimer is null)
  1085. {
  1086. clicktimer = new DispatcherTimer();
  1087. clicktimer.Interval = TimeSpan.FromMilliseconds(200);
  1088. clicktimer.Tick += (o, e) =>
  1089. {
  1090. clicktimer.IsEnabled = false;
  1091. SelectItems(SelectedRows);
  1092. };
  1093. }
  1094. clicktimer.IsEnabled = true;
  1095. }
  1096. private void StopTimer()
  1097. {
  1098. if (clicktimer is not null)
  1099. clicktimer.IsEnabled = false;
  1100. }
  1101. private void DataGrid_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
  1102. {
  1103. if (!IsEnabled)
  1104. return;
  1105. var visualContainer = DataGrid.GetVisualContainer();
  1106. var rowcolumnindex = visualContainer.PointToCellRowColumnIndex(e.GetPosition(visualContainer));
  1107. var columnindex = DataGrid.ResolveToGridVisibleColumnIndex(rowcolumnindex.ColumnIndex);
  1108. if ((columnindex < 0) || (columnindex >= ColumnList.Count))
  1109. return;
  1110. var column = ColumnList[columnindex] as DynamicActionColumn;
  1111. var rowindex = rowcolumnindex.RowIndex - (HasOption(DynamicGridOption.FilterRows) ? 2 : 1);
  1112. if (rowindex < 0 || rowindex >= Data.Rows.Count)
  1113. return;
  1114. var row = Data.Rows[rowindex];
  1115. var menu = column?.ContextMenu?.Invoke(SelectedRows);
  1116. if (menu != null && menu.Items.Count > 0)
  1117. {
  1118. menu.IsOpen = true;
  1119. }
  1120. }
  1121. private void DataGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  1122. {
  1123. if (!IsEnabled)
  1124. return;
  1125. // Header Click Here!
  1126. if (DataGrid.SelectedIndex == -1)
  1127. {
  1128. var visualContainer = DataGrid.GetVisualContainer();
  1129. var rowcolumnindex = visualContainer.PointToCellRowColumnIndex(e.GetPosition(visualContainer));
  1130. var columnindex = DataGrid.ResolveToGridVisibleColumnIndex(rowcolumnindex.ColumnIndex);
  1131. if (columnindex > -1 && columnindex < ColumnList.Count)
  1132. {
  1133. var bRefresh = false;
  1134. var dac = ColumnList[columnindex] as DynamicActionColumn;
  1135. if (dac != null)
  1136. if (dac.Action?.Invoke(null) == true)
  1137. bRefresh = true;
  1138. if (bRefresh)
  1139. Dispatcher.Invoke(() => { Refresh(false, true); });
  1140. }
  1141. }
  1142. else if (!bFilterVisible)
  1143. {
  1144. StartTimer();
  1145. }
  1146. bSwallowKey = false;
  1147. }
  1148. private void DataGrid_CellTapped(object? sender, GridCellTappedEventArgs e)
  1149. {
  1150. if (!IsEnabled)
  1151. return;
  1152. var dac = ColumnList[e.RowColumnIndex.ColumnIndex] as DynamicActionColumn;
  1153. if (dac != null)
  1154. {
  1155. var bRefresh = false;
  1156. if(e.ChangedButton == MouseButton.Left || (e.ChangedButton == MouseButton.Right && dac is DynamicMenuColumn))
  1157. {
  1158. foreach (var row in SelectedRows)
  1159. if (dac.Action?.Invoke(row) == true)
  1160. bRefresh = true;
  1161. }
  1162. if (bRefresh)
  1163. Task.Run(() => { Dispatcher.Invoke(() => { Refresh(true, true); }); });
  1164. }
  1165. else
  1166. {
  1167. StartTimer();
  1168. }
  1169. }
  1170. protected virtual void DoDoubleClick(object sender)
  1171. {
  1172. if (IsDirectEditMode())
  1173. return;
  1174. SelectItems(SelectedRows);
  1175. var args = new HandledEventArgs(false);
  1176. OnDoubleClick?.Invoke(sender, args);
  1177. if (args.Handled)
  1178. return;
  1179. if (HasOption(DynamicGridOption.EditRows))
  1180. DoEdit();
  1181. }
  1182. private void DataGrid_CellDoubleTapped(object? sender, GridCellDoubleTappedEventArgs e)
  1183. {
  1184. StopTimer();
  1185. if (OnCellDoubleClick is not null && ColumnList[e.RowColumnIndex.ColumnIndex] is DynamicGridColumn column)
  1186. {
  1187. var row = GetRowFromIndex(e.RowColumnIndex.RowIndex);
  1188. var args = new DynamicGridCellClickEventArgs(row, column);
  1189. OnCellDoubleClick?.Invoke(this, args);
  1190. if (args.Handled)
  1191. return;
  1192. }
  1193. if (e.Record != null)
  1194. DoDoubleClick(this);
  1195. }
  1196. #endregion
  1197. #region Column Handling
  1198. private readonly List<DynamicColumnBase> ColumnList = new();
  1199. protected virtual DynamicGridColumns LoadColumns()
  1200. {
  1201. var result = new DynamicGridColumns();
  1202. var cols = IsDirectEditMode()
  1203. ? new Columns<T>().Default(ColumnType.IncludeForeignKeys, ColumnType.ExcludeID)
  1204. : new Columns<T>().Default(ColumnType.IncludeLinked, ColumnType.ExcludeID);
  1205. result.AddRange(MasterColumns.Where(x => cols.Items.Any(c => c.Property.Equals(x.ColumnName)))
  1206. .OrderBy(x => CoreUtils.GetPropertySequence(typeof(T), x.ColumnName)));
  1207. return result;
  1208. }
  1209. /// <summary>
  1210. /// Provide a set of columns which is the default for this grid.
  1211. /// </summary>
  1212. public virtual DynamicGridColumns GenerateColumns()
  1213. {
  1214. var columns = new DynamicGridColumns();
  1215. var cols = IsDirectEditMode()
  1216. ? new Columns<T>().Default(ColumnType.IncludeForeignKeys, ColumnType.ExcludeID)
  1217. : new Columns<T>().Default(ColumnType.IncludeLinked, ColumnType.ExcludeID);
  1218. if (cols != null)
  1219. {
  1220. foreach (var col in cols.Items)
  1221. {
  1222. var mc = MasterColumns.FirstOrDefault(x => x.ColumnName.Equals(col.Property));
  1223. if (mc != null && mc.Editor is not NullEditor && mc.Editor.Visible != Visible.Hidden)
  1224. columns.Add(mc);
  1225. }
  1226. }
  1227. return columns;
  1228. }
  1229. private bool SwapRows(int row1, int row2)
  1230. {
  1231. CoreRow[] rows = Data.Rows.Where(x => x.Index.Equals(row1) || x.Index.Equals(row2)).ToArray();
  1232. var items = LoadItems(rows);
  1233. var first = (items.First() as ISequenceable)!;
  1234. var last = (items.Last() as ISequenceable)!;
  1235. var iBuf1 = first.Sequence;
  1236. var iBuf2 = last.Sequence;
  1237. first.Sequence = iBuf2;
  1238. last.Sequence = iBuf1;
  1239. SaveItems(items);
  1240. return true;
  1241. }
  1242. protected virtual void SaveColumns(DynamicGridColumns columns)
  1243. {
  1244. }
  1245. public override int DesiredWidth()
  1246. {
  1247. var result = 0;
  1248. for (var i = 0; i < ColumnList.Count; i++)
  1249. {
  1250. var col = ColumnList[i];
  1251. if (col is DynamicActionColumn)
  1252. {
  1253. result += (int)RowHeight;
  1254. }
  1255. else if (col is DynamicGridColumn)
  1256. {
  1257. var dgc = (DynamicGridColumn)col;
  1258. result += dgc.Width > 0 ? dgc.Width : 300;
  1259. }
  1260. }
  1261. return result;
  1262. }
  1263. private void ResizeColumns(SfDataGrid grid, double width, double height)
  1264. {
  1265. if (Data == null || width <= 0)
  1266. return;
  1267. Dispatcher.BeginInvoke(() =>
  1268. {
  1269. //var vc = DataGrid.GetVisualContainer();
  1270. //vc.RowHeightManager.Reset();
  1271. //vc.InvalidateMeasureInfo();
  1272. var fAvailWidth = width - (SystemParameters.VerticalScrollBarWidth);
  1273. //if (Data.Rows.Count * (DataGrid.RowHeight + 1) + DataGrid.HeaderRowHeight > height + 0.5F)
  1274. //if (height < DataGrid.AutoScroller.VScrollBar.Maximum)
  1275. // fAvailWidth -= (SystemParameters.VerticalScrollBarWidth + 0.75);
  1276. double fCurWidth = 0.0F;
  1277. var NumAutoCols = 0;
  1278. var colWidths = new Dictionary<int, double>();
  1279. for (var i = 0; i < ColumnList.Count; i++)
  1280. {
  1281. var col = ColumnList[i];
  1282. if (col is DynamicImageColumn dic)
  1283. {
  1284. colWidths[i] = RowHeight;
  1285. fCurWidth += colWidths[i];
  1286. }
  1287. else if (col is DynamicTextColumn dxc)
  1288. {
  1289. colWidths[i] = dxc.Width;
  1290. if (dxc.Width != 0)
  1291. fCurWidth += Math.Max(0.0F, dxc.Width);
  1292. else
  1293. NumAutoCols++;
  1294. }
  1295. else if (col is DynamicTemplateColumn dtc)
  1296. {
  1297. colWidths[i] = dtc.Width;
  1298. if (dtc.Width != 0)
  1299. fCurWidth += Math.Max(0.0F, dtc.Width);
  1300. else
  1301. NumAutoCols++;
  1302. }
  1303. else if (col is DynamicGridColumn dgc)
  1304. {
  1305. colWidths[i] = dgc.Width;
  1306. if (dgc.Width != 0)
  1307. fCurWidth += Math.Max(0.0F, dgc.Width);
  1308. else
  1309. NumAutoCols++;
  1310. }
  1311. }
  1312. if (NumAutoCols > 0)
  1313. {
  1314. var fAutoWidth = (fAvailWidth - fCurWidth) / NumAutoCols;
  1315. if (fAutoWidth < 100)
  1316. fAutoWidth = 100;
  1317. for (var i = 0; i < ColumnList.Count; i++)
  1318. if (colWidths[i] == 0)
  1319. colWidths[i] = fAutoWidth;
  1320. }
  1321. foreach (var index in colWidths.Keys)
  1322. DataGrid.Columns[index].Width = Math.Max(0.0F, colWidths[index]);
  1323. });
  1324. //
  1325. // var vc = DataGrid.GetVisualContainer();
  1326. // vc.RowHeightManager.Reset();
  1327. // vc.InvalidateMeasureInfo();
  1328. // if (vc.ScrollOwner != null)
  1329. // vc.ScrollOwner.HorizontalScrollBarVisibility = vc.ExtentWidth <= fAvailWidth ? ScrollBarVisibility.Hidden : ScrollBarVisibility.Visible;
  1330. }
  1331. private void LoadActionColumns(DynamicActionColumnPosition position)
  1332. {
  1333. for (var i = 0; i < ActionColumns.Count; i++)
  1334. {
  1335. var column = ActionColumns[i];
  1336. if (column.Position == position)
  1337. {
  1338. //String sColName = String.Format("ActionColumn{0}{1}", i, position == DynamicActionColumnPosition.Start ? "L" : "R");
  1339. var sColName = string.Format("ActionColumn{0}", i);
  1340. gridRowResizingOptions.ExcludeColumns.Add(sColName);
  1341. if (column is DynamicImageColumn imgcol)
  1342. {
  1343. var newcol = new GridImageColumn();
  1344. newcol.MappingName = sColName;
  1345. //newcol.Stretch = Stretch.Uniform;
  1346. newcol.Width = column.Width == 0 ? DataGrid.RowHeight : column.Width;
  1347. newcol.Padding = new Thickness(4);
  1348. newcol.ImageHeight = DataGrid.RowHeight - 8;
  1349. newcol.ImageWidth = DataGrid.RowHeight - 8;
  1350. newcol.ColumnSizer = GridLengthUnitType.None;
  1351. newcol.HeaderText = column.HeaderText;
  1352. newcol.AllowSorting = false;
  1353. ApplyFilterStyle(newcol, true, true);
  1354. newcol.ShowToolTip = column.ToolTip != null;
  1355. newcol.ShowHeaderToolTip = column.ToolTip != null;
  1356. var style = new Style();
  1357. style.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  1358. style.Setters.Add(new Setter(IsEnabledProperty, false));
  1359. newcol.FilterRowCellStyle = style;
  1360. var headstyle = new Style(typeof(GridHeaderCellControl));
  1361. headstyle.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  1362. headstyle.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Black)));
  1363. headstyle.Setters.Add(new Setter(FontSizeProperty, 12D));
  1364. if (!string.IsNullOrWhiteSpace(column.HeaderText))
  1365. {
  1366. //headstyle.Setters.Add(new Setter(LayoutTransformProperty, new RotateTransform(270.0F)));
  1367. headstyle.Setters.Add(new Setter(BorderThicknessProperty, new Thickness(0.0, 0.0, 0, 0)));
  1368. headstyle.Setters.Add(new Setter(MarginProperty, new Thickness(0, 0, 0.75, 0.75)));
  1369. if (imgcol.VerticalHeader)
  1370. headstyle.Setters.Add(new Setter(TemplateProperty,
  1371. Application.Current.Resources["VerticalColumnHeader"] as ControlTemplate));
  1372. }
  1373. else
  1374. {
  1375. var image = imgcol.Image?.Invoke(null);
  1376. if (image != null)
  1377. {
  1378. var template = new ControlTemplate(typeof(GridHeaderCellControl));
  1379. var border = new FrameworkElementFactory(typeof(Border));
  1380. border.SetValue(Border.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro));
  1381. border.SetValue(Border.PaddingProperty, new Thickness(4));
  1382. border.SetValue(MarginProperty, new Thickness(0, 0, 1, 1));
  1383. var img = new FrameworkElementFactory(typeof(Image));
  1384. img.SetValue(Image.SourceProperty, image);
  1385. border.AppendChild(img);
  1386. template.VisualTree = border;
  1387. headstyle.Setters.Add(new Setter(TemplateProperty, template));
  1388. }
  1389. }
  1390. newcol.HeaderStyle = headstyle;
  1391. DataGrid.Columns.Add(newcol);
  1392. ColumnList.Add(column);
  1393. }
  1394. else if (column is DynamicTextColumn txtCol)
  1395. {
  1396. var newcol = new GridTextColumn();
  1397. gridRowResizingOptions.ExcludeColumns.Add(sColName);
  1398. newcol.TextWrapping = TextWrapping.NoWrap;
  1399. newcol.TextAlignment = txtCol.Alignment == Alignment.NotSet
  1400. ? TextAlignment.Left
  1401. : txtCol.Alignment == Alignment.BottomLeft || txtCol.Alignment == Alignment.MiddleLeft ||
  1402. txtCol.Alignment == Alignment.TopLeft
  1403. ? TextAlignment.Left
  1404. : txtCol.Alignment == Alignment.BottomCenter || txtCol.Alignment == Alignment.MiddleCenter ||
  1405. txtCol.Alignment == Alignment.TopCenter
  1406. ? TextAlignment.Center
  1407. : TextAlignment.Right;
  1408. newcol.AllowEditing = false;
  1409. newcol.UpdateTrigger = UpdateSourceTrigger.PropertyChanged;
  1410. newcol.MappingName = sColName;
  1411. newcol.Width = column.Width;
  1412. newcol.ColumnSizer = GridLengthUnitType.None;
  1413. newcol.HeaderText = column.HeaderText;
  1414. newcol.AllowFiltering = column.Filters != null && column.Filters.Any();
  1415. newcol.AllowSorting = false;
  1416. newcol.FilterRowOptionsVisibility = Visibility.Collapsed;
  1417. newcol.ShowHeaderToolTip = column.ToolTip != null;
  1418. var style = new Style();
  1419. style.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  1420. style.Setters.Add(new Setter(IsEnabledProperty, false));
  1421. newcol.FilterRowCellStyle = style;
  1422. var headstyle = new Style(typeof(GridHeaderCellControl));
  1423. headstyle.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  1424. headstyle.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Black)));
  1425. headstyle.Setters.Add(new Setter(FontSizeProperty, 12D));
  1426. headstyle.Setters.Add(new Setter(MarginProperty, new Thickness(0, -0.75, 0, 0.75)));
  1427. headstyle.Setters.Add(new Setter(BorderThicknessProperty, new Thickness(0.75)));
  1428. if (txtCol.VerticalHeader)
  1429. {
  1430. headstyle.Setters.Add(new Setter(HorizontalContentAlignmentProperty, HorizontalAlignment.Left));
  1431. headstyle.Setters.Add(new Setter(TemplateProperty,
  1432. Application.Current.Resources["VerticalColumnHeader"] as ControlTemplate));
  1433. }
  1434. newcol.HeaderStyle = headstyle;
  1435. DataGrid.Columns.Add(newcol);
  1436. ColumnList.Add(column);
  1437. }
  1438. else if (column is DynamicTemplateColumn tmplCol)
  1439. {
  1440. var newcol = new GridTemplateColumn();
  1441. newcol.CellTemplateSelector = new TemplateColumnSelector() { DataTemplate = tmplCol.Template };
  1442. newcol.AllowEditing = false;
  1443. newcol.UpdateTrigger = UpdateSourceTrigger.PropertyChanged;
  1444. newcol.Width = tmplCol.Width;
  1445. newcol.ColumnSizer = GridLengthUnitType.None;
  1446. newcol.HeaderText = column.HeaderText;
  1447. newcol.AllowFiltering = false;
  1448. newcol.AllowSorting = false;
  1449. newcol.FilterRowOptionsVisibility = Visibility.Collapsed;
  1450. newcol.ShowToolTip = false;
  1451. newcol.ShowHeaderToolTip = false;
  1452. var style = new Style();
  1453. style.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  1454. style.Setters.Add(new Setter(IsEnabledProperty, false));
  1455. newcol.FilterRowCellStyle = style;
  1456. var headstyle = new Style(typeof(GridHeaderCellControl));
  1457. headstyle.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  1458. headstyle.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Black)));
  1459. headstyle.Setters.Add(new Setter(FontSizeProperty, 12D));
  1460. headstyle.Setters.Add(new Setter(MarginProperty, new Thickness(0, -0.75, 0, 0.75)));
  1461. headstyle.Setters.Add(new Setter(BorderThicknessProperty, new Thickness(0.75)));
  1462. newcol.HeaderStyle = headstyle;
  1463. DataGrid.Columns.Add(newcol);
  1464. ColumnList.Add(column);
  1465. }
  1466. }
  1467. }
  1468. }
  1469. private class TemplateColumnSelector : DataTemplateSelector
  1470. {
  1471. public Func<FrameworkElement> DataTemplate { get; init; }
  1472. public override DataTemplate SelectTemplate(object item, DependencyObject container)
  1473. => TemplateGenerator.CreateDataTemplate(DataTemplate);
  1474. }
  1475. private bool CanSort()
  1476. {
  1477. return !IsSequenced;
  1478. }
  1479. private void ReloadColumns()
  1480. {
  1481. ConfigureColumns(MasterColumns /*, false */);
  1482. VisibleColumns = LoadColumns();
  1483. ConfigureColumns(VisibleColumns /*, true */);
  1484. DataGrid.Columns.Suspend();
  1485. ColumnList.Clear();
  1486. DataGrid.Columns.Clear();
  1487. DataGrid.TableSummaryRows.Clear();
  1488. var Summaries = new ObservableCollection<ISummaryColumn>();
  1489. gridRowResizingOptions.ExcludeColumns = new List<string>();
  1490. LoadActionColumns(DynamicActionColumnPosition.Start);
  1491. foreach (var column in VisibleColumns)
  1492. {
  1493. IProperty? prop;
  1494. try
  1495. {
  1496. prop = DatabaseSchema.Property(typeof(T), column.ColumnName);
  1497. }
  1498. catch (Exception e)
  1499. {
  1500. Logger.Send(LogType.Error, ClientFactory.UserID,
  1501. string.Format("Error constructing Column [{0}] : {1}\n{2}", column.ColumnName, e.Message, e.StackTrace));
  1502. prop = null;
  1503. }
  1504. if (prop != null)
  1505. {
  1506. IDynamicGridEditorColumn? newcol = null;
  1507. if (prop.Editor is IntegerEditor)
  1508. newcol = new DynamicGridIntegerColumn<T>(column);
  1509. else if (prop.Editor is CurrencyEditor)
  1510. newcol = new DynamicGridCurrencyColumn<T>(column);
  1511. else if (prop.Editor is DoubleEditor)
  1512. newcol = new DynamicGridDoubleColumn<T>(column);
  1513. else if (prop.Editor is DateTimeEditor)
  1514. newcol = new DynamicGridDateTimeColumn<T>(column);
  1515. else if (prop.Editor is DateEditor)
  1516. newcol = new DynamicGridDateColumn<T>(column);
  1517. else if (prop.Editor is TimeOfDayEditor)
  1518. newcol = new DynamicGridTimeOfDayColumn<T>(column);
  1519. else if (prop.Editor is TimestampEditor)
  1520. newcol = new DynamicGridTimeStampColumn<T>(column);
  1521. else if (prop.Editor is DurationEditor)
  1522. newcol = new DynamicGridDurationColumn<T>(column);
  1523. else if (prop.Editor is CheckBoxEditor)
  1524. newcol = new DynamicGridCheckBoxColumn<T>(column);
  1525. else if (prop.Editor is ColorEditor)
  1526. newcol = new DynamicGridColorColumn<T>(column, column.Width, (int)DataGrid.RowHeight);
  1527. else if (prop.Editor is PopupEditor)
  1528. newcol = new DynamicGridPopupColumn<T>(column);
  1529. else if (prop.Editor is CodePopupEditor)
  1530. newcol = new DynamicGridCodePopupColumn<T>(column);
  1531. else if (prop.Editor is EnumLookupEditor)
  1532. newcol = new DynamicGridEnumLookupColumn<T>(column);
  1533. else if (prop.Editor is ComboLookupEditor)
  1534. newcol = new DynamicGridComboLookupColumn<T>(column);
  1535. else if (prop.Editor is LookupEditor)
  1536. newcol = new DynamicGridLookupColumn<T>(column);
  1537. else if (prop.Editor is MemoEditor)
  1538. newcol = new DynamicGridMemoColumn<T>(column);
  1539. else if (prop.Editor is CodeEditor)
  1540. newcol = new DynamicGridCodeColumn<T>(column);
  1541. else if (prop.Editor is UniqueCodeEditor)
  1542. newcol = new DynamicGridUniqueCodeColumn<T>(column);
  1543. else if (prop.Editor is TextBoxEditor)
  1544. newcol = new DynamicGridTextBoxColumn<T>(column);
  1545. if (newcol != null)
  1546. {
  1547. newcol.GetEntity = () => inplaceeditor;
  1548. newcol.EntityChanged += DoEntityChanged;
  1549. if (!newcol.VariableHeight)
  1550. gridRowResizingOptions.ExcludeColumns.Add(newcol.MappingName);
  1551. newcol.Column.AllowEditing = newcol.Editable && IsDirectEditMode();
  1552. var summary = newcol.Summary();
  1553. if (summary != null)
  1554. Summaries.Add(summary);
  1555. ApplyFilterStyle(newcol.Column, newcol.Filtered, false);
  1556. var headstyle = new Style(typeof(GridHeaderCellControl));
  1557. headstyle.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  1558. headstyle.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Black)));
  1559. headstyle.Setters.Add(new Setter(FontSizeProperty, 12D));
  1560. newcol.Column.HeaderStyle = headstyle;
  1561. var cellstyle = new Style();
  1562. if (IsDirectEditMode())
  1563. {
  1564. if (prop.Editor is null || !prop.Editor.Editable.IsDirectEditable())
  1565. {
  1566. cellstyle.Setters.Add(new Setter(BackgroundProperty,
  1567. new SolidColorBrush(Colors.WhiteSmoke)));
  1568. newcol.Column.AllowEditing = false;
  1569. }
  1570. else
  1571. {
  1572. cellstyle.Setters.Add(new Setter(BackgroundProperty,
  1573. new SolidColorBrush(Colors.LightYellow)));
  1574. newcol.Column.AllowEditing = true;
  1575. }
  1576. cellstyle.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Black)));
  1577. newcol.Column.CellStyle = cellstyle;
  1578. }
  1579. else
  1580. {
  1581. cellstyle.Setters.Add(new Setter(BackgroundProperty,
  1582. new Binding()
  1583. {
  1584. Path = new PropertyPath("."), Converter = CellBackgroundConverter,
  1585. ConverterParameter = column.ColumnName
  1586. }));
  1587. cellstyle.Setters.Add(new Setter(ForegroundProperty,
  1588. new Binding()
  1589. { Converter = CellForegroundConverter, ConverterParameter = column.ColumnName }));
  1590. cellstyle.Setters.Add(new Setter(FontSizeProperty,
  1591. new Binding()
  1592. { Converter = CellFontSizeConverter, ConverterParameter = column.ColumnName }));
  1593. cellstyle.Setters.Add(new Setter(FontStyleProperty,
  1594. new Binding()
  1595. { Converter = CellFontStyleConverter, ConverterParameter = column.ColumnName }));
  1596. cellstyle.Setters.Add(new Setter(FontWeightProperty,
  1597. new Binding()
  1598. { Converter = CellFontWeightConverter, ConverterParameter = column.ColumnName }));
  1599. newcol.Column.CellStyle = cellstyle;
  1600. }
  1601. DataGrid.Columns.Add(newcol.Column);
  1602. ColumnList.Add(column);
  1603. foreach (var extra in newcol.ExtraColumns)
  1604. AddHiddenColumn(extra);
  1605. }
  1606. }
  1607. }
  1608. LoadActionColumns(DynamicActionColumnPosition.End);
  1609. if (Summaries.Any())
  1610. {
  1611. DataGrid.CellRenderers.Remove("TableSummary");
  1612. DataGrid.CellRenderers.Add("TableSummary", new DynamicGridAggregateRenderer());
  1613. DataGrid.TableSummaryRows.Add(new GridTableSummaryRow
  1614. {
  1615. ShowSummaryInRow = false,
  1616. Position = TableSummaryRowPosition.Bottom,
  1617. SummaryColumns = Summaries
  1618. });
  1619. }
  1620. DataGrid.Columns.Resume();
  1621. DataGrid.RefreshColumns();
  1622. foreach (var key in _filterpredicates.Keys.ToArray())
  1623. if (DataGrid.Columns.Any(x => string.Equals(x.MappingName, key)))
  1624. {
  1625. var predicates = Serialization.Deserialize<List<FilterPredicate>>(_filterpredicates[key]);
  1626. foreach (var predicate in predicates)
  1627. {
  1628. DataGrid.Columns[key].FilterPredicates.Add(predicate);
  1629. DataGrid.Columns[key].FilteredFrom = FilteredFrom.FilterRow;
  1630. }
  1631. }
  1632. else
  1633. {
  1634. _filterpredicates.Remove(key);
  1635. }
  1636. ResizeColumns(DataGrid, DataGrid.ActualWidth - 2, DataGrid.ActualHeight - 2);
  1637. }
  1638. private void DoEntityChanged(object column, DynamicColumnEntityChangedEventArgs args)
  1639. {
  1640. OnAfterEditorValueChanged(null, new T[] { inplaceeditor }, new AfterEditorValueChangedArgs(args.ColumnName, args.Changes), args.Changes);
  1641. SaveItem(inplaceeditor);
  1642. UpdateRow(args.Changes);
  1643. //DataGrid.SelectionController.CurrentCellManager.EndEdit();
  1644. }
  1645. private void ApplyFilterStyle(GridColumn column, bool filtering, bool isactioncolumn)
  1646. {
  1647. var filterstyle = new Style();
  1648. if (filtering)
  1649. {
  1650. filterstyle.Setters.Add(new Setter(BackgroundProperty, BaseDynamicGrid.FilterBackground));
  1651. column.ImmediateUpdateColumnFilter = true;
  1652. column.ColumnFilter = ColumnFilter.Value;
  1653. column.FilterRowCondition = FilterRowCondition.Contains;
  1654. column.FilterRowOptionsVisibility = Visibility.Collapsed;
  1655. column.AllowBlankFilters = true;
  1656. column.AllowSorting = isactioncolumn
  1657. ? false
  1658. : CanSort();
  1659. }
  1660. else
  1661. {
  1662. filterstyle.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  1663. filterstyle.Setters.Add(new Setter(IsEnabledProperty, false));
  1664. column.ColumnFilter = ColumnFilter.Value;
  1665. column.AllowFiltering = false;
  1666. column.AllowSorting = false;
  1667. column.FilterRowEditorType = "TextBox";
  1668. column.FilterRowOptionsVisibility = Visibility.Collapsed;
  1669. }
  1670. column.FilterRowCellStyle = filterstyle;
  1671. }
  1672. #endregion
  1673. #region Refresh / Reload
  1674. protected abstract void Reload(Filters<T> criteria, Columns<T> columns, ref SortOrder<T>? sort, Action<CoreTable?, Exception?> action);
  1675. protected virtual bool FilterRecord(CoreRow row)
  1676. {
  1677. var bOK = ActionColumns.All(x =>
  1678. {
  1679. return x.FilterRecord is null || x.SelectedFilters is null || !x.SelectedFilters.Any()
  1680. || x.FilterRecord.Invoke(row, x.SelectedFilters);
  1681. });
  1682. if (bOK && OnFilterRecord is not null)
  1683. bOK = OnFilterRecord(row);
  1684. return bOK;
  1685. }
  1686. public override void Refresh(bool reloadcolumns, bool reloaddata)
  1687. {
  1688. if (bRefreshing)
  1689. return;
  1690. if (!DoBeforeRefresh())
  1691. return;
  1692. DataGrid.SelectionForegroundBrush = BaseDynamicGrid.SelectionForeground;
  1693. DataGrid.RowSelectionBrush = BaseDynamicGrid.SelectionBackground;
  1694. var cursor = UseWaitCursor ? new WaitCursor() : null;
  1695. Loading.Visibility = Visibility.Visible;
  1696. Loading.BeginAnimation(Label.OpacityProperty, LoadingFader);
  1697. bRefreshing = true;
  1698. // Yo, please don't remove this.
  1699. // The issue was when we were dynamically adding ActionColumns, and if we had to remove and then re-add them, we were getting massive performance hits
  1700. // for no reason. I think perhaps the image columns were trying to refer to data that didn't exist anymore when calling DataGrid.Columns.Refresh(),
  1701. // and thus some mega problems (perhaps even exceptions within Syncfusion) were occurring, and this seems to fix it.
  1702. // I don't pretend to know why it works; this is probably the strangest problem I've ever come across.
  1703. if (reloadcolumns)
  1704. DataGrid.ItemsSource = null;
  1705. if (reloadcolumns)
  1706. ReloadColumns();
  1707. if (reloaddata)
  1708. {
  1709. _lookupcache.Clear();
  1710. var criteria = new Filters<T>();
  1711. var filter = DefineFilter();
  1712. if (filter != null)
  1713. criteria.Add(filter);
  1714. var columns = DataColumns();
  1715. var sort = LookupFactory.DefineSort<T>();
  1716. if (sort == null && IsSequenced)
  1717. sort = new SortOrder<T>("Sequence");
  1718. Reload(
  1719. criteria
  1720. , columns
  1721. , ref sort
  1722. , (table, exception) =>
  1723. {
  1724. if (exception != null)
  1725. {
  1726. Dispatcher.Invoke(() =>
  1727. {
  1728. MessageWindow.ShowError("Sorry! We couldn't load the data.", exception);
  1729. });
  1730. }
  1731. else if (table is not null)
  1732. {
  1733. MasterData = table;
  1734. Dispatcher.Invoke(() =>
  1735. {
  1736. ProcessData(reloadcolumns, reloaddata);
  1737. DoAfterRefresh();
  1738. bRefreshing = false;
  1739. IsReady = true;
  1740. });
  1741. }
  1742. }
  1743. );
  1744. }
  1745. else
  1746. {
  1747. ProcessData(reloadcolumns, reloaddata);
  1748. DoAfterRefresh();
  1749. bRefreshing = false;
  1750. IsReady = true;
  1751. Loading.BeginAnimation(Label.OpacityProperty, null);
  1752. Loading.Visibility = Visibility.Collapsed;
  1753. }
  1754. if (cursor != null)
  1755. {
  1756. cursor.Dispose();
  1757. cursor = null;
  1758. }
  1759. bRefreshing = false;
  1760. }
  1761. protected override bool OnBeforeRefresh()
  1762. {
  1763. return true;
  1764. }
  1765. private bool DoBeforeRefresh()
  1766. {
  1767. var result = OnBeforeRefresh();
  1768. if (result)
  1769. {
  1770. var args = new BeforeRefreshEventArgs() { Cancel = false };
  1771. NotifyBeforeRefresh(args);
  1772. result = args.Cancel == false;
  1773. }
  1774. return result;
  1775. }
  1776. protected override void OnAfterRefresh()
  1777. {
  1778. }
  1779. protected void DoAfterRefresh()
  1780. {
  1781. OnAfterRefresh();
  1782. NotifyAfterRefresh(new AfterRefreshEventArgs());
  1783. }
  1784. public Columns<T> DataColumns()
  1785. {
  1786. var columns = new Columns<T>();
  1787. foreach (var column in VisibleColumns)
  1788. columns.Add(column.ColumnName);
  1789. foreach (var column in HiddenColumns.ColumnNames)
  1790. columns.Add(new Column<T>(column));
  1791. return columns;
  1792. }
  1793. private void ProcessData(bool reloadcolumns, bool reloaddata)
  1794. {
  1795. Data.Columns.Clear();
  1796. Data.Setters.Clear();
  1797. if (MasterData != null)
  1798. foreach (var column in MasterData.Columns)
  1799. Data.Columns.Add(column);
  1800. LoadData();
  1801. }
  1802. protected readonly Dictionary<CoreRow, CoreRow> _recordmap = new();
  1803. public override void UpdateRow<TRow, TType>(CoreRow row, Expression<Func<TRow, TType>> column, TType value, bool refresh = true)
  1804. {
  1805. row.Set(column, value);
  1806. _recordmap[row].Set(column, value);
  1807. if (refresh)
  1808. InvalidateRow(row);
  1809. }
  1810. public override void UpdateRow<TType>(CoreRow row, string column, TType value, bool refresh = true)
  1811. {
  1812. row.Set(column, value);
  1813. _recordmap[row].Set(column, value);
  1814. if (refresh)
  1815. InvalidateRow(row);
  1816. }
  1817. public void AddRow(CoreRow row)
  1818. {
  1819. if (MasterData is null) return;
  1820. var masterrow = MasterData.NewRow();
  1821. MasterData.LoadRow(masterrow, row);
  1822. Refresh(false, false);
  1823. }
  1824. public void AddRow(T data)
  1825. {
  1826. if (MasterData is null) return;
  1827. var masterrow = MasterData.NewRow();
  1828. MasterData.LoadRow(masterrow, data);
  1829. MasterData.Rows.Add(masterrow);
  1830. Refresh(false, false);
  1831. }
  1832. public void DeleteRow(CoreRow row)
  1833. {
  1834. if (MasterData is null) return;
  1835. var masterrow = _recordmap[row];
  1836. MasterData.Rows.Remove(masterrow);
  1837. Refresh(false, false);
  1838. }
  1839. private void FilterRows(CoreTable from, CoreTable into, Dictionary<CoreRow, CoreRow>? recordMap = null, Func<CoreRow, bool>? filter = null)
  1840. {
  1841. into.Rows.Clear();
  1842. recordMap?.Clear();
  1843. foreach (var row in from.Rows.ToArray())
  1844. if (FilterRecord(row) && filter?.Invoke(row) != false)
  1845. {
  1846. var newrow = into.NewRow();
  1847. for (var i = 0; i < into.Columns.Count; i++)
  1848. {
  1849. var value = i < row.Values.Count ? row.Values[i] : null;
  1850. if (into.Columns[i].DataType.IsNumeric())
  1851. value = into.Columns[i].DataType.IsDefault(value) ? null : value;
  1852. //else if (Data.Columns[i].DataType == typeof(String[]))
  1853. // value = String.Join("\n", value as String[]);
  1854. newrow.Values.Add(value);
  1855. }
  1856. //newrow.Values.AddRange(row.Values);
  1857. //if ((OnFilterRecord == null) || (OnFilterRecord(row)))
  1858. into.Rows.Add(newrow);
  1859. recordMap?.TryAdd(newrow, row);
  1860. }
  1861. }
  1862. private void LoadData()
  1863. {
  1864. ResetClipBuffer();
  1865. if (MasterData is null)
  1866. return;
  1867. FilterRows(MasterData, Data, _recordmap);
  1868. InvalidateGrid();
  1869. //ScrollBar.Value = _CurrentRow <= 0 ? 0 : _CurrentRow;
  1870. SelectedRows = Array.Empty<CoreRow>();
  1871. }
  1872. //IncrementalList<T> _data = null;
  1873. public void InvalidateRow(CoreRow row)
  1874. {
  1875. var table = DataGridItems;
  1876. if(table is null)
  1877. {
  1878. return;
  1879. }
  1880. var rowdata = new List<object?>(row.Values);
  1881. foreach (var ac in ActionColumns)
  1882. rowdata.Add(ac.Data(row));
  1883. var datarow = DataGridItems.Rows[row.Index];
  1884. for (var i = 0; i < rowdata.Count; i++)
  1885. datarow[i] = rowdata[i] ?? DBNull.Value;
  1886. //datarow.ItemArray = rowdata.ToArray();
  1887. }
  1888. private void InvalidateGrid()
  1889. {
  1890. var defaults = new List<object?>();
  1891. var result = new DataTable();
  1892. foreach (var column in Data.Columns)
  1893. {
  1894. var colname = column.ColumnName.Replace('.', '_');
  1895. if (!result.Columns.Contains(colname))
  1896. {
  1897. result.Columns.Add(colname, column.DataType);
  1898. if (!IsDirectEditMode())
  1899. defaults.Add(column.DataType.GetDefault());
  1900. }
  1901. }
  1902. for (var i = 0; i < ActionColumns.Count; i++)
  1903. result.Columns.Add(string.Format("ActionColumn{0}", i),
  1904. ActionColumns[i] is DynamicImageColumn
  1905. ? typeof(BitmapImage)
  1906. : typeof(String)
  1907. );
  1908. foreach (var row in Data.Rows)
  1909. {
  1910. var newrow = result.NewRow();
  1911. CoreRowToDataRow(newrow, row, defaults);
  1912. result.Rows.Add(newrow);
  1913. }
  1914. if (RowStyleSelector != null)
  1915. RowStyleSelector.Data = Data;
  1916. //int rowIndex = DataGrid.SelectionController.CurrentCellManager.CurrentRowColumnIndex.RowIndex;
  1917. //int columnIndex = DataGrid.SelectionController.CurrentCellManager.CurrentRowColumnIndex.ColumnIndex;
  1918. //int scrollRowIndex = DataGrid.GetVisualContainer().ScrollRows.LastBodyVisibleLineIndex;
  1919. DataGrid.ItemsSource = result;
  1920. //this.DataGrid.ScrollInView(new Syncfusion.UI.Xaml.ScrollAxis.RowColumnIndex(scrollRowIndex, columnIndex));
  1921. ResizeColumns(DataGrid, DataGrid.ActualWidth - 1, DataGrid.ActualHeight);
  1922. UpdateRecordCount();
  1923. Loading.BeginAnimation(Label.OpacityProperty, null);
  1924. Loading.Visibility = Visibility.Collapsed;
  1925. }
  1926. private void UpdateRecordCount()
  1927. {
  1928. var count = DataGrid.View != null ? DataGrid.View.Records.Count : Data.Rows.Count;
  1929. Count.Content = string.Format("{0} Records", count);
  1930. //Count.Visibility = _HasOption(DynamicGridOptions.RecordCount) && (count > 0) ? Visibility.Visible : Visibility.Collapsed;
  1931. }
  1932. public IList<CoreRow> FilteredRows()
  1933. {
  1934. var result = new List<CoreRow>();
  1935. var table = DataGridItems;
  1936. if(table is null)
  1937. {
  1938. return Array.Empty<CoreRow>();
  1939. }
  1940. var rows = DataGrid.View.Records.Select(x => (x.Data as DataRowView)!).ToList();
  1941. foreach (var row in rows)
  1942. {
  1943. var iRow = table.Rows.IndexOf(row.Row);
  1944. result.Add(Data.Rows[iRow]);
  1945. }
  1946. return result;
  1947. }
  1948. // Doesn't appear to be used - removed 19/12/2022
  1949. /*private object?[] CreateRowValues(CoreRow row, List<object> defaults)
  1950. {
  1951. var rowdata = new List<object?>(row.Values);
  1952. foreach (var ac in ActionColumns)
  1953. rowdata.Add(ac.Image.Invoke(row));
  1954. var result = ProcessRow(rowdata, defaults);
  1955. return result.ToArray();
  1956. }*/
  1957. private void CoreRowToDataRow(DataRow newrow, CoreRow row, List<object?> defaults)
  1958. {
  1959. var rowdata = new List<object?>(row.Values);
  1960. foreach (var ac in ActionColumns)
  1961. rowdata.Add(ac.Data(row));
  1962. try
  1963. {
  1964. var data = ProcessRow(rowdata, defaults).ToArray();
  1965. newrow.ItemArray = data;
  1966. }
  1967. catch (Exception)
  1968. {
  1969. throw;
  1970. }
  1971. }
  1972. private static IEnumerable<object?> ProcessRow(List<object?> values, List<object?> defaults)
  1973. {
  1974. if (defaults == null || !defaults.Any())
  1975. return values;
  1976. var result = new List<object?>();
  1977. for (var i = 0; i < values.Count; i++)
  1978. {
  1979. var value = values[i];
  1980. var defaultvalue = i < defaults.Count ? defaults[i] : null;
  1981. result.Add(value == null || (value.Equals(defaultvalue) && !value.GetType().IsEnum) ? null : value);
  1982. }
  1983. return result;
  1984. }
  1985. //private void LoadMoreItems(uint count, int from)
  1986. //{
  1987. // var rows = Data.Rows.Skip(from).AsQueryable().Take(50);
  1988. // _data.LoadItems(rows.Select(x => x.ToObject<T>()));
  1989. // //var list = _orders.Skip(baseIndex).Take(50).ToList();
  1990. // //IncrementalItemsSource.LoadItems(list);
  1991. //}
  1992. public override void AddVisualFilter(string column, string value, FilterType filtertype = FilterType.Contains)
  1993. {
  1994. if (string.IsNullOrWhiteSpace(value))
  1995. return;
  1996. var col = DataGrid.Columns.FirstOrDefault((x=>String.Equals(x.MappingName?.ToUpper(),column?.Replace(".", "_").ToUpper())));
  1997. if (col != null)
  1998. {
  1999. col.FilterPredicates.Add(new FilterPredicate { FilterType = filtertype, FilterValue = value });
  2000. col.FilteredFrom = FilteredFrom.FilterRow;
  2001. }
  2002. }
  2003. #endregion
  2004. #region Item Manipulation
  2005. #region Load/Save/Delete
  2006. protected virtual T[] LoadItems(CoreRow[] rows)
  2007. {
  2008. var result = new List<T>();
  2009. foreach (var row in rows)
  2010. {
  2011. var index = Data.Rows.IndexOf(row);
  2012. result.Add(LoadItem(row));
  2013. }
  2014. return result.ToArray();
  2015. }
  2016. protected abstract T LoadItem(CoreRow row);
  2017. public abstract void SaveItem(T item);
  2018. public virtual void SaveItems(T[] items)
  2019. {
  2020. foreach (var item in items)
  2021. SaveItem(item);
  2022. }
  2023. protected virtual bool CanDeleteItems(params CoreRow[] rows)
  2024. {
  2025. return true;
  2026. }
  2027. protected abstract void DeleteItems(params CoreRow[] rows);
  2028. protected virtual void DoDelete()
  2029. {
  2030. var rows = SelectedRows.ToArray();
  2031. if (rows.Any())
  2032. if (CanDeleteItems(rows))
  2033. if (MessageBox.Show("Are you sure you wish to delete the selected records?", "Confirm Delete", MessageBoxButton.YesNo) ==
  2034. MessageBoxResult.Yes)
  2035. {
  2036. DeleteItems(rows);
  2037. SelectedRows = Array.Empty<CoreRow>();
  2038. OnChanged?.Invoke(this, EventArgs.Empty);
  2039. Refresh(false, true);
  2040. SelectItems(null);
  2041. }
  2042. }
  2043. private void Delete_Click(object sender, RoutedEventArgs e)
  2044. {
  2045. DoDelete();
  2046. }
  2047. #endregion
  2048. #region Edit
  2049. protected virtual void DoEdit()
  2050. {
  2051. if (!SelectedRows.Any())
  2052. return;
  2053. var sel = SelectedRows.ToArray();
  2054. if (AddEditClick(SelectedRows))
  2055. {
  2056. InvalidateGrid();
  2057. SelectedRows = sel;
  2058. SelectItems(SelectedRows);
  2059. }
  2060. }
  2061. private void Edit_Click(object sender, RoutedEventArgs e)
  2062. {
  2063. DoEdit();
  2064. }
  2065. /*private void MultiEdit_Click(object sender, RoutedEventArgs e)
  2066. {
  2067. using (new WaitCursor())
  2068. {
  2069. var criteria = new Filters<T>();
  2070. var columns = new Columns<T>();
  2071. columns.Add("ID");
  2072. var iprops = DatabaseSchema.Properties(typeof(T)).Where(x => x.Editor is not NullEditor);
  2073. foreach (var iprop in iprops)
  2074. columns.Add(iprop.Name);
  2075. var sort = LookupFactory.DefineSort<T>();
  2076. Reload(
  2077. criteria,
  2078. columns,
  2079. ref sort,
  2080. (table, exception) =>
  2081. {
  2082. if(table is not null)
  2083. {
  2084. Dispatcher.Invoke(() => { DirectEdit(table); });
  2085. }
  2086. else if(exception is not null)
  2087. {
  2088. Logger.Send(LogType.Error, "", $"Error in MultiEdit: {CoreUtils.FormatException(exception)}");
  2089. MessageBox.Show(exception.Message);
  2090. }
  2091. }
  2092. );
  2093. }
  2094. }*/
  2095. /*public override bool DirectEdit(CoreTable data)
  2096. {
  2097. var window = new DynamicEditWindow<T>();
  2098. window.OnCreateItem += () => CreateItem();
  2099. window.OnCustomiseColumns += (o, c) =>
  2100. {
  2101. ConfigureColumns(MasterColumns);
  2102. if (OnCustomiseColumns != null)
  2103. return OnCustomiseColumns(this, MasterColumns);
  2104. return MasterColumns;
  2105. };
  2106. window.OnGetEditor += c =>
  2107. {
  2108. var result = GetEditor(this, c)?.CloneEditor();
  2109. if (result == null)
  2110. return null;
  2111. OnCustomiseEditor?.Invoke(window, null, c, result);
  2112. return result;
  2113. };
  2114. window.OnGetSequence += c =>
  2115. {
  2116. decimal result = 0.0M;
  2117. var customprop = DatabaseSchema.Property(typeof(T), c.ColumnName);
  2118. if (customprop != null && customprop is CustomProperty)
  2119. {
  2120. result = customprop.Sequence;
  2121. }
  2122. else
  2123. {
  2124. var bits = c.ColumnName.Split('.');
  2125. for (var i = 0; i < bits.Length; i++)
  2126. {
  2127. var sProp = string.Join(".", bits.Take(bits.Length - i));
  2128. PropertyInfo? prop;
  2129. try
  2130. {
  2131. prop = CoreUtils.GetProperty(typeof(T), sProp);
  2132. }
  2133. catch (Exception e)
  2134. {
  2135. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  2136. prop = null;
  2137. }
  2138. if (prop != null)
  2139. {
  2140. result = prop.GetSequence() + result / 1000.0M;
  2141. }
  2142. else
  2143. {
  2144. var cprop = DatabaseSchema.Property(typeof(T), sProp);
  2145. if (cprop != null)
  2146. result = cprop.Sequence;
  2147. else
  2148. result /= 1000.0M;
  2149. }
  2150. }
  2151. }
  2152. return result;
  2153. };
  2154. window.Load(data);
  2155. if (window.ShowDialog() == true)
  2156. {
  2157. SaveItems(window.Updates);
  2158. return true;
  2159. }
  2160. return false;
  2161. }*/
  2162. protected virtual void DoAdd(bool OpenEditorOnDirectEdit = false)
  2163. {
  2164. //CoreRow row = (SelectedRow > -1) && (SelectedRow < Data.Rows.Count) ? Data.Rows[this.SelectedRow] : null;
  2165. if (IsDirectEditMode() && !OpenEditorOnDirectEdit)
  2166. {
  2167. var item = CreateItem();
  2168. SaveItem(item);
  2169. var datarow = Data.NewRow();
  2170. ObjectToRow(item, datarow);
  2171. Data.Rows.Add(datarow);
  2172. var masterrow = MasterData.NewRow();
  2173. ObjectToRow(item, masterrow);
  2174. MasterData.Rows.Add(masterrow);
  2175. _recordmap[datarow] = masterrow;
  2176. InvalidateGrid();
  2177. SelectedRows = new[] { datarow };
  2178. OnChanged?.Invoke(this, EventArgs.Empty);
  2179. }
  2180. else if (AddEditClick(null))
  2181. {
  2182. Refresh(false, true);
  2183. }
  2184. }
  2185. private void Add_Click(object sender, RoutedEventArgs e)
  2186. {
  2187. if (CanCreateItems())
  2188. DoAdd();
  2189. }
  2190. public virtual DynamicEditorPages LoadEditorPages(T item)
  2191. {
  2192. DynamicEditorPages pages = new DynamicEditorPages();
  2193. DynamicGridUtils.LoadOneToManyPages(typeof(T), pages);
  2194. DynamicGridUtils.LoadEnclosedListPages(typeof(T), pages);
  2195. DynamicGridUtils.LoadManyToManyPages(typeof(T), pages);
  2196. DynamicGridUtils.LoadCustomEditorPages(typeof(T), pages);
  2197. foreach (var page in pages)
  2198. page.Ready = false;
  2199. return pages;
  2200. }
  2201. public virtual void LoadEditorButtons(T item, DynamicEditorButtons buttons)
  2202. {
  2203. buttons.Clear();
  2204. buttons.Add(
  2205. "",
  2206. Wpf.Resources.help.AsBitmapImage(),
  2207. item,
  2208. (f, i) =>
  2209. {
  2210. Process.Start(new ProcessStartInfo("https://prsdigital.com.au/wiki/index.php/" + typeof(T).Name.SplitCamelCase().Replace(" ", "_"))
  2211. { UseShellExecute = true });
  2212. }
  2213. );
  2214. }
  2215. protected virtual void BeforeLoad(IDynamicEditorForm form, T[] items)
  2216. {
  2217. form.BeforeLoad();
  2218. }
  2219. public override void InitialiseEditorForm(IDynamicEditorForm editor, T[] items, Func<Type, CoreTable?>? pageDataHandler = null, bool preloadPages = false)
  2220. {
  2221. var pages = items.Length == 1 ? LoadEditorPages(items.First()) : new DynamicEditorPages();
  2222. var buttons = new DynamicEditorButtons();
  2223. if (items.Length == 1)
  2224. LoadEditorButtons(items.First(), buttons);
  2225. editor.Setup(items.Any() ? items.First().GetType() : typeof(T), pages, buttons, pageDataHandler, preloadPages);
  2226. editor.OnCustomiseColumns = (sender, columns) =>
  2227. {
  2228. columns.Clear();
  2229. columns.AddRange(MasterColumns);
  2230. ConfigureColumns(columns);
  2231. };
  2232. editor.OnDefineEditor = (o, c) =>
  2233. {
  2234. var result = GetEditor(o, c);
  2235. if (result != null)
  2236. result = result.CloneEditor();
  2237. return result;
  2238. };
  2239. editor.OnFormCustomiseEditor += DoCustomiseEditor;
  2240. editor.OnDefineFilter = (type) => { return DefineFilter(type, items); };
  2241. //editor.OnDefineFilter += (o, e) => { return DefineFilter(items, e); };
  2242. editor.OnDefineLookups = editor => DefineLookups(editor, items);
  2243. editor.OnEditorValueChanged += (s, n, v) => EditorValueChanged(editor, items, n, v);
  2244. editor.OnAfterEditorValueChanged += (g, args) => AfterEditorValueChanged(g, items, args);
  2245. editor.OnReconfigureEditors = g => DoReconfigureEditors(g, items);
  2246. editor.OnValidateData += (o, i) => ValidateData(items);
  2247. editor.OnSelectPage += SelectPage;
  2248. editor.OnSaveItem = (o, e) =>
  2249. {
  2250. try
  2251. {
  2252. using var Wait = new WaitCursor();
  2253. DoBeforeSave(editor, items);
  2254. if (items.Length == 1)
  2255. editor.UnloadEditorPages(false);
  2256. foreach (var item in items)
  2257. SaveItem(item);
  2258. if (items.Length == 1)
  2259. editor.UnloadEditorPages(true);
  2260. DoAfterSave(editor, items);
  2261. }
  2262. catch (Exception err)
  2263. {
  2264. MessageBox.Show(err.Message);
  2265. e.Cancel = true;
  2266. }
  2267. };
  2268. BeforeLoad(editor, items);
  2269. editor.Items = items;
  2270. AfterLoad(editor, items);
  2271. }
  2272. private void DoCustomiseEditor(IDynamicEditorForm sender, object[] items, DynamicGridColumn column, BaseEditor editor)
  2273. {
  2274. CustomiseEditor((T[])items, column, editor);
  2275. OnCustomiseEditor?.Invoke(sender, (T[])items, column, editor);
  2276. }
  2277. protected virtual void CustomiseEditor(T[] items, DynamicGridColumn column, BaseEditor editor)
  2278. {
  2279. }
  2280. protected virtual void DoAfterSave(IDynamicEditorForm editor, T[] items)
  2281. {
  2282. OnAfterSave?.Invoke(editor, items);
  2283. }
  2284. protected virtual void DoBeforeSave(IDynamicEditorForm editor, T[] items)
  2285. {
  2286. OnBeforeSave?.Invoke(editor, items);
  2287. }
  2288. public override bool EditItems(T[] items, Func<Type, CoreTable?>? PageDataHandler = null, bool PreloadPages = false)
  2289. {
  2290. DynamicEditorForm editor;
  2291. using (var cursor = new WaitCursor())
  2292. {
  2293. editor = new DynamicEditorForm();
  2294. editor.SetValue(Panel.ZIndexProperty, 999);
  2295. InitialiseEditorForm(editor, items, PageDataHandler, PreloadPages);
  2296. OnEditorLoaded?.Invoke(editor, items);
  2297. }
  2298. return editor.ShowDialog() == true;
  2299. }
  2300. private Dictionary<String, object?> AfterEditorValueChanged(DynamicEditorGrid grid, T[] items, AfterEditorValueChangedArgs args)
  2301. {
  2302. var changes = new Dictionary<string, object?>();
  2303. OnAfterEditorValueChanged(grid, items, args, changes);
  2304. return changes;
  2305. }
  2306. protected virtual void OnAfterEditorValueChanged(DynamicEditorGrid grid, T[] items, AfterEditorValueChangedArgs args, Dictionary<String, object?> changes)
  2307. {
  2308. }
  2309. protected virtual void DoReconfigureEditors(DynamicEditorGrid grid, T[] items)
  2310. {
  2311. /*if (items.First() is IDimensioned dimensioned)
  2312. {
  2313. UpdateEditor(grid, x => x.Dimensions.Quantity, dimensioned.Dimensions.GetUnit().HasQuantity);
  2314. UpdateEditor(grid, x => x.Dimensions.Length, dimensioned.Dimensions.GetUnit().HasLength);
  2315. UpdateEditor(grid, x => x.Dimensions.Width, dimensioned.Dimensions.GetUnit().HasWidth);
  2316. UpdateEditor(grid, x => x.Dimensions.Height, dimensioned.Dimensions.GetUnit().HasHeight);
  2317. UpdateEditor(grid, x => x.Dimensions.Weight, dimensioned.Dimensions.GetUnit().HasWeight);
  2318. }*/
  2319. }
  2320. private string[]? ValidateData(T[] items)
  2321. {
  2322. var errors = new List<string>();
  2323. DoValidate(items, errors);
  2324. OnValidate?.Invoke(this, items, errors);
  2325. return errors.Any() ? errors.ToArray() : null;
  2326. }
  2327. protected virtual void DoValidate(T[] items, List<string> errors)
  2328. {
  2329. }
  2330. protected virtual void AfterLoad(IDynamicEditorForm editor, T[] items)
  2331. {
  2332. editor.AfterLoad();
  2333. }
  2334. protected virtual void SelectPage(object sender, BaseObject[]? items)
  2335. {
  2336. }
  2337. protected virtual Dictionary<string, object?> EditorValueChanged(IDynamicEditorForm editor, T[] items, string name, object value)
  2338. {
  2339. var result = DynamicGridUtils.UpdateEditorValue(items, name, value);
  2340. if (OnEditorValueChanged != null)
  2341. {
  2342. var newchanges = OnEditorValueChanged(editor, name, value);
  2343. foreach (var key in newchanges.Keys)
  2344. result[key] = newchanges[key];
  2345. }
  2346. return result;
  2347. }
  2348. private readonly Dictionary<Tuple<Type, Type>, Dictionary<object, object>> _lookupcache = new();
  2349. protected virtual void DefineLookups(ILookupEditorControl sender, T[] items, bool async = true)
  2350. {
  2351. if (sender.EditorDefinition is not ILookupEditor editor)
  2352. return;
  2353. var colname = sender.ColumnName;
  2354. if (async)
  2355. {
  2356. Task.Run(() =>
  2357. {
  2358. try
  2359. {
  2360. var values = editor.Values(colname, items);
  2361. Dispatcher.Invoke(
  2362. () =>
  2363. {
  2364. try
  2365. {
  2366. //Logger.Send(LogType.Information, typeof(T).Name, "Dispatching Results" + colname);
  2367. sender.LoadLookups(values);
  2368. }
  2369. catch (Exception e2)
  2370. {
  2371. Logger.Send(LogType.Information, typeof(T).Name,
  2372. "Exception (2) in LoadLookups: " + e2.Message + "\n" + e2.StackTrace);
  2373. }
  2374. }
  2375. );
  2376. }
  2377. catch (Exception e)
  2378. {
  2379. Logger.Send(LogType.Information, typeof(T).Name,
  2380. "Exception (1) in LoadLookups: " + e.Message + "\n" + e.StackTrace);
  2381. }
  2382. });
  2383. }
  2384. else
  2385. {
  2386. var values = editor.Values(colname, items);
  2387. sender.LoadLookups(values);
  2388. }
  2389. }
  2390. /// <summary>
  2391. /// Retrieves an editor to display for the given column of <paramref name="item"/>.
  2392. /// </summary>
  2393. /// <param name="item">The object being edited.</param>
  2394. /// <param name="column">The column of the editor.</param>
  2395. /// <returns>A new editor, or <see langword="null"/> if no editor defined and no sensible default exists.</returns>
  2396. protected virtual BaseEditor? GetEditor(object item, DynamicGridColumn column)
  2397. {
  2398. return column.Editor ?? CoreUtils.GetProperty(item.GetType(), column.ColumnName).GetEditor();
  2399. }
  2400. protected IFilter? DefineFilter(Type type, T[] items)
  2401. {
  2402. return LookupFactory.DefineFilter(items, type);
  2403. }
  2404. protected virtual void SetEditorValue(object item, string name, object value)
  2405. {
  2406. try
  2407. {
  2408. CoreUtils.SetPropertyValue(item, name, value);
  2409. }
  2410. catch (Exception e)
  2411. {
  2412. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  2413. }
  2414. }
  2415. protected virtual object? GetEditorValue(object item, string name)
  2416. {
  2417. return CoreUtils.GetPropertyValue(item, name);
  2418. }
  2419. protected virtual bool CanCreateItems()
  2420. {
  2421. return true;
  2422. }
  2423. private bool AddEditClick(CoreRow[]? rows)
  2424. {
  2425. if (!IsEnabled || bRefreshing)
  2426. return false;
  2427. if (rows == null || !rows.Any())
  2428. {
  2429. if (!CanCreateItems())
  2430. return false;
  2431. var item = CreateItem();
  2432. // Yea, and this won't work, because we're actually usually showing the description of a linked item,
  2433. // not the id of the link, and we need to set the ID to have it work properly :-(
  2434. //foreach (String key in VisualFilters.Keys)
  2435. // CoreUtils.SetPropertyValue(item, key, VisualFilters[key]);
  2436. if (EditItems(new[] { item }))
  2437. {
  2438. //_CurrentRow = Data.Rows.Count;
  2439. var row = Data.NewRow();
  2440. ObjectToRow(item, row);
  2441. Data.Rows.Add(row);
  2442. InvalidateGrid();
  2443. SelectedRows = new[] { row };
  2444. OnChanged?.Invoke(this, EventArgs.Empty);
  2445. return true;
  2446. }
  2447. return false;
  2448. }
  2449. var items = Array.Empty<T>();
  2450. using (new WaitCursor())
  2451. {
  2452. Stopwatch sw = new Stopwatch();
  2453. sw.Start();
  2454. items = LoadItems(rows);
  2455. //Logger.Send(LogType.Information, "DG:LoadItems", String.Format("Loaded Items: {0}ms", sw.ElapsedMilliseconds));
  2456. sw.Stop();
  2457. }
  2458. if (items.Any())
  2459. {
  2460. var sel = SelectedRows;
  2461. if (EditItems(items))
  2462. {
  2463. for (var i = 0; i < items.Length; i++)
  2464. {
  2465. ObjectToRow(items[i], rows[i]);
  2466. ObjectToRow(items[i], _recordmap[rows[i]]);
  2467. }
  2468. InvalidateGrid();
  2469. SelectedRows = sel;
  2470. OnChanged?.Invoke(this, EventArgs.Empty);
  2471. return true;
  2472. }
  2473. return false;
  2474. }
  2475. return false;
  2476. }
  2477. #endregion
  2478. #region Duplicate
  2479. protected virtual IEnumerable<T> LoadDuplicatorItems(CoreRow[] rows)
  2480. {
  2481. return LoadItems(rows);
  2482. }
  2483. private bool DoDuplicate(Button button, CoreRow[] rows)
  2484. {
  2485. if (!rows.Any())
  2486. {
  2487. MessageBox.Show("Please select at least one record to duplicate!");
  2488. return false;
  2489. }
  2490. /*var ids = ExtractValues(x => x.ID, Selection.Selected).ToArray();
  2491. if (!ids.Any())
  2492. {
  2493. MessageBox.Show("Please select at least one record to duplicate!");
  2494. return false;
  2495. }*/
  2496. var duplicator = (new T() as IDuplicatable)?.GetDuplicator();
  2497. if (duplicator is null)
  2498. {
  2499. MessageBox.Show($"Cannot duplicate {typeof(T)}");
  2500. return false;
  2501. }
  2502. duplicator.Duplicate(LoadDuplicatorItems(rows));// new Filter<T>(x => x.ID).InList(ids));
  2503. return true;
  2504. }
  2505. #endregion
  2506. protected virtual void ShowHelp(string slug)
  2507. {
  2508. Process.Start(new ProcessStartInfo("https://prsdigital.com.au/wiki/index.php/" + slug) { UseShellExecute = true });
  2509. }
  2510. protected void ReloadForms<TTargetType, TTargetForm, TSourceForm>(IDynamicEditorForm editor, TTargetType item,
  2511. Expression<Func<TSourceForm, object?>> sourcekey, Guid sourceid)
  2512. where TTargetType : Entity, new()
  2513. where TTargetForm : Entity, IRemotable, IPersistent, IDigitalFormInstance, new()
  2514. where TSourceForm : Entity, IRemotable, IPersistent, IDigitalForm<TTargetType>, new()
  2515. {
  2516. var type = typeof(IDynamicOneToManyGrid<,>).MakeGenericType(typeof(TTargetType), typeof(TTargetForm));
  2517. var page =
  2518. editor.Pages?.FirstOrDefault(x => x.GetType().GetInterfaces().Contains(type)) as IDynamicOneToManyGrid<TTargetType, TTargetForm>;
  2519. if (page != null && item != null)
  2520. {
  2521. if (!page.Ready)
  2522. page.Load(item, null);
  2523. CoreTable table;
  2524. if (sourceid == Guid.Empty)
  2525. {
  2526. table = new CoreTable();
  2527. table.LoadColumns(typeof(TSourceForm));
  2528. }
  2529. else
  2530. {
  2531. table = new Client<TSourceForm>().Query(
  2532. new Filter<TSourceForm>(sourcekey).IsEqualTo(sourceid).And(x => x.Form.AppliesTo)
  2533. .IsEqualTo(typeof(TTargetType).EntityName().Split('.').Last())
  2534. );
  2535. }
  2536. var newforms = new List<TTargetForm>();
  2537. foreach (var row in table.Rows)
  2538. {
  2539. var sourceform = row.ToObject<TSourceForm>();
  2540. var targetform = new TTargetForm();
  2541. targetform.Form.ID = sourceform.Form.ID;
  2542. targetform.Form.Synchronise(sourceform.Form);
  2543. newforms.Add(targetform);
  2544. }
  2545. page.Items.Clear();
  2546. page.LoadItems(newforms.ToArray());
  2547. }
  2548. }
  2549. #region ClipBuffer
  2550. private Tuple<ClipAction, CoreRow[]>? ClipBuffer;
  2551. protected void ResetClipBuffer()
  2552. {
  2553. ClipBuffer = null;
  2554. }
  2555. protected void SetClipBuffer(ClipAction action, CoreRow[] rows)
  2556. {
  2557. ClipBuffer = new Tuple<ClipAction, CoreRow[]>(action, rows);
  2558. }
  2559. private void CutToClipBuffer()
  2560. {
  2561. SetClipBuffer(ClipAction.Cut, SelectedRows);
  2562. InvalidateGrid();
  2563. }
  2564. private void CopyToClipBuffer()
  2565. {
  2566. SetClipBuffer(ClipAction.Copy, SelectedRows);
  2567. InvalidateGrid();
  2568. }
  2569. private void PasteFromClipBuffer()
  2570. {
  2571. if (ClipBuffer == null)
  2572. return;
  2573. if (!IsSequenced)
  2574. return;
  2575. using (new WaitCursor())
  2576. {
  2577. var updates = ClipBuffer.Item2.Select(x => x.ToObject<T>()).ToList();
  2578. if (BeforePaste(updates, ClipBuffer.Item1))
  2579. {
  2580. var currow = SelectedRows.FirstOrDefault()
  2581. ?? Data.Rows.LastOrDefault();
  2582. var sequence = currow != null ? currow.Get<T, long>(c => ((ISequenceable)c).Sequence) : 0;
  2583. var postrows = Data.Rows.Where(r => !ClipBuffer.Item2.Contains(r) && r.Get<ISequenceable, long>(x => x.Sequence) >= sequence);
  2584. updates.AddRange(LoadItems(postrows.ToArray()));
  2585. foreach (var update in updates)
  2586. {
  2587. sequence++;
  2588. ((ISequenceable)update).Sequence = sequence;
  2589. }
  2590. }
  2591. if (updates.Any())
  2592. {
  2593. SaveItems(updates.ToArray());
  2594. Refresh(false, true);
  2595. }
  2596. }
  2597. }
  2598. protected virtual bool BeforePaste(IEnumerable<T> items, ClipAction action)
  2599. {
  2600. return true;
  2601. }
  2602. private void Cut_Click(object sender, RoutedEventArgs e)
  2603. {
  2604. CutToClipBuffer();
  2605. }
  2606. private void Copy_Click(object sender, RoutedEventArgs e)
  2607. {
  2608. CopyToClipBuffer();
  2609. }
  2610. private void Paste_Click(object sender, RoutedEventArgs e)
  2611. {
  2612. PasteFromClipBuffer();
  2613. }
  2614. #endregion
  2615. protected virtual void ObjectToRow(T obj, CoreRow row)
  2616. {
  2617. row.Table.LoadRow(row, obj);
  2618. }
  2619. #region Import / Export
  2620. protected virtual CoreTable LoadImportKeys(String[] fields)
  2621. {
  2622. var result = new CoreTable();
  2623. result.LoadColumns(new Columns<T>(fields));
  2624. return result;
  2625. }
  2626. protected virtual Guid GetImportID()
  2627. {
  2628. return Guid.Empty;
  2629. }
  2630. protected virtual bool CustomiseImportItem(T item)
  2631. {
  2632. if (IsSequenced)
  2633. ((ISequenceable)item).Sequence = CoreUtils.GenerateSequence();
  2634. return true;
  2635. }
  2636. protected virtual string CustomiseImportFileName(string filename)
  2637. {
  2638. return filename;
  2639. }
  2640. protected virtual void DoImport()
  2641. {
  2642. var list = new DynamicImportList(
  2643. typeof(T),
  2644. GetImportID()
  2645. );
  2646. list.OnImportItem += o => { return CustomiseImportItem((T)o); };
  2647. list.OnCustomiseImport += (o, args) => { args.FileName = CustomiseImportFileName(args.FileName); };
  2648. list.OnSave += (sender, entity) => SaveItem(entity as T);
  2649. list.OnLoad += (sender, type, fields, id) => LoadImportKeys(fields);
  2650. list.ShowDialog();
  2651. Refresh(false, true);
  2652. }
  2653. private void Import_Click(object sender, RoutedEventArgs e)
  2654. {
  2655. DoImport();
  2656. }
  2657. protected virtual void CustomiseExportColumns(List<string> columnnames)
  2658. {
  2659. }
  2660. protected virtual string CustomiseExportFileName(string filename)
  2661. {
  2662. return filename;
  2663. }
  2664. protected virtual void CustomiseExportFilters(Filters<T> filters, CoreRow[] visiblerows)
  2665. {
  2666. }
  2667. protected virtual void ApplyExportFilter(CoreTable table, object data)
  2668. {
  2669. }
  2670. private static bool FilterByPredicate(CoreRow row, string column, FilterPredicate predicate)
  2671. {
  2672. var value = row[column];
  2673. var vStr = value?.ToString() ?? "";
  2674. var pValue = predicate.FilterValue;
  2675. var pStr = pValue?.ToString() ?? "";
  2676. return predicate.FilterType switch
  2677. {
  2678. FilterType.Contains => vStr.Contains(pStr),
  2679. FilterType.EndsWith => vStr.EndsWith(pStr),
  2680. FilterType.Equals => vStr.Equals(pStr),
  2681. FilterType.GreaterThan => vStr.CompareTo(pStr) > 0,
  2682. FilterType.GreaterThanOrEqual => vStr.CompareTo(pStr) >= 0,
  2683. FilterType.LessThan => vStr.CompareTo(pStr) < 0,
  2684. FilterType.LessThanOrEqual => vStr.CompareTo(pStr) <= 0,
  2685. FilterType.NotContains => !vStr.Contains(pStr),
  2686. FilterType.NotEndsWith => !vStr.EndsWith(pStr),
  2687. FilterType.NotEquals => !vStr.Equals(pStr),
  2688. FilterType.NotStartsWith => !vStr.StartsWith(pStr),
  2689. FilterType.StartsWith => vStr.StartsWith(pStr),
  2690. _ => true,
  2691. };
  2692. }
  2693. private List<Tuple<string, FilterPredicate>> GetFilterPredicates()
  2694. {
  2695. var list = new List<Tuple<string, FilterPredicate>>();
  2696. foreach (var column in DataGrid.Columns)
  2697. {
  2698. var colIndex = DataGrid.Columns.IndexOf(column);
  2699. var col = ColumnList[colIndex];
  2700. if (col is DynamicGridColumn gridColumn)
  2701. {
  2702. foreach (var predicate in column.FilterPredicates)
  2703. {
  2704. list.Add(new(gridColumn.ColumnName, predicate));
  2705. }
  2706. }
  2707. }
  2708. return list;
  2709. }
  2710. protected virtual void DoExport()
  2711. {
  2712. var columnnames = VisibleColumns.Select(x => x.ColumnName).ToList();
  2713. CustomiseExportColumns(columnnames);
  2714. var form = new DynamicExportForm(typeof(T), columnnames);
  2715. if (form.ShowDialog() != true)
  2716. return;
  2717. var filters = new Filters<T>();
  2718. filters.Add(DefineFilter());
  2719. var predicates = GetFilterPredicates();
  2720. var visiblerows = GetVisibleRows();
  2721. CustomiseExportFilters(filters, visiblerows);
  2722. var columns = new Columns<T>(form.Fields);
  2723. var otherColumns = form.GetChildFields()
  2724. .Select(x => new Tuple<Type, IColumns>(
  2725. x.Key,
  2726. (Activator.CreateInstance(typeof(Columns<>).MakeGenericType(x.Key), new object[] { x.Value }) as IColumns)!))
  2727. .Where(x => x.Item2.ColumnNames().Any()).ToList();
  2728. var reloadColumns = new Columns<T>();
  2729. foreach (var column in columns.ColumnNames())
  2730. {
  2731. reloadColumns.Add(column);
  2732. }
  2733. foreach (var column in HiddenColumns.ColumnNames)
  2734. {
  2735. reloadColumns.Add(column);
  2736. }
  2737. foreach (var (column, _) in predicates)
  2738. {
  2739. reloadColumns.Add(column);
  2740. }
  2741. var sort = LookupFactory.DefineSort<T>();
  2742. Reload(filters, reloadColumns, ref sort, (data, err) => Dispatcher.Invoke(() =>
  2743. {
  2744. if (data is not null)
  2745. {
  2746. var newData = new CoreTable();
  2747. foreach (var column in columns.Items)
  2748. newData.Columns.Add(new CoreColumn { ColumnName = column.Property, DataType = column.Type });
  2749. FilterRows(data, newData, filter: (row) =>
  2750. {
  2751. foreach (var (column, predicate) in predicates)
  2752. {
  2753. if (!FilterByPredicate(row, column, predicate))
  2754. {
  2755. return false;
  2756. }
  2757. }
  2758. return true;
  2759. });
  2760. var list = new List<Tuple<Type?, CoreTable>>() { new(typeof(T), newData) };
  2761. list.AddRange(LoadExportTables(filters, otherColumns));
  2762. DoExportTables(list);
  2763. }
  2764. else if (err is not null)
  2765. {
  2766. Logger.Send(LogType.Error, "", $"Error in export: {CoreUtils.FormatException(err)}");
  2767. MessageBox.Show(err.Message);
  2768. }
  2769. }));
  2770. }
  2771. private void Export_Click(object sender, RoutedEventArgs e)
  2772. {
  2773. DoExport();
  2774. }
  2775. /// <summary>
  2776. /// Loads the child tables for an export, based on the filter of the parent table.
  2777. /// </summary>
  2778. /// <remarks>
  2779. /// If not overriden, defaults to creating empty tables with no records.
  2780. /// </remarks>
  2781. /// <param name="filter">Filter for the parent table.</param>
  2782. /// <param name="tableColumns">A list of the child table types, with columns to load for each</param>
  2783. /// <returns>A list of tables, in the same order as they came in <paramref name="tableColumns"/></returns>
  2784. protected virtual IEnumerable<Tuple<Type?, CoreTable>> LoadExportTables(Filters<T> filter, IEnumerable<Tuple<Type, IColumns>> tableColumns)
  2785. {
  2786. return tableColumns.Select(x =>
  2787. {
  2788. var table = new CoreTable();
  2789. table.LoadColumns(x.Item2);
  2790. return new Tuple<Type?, CoreTable>(x.Item1, table);
  2791. });
  2792. }
  2793. private void DoExportTables(List<Tuple<Type?, CoreTable>> data)
  2794. {
  2795. var filename = CustomiseExportFileName(typeof(T).EntityName().Split('.').Last());
  2796. ExcelExporter.DoExport(data, filename);
  2797. }
  2798. #endregion
  2799. public void ScrollIntoView(CoreRow row)
  2800. {
  2801. DataGrid.ScrollInView(new RowColumnIndex(row.Index + 1, 0));
  2802. }
  2803. #endregion
  2804. #region Custom Buttons
  2805. private Button CreateButton(BitmapImage? image = null, string? text = null, string? tooltip = null)
  2806. {
  2807. var button = new Button();
  2808. button.SetValue(BorderBrushProperty, new SolidColorBrush(Colors.Gray));
  2809. button.SetValue(BorderThicknessProperty, new Thickness(0.75));
  2810. button.Height = 30;
  2811. UpdateButton(button, image, text, tooltip);
  2812. return button;
  2813. }
  2814. public override void UpdateButton(Button button, BitmapImage? image, string? text, string? tooltip = null)
  2815. {
  2816. var stackPnl = new StackPanel();
  2817. stackPnl.Orientation = Orientation.Horizontal;
  2818. //stackPnl.Margin = new Thickness(2);
  2819. if (image != null)
  2820. {
  2821. var img = new Image();
  2822. img.Source = image;
  2823. img.Margin = new Thickness(2);
  2824. img.ToolTip = tooltip;
  2825. stackPnl.Children.Add(img);
  2826. }
  2827. if (!string.IsNullOrEmpty(text))
  2828. {
  2829. button.MaxWidth = double.MaxValue;
  2830. var lbl = new Label();
  2831. lbl.Content = text;
  2832. lbl.VerticalAlignment = VerticalAlignment.Stretch;
  2833. lbl.VerticalContentAlignment = VerticalAlignment.Center;
  2834. lbl.Margin = new Thickness(2, 0, 5, 0);
  2835. lbl.ToolTip = ToolTip;
  2836. stackPnl.Children.Add(lbl);
  2837. }
  2838. else
  2839. button.MaxWidth = 30;
  2840. button.Content = stackPnl;
  2841. button.ToolTip = tooltip;
  2842. }
  2843. private bool bFirstButtonAdded = true;
  2844. private bool AnyButtonsVisible()
  2845. {
  2846. if (Add.Visibility != Visibility.Collapsed)
  2847. return true;
  2848. if (Edit.Visibility != Visibility.Collapsed)
  2849. return true;
  2850. /*if (MultiEdit.Visibility != Visibility.Collapsed)
  2851. return true;*/
  2852. if (Export.Visibility != Visibility.Collapsed)
  2853. return true;
  2854. return false;
  2855. }
  2856. public override Button AddButton(string? caption, BitmapImage? image, string? tooltip, Func<Button, CoreRow[], bool> action, DynamicGridButtonPosition position = DynamicGridButtonPosition.Left)
  2857. {
  2858. var button = CreateButton(image, caption, tooltip);
  2859. button.Margin = position == DynamicGridButtonPosition.Right
  2860. ? new Thickness(2, 2, 0, 0)
  2861. : bFirstButtonAdded && AnyButtonsVisible()
  2862. ? new Thickness(0, 2, 0, 0)
  2863. : new Thickness(0, 2, 2, 0);
  2864. button.Padding = !String.IsNullOrWhiteSpace(caption) ? new Thickness(5, 1, 5, 1) : new Thickness(1);
  2865. button.Tag = action;
  2866. button.Click += Button_Click;
  2867. if (position == DynamicGridButtonPosition.Right)
  2868. RightButtonStack.Children.Add(button);
  2869. else
  2870. LeftButtonStack.Children.Add(button);
  2871. bFirstButtonAdded = false;
  2872. return button;
  2873. }
  2874. private void Button_Click(object sender, RoutedEventArgs e)
  2875. {
  2876. var button = (Button)sender;
  2877. var action = (Func<Button, CoreRow[], bool>)button.Tag;
  2878. //CoreRow row = (CurrentRow > -1) && (CurrentRow < Data.Rows.Count) ? Data.Rows[this.CurrentRow] : null;
  2879. if (action.Invoke(button, SelectedRows))
  2880. Refresh(false, true);
  2881. }
  2882. #endregion
  2883. #region Header Actions
  2884. private void ColumnsMenu_ContextMenuOpening(object sender, RoutedEventArgs e)
  2885. {
  2886. if (sender is not ContextMenu menu) return;
  2887. menu.Items.Clear();
  2888. menu.AddItem("Select Columns", null, SelectColumnsClick);
  2889. LoadColumnsMenu(menu);
  2890. }
  2891. private void SelectColumnsClick()
  2892. {
  2893. var editor = new DynamicGridColumnsEditor(typeof(T));
  2894. editor.DirectEdit = IsDirectEditMode();
  2895. editor.Columns.AddRange(VisibleColumns);
  2896. if (editor.ShowDialog().Equals(true))
  2897. {
  2898. VisibleColumns.Clear();
  2899. VisibleColumns.AddRange(editor.Columns);
  2900. SaveColumns(VisibleColumns);
  2901. //OnSaveColumns?.Invoke(this, editor.Columns);
  2902. Refresh(true, true);
  2903. }
  2904. }
  2905. #endregion
  2906. #region Drag + Drop
  2907. private static string DragFormat => typeof(DynamicGridDragFormat).FullName ?? "";
  2908. /// <summary>
  2909. /// Handle a number of rows from a different <see cref="DynamicGrid{T}"/> being dragged into this one.
  2910. /// </summary>
  2911. /// <param name="entity">The type of entity that that the rows of <paramref name="table"/> represent.</param>
  2912. /// <param name="table">The data being dragged.</param>
  2913. /// <param name="e"></param>
  2914. protected virtual void OnDragEnd(Type entity, CoreTable table, DragEventArgs e)
  2915. {
  2916. Logger.Send(LogType.Information,"","OnDragEnd");
  2917. }
  2918. private void DataGrid_DragOver(object sender, DragEventArgs e)
  2919. {
  2920. HandleDragOver(sender, e);
  2921. }
  2922. private void DataGrid_Drop(object sender, DragEventArgs e)
  2923. {
  2924. Logger.Send(LogType.Information,"","DataGrid_Drop");
  2925. if (!HasOption(DynamicGridOption.DragTarget))
  2926. return;
  2927. Logger.Send(LogType.Information,"","DataGrid_Drop::DragTarget==true");
  2928. if (e.Data.GetDataPresent(DragFormat))
  2929. {
  2930. Logger.Send(LogType.Information,"","DataGrid_Drop::DataPresent==true");
  2931. var data = e.Data.GetData(DragFormat) as DynamicGridDragFormat;
  2932. if (data is not null)
  2933. {
  2934. Logger.Send(LogType.Information,"","DataGrid_Drop::DragData==DynamicGridDragFormat");
  2935. var table = new CoreTable();
  2936. foreach (var column in data.Table.Columns)
  2937. {
  2938. if (column is DataColumn dataColumn)
  2939. {
  2940. table.Columns.Add(new CoreColumn { ColumnName = dataColumn.ColumnName.Replace('_', '.'), DataType = dataColumn.DataType });
  2941. }
  2942. }
  2943. foreach (var row in data.Table.Rows)
  2944. {
  2945. if (row is DataRow dataRow)
  2946. {
  2947. var coreRow = table.NewRow();
  2948. coreRow.LoadValues(dataRow.ItemArray);
  2949. table.Rows.Add(coreRow);
  2950. }
  2951. }
  2952. OnDragEnd(data.Entity, table, e);
  2953. DoChanged();
  2954. }
  2955. }
  2956. else
  2957. {
  2958. HandleDragDrop(sender, e);
  2959. }
  2960. }
  2961. /// <summary>
  2962. /// Handle all types of items being dragged onto this grid that aren't handled by <see cref="OnDragEnd(Type, CoreTable, DragEventArgs)"/>,
  2963. /// i.e., data which is not a <see cref="CoreTable"/> from another <see cref="DynamicGrid{T}"/>
  2964. /// </summary>
  2965. /// <remarks>
  2966. /// Can be used to handle files, for example.
  2967. /// </remarks>
  2968. /// <param name="sender"></param>
  2969. /// <param name="e"></param>
  2970. protected virtual void HandleDragDrop(object sender, DragEventArgs e)
  2971. {
  2972. }
  2973. protected virtual void HandleDragOver(object sender, DragEventArgs e)
  2974. {
  2975. }
  2976. protected DragDropEffects DragTable(Type entity, CoreTable table)
  2977. {
  2978. Logger.Send(LogType.Information,"","DragTable");
  2979. var data = new DataObject();
  2980. data.SetData(DragFormat, new DynamicGridDragFormat(table.ToDataTable(), entity));
  2981. var effect = DragDrop.DoDragDrop(this, data, DragDropEffects.All);
  2982. return effect;
  2983. }
  2984. protected virtual DragDropEffects OnRowsDragStart(CoreRow[] rows)
  2985. {
  2986. Logger.Send(LogType.Information,"","OnRowsDragStart");
  2987. var table = new CoreTable();
  2988. table.LoadColumns(Data.Columns);
  2989. table.LoadRows(rows);
  2990. return DragTable(typeof(T), table);
  2991. }
  2992. private void RowDragDropController_DragStart(object? sender, GridRowDragStartEventArgs e)
  2993. {
  2994. Logger.Send(LogType.Information,"","RowDragDropController_DragStart");
  2995. //e.Handled = true;
  2996. if (!HasOption(DynamicGridOption.DragSource))
  2997. return;
  2998. var rows = new List<CoreRow>();
  2999. foreach (var record in e.DraggingRecords)
  3000. {
  3001. var rowIndex = DataGrid.ResolveToRowIndex(record);
  3002. rows.Add(GetRowFromIndex(rowIndex));
  3003. }
  3004. var rowArr = rows.ToArray();
  3005. OnRowsDragStart(rowArr);
  3006. }
  3007. #endregion
  3008. /* Removed as appears unused; removed as of 19/12/2022
  3009. #region CellRendering
  3010. private void PopulateDynamicActionCell(DynamicActionColumn column, int rowIndex, int columnIndex, GridStyleInfo style)
  3011. {
  3012. style.CellType = "ImageCell";
  3013. var bi = column.Image?.Invoke(rowIndex < 0 ? null : Data.Rows[rowIndex]);
  3014. if (bi != null)
  3015. {
  3016. style.CellValue = bi;
  3017. style.BorderMargins = new CellMarginsInfo(4.0F);
  3018. }
  3019. }
  3020. //bool rowstylehelperinitialised = false;
  3021. //protected virtual void ProcessCellStyle(CoreRow row, int column, GridStyleInfo style)
  3022. //{
  3023. // if (!rowstylehelperinitialised)
  3024. // {
  3025. // Script stylescript = new Client<Script>().Load(new Filter<Script>(x => x.Section).IsEqualTo(typeof(T).EntityName()).And(x => x.ScriptType).IsEqualTo(ScriptType.RowStyle)).FirstOrDefault(); ;
  3026. // if (stylescript != null)
  3027. // {
  3028. // rowstylehelper = new ScriptDocument(stylescript.Code);
  3029. // if (!rowstylehelper.Compile())
  3030. // {
  3031. // MessageBox.Show("Unable to Load Row Style Helper!\r\n\r\n" + rowstylehelper.Result);
  3032. // rowstylehelper = null;
  3033. // }
  3034. // }
  3035. // rowstylehelperinitialised = true;
  3036. // }
  3037. // if (rowstylehelper != null)
  3038. // {
  3039. // try
  3040. // {
  3041. // rowstylehelper.SetValue("Row", row);
  3042. // rowstylehelper.SetValue("Column", Data.Columns[column].ColumnName);
  3043. // rowstylehelper.SetValue("Background", style.Background);
  3044. // rowstylehelper.SetValue("Foreground", style.Foreground);
  3045. // rowstylehelper.SetValue("Style", style.Font.FontStyle);
  3046. // rowstylehelper.SetValue("Weight", style.Font.FontWeight);
  3047. // if (rowstylehelper.Execute())
  3048. // {
  3049. // style.Background = (System.Windows.Media.Brush)rowstylehelper.GetValue("Background");
  3050. // style.Foreground = (System.Windows.Media.Brush)rowstylehelper.GetValue("Foreground");
  3051. // style.Font.FontStyle = (FontStyle)rowstylehelper.GetValue("Style");
  3052. // style.Font.FontWeight = (FontWeight)rowstylehelper.GetValue("Weight");
  3053. // }
  3054. // }
  3055. // catch (Exception e)
  3056. // {
  3057. // //MessageBox.Show("Unable to Invoke Row Style Helper!\r\n\r\n" + e.Message);
  3058. // }
  3059. // }
  3060. //}
  3061. private readonly Dictionary<string, BaseEditor> editorcache = new();
  3062. private void PopulateDataCell(int rowIndex, int columnIndex, GridStyleInfo style)
  3063. {
  3064. if (columnIndex > -1 && columnIndex < ColumnList.Count)
  3065. {
  3066. var o = ColumnList[columnIndex];
  3067. if (o is DynamicActionColumn)
  3068. {
  3069. PopulateDynamicActionCell((DynamicActionColumn)o, rowIndex, columnIndex, style);
  3070. }
  3071. else
  3072. {
  3073. var dgc = (DynamicGridColumn)o;
  3074. var dc = Data.Columns.FirstOrDefault(x => x.ColumnName.Equals(dgc.ColumnName));
  3075. var fmt = string.IsNullOrWhiteSpace(dgc.Format) ? "{0}" : "{0:" + dgc.Format.Replace("\\:", ":").Replace(":", "\\:") + "}";
  3076. object? val = null;
  3077. if (rowIndex < Data.Rows.Count)
  3078. val = Data.Rows[rowIndex][dgc.ColumnName];
  3079. if (val != null && dgc.Lookups.ContainsKey(val))
  3080. val = dgc.Lookups[val];
  3081. if (dc != null)
  3082. {
  3083. if(!editorcache.TryGetValue(dc.ColumnName, out var editor))
  3084. {
  3085. var prop = DatabaseSchema.Property(typeof(T), dc.ColumnName);
  3086. if (prop != null)
  3087. editor = prop.Editor;
  3088. else
  3089. editor = EditorUtils.GetEditor(dc.DataType) ?? new NullEditor();
  3090. editorcache[dc.ColumnName] = editor;
  3091. }
  3092. if (editor is CheckBoxEditor)
  3093. {
  3094. style.CellType = "CheckBox";
  3095. style.CellValue = val;
  3096. style.HorizontalAlignment = dc == null ? HorizontalAlignment.Left : dgc.HorizontalAlignment(dc.DataType);
  3097. style.VerticalAlignment = dgc.VerticalAlignment();
  3098. style.TextMargins = new CellMarginsInfo(2.0F);
  3099. }
  3100. else if (editor is ColorEditor)
  3101. {
  3102. style.CellType = "ImageCell";
  3103. var str = val?.ToString();
  3104. if (!string.IsNullOrWhiteSpace(str))
  3105. {
  3106. var color = ColorTranslator.FromHtml(str); // System.Drawing.Color.FromName(val.ToString());
  3107. var bitmap = ImageUtils.BitmapFromColor(color, (int)style.GridModel.ColumnWidths[columnIndex],
  3108. (int)style.GridModel.RowHeights[rowIndex], Color.Black);
  3109. //bitmap.Save(val.ToString().Replace("#","") + ".png");
  3110. style.CellValue = bitmap.AsBitmapImage(false);
  3111. style.BorderMargins = new CellMarginsInfo(4.0F);
  3112. }
  3113. }
  3114. else
  3115. {
  3116. string value;
  3117. try
  3118. {
  3119. if(val is null)
  3120. {
  3121. value = "";
  3122. }
  3123. else if (val.GetType().IsEnum)
  3124. {
  3125. value = val.ToString()!;
  3126. }
  3127. else if (val.GetType().IsDefault(val))
  3128. {
  3129. value = "";
  3130. }
  3131. else
  3132. {
  3133. value = string.Format(new TimeSpanFormatter(), fmt, val);
  3134. }
  3135. }
  3136. catch (Exception e)
  3137. {
  3138. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  3139. value = val?.ToString() ?? "";
  3140. }
  3141. if (editor is PasswordEditor)
  3142. style.CellValue = "".PadLeft(value.Length, '●');
  3143. else
  3144. style.CellValue = value;
  3145. style.HorizontalAlignment = dc == null ? HorizontalAlignment.Left : dgc.HorizontalAlignment(dc.DataType);
  3146. style.VerticalAlignment = dgc.VerticalAlignment();
  3147. style.CellType = "Static";
  3148. style.TextMargins = new CellMarginsInfo(2.0F);
  3149. }
  3150. }
  3151. }
  3152. }
  3153. }
  3154. private void PopulateHeaderCell(int columnIndex, GridStyleInfo style)
  3155. {
  3156. if (columnIndex > -1 && columnIndex < ColumnList.Count)
  3157. {
  3158. var o = ColumnList[columnIndex];
  3159. if (o is DynamicActionColumn)
  3160. {
  3161. PopulateDynamicActionCell((DynamicActionColumn)o, -1, columnIndex, style);
  3162. }
  3163. else
  3164. {
  3165. var dgc = (DynamicGridColumn)o;
  3166. if (Data != null)
  3167. {
  3168. var dc = Data.Columns.FirstOrDefault(x => x.ColumnName.Equals(dgc.ColumnName));
  3169. style.HorizontalAlignment = dc != null ? dgc.HorizontalAlignment(dc.DataType) : HorizontalAlignment.Left;
  3170. }
  3171. style.CellValue = string.IsNullOrWhiteSpace(dgc.Caption) ? dgc.ColumnName : dgc.Caption;
  3172. style.VerticalAlignment = dgc.VerticalAlignment();
  3173. style.CellType = "Static";
  3174. style.TextMargins = new CellMarginsInfo(2.0F);
  3175. }
  3176. }
  3177. }
  3178. #endregion
  3179. */
  3180. /* Removed as appears unused; removed as of 19/12/2022
  3181. #region Drag and Drop
  3182. private Point startpoint;
  3183. private void CheckPreviewMouseDown(object sender, MouseButtonEventArgs e)
  3184. {
  3185. if (!HasOption(DynamicGridOption.DragSource))
  3186. return;
  3187. if (e.LeftButton == MouseButtonState.Pressed)
  3188. {
  3189. Logger.Send(LogType.Information, GetType().EntityName(), "Initiating Start Point");
  3190. startpoint = e.GetPosition(DataGrid);
  3191. }
  3192. }
  3193. //private void CheckPreviewMouseMove(object sender, MouseEventArgs e)
  3194. //{
  3195. // Logger.Send(LogType.Information, this.GetType().EntityName(), String.Format("Checking Mouse Move: StartPoint = {0},{1}", startpoint.X, startpoint.Y));
  3196. // if (!_HasOption(DynamicGridOptions.DragSource))
  3197. // return;
  3198. // Vector diff = startpoint - e.GetPosition(null);
  3199. // Logger.Send(LogType.Information, this.GetType().EntityName(), String.Format("Checking Mouse Move: StartPoint = {0},{1} Diff = {2},{3}", startpoint.X, startpoint.Y, diff.X, diff.Y));
  3200. // if ( (startpoint.X != 0) && (startpoint.Y != 0))
  3201. // {
  3202. // if ((Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance) || (Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
  3203. // {
  3204. // Logger.Send(LogType.Information, this.GetType().EntityName(), "Starting Drag Drop Operation");
  3205. // DataObject dragData = new DataObject(typeof(T).EntityName(), SelectedRows);
  3206. // DragDrop.DoDragDrop(DataGrid, dragData, DragDropEffects.Copy);
  3207. // }
  3208. // }
  3209. //}
  3210. private void CheckPreviewMouseUp(object sender, MouseButtonEventArgs e)
  3211. {
  3212. if (!HasOption(DynamicGridOption.DragSource))
  3213. return;
  3214. Logger.Send(LogType.Information, GetType().EntityName(), "Clearing Start Point");
  3215. startpoint = new Point();
  3216. }
  3217. #endregion
  3218. */
  3219. }
  3220. }