示例#1
0
        /// <summary>
        /// Checks that the content page does not contain invalid content.
        /// </summary>
        private List <Content> GetChildPageContents(DotvvmView childPage, List <ContentPlaceHolder> parentPlaceHolders)
        {
            // make sure that the body contains only whitespace and Content controls
            var nonContentElements =
                childPage.Children.Where(c => !((c is RawLiteral && ((RawLiteral)c).IsWhitespace) || (c is Content)));

            if (nonContentElements.Any())
            {
                // show all error lines
                var innerExceptions = nonContentElements.Select(s =>
                                                                new Exception($"Error occurred near line: {(s.GetValue(Internal.MarkupLineNumberProperty)?.ToString() ?? "")}.")).ToList(); // the message cannot be specifically to the line, because MarkupLineNumber shows the last character position which is a line under the error in some cases.

                var corruptedFile = childPage.GetValue(Internal.MarkupFileNameProperty)?.ToString();
                throw new AggregateException("If the page contains @masterpage directive, it can only contain white space and <dot:Content /> controls! \r\n"
                                             + (string.IsNullOrWhiteSpace(corruptedFile) ? "" : $"Corrupted file name: {corruptedFile}"), innerExceptions);
            }

            // make sure that the Content controls are not nested in other elements
            var contents = childPage.GetAllDescendants().OfType <Content>()
                           .Where(c => !(bool)c.GetValue(Internal.IsMasterPageCompositionFinishedProperty))
                           .ToList();

            if (contents.Any(c => c.Parent != childPage))
            {
                throw new Exception("The control <dot:Content /> cannot be placed inside any control!");    // TODO: exception handling
            }

            return(contents);
        }
        /// <summary>
        /// Performs the master page nesting.
        /// </summary>
        private void PerformMasterPageComposition(DotvvmView childPage, DotvvmView masterPage)
        {
            if (!masterPage.ViewModelType.IsAssignableFrom(childPage.ViewModelType))
            {
                throw new DotvvmControlException(childPage, $"Master page requires viewModel of type '{masterPage.ViewModelType}' and it is not assignable from '{childPage.ViewModelType}'.");
            }

            // find content place holders
            var placeHolders = GetMasterPageContentPlaceHolders(masterPage);

            // find contents
            var contents = GetChildPageContents(childPage, placeHolders);

            // perform the composition
            foreach (var content in contents)
            {
                // find the corresponding placeholder
                var placeHolder = placeHolders.SingleOrDefault(p => p.ID == content.ContentPlaceHolderID);
                if (placeHolder == null)
                {
                    throw new DotvvmControlException(content, $"The placeholder with ID '{content.ContentPlaceHolderID}' was not found in the master page '{masterPage.GetValue(Internal.MarkupFileNameProperty)}'!");
                }

                // replace the contents
                var contentPlaceHolder = new PlaceHolder();
                contentPlaceHolder.SetDataContextType(content.Parent.GetDataContextType());
                (content.Parent as DotvvmControl)?.Children.Remove(content);

                placeHolder.Children.Clear();
                placeHolder.Children.Add(contentPlaceHolder);

                contentPlaceHolder.Children.Add(content);
                content.SetValue(Internal.IsMasterPageCompositionFinishedProperty, true);
                content.SetValue(DotvvmView.DirectivesProperty, childPage.Directives);
                content.SetValue(Internal.MarkupFileNameProperty, childPage.GetValue(Internal.MarkupFileNameProperty));
            }

            // copy the directives from content page to the master page (except the @masterpage)
            masterPage.ViewModelType = childPage.ViewModelType;
        }