Exemple #1
0
        private void buttonOk_Click(object sender, EventArgs e)
        {
            Details = new GenerationDetails()
            {
                TileWidth  = (int)numericTileWidth.Value,
                TileHeight = (int)numericTileHeight.Value
            };

            Close();
        }
        /// <summary>
        /// buttonOkay_Click(object, EventArgs)
        /// Handler for when the 'OK' button is clicked in the GenerateFramesDialog;
        /// Creates instance of generationDetails, getting values from the NumericUpDown boxes.
        /// Closes then dialog.
        /// <param name="sender">(object) - The object signaling the event.</param>
        /// <param name="e">(EventArgs) - The type of event being sent.</param>
        private void buttonOkay_Click(object sender, EventArgs e)
        {
            // Create new generationDetails object from data returned form NumericUpDown boxes
            generationDetails = new GenerationDetails()
            {
                TileWidth  = (int)numericTileWidth.Value,
                TileHeight = (int)numericTileHeight.Value
            };

            Close(); // Close the dialog.
        }
Exemple #3
0
        private void ApppendSource(GeneratorExecutionContext context, StringBuilder sourceBuilder, GenerationDetails generateThis)
        {
            string propertyName  = generateThis.MethodNameNode.Identifier.ValueText;
            string dpMemberName  = propertyName + "Property";
            string dpkMemberName = propertyName + "PropertyKey";

            Accessibility dpAccess  = generateThis.FieldSymbol.DeclaredAccessibility;
            Accessibility dpkAccess = generateThis.FieldSymbol.DeclaredAccessibility;

            // If this is a DependencyPropertyKey, then we may need to create the corresponding DependencyProperty field.
            // We do this because it's proper to always have a DependencyProperty field & because the DependencyProperty
            // field is required when using TemplateBindings in XAML.
            if (generateThis.IsDpk)
            {
                ISymbol?dpMemberSymbol = generateThis.FieldSymbol.ContainingType.GetMembers(dpMemberName).FirstOrDefault();
                if (dpMemberSymbol != null)
                {
                    dpAccess = dpMemberSymbol.DeclaredAccessibility;
                }
                else
                {
                    dpAccess = Accessibility.Public;

                    // Something like...
                    //	public static readonly DependencyProperty FooProperty = FooPropertyKey.DependencyProperty;
                    sourceBuilder.Append($@"
		public static readonly DependencyProperty {dpMemberName} = {dpkMemberName}.DependencyProperty;"        );
                }
            }

            // Try to get the generic type argument (if it exists, this will be the type of the property).
            GeneratorOps.TryGetGenericTypeArgument(context, generateThis.MethodNameNode, out ITypeSymbol? genTypeArg);

            // We support 0, 1, or 2 arguments. Check for default value and/or flags arguments.
            //	(A) Gen.Foo<T>()
            //	(B) Gen.Foo(defaultValue)
            //	(C) Gen.Foo<T>(flags)
            //	(D) Gen.Foo(defaultValue, flags)
            // The first argument is either the default value or the flags.
            // Note: We do not support properties whose default value is `FrameworkPropertyMetadataOptions` because
            // it's a niche case that would add code complexity.
            ArgumentSyntax?defaultValueArgNode = null;
            ITypeSymbol?   typeOfFirstArg      = null;
            bool           hasFlags            = false;

            if (GeneratorOps.TryGetAncestor(generateThis.MethodNameNode, out InvocationExpressionSyntax? invocationExpressionNode))
            {
                var args = invocationExpressionNode.ArgumentList.Arguments;
                if (args.Count > 0)
                {
                    // If the first argument is the flags, then we generate (C); otherwise, we generate (B) or (D).
                    typeOfFirstArg = GetArgumentType(context, args[0]) ?? this.objTypeSymbol;
                    if (typeOfFirstArg.Equals(this.flagsTypeSymbol, SymbolEqualityComparer.Default))
                    {
                        hasFlags = true;
                    }
                    else
                    {
                        defaultValueArgNode = args[0];
                        hasFlags            = args.Count > 1;
                    }
                }
            }

            bool hasDefaultValue = defaultValueArgNode != null;

            // Determine the type of the property.
            // If there is a generic type argument, then use that; otherwise, use the type of the default value argument.
            // As a safety precaution - ensure that the generated code is always valid by defaulting to use `object`.
            // But really, if we were unable to get the type, that means the user's code doesn't compile anyhow.
            generateThis.PropertyType =
                genTypeArg
                ?? (hasDefaultValue ? typeOfFirstArg : null)
                ?? this.objTypeSymbol;

            generateThis.PropertyTypeName = generateThis.PropertyType.ToDisplayString();

            string genClassDecl;
            string?moreDox = null;

            if (generateThis.IsAttached)
            {
                string targetTypeName = "DependencyObject";

                if (generateThis.MethodNameNode.Parent is MemberAccessExpressionSyntax memberAccessExpr &&
                    memberAccessExpr.Expression is GenericNameSyntax genClassNameNode)
                {
                    genClassDecl = "GenAttached<__TTarget> where __TTarget : DependencyObject";

                    if (GeneratorOps.TryGetGenericTypeArgument(context, genClassNameNode, out ITypeSymbol? attachmentNarrowingType))
                    {
                        generateThis.AttachmentNarrowingType = attachmentNarrowingType;
                        targetTypeName = attachmentNarrowingType.ToDisplayString();
                        moreDox        = $@"<br/>This attached property is only for use with objects of type <typeparamref name=""__TTarget""/>.";
                    }
                }
                else
                {
                    genClassDecl = "GenAttached";
                }

                // Write the static get/set methods source code.
                string getterAccess = dpAccess.ToString().ToLower();
                string setterAccess = generateThis.IsDpk ? dpkAccess.ToString().ToLower() : getterAccess;
                string setterArg0   = generateThis.IsDpk ? dpkMemberName : dpMemberName;

                // Something like...
                //	public static int GetFoo(DependencyObject d) => (int)d.GetValue(FooProperty);
                //	private static void SetFoo(DependencyObject d, int value) => d.SetValue(FooPropertyKey);
                sourceBuilder.Append($@"
		{getterAccess} static {generateThis.PropertyTypeName} Get{propertyName}({targetTypeName} d) => ({generateThis.PropertyTypeName})d.GetValue({dpMemberName});
		{setterAccess} static void Set{propertyName}({targetTypeName} d, {generateThis.PropertyTypeName} value) => d.SetValue({setterArg0}, value);"        );
            }
        private void ApppendSource(GeneratorExecutionContext context, StringBuilder sourceBuilder, GenerationDetails generateThis)
        {
            string eventName             = generateThis.MethodNameNode.Identifier.ValueText;
            string routedEventMemberName = generateThis.FieldSymbol.Name;

            string eventHandlerTypeDoxString = $@"<see cref=""{this.rehTypeSymbol.ToDisplayString()}""/>";

            // Try to get the generic type argument (if it exists, this will be the type of the event handler).
            if (GeneratorOps.TryGetGenericTypeArgument(context, generateThis.MethodNameNode, out ITypeSymbol? genTypeArg))
            {
                // If the type is a multicast delegate, then use it;
                // otherwise, use the type in a `RoutedPropertyChangedEventHandler<>`.
                if (genTypeArg.BaseType?.Equals(this.mdTypeSymbol, SymbolEqualityComparer.Default) ?? false)
                {
                    // Good to go! Documentation can reference the generic type parameter.
                    eventHandlerTypeDoxString = @"<typeparamref name=""__T""/>";
                }
                else
                {
                    // Example: Transform `double` into `RoutedPropertyChangedEventHandler<double>`.
                    genTypeArg = this.rpcehTypeSymbol.Construct(genTypeArg);

                    // Documentation will appear as something like...
                    //	RoutedPropertyChangedEventHandler<T> of double
                    string rpcehT = GeneratorOps.ReplaceBrackets(this.rpcehTypeSymbol.ToDisplayString());
                    eventHandlerTypeDoxString = $@"<see cref=""{rpcehT}""/> of <typeparamref name=""__T""/>";
                }
            }

            // Determine the type of the handler.
            // If there is a generic type argument, then use that; otherwise, use `RoutedEventHandler`.
            generateThis.EventHandlerType     = genTypeArg ?? this.rehTypeSymbol;
            generateThis.EventHandlerTypeName = generateThis.EventHandlerType.ToDisplayString();

            string genClassDecl;
            string?moreDox = null;

            if (generateThis.IsAttached)
            {
                string targetTypeName   = "DependencyObject";
                string callerExpression = "(d as UIElement)?";

                if (generateThis.MethodNameNode.Parent is MemberAccessExpressionSyntax memberAccessExpr &&
                    memberAccessExpr.Expression is GenericNameSyntax genClassNameNode)
                {
                    genClassDecl = "GenAttached<__TTarget> where __TTarget : DependencyObject";

                    if (GeneratorOps.TryGetGenericTypeArgument(context, genClassNameNode, out ITypeSymbol? attachmentNarrowingType))
                    {
                        generateThis.AttachmentNarrowingType = attachmentNarrowingType;
                        targetTypeName   = attachmentNarrowingType.ToDisplayString();
                        callerExpression = "d";
                        moreDox          = $@"<br/>This attached event is only for use with objects of type <typeparamref name=""__TTarget""/>.";
                    }
                }
                else
                {
                    genClassDecl = "GenAttached";
                }

                // Write the static get/set methods source code.
                string methodsAccess = generateThis.FieldSymbol.DeclaredAccessibility.ToString().ToLower();

                // Something like...
                //	public static void AddFooChangedHandler(DependencyObject d, RoutedPropertyChangedEventHandler<int> handler) => (d as UIElement)?.AddHandler(FooChangedEvent, handler);
                //	public static void RemoveFooChangedHandler(DependencyObject d, RoutedPropertyChangedEventHandler<int> handler) => (d as UIElement)?.RemoveHandler(FooChangedEvent, handler);
                sourceBuilder.Append($@"
		{methodsAccess} static void Add{eventName}Handler({targetTypeName} d, {generateThis.EventHandlerTypeName} handler) => {callerExpression}.AddHandler({routedEventMemberName}, handler);
		{methodsAccess} static void Remove{eventName}Handler({targetTypeName} d, {generateThis.EventHandlerTypeName} handler) => {callerExpression}.RemoveHandler({routedEventMemberName}, handler);"        );
            }