/// <summary> /// Invoked when an unhandled DragDrop.DragEnter attached event reaches an element in its route that is derived from this class. /// </summary> /// <param name="dragEventArgs">The DragEventArgs that contains the event data.</param> protected override void OnDrop(DragEventArgs dragEventArgs) { // Close (and dereference) the window used to display the object being dragged. this.dragWindow.Close(); this.dragWindow = null; // Attempt to find the element currently selected in the page. This item will be the parent of any object dropped onto the surface. AssetNetworkItem parentItem = ExplorerHelper.FindExplorerItem(this.DataContext as AssetNetworkItem, this.Source) as AssetNetworkItem; if (parentItem != null) { // We can import files dropped onto the surface. If the format specifies one or more files dragged from the Windows Explorer, then set call a // handler to import each filed based on the file type (that is, the extension). String[] paths = dragEventArgs.Data.GetData("FileDrop") as String[]; if (paths != null) { foreach (String path in paths) { DocumentProperty externalObject; if (DirectoryPage.documentProperties.TryGetValue(Path.GetExtension(path).ToLower(), out externalObject)) { DirectoryPage.CreateDocument(parentItem, path, externalObject); } } } } }
/// <summary> /// Creates a data model entry for the given path element. /// </summary> /// <param name="parentItem"></param> /// <param name="path">The full file name of the document to be loaded.</param> /// <param name="externalDocument">The properties used to build the document.</param> static void CreateDocument(AssetNetworkItem parentItem, String path, DocumentProperty externalDocument) { // The general idea here is to create the data structure that will be passed to the server to create the documents. Once built, the same data is used // to modify the client side so it will look like the file was imported instantaneously. If the operation to add the document fails, then we will undo // the transaction but most of the time it will just look zippin' quick. This is list of metadata properties used to create the document. List <PropertyStoreInfo> propertyStoreList = new List <PropertyStoreInfo>(); // Each document requires an image so we can display an icon on the directory page. The icon used for the documents is acquired from the type // information (each type is associated with an icon). DataModel.TypeRow typeRow = DataModel.Type.TypeKey.Find(externalDocument.typeId); // IMPORTANT CONCEPT: In order to create the document on the client side, we need to have unique identifiers. These unique identifiers will be passed // to the server when it is time to create the document and all the records that go with it (metadata, entity tree, etc.). If the operation is not // successful, then we roll back this transaction and all these records will go away, but if the operation is successful, then we'll get back the // actual database record which will, by virtue of having the same identifiers created here, update these records with the actual server information // (most importantly, we'll get back a RowVersion and all the other server-side defaults). CreateDocumentInfo createDocumentInfo = new CreateDocumentInfo(); createDocumentInfo.EntityId = Guid.NewGuid(); createDocumentInfo.EntityTreeId = Guid.NewGuid(); createDocumentInfo.Name = Path.GetFileName(path); createDocumentInfo.ParentEntityId = parentItem.EntityId; createDocumentInfo.TypeId = typeRow.TypeId; // If a viewer has been specified for this file type, then create a metadata property for the viewer. if (!String.IsNullOrEmpty(externalDocument.ViewerUri)) { PropertyStoreInfo viewerPropertyInfo = new PropertyStoreInfo(); viewerPropertyInfo.PropertyStoreId = Guid.NewGuid(); viewerPropertyInfo.PropertyId = PropertyId.Viewer; viewerPropertyInfo.Value = Encoding.Unicode.GetBytes(externalDocument.ViewerUri); propertyStoreList.Add(viewerPropertyInfo); } // This will create a metadata property for the data that goes with an item. In this case, the data is the file contents. PropertyStoreInfo dataPropertyInfo = new PropertyStoreInfo(); dataPropertyInfo.PropertyId = PropertyId.Data; dataPropertyInfo.PropertyStoreId = Guid.NewGuid(); using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read)) { MemoryStream memoryStream = new MemoryStream(); DirectoryPage.Copy(fileStream, memoryStream); Byte[] buffer = new Byte[memoryStream.Length]; Array.Copy(memoryStream.GetBuffer(), buffer, memoryStream.Length); dataPropertyInfo.Value = buffer; } propertyStoreList.Add(dataPropertyInfo); // Package the properties up in an array. createDocumentInfo.Properties = propertyStoreList.ToArray(); // At this point, we have enough data to create the document on the server. We could quit now and just send the message off to the server and wait for // the server to update the client with the newly created document. However, this involves a lag time which can be noticable on public systems. To // make it look like the operation was instantaneous, we're going to create the document on the client side. If the server accepts the web service // call, then all this data will be overwritten by the actual server version. If the operation fails, all this data will be rolled back. DataModel.EntityRow entityRow = DataModel.Entity.NewRow() as DataModel.EntityRow; entityRow.EntityId = createDocumentInfo.EntityId; entityRow.CreatedTime = DateTime.Now; entityRow.ImageId = typeRow.ImageId; entityRow.Name = createDocumentInfo.Name; entityRow.ModifiedTime = DateTime.Now; entityRow.RowVersion = 0; entityRow.IsContainer = false; entityRow.TypeId = createDocumentInfo.TypeId; DataModel.Entity.Rows.Add(entityRow); // This will create the client side version of all the properties associated with this document. foreach (PropertyStoreInfo propertyStoreInfo in createDocumentInfo.Properties) { DataModel.PropertyStoreRow viewerPropertyRow = DataModel.PropertyStore.NewRow() as DataModel.PropertyStoreRow; viewerPropertyRow.EntityId = createDocumentInfo.EntityId; viewerPropertyRow.PropertyId = propertyStoreInfo.PropertyId; viewerPropertyRow.PropertyStoreId = propertyStoreInfo.PropertyStoreId; viewerPropertyRow.RowVersion = 0; viewerPropertyRow.Value = propertyStoreInfo.Value; DataModel.PropertyStore.Rows.Add(viewerPropertyRow); } // Finally, we need a relation built between the parent container and this document. DataModel.EntityTreeRow entityTreeRow = DataModel.EntityTree.NewRow() as DataModel.EntityTreeRow; entityTreeRow.ParentId = parentItem.EntityId; entityTreeRow.ChildId = createDocumentInfo.EntityId; entityTreeRow.EntityTreeId = createDocumentInfo.EntityTreeId; entityTreeRow.RowVersion = 0; DataModel.EntityTree.Rows.Add(entityTreeRow); // The object will be added to the common data model from a background thread. ThreadPool.QueueUserWorkItem(DirectoryPage.CreateItemThread, createDocumentInfo); }