internal void ConnectStyleEvent(XamlClrEventNode xamlClrEventNode) { CodeConditionStatement ccsConnector = null; // validate the event handler name per C# grammar for identifiers ValidateEventHandlerName(xamlClrEventNode.EventName, xamlClrEventNode.Value); EnsureStyleConnector(); if (!xamlClrEventNode.IsSameScope) { int connectionId = xamlClrEventNode.ConnectionId; if (SwitchStatementSupported()) { // break any previous case staements as we are starting a new connection scope. if (_ccRoot.StyleConnectorFn.Statements.Count > 1) { CodeSnippetStatement cssBreak = new CodeSnippetStatement(BREAK_STATEMENT); _ccRoot.StyleConnectorFn.Statements.Add(cssBreak); } // case 1: // CodeSnippetStatement cssCase = new CodeSnippetStatement(CASE_STATEMENT + connectionId + COLON); _ccRoot.StyleConnectorFn.Statements.Add(cssCase); } else { // if (connectionId == 1) // ccsConnector = new CodeConditionStatement(); ccsConnector.Condition = new CodeBinaryOperatorExpression(new CodeArgumentReferenceExpression(CONNECTIONID), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(connectionId)); } } else if (!SwitchStatementSupported()) { // if in the same scope then use the if statement that was last generated // at the start of the scope Debug.Assert(_ccRoot.StyleConnectorFn.Statements.Count > 0); ccsConnector = _ccRoot.StyleConnectorFn.Statements[_ccRoot.StyleConnectorFn.Statements.Count - 1] as CodeConditionStatement; Debug.Assert(ccsConnector != null); } CodeArgumentReferenceExpression careTarget = new CodeArgumentReferenceExpression(TARGET); if (xamlClrEventNode.IsStyleSetterEvent) { // EventSetter declaration only once to avoid warning! if (!_hasEmittedEventSetterDeclaration) { _hasEmittedEventSetterDeclaration = true; // EventSetter eventSetter; // CodeVariableDeclarationStatement cvdsES = new CodeVariableDeclarationStatement(KnownTypes.Types[(int)KnownElements.EventSetter], EVENTSETTER); _ccRoot.StyleConnectorFn.Statements.Insert(0, cvdsES); } // eventSetter = new EventSetter(); // CodeExpression[] esParams = {}; CodeVariableReferenceExpression cvreES = new CodeVariableReferenceExpression(EVENTSETTER); CodeAssignStatement casES = new CodeAssignStatement(cvreES, new CodeObjectCreateExpression(KnownTypes.Types[(int)KnownElements.EventSetter], esParams)); // eventSetter.Event = Button.ClickEvent; // CodePropertyReferenceExpression cpreEvent = new CodePropertyReferenceExpression(cvreES, EVENT); CodeAssignStatement casEvent = new CodeAssignStatement(cpreEvent, GetEvent(xamlClrEventNode.EventMember, xamlClrEventNode.EventName, xamlClrEventNode.Value)); // eventSetter.Handler = new RoutedEventHandler(OnClick); // CodePropertyReferenceExpression cpreHandler = new CodePropertyReferenceExpression(cvreES, HANDLER); CodeAssignStatement casHandler = new CodeAssignStatement(cpreHandler, GetEventDelegate(null, xamlClrEventNode.EventMember, xamlClrEventNode.EventName, xamlClrEventNode.Value)); AddLinePragma(casHandler, xamlClrEventNode.LineNumber); // ((Style)target).Setters.Add(eventSetter); // CodeCastExpression cceTarget = new CodeCastExpression(KnownTypes.Types[(int)KnownElements.Style], careTarget); CodePropertyReferenceExpression cpreSetters = new CodePropertyReferenceExpression(cceTarget, SETTERS); CodeMethodInvokeExpression cmieAdd = new CodeMethodInvokeExpression(cpreSetters, ADD, cvreES); if (SwitchStatementSupported()) { _ccRoot.StyleConnectorFn.Statements.Add(casES); _ccRoot.StyleConnectorFn.Statements.Add(casEvent); _ccRoot.StyleConnectorFn.Statements.Add(casHandler); _ccRoot.StyleConnectorFn.Statements.Add(new CodeExpressionStatement(cmieAdd)); } else { ccsConnector.TrueStatements.Add(casES); ccsConnector.TrueStatements.Add(casEvent); ccsConnector.TrueStatements.Add(casHandler); ccsConnector.TrueStatements.Add(new CodeExpressionStatement(cmieAdd)); // Only add if statement at start of new scope if (!xamlClrEventNode.IsSameScope) { _ccRoot.StyleConnectorFn.Statements.Add(ccsConnector); } } } else { // // ((Foo)target).Bar += new BarEventHandler(OnBar); // // *or* // // ((Foo)target).AddHandler( Baz.BarEvent, new BarEventHandler(OnBar)); // CodeCastExpression cceTarget; Type eventTarget; // Create the markup event information MarkupEventInfo mei = new MarkupEventInfo( xamlClrEventNode.Value, // Event handler string xamlClrEventNode.EventName, // Event name string xamlClrEventNode.EventMember, // MemberInfo xamlClrEventNode.LineNumber); // LineNumber // Get the type that defines the event (e.g. typeof(Button) for Button.Clicked or typeof(Mouse) for Mouse.MouseMove) eventTarget = xamlClrEventNode.ListenerType; // Create the type cast expression "(Foo)target" cceTarget = new CodeCastExpression( eventTarget, careTarget); // Create the whole code statement (either in += form or in AddHandler form) CodeStatement csAddCLREvent = AddCLREvent( eventTarget, null, cceTarget, mei ); if (SwitchStatementSupported()) { _ccRoot.StyleConnectorFn.Statements.Add( csAddCLREvent ); } else { ccsConnector.TrueStatements.Add( csAddCLREvent ); // Only add if statement at start of new scope if (!xamlClrEventNode.IsSameScope) { _ccRoot.StyleConnectorFn.Statements.Add(ccsConnector); } } } }
internal void AddApplicationEvent(MarkupEventInfo mei) { // validate the event handler name per C# grammar for identifiers ValidateEventHandlerName(mei.eventName, mei.eventHandler); // this.FooEvent += new FooEventHandlerDelegate(this.OnFoo); CodeThisReferenceExpression ctre = new CodeThisReferenceExpression(); CodeStatement csEvent = AddCLREvent(_ccRoot, ctre, mei); Debug.Assert(_ccRoot == (_codeContexts.Peek() as CodeContextRoot)); _ccRoot.EnsureInitializeComponentFn.Statements.Add(csEvent); }
private CodeStatement AddCLREvent(Type eventTarget, CodeContext cc, CodeExpression ce, MarkupEventInfo mei) { bool subClassed = _ccRoot.SubClass.Length > 0; CodeStatement csEvent = null; // param2: <FooEventHandler> CodeExpression cDelExp = GetEventDelegate(cc, mei.mi, mei.eventName, mei.eventHandler); if (mei.mi.DeclaringType.IsAssignableFrom(eventTarget)) { // _element.FooEvent += new FooEventHandlerDelegate(OnFoo); csEvent = new CodeAttachEventStatement(ce, mei.eventName, cDelExp); } else if (eventTarget == null || // for known attached events on unknown local tags KnownTypes.Types[(int)KnownElements.UIElement].IsAssignableFrom(eventTarget) || KnownTypes.Types[(int)KnownElements.ContentElement].IsAssignableFrom(eventTarget)) { // _element.AddHandler(FooEvent, new FooEventHandlerDelegate(OnFoo)); CodeFieldReferenceExpression cfreEvent = GetEvent(mei.mi, mei.eventName, mei.eventHandler); CodeMethodInvokeExpression cmieAddHandler = new CodeMethodInvokeExpression(ce, ADDHANDLER, cfreEvent, cDelExp); csEvent = new CodeExpressionStatement(cmieAddHandler); } else { string eventTargetName = eventTarget != null ? eventTarget.FullName : cc.LocalElementFullName; ThrowCompilerException(SRID.UnknownEventAttribute, mei.eventName, mei.eventHandler, eventTargetName); } // When x:SubClass is used, event handlers can be specified in a code-behind file, under this sub class. // But these handler methods need to be accessible from the intermediary generated sub class. So an empty // internal virtual method with the same signature as the handler method is generated in this intermediary // sub class (in the generated file): // // internal virtual void OnFooEvent(object sender, FooEventArgs ea) // { // } // // Since a delegate cannot take the address of a virtual function, a non-virtual helper function // with the same signature as the above function & which calls the above function is also generated: // // private void OnFooEventHelper(object sender, FooEventArgs ea) // { // OnFooEvent(sender, ea); // } // // All this is done only if x:Subclass is specified, since this means that this sub class would need to be // defined in a code-behind file. This also means that inline events (in <x:Code>) will not be supported. if (subClassed) { GenerateProtectedEventHandlerMethod(mei); } AddLinePragma(csEvent, mei.lineNumber); return csEvent; }
private void GenerateProtectedEventHandlerMethod(MarkupEventInfo mei) { Debug.Assert(_ccRoot != null && _ccRoot.SubClass.Length > 0); // Fetch the EventHandlerType from either the EventInfo or the MethodInfo // for the Add{Propertyname}Handler method's MethodInfo Type eventHandlerType = GetEventHandlerType(mei.mi); MethodInfo methodInvoke = eventHandlerType.GetMethod("Invoke"); ParameterInfo[] pars = methodInvoke.GetParameters(); CodeMemberMethod cmmEventHandler = new CodeMemberMethod(); CodeMemberMethod cmmEventHandlerHelper = new CodeMemberMethod(); AddDebuggerNonUserCodeAttribute(cmmEventHandlerHelper); AddGeneratedCodeAttribute(cmmEventHandlerHelper); cmmEventHandler.Attributes = MemberAttributes.Assembly | MemberAttributes.Overloaded; cmmEventHandler.ReturnType = new CodeTypeReference(typeof(void)); cmmEventHandler.Name = mei.eventHandler.Trim(); CodeMethodInvokeExpression cmieOnEvent = new CodeMethodInvokeExpression(null, cmmEventHandler.Name); for (int i = 0; i < pars.Length; i++) { CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(pars[i].ParameterType, pars[i].Name); cmmEventHandler.Parameters.Add(param); cmmEventHandlerHelper.Parameters.Add(param); cmieOnEvent.Parameters.Add(new CodeArgumentReferenceExpression(pars[i].Name)); } // // internal virtual void OnFooEvent(object sender, FooEventArgs ea) // { // } // _ccRoot.CodeClass.Members.Add(cmmEventHandler); cmmEventHandlerHelper.Name = cmmEventHandler.Name + HELPER; cmmEventHandlerHelper.ReturnType = new CodeTypeReference(typeof(void)); cmmEventHandlerHelper.Statements.Add(new CodeExpressionStatement(cmieOnEvent)); // // private void OnFooEventHelper(object sender, FooEventArgs ea) // { // OnFooEvent(sender, ea); // } // _ccRoot.CodeClass.Members.Add(cmmEventHandlerHelper); }
private CodeStatement AddCLREvent(CodeContext cc, CodeExpression ce, MarkupEventInfo mei) { // Infer the event target's (aka the listener) type from the current code context return AddCLREvent( cc.ElementType, cc, ce, mei ); }