diff --git a/MAU.Net/Attributes/MauContainer.cs b/MAU.Net/Attributes/MauContainer.cs index 5a4624e..5401ed9 100644 --- a/MAU.Net/Attributes/MauContainer.cs +++ b/MAU.Net/Attributes/MauContainer.cs @@ -3,8 +3,8 @@ namespace MAU.Attributes { [AttributeUsage(AttributeTargets.Class)] - public sealed class MauContainer : Attribute + public sealed class MauContainerAttribute : Attribute { - public static bool HasAttribute(Type type) => Attribute.IsDefined(type, typeof(MauContainer)); + public static bool HasAttribute(Type type) => Attribute.IsDefined(type, typeof(MauContainerAttribute)); } } diff --git a/MAU.Net/Attributes/MauEnumMember.cs b/MAU.Net/Attributes/MauEnumMember.cs index f9a030e..08a6516 100644 --- a/MAU.Net/Attributes/MauEnumMember.cs +++ b/MAU.Net/Attributes/MauEnumMember.cs @@ -5,7 +5,7 @@ namespace MAU.Attributes { [AttributeUsage(AttributeTargets.Field)] - public sealed class MauEnumMember : Attribute + public sealed class MauEnumMemberAttribute : Attribute { public enum EnumParser { @@ -17,24 +17,24 @@ public enum EnumParser public long ValueAsNum { get; } public EnumParser Parser { get; } - public MauEnumMember(string value) + public MauEnumMemberAttribute(string value) { ValueAsStr = value; Parser = EnumParser.String; } - public MauEnumMember(long value) + public MauEnumMemberAttribute(long value) { ValueAsNum = value; Parser = EnumParser.Number; } - public static bool HasAttribute(PropertyInfo pi) => Attribute.IsDefined(pi, typeof(MauEnumMember)); - public static bool HasAttribute(FieldInfo fi) => Attribute.IsDefined(fi, typeof(MauEnumMember)); + public static bool HasAttribute(PropertyInfo pi) => Attribute.IsDefined(pi, typeof(MauEnumMemberAttribute)); + public static bool HasAttribute(FieldInfo fi) => Attribute.IsDefined(fi, typeof(MauEnumMemberAttribute)); public static bool HasAttribute(Enum enumValue) { Type enumType = enumValue.GetType(); string name = Enum.GetName(enumType, enumValue); - return Attribute.IsDefined(enumType.GetField(name), typeof(MauEnumMember)); + return Attribute.IsDefined(enumType.GetField(name), typeof(MauEnumMemberAttribute)); } public static bool HasNotSetValue(Type enumType) @@ -48,15 +48,15 @@ public static bool GetValidEnumValue(Type valueType, ref object originalValue) if (!valueType.IsEnum) return false; - if (!MauEnumMember.HasNotSetValue(valueType)) + if (!MauEnumMemberAttribute.HasNotSetValue(valueType)) throw new Exception($"'MauEnumMember.NotSet' must to be in any 'Enum' used as 'MauProperty' type or return of 'MauMethod'. {valueType.FullName}"); object o = originalValue; string enumValName = valueType.GetFields() - .Where(MauEnumMember.HasAttribute) + .Where(MauEnumMemberAttribute.HasAttribute) .FirstOrDefault(f => { - MauEnumMember f1 = f.GetCustomAttributes(false) + var f1 = f.GetCustomAttributes(false) .FirstOrDefault(memEnum => memEnum.IsEqual(o)); return f1?.IsEqual(o) == true; @@ -89,13 +89,13 @@ public static object GetValue(Enum enumValue) { Type enumType = enumValue.GetType(); string name = Enum.GetName(enumType, enumValue); - MauEnumMember instance = enumType.GetField(name).GetCustomAttributes(false).FirstOrDefault(); + var instance = enumType.GetField(name).GetCustomAttributes(false).FirstOrDefault(); if (instance == null) return null; return instance.Parser == EnumParser.Number ? instance.ValueAsNum - : (object)instance.ValueAsStr; + : instance.ValueAsStr; } } } diff --git a/MAU.Net/Attributes/MauEvent.cs b/MAU.Net/Attributes/MauEvent.cs index 3a97c8c..167ac21 100644 --- a/MAU.Net/Attributes/MauEvent.cs +++ b/MAU.Net/Attributes/MauEvent.cs @@ -7,13 +7,13 @@ namespace MAU.Attributes { [AttributeUsage(AttributeTargets.Event)] - public sealed class MauEvent : Attribute + public sealed class MauEventAttribute : Attribute { public string EventName { get; } - public static bool HasAttribute(EventInfo eventInfo) => Attribute.IsDefined(eventInfo, typeof(MauEvent)); + public static bool HasAttribute(EventInfo eventInfo) => Attribute.IsDefined(eventInfo, typeof(MauEventAttribute)); - public MauEvent(string eventName) + public MauEventAttribute(string eventName) { EventName = eventName; } diff --git a/MAU.Net/Attributes/MauMethod.cs b/MAU.Net/Attributes/MauMethod.cs index 06d22ea..acdab5b 100644 --- a/MAU.Net/Attributes/MauMethod.cs +++ b/MAU.Net/Attributes/MauMethod.cs @@ -4,6 +4,8 @@ using PostSharp.Extensibility; using PostSharp.Serialization; using System; +using System.Collections.Generic; +using System.Linq; using System.Reflection; namespace MAU.Attributes @@ -51,38 +53,48 @@ public override void OnEntry(MethodExecutionArgs args) } public override void OnExit(MethodExecutionArgs args) { - if (MethodCallType == MauMethodCallType.ExecuteFromAngular) + Type retType = ((MethodInfo)args.Method).ReturnType; + + if (MethodCallType == MauMethodCallType.ExecuteFromAngular || !MyAngularUi.IsConnected) { base.OnExit(args); return; } - if (!MyAngularUi.IsConnected) + // Prepare Args + List argsToSend = args.Arguments.ToList(); + for (int i = 0; i < argsToSend.Count; i++) { - base.OnExit(args); - return; + object param = argsToSend[i]; + if (!param.GetType().IsEnum || !MauEnumMemberAttribute.HasAttribute((Enum) param)) + continue; + + argsToSend[i] = MauEnumMemberAttribute.GetValue((Enum)param); } + // Send var holder = (MauComponent)args.Instance; var data = new JObject { {"methodType", (int)MethodType}, {"methodName", MethodName}, - {"methodArgs", JArray.FromObject(args.Arguments.ToArray())} + {"methodArgs", JArray.FromObject(argsToSend)} }; - MyAngularUi.RequestState request = MyAngularUi.SendRequestAsync(holder.MauId, MyAngularUi.RequestType.CallMethod, data).GetAwaiter().GetResult(); + // Wait return // If its void function then just wait until execution finish - if (((MethodInfo)args.Method).ReturnType == typeof(void)) + if (retType == typeof(void)) { // Wait function holder.GetMethodRetValue(request.RequestId); return; } - // Set return value of function - args.ReturnValue = holder.GetMethodRetValue(request.RequestId); + // Wait and set return value of function + object ret = holder.GetMethodRetValue(request.RequestId); + if (ret is not null) + args.ReturnValue = ret /*?? Activator.CreateInstance(retType)*/; } } } diff --git a/MAU.Net/Attributes/MauProperty.cs b/MAU.Net/Attributes/MauProperty.cs index 5001b24..9f3c3d7 100644 --- a/MAU.Net/Attributes/MauProperty.cs +++ b/MAU.Net/Attributes/MauProperty.cs @@ -32,6 +32,11 @@ public enum MauPropertyStatus public MauPropertyStatus PropStatus { get; set; } public bool Important { get; set; } + /// + /// Set property value even not exists + /// + public bool ForceSet { get; set; } + public MauProperty(string propertyName, MauPropertyType propType) { PropertyName = propertyName; @@ -60,11 +65,11 @@ internal static void SendMauProp(MauComponent holder, string mauPropName) } else if (propType.IsEnum) { - if (!MauEnumMember.HasNotSetValue(propValue.GetType())) + if (!MauEnumMemberAttribute.HasNotSetValue(propValue.GetType())) throw new Exception($"NotSet must to be in any MauProperty value is 'Enum', {propValue.GetType().FullName}"); - if (MauEnumMember.HasAttribute((Enum)propValue)) - propValue = MauEnumMember.GetValue((Enum)propValue); + if (MauEnumMemberAttribute.HasAttribute((Enum)propValue)) + propValue = MauEnumMemberAttribute.GetValue((Enum)propValue); // If it's NotSet just ignore so the angular value will be set, // Angular value will be in .Net side, so the value will be correct here. @@ -96,6 +101,7 @@ internal static void SendMauProp(MauComponent holder, string mauPropName) { {"propType", (int)mauPropHolder.PropAttr.PropType}, {"propStatus", (int)mauPropHolder.PropAttr.PropStatus}, + {"propForce", mauPropHolder.PropAttr.ForceSet}, {"propName", mauPropName}, {"propVal", MyAngularUi.ParseMauDataToFrontEnd(propType, propValue)} }; diff --git a/MAU.Net/Core/MauComponent.cs b/MAU.Net/Core/MauComponent.cs index b783d00..2c64910 100644 --- a/MAU.Net/Core/MauComponent.cs +++ b/MAU.Net/Core/MauComponent.cs @@ -64,12 +64,13 @@ public abstract class MauComponent #region [ UI Methods ] - public void SetStyle(string styleName, string styleValue) + public void SetStyle(string styleName, string styleValue, string childQuerySelector = "") { var data = new JObject { {"styleName", styleName}, {"styleValue", styleValue}, + {"childQuerySelector", childQuerySelector}, }; MyAngularUi.SendRequestAsync(MauId, MyAngularUi.RequestType.SetStyle, data); @@ -149,9 +150,9 @@ private void Init() // Events { EventInfo[] eventInfos = this.GetType().GetEvents(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - foreach (EventInfo eventInfo in eventInfos.Where(MauEvent.HasAttribute)) + foreach (EventInfo eventInfo in eventInfos.Where(MauEventAttribute.HasAttribute)) { - var attr = eventInfo.GetCustomAttribute(); + var attr = eventInfo.GetCustomAttribute(); HandledEvents.Add(attr.EventName, eventInfo); } } @@ -211,7 +212,7 @@ internal void FireEvent(string eventName, string eventType, JObject eventData) var eventDelegate = (MulticastDelegate)fi.GetValue(this); // There any subscriber .? - if (eventDelegate == null) + if (eventDelegate is null) return; // Invoke all subscribers @@ -271,7 +272,8 @@ internal void RequestPropValue(string propName) { {"propName", propName}, {"propType", (int)mauProperty.PropAttr.PropType}, - {"propStatus", (int)mauProperty.PropAttr.PropStatus} // Needed by `SetPropHandler` + {"propStatus", (int)mauProperty.PropAttr.PropStatus}, // Needed by `SetPropHandler` + {"propForce", mauProperty.PropAttr.ForceSet} // Needed by `SetPropHandler` }; MyAngularUi.SendRequestAsync(MauId, MyAngularUi.RequestType.GetPropValue, data); @@ -285,7 +287,7 @@ internal void SetPropValue(string propName, JToken propValueJson) object propValue = MyAngularUi.ParseMauDataFromFrontEnd(propValType, propValueJson); // Make valid enum value - MauEnumMember.GetValidEnumValue(propValType, ref propValue); + MauEnumMemberAttribute.GetValidEnumValue(propValType, ref propValue); // Deadlock will not happen because of 'HandledProps[propName].HandleOnSet' lock (HandledProps[propName]) @@ -301,7 +303,7 @@ internal void SetMethodRetValue(int callMethodRequestId, string methodName, JTok object methodRet = MyAngularUi.ParseMauDataFromFrontEnd(methodRetType, methodRetValueJson); // Make valid enum value - MauEnumMember.GetValidEnumValue(methodRetType, ref methodRet); + MauEnumMemberAttribute.GetValidEnumValue(methodRetType, ref methodRet); MyAngularUi.OrdersResponse.TryAdd(callMethodRequestId, methodRet); } diff --git a/MAU.Net/MyAngularUi.cs b/MAU.Net/MyAngularUi.cs index 8988bc0..6c2f09d 100644 --- a/MAU.Net/MyAngularUi.cs +++ b/MAU.Net/MyAngularUi.cs @@ -10,6 +10,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Linq; using System.Reflection; using System.Threading.Tasks; @@ -259,8 +260,8 @@ public static async Task StartAsync(int webSocketPort = 2911) Port = webSocketPort; WebSocket = new MauWebSocket(Port); - WebSocket.OnOpen += () => Task.Run(OnOpen); - WebSocket.OnClose += () => Task.Run(OnClose); + WebSocket.OnOpen += () => Task.Run(OpenCallback); + WebSocket.OnClose += () => Task.Run(CloseCallback); WebSocket.OnMessage += (message) => Task.Run(() => OnMessage(message)); WebSocket.Start(); @@ -289,11 +290,12 @@ private static void ReSyncMauComponents() MauVariable.SendMauVariable(mauComponent, varName); // Props - foreach ((string propName, _) in mauComponent.GetValidToSetHandledProps()) + Dictionary props = mauComponent.GetValidToSetHandledProps(); + foreach ((string propName, _) in props) MauProperty.SendMauProp(mauComponent, propName); // Events - MauEvent.SendMauEventsAsync(mauComponent); + MauEventAttribute.SendMauEventsAsync(mauComponent); } if (_mauComponents.Count > 0) @@ -457,13 +459,13 @@ internal static void OnMessage(string message) } } - internal static void OnOpen() + internal static void OpenCallback() { IsConnected = true; ReSyncMauComponents(); } - internal static void OnClose() + internal static void CloseCallback() { IsConnected = false; } @@ -513,7 +515,7 @@ internal static void RegisterComponent(MauComponent mauComponent) private static void BootStrapMau() { // Create instance of all 'MauParentComponent' - foreach (Type item in AppAssembly.GetTypes().Where(t => !t.IsAbstract && MauContainer.HasAttribute(t))) + foreach (Type item in AppAssembly.GetTypes().Where(t => !t.IsAbstract && MauContainerAttribute.HasAttribute(t))) { if (!item.IsSealed) throw new Exception($"MauContainer must be 'Sealed', '{item.FullName}'."); @@ -531,7 +533,7 @@ private static void BootStrapMau() public static T GetMauContainer() where T : class { Type t = typeof(T); - if (!MauContainer.HasAttribute(t)) + if (!MauContainerAttribute.HasAttribute(t)) throw new Exception($"'{t.FullName}' not a MauContainer."); string compName = typeof(T).FullName; diff --git a/MAU.Net/ReadyComponents/Angular/MauAutocomplete.cs b/MAU.Net/ReadyComponents/Angular/MauAutocomplete.cs new file mode 100644 index 0000000..4adb08f --- /dev/null +++ b/MAU.Net/ReadyComponents/Angular/MauAutocomplete.cs @@ -0,0 +1,87 @@ +using MAU.Attributes; +using MAU.Core; +using MAU.Events; +using MAU.Helper.Enums; +using MAU.Helper.Types; +using Newtonsoft.Json.Linq; +using static MAU.Attributes.MauMethod; +using static MAU.Attributes.MauProperty; +using static MAU.Events.MauEventHandlers; + +namespace MAU.ReadyComponents.Angular +{ + public class MauAutocomplete : MauComponent + { + #region [ Mau Variable ] + + [MauVariable("Data")] + public MauDataList Data { get; set; } + + #endregion + + #region [ Mau Events ] + + [MauEvent("selected")] + public event MauEventHandlerAsync OnSelected; + + [MauEvent("inputChanged")] + public event MauEventHandlerAsync OnInputChanged; + + [MauEvent("inputFocused")] + public event MauEventHandlerAsync OnInputFocused; + + [MauEvent("inputCleared")] + public event MauEventHandlerAsync OnInputCleared; + + [MauEvent("opened")] + public event MauEventHandlerAsync OnOpened; + + [MauEvent("closed")] + public event MauEventHandlerAsync OnClosed; + + [MauEvent("scrolledToEnd")] + public event MauEventHandlerAsync OnScrolledToEnd; + + [MauEvent("input")] + public event MauEventHandlerAsync OnInputChange; + + #endregion + + #region [ Mau Properties ] + + [MauProperty("disabled", MauPropertyType.ComponentProperty, ForceSet = true)] + public bool Disabled { get; set; } + + [MauProperty("placeholder", MauPropertyType.ComponentProperty)] + public string Placeholder { get; set; } + + [MauProperty("query", MauPropertyType.ComponentProperty)] + public string Query { get; set; } + + [MauProperty("selectedIdx", MauPropertyType.ComponentProperty)] + public int SelectedIdx { get; set; } + + #endregion + + #region [ Mau Methods ] + + [MauMethod("open", MauMethodType.ComponentMethod, MauMethodCallType.ExecuteInAngular)] + public void Open() { } + + [MauMethod("close", MauMethodType.ComponentMethod, MauMethodCallType.ExecuteInAngular)] + public void Close() { } + + [MauMethod("focus", MauMethodType.ComponentMethod, MauMethodCallType.ExecuteInAngular)] + public void Focus() { } + + [MauMethod("clear", MauMethodType.ComponentMethod, MauMethodCallType.ExecuteInAngular)] + public void Clear() { } + + #endregion + + public MauAutocomplete(string mauId) : base(mauId) + { + Data = new MauDataList(this, nameof(Data)); + } + } +} diff --git a/MAU.Net/ReadyComponents/Angular/MauNgAlert.cs b/MAU.Net/ReadyComponents/Angular/MauNgAlert.cs new file mode 100644 index 0000000..f1183cf --- /dev/null +++ b/MAU.Net/ReadyComponents/Angular/MauNgAlert.cs @@ -0,0 +1,80 @@ +using MAU.Attributes; +using MAU.Core; +using static MAU.Attributes.MauMethod; +using static MAU.Attributes.MauProperty; +using static MAU.Events.MauEventHandlers; + +namespace MAU.ReadyComponents.Angular +{ + public enum NgAlertType + { + [MauEnumMember("")] + NotSet, + + [MauEnumMember("success")] + Success, + + [MauEnumMember("info")] + Info, + + [MauEnumMember("warning")] + Warning, + + [MauEnumMember("danger")] + Danger, + + [MauEnumMember("primary")] + Primary, + + [MauEnumMember("secondary")] + Secondary, + + [MauEnumMember("light")] + Light, + + [MauEnumMember("dark")] + Dark, + } + + public class MauNgAlert : MauComponent + { + #region [ Mau Events ] + + [MauEvent("closed")] + public event MauEventHandlerAsync OnClosed; + + #endregion + + #region [ Mau Variable ] + + [MauVariable("Text")] + public string Text { get; set; } + + [MauVariable("Visible")] + public bool Visible { get; set; } + + #endregion + + #region [ Mau Properties ] + + [MauProperty("dismissible", MauPropertyType.ComponentProperty)] + public bool Dismissible { get; set; } + + [MauProperty("animation", MauPropertyType.ComponentProperty)] + public bool Animation { get; set; } + + [MauProperty("type", MauPropertyType.ComponentProperty)] + public NgAlertType Type { get; set; } + + #endregion + + #region [ Mau Methods ] + + [MauMethod("close", MauMethodType.ComponentMethod, MauMethodCallType.ExecuteInAngular)] + public void Close() { } + + #endregion + + public MauNgAlert(string mauId) : base(mauId) { } + } +} diff --git a/MAU.Net/ReadyComponents/Angular/MauNgSelect.cs b/MAU.Net/ReadyComponents/Angular/MauNgSelect.cs index 4355b23..10ef5e3 100644 --- a/MAU.Net/ReadyComponents/Angular/MauNgSelect.cs +++ b/MAU.Net/ReadyComponents/Angular/MauNgSelect.cs @@ -1,4 +1,5 @@ -using MAU.Attributes; +using System.Collections.Generic; +using MAU.Attributes; using MAU.Core; using MAU.Helper.Types; using static MAU.Attributes.MauMethod; @@ -7,35 +8,67 @@ namespace MAU.ReadyComponents.Angular { + // Todo: Make MauValues + /* + public class NgSelectNgOption + { + [MauProperty("disabled", MauPropertyType.ComponentProperty)] + public bool Disabled { get; set; } + + [MauProperty("htmlId", MauPropertyType.ComponentProperty)] + public string HtmlId { get; set; } + + [MauProperty("index", MauPropertyType.ComponentProperty)] + public int Index { get; set; } + + [MauProperty("label", MauPropertyType.ComponentProperty)] + public string Label { get; set; } + + [MauProperty("marked", MauPropertyType.ComponentProperty)] + public bool Marked { get; set; } + + [MauProperty("selected", MauPropertyType.ComponentProperty)] + public bool Selected { get; set; } + + [MauProperty("value", MauPropertyType.ComponentProperty)] + public string Value { get; set; } + } + + public class NgSelectItemsList + { + [MauProperty("_items", MauPropertyType.ComponentProperty)] + public List Items { get; set; } + } + */ public class MauNgSelect : MauComponent { #region [ Mau Events ] - [MauEvent("add")] + [MauEvent("addEvent")] public event MauEventHandlerAsync OnAdd; - [MauEvent("blur")] + [MauEvent("blurEvent")] public event MauEventHandlerAsync OnBlur; - [MauEvent("change")] + [MauEvent("changeEvent")] public event MauEventHandlerAsync OnChange; - [MauEvent("close")] + [MauEvent("closeEvent")] public event MauEventHandlerAsync OnClose; - [MauEvent("clear")] + [MauEvent("clearEvent")] public event MauEventHandlerAsync OnClear; - [MauEvent("focus")] + [MauEvent("focusEvent")] public event MauEventHandlerAsync OnFocus; - [MauEvent("search")] + [MauEvent("searchEvent")] public event MauEventHandlerAsync OnSearch; - [MauEvent("open")] + [MauEvent("openEvent")] public event MauEventHandlerAsync OnOpen; - [MauEvent("remove")] + [MauEvent("removeEvent")] public event MauEventHandlerAsync OnRemove; [MauEvent("scroll")] @@ -55,9 +88,14 @@ public class MauNgSelect : MauComponent #region [ Mau Properties ] - public bool Disabled { get; set; } - public string SelectedItem { get; set; } + [MauProperty("readonly", MauPropertyType.ComponentProperty)] + public bool Readonly { get; set; } + /*[MauProperty("itemsList", MauPropertyType.ComponentProperty)] + public NgSelectItemsList ItemsList { get; set; }*/ + + [MauProperty("selectedValues", MauPropertyType.ComponentProperty)] + public List SelectedValues { get; set; } [MauProperty("appearance", MauPropertyType.ComponentProperty)] public string Appearance { get; set; } @@ -77,6 +115,9 @@ public class MauNgSelect : MauComponent [MauProperty("clearAllText", MauPropertyType.ComponentProperty)] public string ClearAllText { get; set; } + [MauProperty("focused", MauPropertyType.ComponentProperty)] + public bool Focused { get; set; } + [MauProperty("clearable", MauPropertyType.ComponentProperty)] public bool Clearable { get; set; } @@ -102,32 +143,14 @@ public class MauNgSelect : MauComponent [MauMethod("blur", MauMethodType.ComponentMethod, MauMethodCallType.ExecuteInAngular)] public void Blur() { } + [MauMethod("select", MauMethodType.ComponentMethod, MauMethodCallType.ExecuteInAngular)] + public void Select(bool state) { } + #endregion public MauNgSelect(string mauId) : base(mauId) { Options = new MauDataList(this, nameof(Options)); } - - #region [ Options Controlling ] - - public bool SelectOption(string newOption) - { - if (!Options.Contains(newOption)) - return false; - - SelectedItem = newOption; - return true; - } - public bool SelectOption(int newOptionIndex) - { - if (newOptionIndex >= Options.Count) - return false; - - SelectedItem = Options[newOptionIndex]; - return true; - } - - #endregion } } diff --git a/MAU.Net/ReadyComponents/MauButton.cs b/MAU.Net/ReadyComponents/MauButton.cs new file mode 100644 index 0000000..4e2c469 --- /dev/null +++ b/MAU.Net/ReadyComponents/MauButton.cs @@ -0,0 +1,27 @@ +using MAU.Attributes; +using MAU.Core; +using MAU.Helper.Enums; +using static MAU.Attributes.MauMethod; +using static MAU.Attributes.MauProperty; + +namespace MAU.ReadyComponents +{ + public class MauButton : MauComponent + { + #region [ Mau Properties ] + + [MauProperty("disabled", MauPropertyType.NativeProperty)] + public bool Disabled { get; set; } + + #endregion + + #region [ Mau Methods ] + + [MauMethod("focus", MauMethodType.ComponentMethod, MauMethodCallType.ExecuteInAngular)] + public void Focus() { } + + #endregion + + public MauButton(string mauId) : base(mauId) { } + } +}