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. }
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);" ); }