File: cdf\src\NetFx40\Tools\System.Activities.Presentation\System\Activities\Presentation\View\WorkflowViewService.cs
Project: ndp\System.Data.csproj (System.Data)
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//----------------------------------------------------------------
 
namespace System.Activities.Presentation.View
{
    using System.Activities.Presentation;
    using System.Activities.Presentation.Internal.PropertyEditing;
    using System.Activities.Presentation.Model;
    using System.Activities.Presentation.Services;
    using System.Activities.XamlIntegration;
    using System.ComponentModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Runtime;
    using System.ServiceModel.Activities;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Collections.Generic;
 
    [Fx.Tag.XamlVisible(false)]
    public class WorkflowViewService : ViewService
    {
        EditingContext context;
 
        public WorkflowViewService(EditingContext context)
        {
            Fx.Assert(context != null, "The passed in EditingContext is null");
            this.context = context;
        }
        public event EventHandler<ViewCreatedEventArgs> ViewCreated;
 
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "Catch all exceptions to prevent crash and always return the error view of the designer with the error message")]
        [SuppressMessage("Reliability", "Reliability108:IsFatalRule",
            Justification = "Catch all exceptions to prevent crash and always return the error view of the designer with the error message")]
        public WorkflowViewElement GetViewElement(ModelItem modelItem)
        {
            WorkflowViewElement viewElement = null;
            string errorString = string.Empty;
            if (modelItem == null)
            {
                return null;
            }
 
            try
            {
                // try to make one from the type specified in Designer attribute.
                // reuse existing views that are not currently parented
                if (modelItem.View != null && ((WorkflowViewElement)modelItem.View).Parent == null)
                {
                    viewElement = (WorkflowViewElement)modelItem.View;
                }
                else
                {
                    viewElement = CreateViewElement(modelItem);
                }
 
                // now we successfully got a viewElement, lets initialize it with ModelItem;
                if (viewElement != null)
                {
                    viewElement.Context = this.context;
                    viewElement.ModelItem = modelItem;
                    ((IModelTreeItem)modelItem).SetCurrentView(viewElement);
                    viewElement.DataContext = viewElement;
 
                    // Generate an event that we created a new view element.  This could be used by 
                    // the Debugger Service to insert a breakpoint on the view element.
                    if (this.ViewCreated != null)
                    {
                        this.ViewCreated(this, new ViewCreatedEventArgs(viewElement));
                    }
                }
            }
            // never crash here
            // always report error to the customer.
            catch (Exception e)
            {
                errorString = e.ToString();
            }
            if (viewElement == null || !(string.IsNullOrEmpty(errorString)))
            {
                viewElement = GenerateErrorElement(modelItem, errorString);
            }
            return viewElement;
        }
 
        internal static void ShowErrorInViewElement(WorkflowViewElement errorElement, string windowText, string toolTipText)
        {
            Grid errorGrid = new Grid();
            errorGrid.Background = Brushes.Red;
            errorGrid.Margin = new Thickness(20.0);
            TextBlock text = new TextBlock();
            text.Text = windowText;
            text.Foreground = SystemColors.WindowBrush;
            errorGrid.Children.Add(text);
            errorGrid.ToolTip = toolTipText;
            errorElement.Content = errorGrid;
        }
 
        private WorkflowViewElement GenerateErrorElement(ModelItem modelItem, string errorString)
        {
            WorkflowViewElement errorElement = new WorkflowViewElement();
            string errorText = string.Format(CultureInfo.CurrentCulture, SR.CouldNotGenerateView, modelItem.ItemType.Name);
            ShowErrorInViewElement(errorElement, errorText, errorString);
            errorElement.Context = this.context;
            errorElement.ModelItem = modelItem;
            ((IModelTreeItem)modelItem).SetCurrentView(errorElement);
            errorElement.DataContext = errorElement;
            return errorElement;
        }
 
        DesignerAttribute GetDesignerAttribute(Type type)
        {
            DesignerAttribute designerAttribute = null;
            //do not return designers for IValueSerializableExpression (i.e. VisualBasicValue or VisualBasicReference
            if (!typeof(IValueSerializableExpression).IsAssignableFrom(type))
            {
                designerAttribute = GetAttribute<DesignerAttribute>(type);
            }
            return designerAttribute;
        }
 
        internal static T GetAttribute<T>(Type type) where T : Attribute
        {
            T attribute = ExtensibilityAccessor.GetAttribute<T>(type);
            if (attribute == null && type.IsGenericType)
            {
                attribute = ExtensibilityAccessor.GetAttribute<T>(type.GetGenericTypeDefinition());
            }
            return attribute;
        }
 
        //Returns the designer type based on the DesignerAttribute associated with the passed in type.
        internal Type GetDesignerType(Type type)
        {
            return GetDesignerType(type, false);
        }
 
        internal Type GetDesignerType(Type type, bool throwOnFailure)
        {
            Type designerType = null;
            // Try to identify a designer using the DesignerAttribute, either on the type or from MetaDataStore
            DesignerAttribute designerAttribute = GetDesignerAttribute(type);
            if (designerAttribute != null && !String.IsNullOrEmpty(designerAttribute.DesignerTypeName))
            {
                designerType = Type.GetType(designerAttribute.DesignerTypeName, throwOnFailure);
 
                //if we have generic activity, check if there is a designer defined at type definition i.e. Assign<T>,
                //rather then using a default one (which happens to be ActivityDesigner)
                if (type.IsGenericType && Type.Equals(designerType, typeof(ActivityDesigner)))
                {
                    Type genericType = type.GetGenericTypeDefinition();
                    DesignerAttribute genericDesignerAttribute =
                        TypeDescriptor.GetAttributes(genericType)[typeof(DesignerAttribute)] as DesignerAttribute;
                    designerType =
                        (null == genericDesignerAttribute ?
                        designerType : Type.GetType(genericDesignerAttribute.DesignerTypeName, throwOnFailure));
                }
            }
            return designerType;
        }
 
        protected WorkflowViewElement CreateViewElement(ModelItem modelItem)
        {
            Fx.Assert(modelItem != null, "The passed in ModelItem is null");
            WorkflowViewElement viewElement = null;
 
            Type designerType = GetDesignerType(modelItem.ItemType, true);
 
            if (designerType != null && typeof(WorkflowViewElement).IsAssignableFrom(designerType))
            {
                viewElement = (WorkflowViewElement)Activator.CreateInstance(designerType);
            }
            return viewElement;
        }
 
        internal WorkflowViewElement CreateDetachedViewElement(ModelItem modelItem)
        {
            WorkflowViewElement viewElement = CreateViewElement(modelItem);
 
            // now we successfully got a viewElement, lets initialize it with ModelItem;
            if (viewElement != null)
            {
                viewElement.Context = this.context;
                viewElement.ModelItem = modelItem;
                viewElement.DataContext = viewElement;
            }
 
            return viewElement;
        }
 
        public override ModelItem GetModel(DependencyObject view)
        {
            if (view == null)
            {
                throw FxTrace.Exception.AsError(new ArgumentNullException("view"));
            }
 
            if (view is WorkflowViewElement)
            {
                return ((WorkflowViewElement)view).ModelItem;
            }
 
            Fx.Assert("we should know if somebody is trying to get model item from thing other than WorkflowViewElement");
            return null;
        }
 
        public override DependencyObject GetView(ModelItem model)
        {
            return GetViewElement(model);
        }
 
        internal bool ShouldAppearOnBreadCrumb(ModelItem modelItem, bool checkIfCanBeMadeRoot)
        {
            bool shouldAppearOnBreadCrumb = false;
            if (modelItem != null)
            {
                Type designerType = this.GetDesignerType(modelItem.ItemType);
                if (null != designerType)
                {
                    if (checkIfCanBeMadeRoot)
                    {
                        ActivityDesignerOptionsAttribute options = WorkflowViewService.GetAttribute<ActivityDesignerOptionsAttribute>(modelItem.ItemType);
                        shouldAppearOnBreadCrumb = (typeof(WorkflowViewElement).IsAssignableFrom(designerType) &&
                                                   (typeof(ActivityDesigner) != designerType || ActivityDelegateUtilities.HasActivityDelegate(modelItem.ItemType)) &&
                                                   typeof(WorkflowService) != designerType &&
                                                   (options == null || options.AllowDrillIn));
                    }
                    else
                    {
                        shouldAppearOnBreadCrumb = typeof(WorkflowViewElement).IsAssignableFrom(designerType);
                    }
                }
            }
            return shouldAppearOnBreadCrumb;
 
        }   
    }
}