Преглед изворни кода

Merge commit '628f41e644453d94b60356ea742102c8faf67580' into frank

Frank van den Bos пре 8 месеци
родитељ
комит
b50b35c872

+ 133 - 1
InABox.Core/DocumentCache.cs

@@ -86,7 +86,8 @@ namespace InABox.Core
     }
 
     /// <summary>
-    /// A cache of documents that is saved in the AppData folder under a specific tag.
+    /// A cache of documents that is saved in the AppData folder under a specific tag. Contrary to the name, this isn't just a <see cref="Document"/> cache, but
+    /// in fact a way to cache any kind of object that implements <see cref="ICachedDocument"/>.
     /// </summary>
     /// <remarks>
     /// The files are stored with the name "&lt;ID&gt;.document", and they contain a binary serialised <see cref="CachedDocument"/>.
@@ -431,4 +432,135 @@ namespace InABox.Core
 
         #endregion
     }
+
+    /// <summary>
+    /// An implementation of <see cref="ICachedDocument"/> for use with entities of type <see cref="Document"/>. The <see cref="Document.TimeStamp"/>
+    /// is saved along with the document, allowing us to refresh updated documents.
+    /// </summary>
+    public class DocumentCachedDocument : ICachedDocument
+    {
+        public DateTime TimeStamp { get; set; }
+
+        public Document? Document { get; set; }
+
+        public Guid ID => Document?.ID ?? Guid.Empty;
+
+        public DocumentCachedDocument() { }
+
+        public DocumentCachedDocument(Document document)
+        {
+            Document = document;
+            TimeStamp = document.TimeStamp;
+        }
+
+        public void DeserializeBinary(CoreBinaryReader reader, bool full)
+        {
+            TimeStamp = reader.ReadDateTime();
+            if (full)
+            {
+                Document = reader.ReadObject<Document>();
+            }
+        }
+
+        public void SerializeBinary(CoreBinaryWriter writer)
+        {
+            writer.Write(TimeStamp);
+            if (Document is null)
+            {
+                throw new Exception("Cannot serialize incomplete CachedDocument");
+            }
+            writer.WriteObject(Document);
+        }
+    }
+
+    /// <summary>
+    /// Implements a <see cref="DocumentCache{T}"/> for use with <see cref="Document"/>.
+    /// </summary>
+    public abstract class DocumentCache : DocumentCache<DocumentCachedDocument>
+    {
+        public DocumentCache(string tag): base(tag) { }
+
+        protected override DocumentCachedDocument? LoadDocument(Guid id)
+        {
+            var document = Client.Query(new Filter<Document>(x => x.ID).IsEqualTo(id))
+                .ToObjects<Document>().FirstOrDefault();
+            if(document != null)
+            {
+                return new DocumentCachedDocument(document);
+            }
+            else
+            {
+                return null;
+            }
+        }
+        
+        /// <summary>
+        /// Fetch a bunch of documents from the cache or the database, optionally checking against the timestamp listed in the database.
+        /// </summary>
+        /// <param name="ids"></param>
+        /// <param name="checkTimestamp">
+        /// If <see langword="true"/>, then loads <see cref="Document.TimeStamp"/> from the database for all cached documents,
+        /// and if they are older, updates the cache.
+        /// </param>
+        public IEnumerable<Document> LoadDocuments(IEnumerable<Guid> ids, bool checkTimestamp = false)
+        {
+            var cached = new List<Guid>();
+            var toLoad = new List<Guid>();
+            foreach (var docID in ids)
+            {
+                if (Has(docID))
+                {
+                    cached.Add(docID);
+                }
+                else
+                {
+                    toLoad.Add(docID);
+                }
+            }
+
+            var loadedCached = new List<Document>();
+            if (cached.Count > 0)
+            {
+                var docs = Client.Query(
+                    new Filter<Document>(x => x.ID).InList(cached.ToArray()),
+                    Columns.None<Document>().Add(x => x.TimeStamp, x => x.ID));
+                foreach (var doc in docs.ToObjects<Document>())
+                {
+                    try
+                    {
+                        var timestamp = GetHeader(doc.ID).Document.TimeStamp;
+                        if (doc.TimeStamp > timestamp)
+                        {
+                            toLoad.Add(doc.ID);
+                        }
+                        else
+                        {
+                            loadedCached.Add(GetFull(doc.ID).Document.Document!);
+                        }
+                    }
+                    catch (Exception e)
+                    {
+                        CoreUtils.LogException("", e, "Error loading cached file");
+                        toLoad.Add(doc.ID);
+                    }
+                }
+            }
+
+            if (toLoad.Count > 0)
+            {
+                var loaded = Client.Query(new Filter<Document>(x => x.ID).InList(toLoad.ToArray()))
+                    .ToObjects<Document>().ToList();
+                foreach (var loadedDoc in loaded)
+                {
+                    Add(new DocumentCachedDocument(loadedDoc));
+                }
+                return loaded.Concat(loadedCached);
+            }
+            else
+            {
+                return loadedCached;
+            }
+        }
+    }
 }
+

+ 10 - 1
inabox.wpf/Converters/BooleanToVisibilityConverter.cs

@@ -3,4 +3,13 @@ using System.Windows.Media;
 
 namespace InABox.WPF;
 
-public class BooleanToVisibilityConverter : BooleanConverter<Visibility> { }
+public class BooleanToVisibilityConverter : BooleanConverter<Visibility>
+{
+    public BooleanToVisibilityConverter(): base() { }
+
+    public BooleanToVisibilityConverter(Visibility trueValue, Visibility falseValue): base()
+    {
+        TrueValue = trueValue;
+        FalseValue = falseValue;
+    }
+}

+ 2 - 3
inabox.wpf/DigitalForms/Designer/DynamicEditFormWindow.xaml.cs

@@ -399,9 +399,8 @@ public partial class DynamicFormEditWindow : Window, IDynamicFormWindow
         }
 
         form.Initialize();
-
-        if (values is not null)
-            form.LoadValues(values);
+        
+        form.LoadValues(values ?? new DFLoadStorage());
 
         customise?.Invoke(form);
 

+ 21 - 2
inabox.wpf/DigitalForms/Designer/DynamicFormDesignGrid.cs

@@ -2161,8 +2161,6 @@ namespace InABox.DynamicGrid
             var field = form.Elements.FirstOrDefault(x => string.Equals(fieldName, (x as DFLayoutField)?.Name)) as DFLayoutField;
             if (field != null)
             {
-                //value = field.ParseValue(value);
-
                 var fieldControl = GetFieldControl(field);
                 if (fieldControl != null)
                 {
@@ -2231,6 +2229,7 @@ namespace InABox.DynamicGrid
         public void LoadValues(DFLoadStorage values)
         {
             _changing = true;
+            InitializeEntityValues();
             foreach (var (key, value) in values.Items())
             {
                 if (!key.Contains('.'))
@@ -2243,6 +2242,26 @@ namespace InABox.DynamicGrid
             _isChanged = false;
         }
 
+        public void InitializeEntityValues()
+        {
+            _changing = true;
+            foreach (var field in form.Elements.OfType<DFLayoutField>())
+            {
+                var property = DataModel != null ? field.GetPropertyValue<string>("Property") : null;
+                if (!property.IsNullOrWhiteSpace())
+                {
+                    var fieldControl = GetFieldControl(field);
+                    if(fieldControl != null)
+                    {
+                        fieldControl.SetValue(DataModel!.GetEntityValue(property));
+                    }
+                }
+            }
+            Form.EvaluateExpressions();
+            _changing = false;
+            _isChanged = false;
+        }
+
         /// <summary>
         /// Takes values from editors and saves them to a dictionary; must be called after <see cref="Initialize"/>.
         /// </summary>

+ 4 - 4
inabox.wpf/DynamicGrid/DynamicDataGrid.cs

@@ -285,11 +285,11 @@ public class DynamicDataGrid<TEntity> : DynamicGrid<TEntity>, IDynamicDataGrid w
         return newFilters.Combine();
     }
 
-    public override TEntity[] LoadItems(CoreRow[] rows)
+    public override TEntity[] LoadItems(IList<CoreRow> rows)
     {
         Filter<TEntity>? filter = null;
-        var results = new List<TEntity>();
-        for (var i = 0; i < rows.Length; i += ChunkSize)
+        var results = new List<TEntity>(rows.Count);
+        for (var i = 0; i < rows.Count; i += ChunkSize)
         {
             var chunk = rows.Skip(i).Take(ChunkSize);
             foreach (var row in chunk)
@@ -326,7 +326,7 @@ public class DynamicDataGrid<TEntity> : DynamicGrid<TEntity>, IDynamicDataGrid w
         Client.Save(item, "Edited by User");
     }
 
-    public override void SaveItems(TEntity[] items)
+    public override void SaveItems(IEnumerable<TEntity> items)
     {
         Client.Save(items, "Edited by User");
     }

+ 0 - 8
inabox.wpf/DynamicGrid/DynamicEnclosedListGrid.cs

@@ -139,14 +139,6 @@ namespace InABox.DynamicGrid
             return Items[row.Index];
         }
 
-        public override TMany[] LoadItems(CoreRow[] rows)
-        {
-            var result = new List<TMany>();
-            foreach (var row in rows)
-                result.Add(Items[row.Index]);
-            return result.ToArray();
-        }
-
         public override void SaveItem(TMany item)
         {
             if (!Items.Contains(item))

+ 2 - 1
inabox.wpf/DynamicGrid/DynamicEntityFormGrid.cs

@@ -65,12 +65,13 @@ public class DynamicEntityFormGrid<TForm, TEntity, TEntityLink> : DynamicDataGri
                 {
                     Description = digitalForm.Description
                 };
-                form.Form.ID = digitalForm.ID;
+                form.Form.CopyFrom(digitalForm);
                 form.Parent.ID = Entity.ID;
 
                 var refresh = false;
                 if (EditOnAdd)
                 {
+                    form.FormStarted = DateTime.Now;
                     if (DynamicFormEditWindow.EditDigitalForm(form, out var dataModel))
                     {
                         dataModel.Update(null);

+ 2 - 2
inabox.wpf/DynamicGrid/DynamicGrid.cs

@@ -1392,7 +1392,7 @@ public abstract class DynamicGrid<T> : DynamicGrid, IDynamicGridUIComponentParen
 
     #region Load/Save/Delete
 
-    public virtual T[] LoadItems(CoreRow[] rows)
+    public virtual T[] LoadItems(IList<CoreRow> rows)
     {
         return rows.ToArray(LoadItem);
     }
@@ -1401,7 +1401,7 @@ public abstract class DynamicGrid<T> : DynamicGrid, IDynamicGridUIComponentParen
 
     public abstract void SaveItem(T item);
 
-    public virtual void SaveItems(T[] items)
+    public virtual void SaveItems(IEnumerable<T> items)
     {
         foreach (var item in items)
             SaveItem(item);

+ 0 - 8
inabox.wpf/DynamicGrid/DynamicOneToManyGrid.cs

@@ -288,14 +288,6 @@ public class DynamicOneToManyGrid<TOne, TMany> : DynamicGrid<TMany>,
         return Items[_recordmap[row].Index];
     }
 
-    public override TMany[] LoadItems(CoreRow[] rows)
-    {
-        var result = new List<TMany>();
-        foreach (var row in rows)
-            result.Add(LoadItem(row));
-        return result.ToArray();
-    }
-
     public override void SaveItem(TMany item)
     {
         if (!Items.Contains(item))

+ 1 - 1
inabox.wpf/DynamicGrid/IDynamicGrid.cs

@@ -116,7 +116,7 @@ public interface IDynamicGrid<T> : IDynamicGrid
 
     void SaveItem(T item);
 
-    void SaveItems(T[] items);
+    void SaveItems(IEnumerable<T> items);
 
     void DeleteItems(CoreRow[] rows);
 

+ 0 - 1
inabox.wpf/Reports/ReportManager.xaml.cs

@@ -27,7 +27,6 @@ namespace InABox.Wpf.Reports
         }
 
         public string Section { get; set; }
-        public Dictionary<Type, CoreTable> DataEnvironment { get; set; }
 
         public DataModel? DataModel { get; set; } = null;
 

+ 0 - 383
inabox.wpf/Reports/ReportUtils.cs

@@ -389,388 +389,5 @@ namespace InABox.Wpf.Reports
         {
             PrintMenu(element, sectionName, model, allowdesign, populate);
         }      
-
-        #region Old RDL Stuff (Deprecated)
-
-        // private static ReportDefinition SetupReportDefinition(String rdl, Dictionary<System.Type, CoreTable> dataenvironment = null)
-        // {
-        //     ReportDefinition report = null;
-        //     if (String.IsNullOrWhiteSpace(rdl))
-        //         report = CreateReport();
-        //     else
-        //         report = DeserialiseReport(rdl);
-        //
-        //     if (dataenvironment != null)
-        //         SetupReportData(report, dataenvironment);
-        //     return report;
-        // }
-
-        // public static String SetupReport(String rdl, Dictionary<System.Type, CoreTable> dataenvironment = null)
-        // {
-        //     var defn = SetupReportDefinition(rdl, dataenvironment);
-        //     return SerialiseReport(defn);
-        // }
-        //
-        // public static MemoryStream SetupReportToStream(String rdl, Dictionary<System.Type, CoreTable> dataenvironment = null)
-        // {
-        //     var defn = SetupReportDefinition(rdl, dataenvironment);
-        //     return SerialiseReportToStream(defn);
-        // }
-
-        //       public static String CleanupReport(String rdl)
-        // {
-        // 	ReportDefinition report = null;
-        // 	if (String.IsNullOrWhiteSpace(rdl))
-        // 		report = CreateReport();
-        // 	else
-        // 		report = DeserialiseReport(rdl);
-        //
-        // 	CleanupReportData(report);
-        //
-        // 	return SerialiseReport(report);
-        //
-        // }
-
-// 		private static ReportDefinition CreateReport()
-// 		{
-// 			ReportDefinition rd = new ReportDefinition();
-// 			rd.DataSources = new DataSources();
-// 			rd.DataSets = new DataSets();
-//
-// 			rd.ReportSections = new ReportSections();
-// 			rd.ReportSections.Add(
-// 				new ReportSection()
-// 				{
-// 					Width = new Syncfusion.RDL.DOM.Size("7.5in"),
-// 					Body = new Body()
-// 					{
-// 						Style = new Syncfusion.RDL.DOM.Style() { BackgroundColor = "White", Border = new Syncfusion.RDL.DOM.Border() },
-// 						Height = new Syncfusion.RDL.DOM.Size("10in"),
-//
-// 					},
-// 					Page = new Syncfusion.RDL.DOM.Page()
-// 					{
-// 						PageHeight = new Syncfusion.RDL.DOM.Size("11in"),
-// 						PageWidth = new Syncfusion.RDL.DOM.Size("8.5in"),
-// 						Style = new Syncfusion.RDL.DOM.Style() { BackgroundColor = "White", Border = new Syncfusion.RDL.DOM.Border() },
-// 					}
-// 				}
-// 			);
-// 			rd.EmbeddedImages = new EmbeddedImages();
-//
-// 			rd.RDLType = RDLType.RDL2010;
-// 			rd.CodeModules = new CodeModules();
-// 			rd.CodeModules.Add(new CodeModule() { Value = "System.Drawing, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b03f5f7f11d50a3a" });
-// 			rd.CodeModules.Add(new CodeModule() { Value = "Syncfusion.Pdf.Base, Version = 13.3350.0.7, Culture = neutral, PublicKeyToken = 3d67ed1f87d44c89" });
-// 			rd.CodeModules.Add(new CodeModule() { Value = "Syncfusion.Linq.Base, Version = 13.3350.0.7, Culture = neutral, PublicKeyToken = 3d67ed1f87d44c89" });
-//
-// 			rd.Classes = new Classes();
-// 			rd.Classes.Add(new Class() { ClassName = "Syncfusion.Pdf.Barcode.PDFCode39Barcode", InstanceName = "Code39" });
-// 			rd.Classes.Add(new Class() { ClassName = "Syncfusion.Pdf.Barcode.PdfQRBarcode", InstanceName = "QRCode" });
-//
-// 			rd.Code = @"
-// Public Function Code39BarCode(Text As String) As String
-//  Dim _msg as String
-//  try
-//    Code39.BarHeight = 100
-//    Code39.Text = Text 
-//    Code39.EnableCheckDigit = True
-//    Code39.EncodeStartStopSymbols = True
-//    Code39.ShowCheckDigit = False
-//    Code39.TextDisplayLocation = 0
-//    Dim _img As System.Drawing.Image = Code39.ToImage()
-//    Dim ms As New System.IO.MemoryStream()
-//    _img.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp)
-//    Dim _bytes = ms.ToArray() 
-//     Return System.Convert.ToBase64String(_bytes, 0, _bytes.Length)
-//   Catch ex As Exception
-//    _msg = ex.toString()
-//   End Try
-//    return Nothing
-// End Function
-//
-// Public Function QRBarCode(Text As String) As String
-//  Dim _msg as String
-//  try
-//    QRCode.Text = Text 
-//    QRCode.XDimension = 4
-//    Dim _img As System.Drawing.Image = QRCode.ToImage()
-//    Dim ms As New System.IO.MemoryStream()
-//    _img.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp)
-//    Dim _bytes = ms.ToArray() 
-//     Return System.Convert.ToBase64String(_bytes, 0, _bytes.Length)
-//   Catch ex As Exception
-//    _msg = ex.toString()
-//   End Try
-//    return Nothing
-// End Function
-//
-// ";
-// 			return rd;
-//
-// 			//MemoryStream memoryStream = new MemoryStream();
-// 			//TextWriter ws2 = new StreamWriter(memoryStream);
-// 			//xs2.Serialize(ws2, rd, serialize);
-// 			//memoryStream.Position = 0;
-// 			////To save to a file.
-// 			//StringWriter ws3 = new StringWriter
-// 			//TextWriter ws3 = new StreamWriter(_tempfile);
-// 			//xs2.Serialize(ws3, rd, serialize);
-// 			//ws2.Close();
-// 			//ws3.Close();
-// 			//memoryStream.Close();
-//
-// 		}
-
-        private static string DataTableToXML(Type type, CoreTable table)
-        {
-            var doc = new XmlDocument();
-
-            var root = doc.CreateElement("", type.Name.ToLower() + "s", "");
-            doc.AppendChild(root);
-
-            //var properties = CoreUtils.PropertyList(type, x => true, true);
-            if (table != null)
-            {
-                if (table.Rows.Any())
-                {
-                    foreach (var datarow in table.Rows)
-                    {
-                        var row = doc.CreateElement("", type.Name.ToLower(), "");
-                        foreach (var column in table.Columns)
-                        {
-                            var field = doc.CreateElement("", column.ColumnName.Replace('.', '_'), "");
-                            var oVal = datarow[column.ColumnName];
-                            var value = doc.CreateTextNode(oVal != null ? oVal.ToString() : "");
-                            field.AppendChild(value);
-                            row.AppendChild(field);
-                        }
-
-                        root.AppendChild(row);
-                    }
-                }
-                else
-                {
-                    var row = doc.CreateElement("", type.Name.ToLower(), "");
-                    foreach (var column in table.Columns)
-                    {
-                        var field = doc.CreateElement("", column.ColumnName.Replace('.', '_'), "");
-                        var value = doc.CreateTextNode("");
-                        field.AppendChild(value);
-                        row.AppendChild(field);
-                    }
-
-                    root.AppendChild(row);
-                }
-            }
-
-            var xmlString = "";
-            using (var wr = new StringWriter())
-            {
-                doc.Save(wr);
-                xmlString = wr.ToString();
-            }
-
-            return xmlString.Replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n", "");
-        }
-
-        public static DataSet CreateReportDataSource(Dictionary<Type, CoreTable> dataenvironment)
-        {
-            var ds = new DataSet();
-            foreach (var key in dataenvironment.Keys)
-            {
-                var table = dataenvironment[key];
-                var dt = new DataTable(key.EntityName().Split('.').Last());
-                foreach (var column in table.Columns)
-                    dt.Columns.Add(column.ColumnName);
-                foreach (var row in table.Rows)
-                    dt.Rows.Add(row.Values.ToArray());
-                ds.Tables.Add(dt);
-            }
-
-            return ds;
-        }
-
-        // private static void SetupReportData(ReportDefinition report, Dictionary<System.Type,CoreTable> dataenvironment)
-        // {
-        //
-        //           report.DataSets.Clear();
-        //           report.DataSources.Clear();
-        //           foreach (System.Type type in dataenvironment.Keys)
-        //           {
-        //               String _tempfile = Path.GetTempFileName();
-        //               String xml = DataTableToXML(type, dataenvironment[type]);
-        //               File.WriteAllText(_tempfile, xml);
-        //               // Create DataSource(s)
-        //               DataSource datasource = new DataSource()
-        //               {
-        //                   Name = type.Name,
-        //                   ConnectionProperties = new ConnectionProperties()
-        //                   {
-        //                       DataProvider = "XML",
-        //                       IntegratedSecurity = true,
-        //                       ConnectString = _tempfile
-        //                   },
-        //                   SecurityType = SecurityType.None,
-        //               };
-        //               report.DataSources.Add(datasource);
-        //
-        //               Syncfusion.RDL.DOM.DataSet dataset = new Syncfusion.RDL.DOM.DataSet() { Name = type.Name };
-        //               dataset.Fields = new Fields();
-        //
-        //               CoreTable table = dataenvironment[type];
-        //               foreach (var column in table.Columns)
-        //               {
-        //                   dataset.Fields.Add(
-        //                       new Field()
-        //                       {
-        //                           Name = column.ColumnName.Replace('.', '_'),
-        //                           DataField = column.ColumnName.Replace('.', '_'),
-        //                           TypeName = column.DataType.Name
-        //                       }
-        //                   );
-        //               }
-        //
-        //               //var properties = CoreUtils.PropertyList(type, x => true, true);
-        //
-        //               //// Create DataSet(s)
-        //               //foreach (String key in properties.Keys)
-        //               //{
-        //               //    dataset.Fields.Add(
-        //               //        new Field()
-        //               //        {
-        //               //            Name = key.Replace('.', '_'),
-        //               //            DataField = key.Replace('.', '_'),
-        //               //            TypeName = properties[key].Name
-        //               //        }
-        //               //    );
-        //               //}
-        //               dataset.Query = new Query()
-        //               {
-        //                   DataSourceName = type.Name,
-        //                   CommandType = Syncfusion.RDL.DOM.CommandType.Text,
-        //                   CommandText = String.Format("{0}s/{0}", type.Name.ToLower())
-        //               };
-        //               report.DataSets.Add(dataset);
-        //           }
-        //       }
-        //
-        // private static void CleanupReportData(ReportDefinition report)
-        // {
-        // 	foreach (var ds in report.DataSources)
-        // 	{
-        // 		String _tempfile = ds.ConnectionProperties.ConnectString;
-        // 		if (File.Exists(_tempfile))
-        // 			File.Delete(_tempfile);
-        // 		ds.ConnectionProperties.ConnectString = "";
-        // 	}
-        // 	report.DataSources[0].ConnectionProperties.ConnectString = "";
-        // }
-        //
-        // private static ReportDefinition DeserialiseReport(String rdl)
-        // {
-        //           String data = rdl;
-        //           try
-        //           {
-        //               byte[] debase64 = Convert.FromBase64String(rdl);
-        //               data = Encoding.UTF8.GetString(debase64);
-        //           }
-        //           catch (Exception e)
-        //           {
-        //               Logger.Send(LogType.Error, "", String.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
-        //           }
-        //           ReportDefinition report = null;
-        // 	XmlSerializer xs = new XmlSerializer(typeof(ReportDefinition), "http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition");
-        // 	using (StringReader stringreader = new StringReader(data)) // root.ToString()))
-        // 	{
-        // 		report = (ReportDefinition)xs.Deserialize(stringreader);
-        // 	}
-        // 	return report;
-        // }
-        //
-        //       [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
-        //       private static String SerialiseReport(ReportDefinition report)
-        //       {
-        //           var stream = SerialiseReportToStream(report);
-        //           return Encoding.UTF8.GetString(stream.ToArray());
-        //
-        //       }
-        //
-        //       [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
-        //       private static MemoryStream SerialiseReportToStream(ReportDefinition report)
-        //       {
-        //
-        //           string nameSpace = "http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition";
-        //
-        //           if (report.RDLType == RDLType.RDL2010)
-        //               nameSpace = "http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition";
-        //
-        //           XmlSerializerNamespaces serialize = new XmlSerializerNamespaces();
-        //           serialize.Add("rd", "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner");
-        //           XmlSerializer xs2 = new XmlSerializer(typeof(Syncfusion.RDL.DOM.ReportDefinition), nameSpace);
-        //           MemoryStream memoryStream = new MemoryStream();
-        //           TextWriter ws2 = new StreamWriter(memoryStream);
-        //           xs2.Serialize(ws2, report, serialize);
-        //           memoryStream.Position = 0;
-        //           return memoryStream;
-        //           //return Encoding.UTF8.GetString(memoryStream.ToArray());
-        //
-        //       }
-
-        //    private static byte[] GhostScriptIt(byte[] pdf)
-        //    {
-        //        String input = Path.GetTempFileName();
-        //        File.WriteAllBytes(input, pdf);
-
-        //        byte[] result = new byte[] { };
-
-        //        GhostscriptVersionInfo gv = new GhostscriptVersionInfo(
-        //            new Version(0, 0, 0),
-        //            "gsdll32.dll",
-        //            "",
-        //            GhostscriptLicense.GPL
-        //        );
-
-        //        GhostscriptPipedOutput gsPipedOutput = new GhostscriptPipedOutput();
-
-        //        // pipe handle format: %handle%hexvalue
-        //        string outputPipeHandle = "%handle%" + int.Parse(gsPipedOutput.ClientHandle).ToString("X2");
-        //        using (GhostscriptProcessor processor = new GhostscriptProcessor(gv, true))
-        //        {
-        //            List<string> switches = new List<string>();
-        //            switches.Add("-empty");
-        //            switches.Add("-dQUIET");
-        //            switches.Add("-dSAFER");
-        //            switches.Add("-dBATCH");
-        //            switches.Add("-dNOPAUSE");
-        //            switches.Add("-dNOPROMPT");
-        //            switches.Add("-dCompatibilityLevel=1.4");
-        //            switches.Add("-sDEVICE=pdfwrite");
-        //            switches.Add("-o" + outputPipeHandle);
-        //            switches.Add("-q");
-        //            switches.Add("-f");
-        //            switches.Add(input);
-
-        //            try
-        //            {
-        //                processor.StartProcessing(switches.ToArray(), null);
-        //                result = gsPipedOutput.Data;
-
-        //            }
-        //            catch (Exception ex)
-        //            {
-        //                Console.WriteLine(ex.Message);
-        //            }
-        //            finally
-        //            {
-        //                gsPipedOutput.Dispose();
-        //                gsPipedOutput = null;
-        //            }
-        //        }
-        //        File.Delete(input);
-        //        return result;
-        //    }
-
-        #endregion
     }
 }

+ 13 - 5
inabox.wpf/TemplateGenerator.cs

@@ -1,4 +1,5 @@
-using System;
+using Org.BouncyCastle.Asn1.Mozilla;
+using System;
 using System.Windows;
 using System.Windows.Controls;
 
@@ -30,17 +31,24 @@ namespace InABox.WPF
             if (controlType == null)
                 throw new ArgumentNullException("controlType");
 
-            if (factory == null)
-                throw new ArgumentNullException("factory");
-
             var frameworkElementFactory = new FrameworkElementFactory(typeof(_TemplateGeneratorControl));
             frameworkElementFactory.SetValue(_TemplateGeneratorControl.FactoryProperty, factory);
 
             var controlTemplate = new ControlTemplate(controlType);
-            controlTemplate.VisualTree = frameworkElementFactory;
+            controlTemplate.VisualTree = CreateFactory(factory);
             return controlTemplate;
         }
 
+        public static FrameworkElementFactory CreateFactory(Func<object?> factory)
+        {
+            if (factory == null)
+                throw new ArgumentNullException("factory");
+
+            var frameworkElementFactory = new FrameworkElementFactory(typeof(_TemplateGeneratorControl));
+            frameworkElementFactory.SetValue(_TemplateGeneratorControl.FactoryProperty, factory);
+            return frameworkElementFactory;
+        }
+
         private sealed class _TemplateGeneratorControl :
             ContentControl
         {