private void SaveState(string fileName)
        {
            FileStream stream = null;

            try
            {
                stream = new FileStream(fileName, FileMode.Create, FileAccess.Write);

                using (var writer = new BinaryWriter(stream))
                {
                    stream = null;

                    IEnumerable <ILayoutItem> itemStates = Documents.Concat(Tools.Cast <ILayoutItem>());

                    int itemCount = 0;
                    // reserve some space for items count, it'll be updated later
                    writer.Write(itemCount);

                    foreach (ILayoutItem item in itemStates)
                    {
                        if (!item.ShouldReopenOnStart)
                        {
                            continue;
                        }

                        ExportAttribute exportAttribute =
                            item.GetType()
                            .GetCustomAttributes(typeof(ExportAttribute), false)
                            .Cast <ExportAttribute>()
                            .FirstOrDefault();

                        string typeName = null;

                        if (exportAttribute != null && exportAttribute.ContractType != null)
                        {
                            typeName = exportAttribute.ContractType.AssemblyQualifiedName;
                        }

                        if (string.IsNullOrEmpty(typeName))
                        {
                            continue;
                        }

                        writer.Write(typeName);
                        writer.Write(item.ContentId);

                        // Here's the tricky part. Because some items might fail to save their state, or they might be removed (a plug-in assembly deleted and etc.)
                        // we need to save the item's state size to be able to skip the data during deserialization.
                        // Save surrent stream position. We'll need it later.
                        long stateSizePosition = writer.BaseStream.Position;

                        // Reserve some space for item state size
                        writer.Write(0L);

                        long stateSize;

                        try
                        {
                            long stateStartPosition = writer.BaseStream.Position;
                            item.SaveState(writer);
                            stateSize = writer.BaseStream.Position - stateStartPosition;
                        }
                        catch
                        {
                            stateSize = 0;
                        }

                        // Go back to the position before item's state and write the actual value.
                        writer.BaseStream.Seek(stateSizePosition, SeekOrigin.Begin);
                        writer.Write(stateSize);

                        if (stateSize > 0)
                        {
                            // Got to the end of the stream
                            writer.BaseStream.Seek(0, SeekOrigin.End);
                        }

                        itemCount++;
                    }

                    writer.BaseStream.Seek(0, SeekOrigin.Begin);
                    writer.Write(itemCount);
                    writer.BaseStream.Seek(0, SeekOrigin.End);

                    var shellView = Views.Values.Single() as IShellView;
                    if (shellView != null)
                    {
                        shellView.SaveLayout(writer.BaseStream);
                    }
                }
            }
            catch
            {
                if (stream != null)
                {
                    stream.Close();
                }
            }
        }
示例#2
0
        private void SaveState(string fileName)
        {
            FileStream stream = null;

            try
            {
                stream = new FileStream(fileName, FileMode.Create, FileAccess.Write);

                using (var writer = new BinaryWriter(stream))
                {
                    stream = null;

                    IEnumerable <ILayoutItem> itemStates = Documents.Concat(Tools.Cast <ILayoutItem>());

                    int itemCount = 0;
                    // reserve some space for items count, it'll be updated later
                    writer.Write(itemCount);

                    foreach (var item in itemStates)
                    {
                        if (!item.ShouldReopenOnStart)
                        {
                            continue;
                        }

                        var itemType = item.GetType();
                        List <ExportAttribute> exportAttributes = itemType
                                                                  .GetCustomAttributes(typeof(ExportAttribute), false)
                                                                  .Cast <ExportAttribute>().ToList();

                        var layoutType = typeof(ILayoutItem);
                        // get exports with explicit types or names that inherit from ILayoutItem
                        var exportTypes = (from att in exportAttributes
                                           // select the contract type if it is of type ILayoutitem. else null
                                           let typeFromContract = att.ContractType != null &&
                                                                  layoutType.IsAssignableFrom(att.ContractType) ? att.ContractType : null
                                                                  // select the contract name if it is of type ILayoutItem. else null
                                                                  let typeFromQualifiedName = GetTypeFromContractNameAsILayoutItem(att)
                                                                                              // select the viewmodel tpye if it is of type ILayoutItem. else null
                                                                                              let typeFromViewModel = layoutType.IsAssignableFrom(itemType) ? itemType : null
                                                                                              // att.ContractType overrides att.ContractName if both are set.
                                                                                              // fall back to the ViewModel type of neither are defined.
                                                                                                                      let type = typeFromContract ?? typeFromQualifiedName ?? typeFromViewModel
                                                                                                                                 where type != null
                                                                                                                                 select type).ToList();

                        // throw exceptions here, instead of failing silently. These are design time errors.
                        var firstExport = exportTypes.FirstOrDefault();
                        if (firstExport == null)
                        {
                            throw new InvalidOperationException(string.Format(
                                                                    "A ViewModel that participates in LayoutItem.ShouldReopenOnStart must be decorated with an ExportAttribute who's ContractType that inherits from ILayoutItem, infringing type is {0}.", itemType));
                        }
                        if (exportTypes.Count > 1)
                        {
                            throw new InvalidOperationException(string.Format(
                                                                    "A ViewModel that participates in LayoutItem.ShouldReopenOnStart can't be decorated with more than one ExportAttribute which inherits from ILayoutItem. infringing type is {0}.", itemType));
                        }

                        var selectedTypeName = firstExport.AssemblyQualifiedName;

                        if (string.IsNullOrEmpty(selectedTypeName))
                        {
                            throw new InvalidOperationException(string.Format(
                                                                    "Could not retrieve the assembly qualified type name for {0}, most likely because the type is generic.", firstExport));
                        }
                        // TODO: it is possible to save generic types. It requires that every generic parameter is saved, along with its position in the generic tree... A lot of work.

                        writer.Write(selectedTypeName);
                        writer.Write(item.ContentId);

                        // Here's the tricky part. Because some items might fail to save their state, or they might be removed (a plug-in assembly deleted and etc.)
                        // we need to save the item's state size to be able to skip the data during deserialization.
                        // Save current stream position. We'll need it later.
                        long stateSizePosition = writer.BaseStream.Position;

                        // Reserve some space for item state size
                        writer.Write(0L);

                        long stateSize;

                        try
                        {
                            long stateStartPosition = writer.BaseStream.Position;
                            item.SaveState(writer);
                            stateSize = writer.BaseStream.Position - stateStartPosition;
                        }
                        catch
                        {
                            stateSize = 0;
                        }

                        // Go back to the position before item's state and write the actual value.
                        writer.BaseStream.Seek(stateSizePosition, SeekOrigin.Begin);
                        writer.Write(stateSize);

                        if (stateSize > 0)
                        {
                            // Got to the end of the stream
                            writer.BaseStream.Seek(0, SeekOrigin.End);
                        }

                        itemCount++;
                    }

                    writer.BaseStream.Seek(0, SeekOrigin.Begin);
                    writer.Write(itemCount);
                    writer.BaseStream.Seek(0, SeekOrigin.End);

                    var shellView = Views.Values.Single() as IShellView;
                    if (shellView != null)
                    {
                        shellView.SaveLayout(writer.BaseStream);
                    }
                }
            }
            catch
            {
                if (stream != null)
                {
                    stream.Dispose();
                }
            }
        }