public SomeChoicesForm() { _view = new SomeChoicesFormView(); LocalActionBuilder.Build(_view.First, () => Ended?.Invoke(this, Outcome.FirstChoice)); LocalActionBuilder.Build(_view.Second, () => Ended?.Invoke(this, Outcome.SecondChoice)); }
public PhotoTakerForm(PhotoTakerFormView view) { _view = view; LocalActionBuilder.Build(_view.TakePhoto, () => _view.InputFile.Click()); LocalActionBuilder.Build(_view.AcceptPhoto, () => { _view.ResetPreviewStyle(true); Ended?.Invoke(this, CompletedOrCanceled.Completed); }); LocalActionBuilder.Build(_view.RetryPhoto, () => { _view.ClearImage(); _view.InputFile.Click(); }); _view.InputFile.OnChange += _ => { var files = _view.InputFile.Files; if (files == null || files.Length <= 0) { Logger.Debug(GetType(), "got no files"); return; } Logger.Debug(GetType(), "got files {0}", files.Length); var fr = new FileReader(); fr.OnLoad += ev => { _view.SetImageFromDataUrl((string)fr.Result); }; fr.ReadAsDataURL(files[0]); }; }
public UploaderDemoForm(IHttpRequester httpRequester) { _view = new UploaderDemoFormView(); _view.Attachments.SetImplementation(new ISomeService_OrderAttachment(httpRequester, () => 124, () => true)); _attachments = LocalValueFieldBuilder.Build(new List <RemoteFileDescr>(), _view.Attachments, (newValue, errors) => { errors.IfTrueAdd(newValue.Count > 10, "Maximum 10 files allowed"); }); //TODO this is experimental feature. It should be added by the above statement (if BeforeChange is supported in IView) _view.Attachments.BeforeChange += (newValue, isUser, preventProp) => { if (newValue.Count > 10) { preventProp(new HashSet <string> { "Maximum 10 files allowed" }); } }; var mayConfirm = new AggregatedErrorsValue <bool>( false, self => !self.Errors.Any(), x => x.Observes(_attachments)); var confirm = LocalActionBuilder.Build(_view.Confirm, () => Ended?.Invoke(this, Unit.Instance)); confirm.BindEnableAndInitialize(mayConfirm); }
public QrScannerForm( QrScannerFormView view, string title, string label, Func <string, Task <T> > getItemByCode, int scannerPopupMmFromTop = 15, int scannerPopupHeightMm = 40) { _view = view; _view.Label = label; _view.PadMmFromTop = scannerPopupMmFromTop; _scannerPopupMmFromTop = scannerPopupMmFromTop; _view.HeightMm = scannerPopupHeightMm; _scannerPopupHeightMm = scannerPopupHeightMm; _title = title; _getItemByCode = getItemByCode; LocalActionBuilder.Build(_view.Unpause, async() => { _view.Unpause.Widget.Style.Display = Display.None; await _errorLbl.DoChange("", false, this, false); _hndl?.ResumeScanning(); }); LocalActionBuilder.Build(_view.Cancel, () => _hndl?.CancelScanning()); _errorLbl = LocalValueFieldBuilder.Build(_view.Error); }
public AllFieldsFilledDataEntryForm() { var view = new AllFieldsFilledDataEntryFormView(); var ended = new Observable.Publisher <Unit>(); Ended = ended; View = view; var strEntry = LocalValueFieldBuilder.Build( view.StringEntry, (x, errors) => errors.IfTrueAdd( string.IsNullOrWhiteSpace(x) || x.Length < 4, "Text must be at least 4 chars long"), (x, errors) => errors.IfTrueAdd( string.IsNullOrWhiteSpace(x) || x.Length > 10, "Text must be no longer than 10 chars long") ); var intEntry = LocalValueFieldBuilder.BuildNullableInt( view.IntEntry, (x, errors) => errors.IfTrueAdd(!x.HasValue || x < 1234, "Number must be bigger than 1234") ); var decEntry = LocalValueFieldBuilder.BuildNullableDecimal( view.DecimalEntry, DecimalFormat.WithTwoDecPlaces, (x, errors) => errors.IfTrueAdd(!x.HasValue || x < 5.6m, "Number must be bigger than " + I18n.Localize(5.6m, DecimalFormat.WithOneDecPlace)) ); //this field is used to show that values on screen are not necessarily values within model. //In other words: when validator rejected value from user wrong value and error message stays on screen BUT model keeps its last-accepted-value var summaryLine = LocalValueFieldBuilder.Build("", view.SummaryLine); void UpdateSummaryLine() { var decVal = !decEntry.Value.HasValue ? "" : I18n.Localize(decEntry.Value.Value, DecimalFormat.WithOneDecPlace); summaryLine.DoProgrammaticChange( $@"Accepted vals: Text={strEntry.Value} Int={intEntry.Value} Decimal={decVal}" ); } strEntry.Changed += (_, __, ___, ____, _____) => UpdateSummaryLine(); intEntry.Changed += (_, __, ___, ____, _____) => UpdateSummaryLine(); decEntry.Changed += (_, __, ___, ____, _____) => UpdateSummaryLine(); UpdateSummaryLine(); var confirm = LocalActionBuilder.Build(view.ConfirmAction, () => ended.Fire(Unit.Instance)); confirm.BindEnableAndInitializeAsObserving(x => { x.Observes(strEntry); x.Observes(intEntry); x.Observes(decEntry); }); }
public DataboundDatagridForm() { _view = new DataboundDatagridFormView(); Func <string, BaseUnboundColumnBuilder <SomeDto> > build = x => UnboundDataGridColumnBuilder.For <SomeDto>(x); Items = DataGridModel <SomeDto> .CreateAndBindReloadable( _view.Items, () => Ended?.Invoke(this, Outcome.ReloadData), (el, theaderHeight, _) => //most of the time you would use Toolkit.DefaultTableBodyHeightProvider() el.GetAvailableHeightForFormElement(0, 2) - theaderHeight - _view.Help.Widget.OffsetHeight, new List <IDataGridColumn <SomeDto> > { build("#") .WithValueLocalized(x => Items.Items.IndexOf(x) + 1) .NonTransformable() .Build(), build("SomeNumber") .WithValueLocalized(x => x.SomeNumber) .TransformableDefault() .Observes(x => nameof(x.SomeNumber)) .Build(), build("SomeText") .WithValue(x => x.SomeText) .TransformableDefault() .Observes(x => nameof(x.SomeText)) .Build(), build("SomeBool") .WithValueLocalized(x => x.SomeBool) .TransformableDefault() .Observes(x => nameof(x.SomeBool)) .Build(), build("SomeTrait") .WithValueAsText(x => x.SomeTrait, x => x.ToString()) .TransformableAsText() .Observes(x => nameof(x.SomeTrait)) .Build(), }).model; Items.Activated.Changed += (sender, oldValue, newValue, errors, isUserChange) => { if (newValue == null) { return; } ChoosenItem = Items.Activated.Value; Ended?.Invoke(this, Outcome.EditItemDemanded); }; LocalActionBuilder.Build(_view.Creator, () => Ended?.Invoke(this, Outcome.CreateItemDemanded)); //button that is activated only if exactly one record is selected in the datagarid var activateEditor = LocalActionBuilder.Build(_view.Editor, () => { ChoosenItem = Items.Selected[0]; Ended?.Invoke(this, Outcome.EditItemDemanded); }); activateEditor.BindSelectionIntoEnabled(Items, SelectionNeeded.ExactlyOneSelected); }
public InformationalMessageForm(InformationalMessageFormView view, string messageOrNull = null, string titleOrNull = null, bool cancellable = true) { _cancellable = cancellable; Title = titleOrNull ?? I18n.Translate("Confirmation"); View = view; _message = new LocalValue <string>(messageOrNull ?? I18n.Translate("Without message")); view.Message.BindReadOnlyAndInitialize(_message); LocalActionBuilder.Build(view.Confirm, () => Ended?.Invoke(this, Unit.Instance)); }
public ConfirmMessageForm(ConfirmMessageFormView view, string messageOrNull = null, string titleOrNull = null) { Title = titleOrNull ?? I18n.Translate("Confirmation"); View = view; _message = new LocalValue <string>(messageOrNull ?? I18n.Translate("Without message")); view.Message.BindReadOnlyAndInitialize(_message); LocalActionBuilder.Build(view.Confirm, () => Ended?.Invoke(this, CompletedOrCanceled.Completed)); LocalActionBuilder.Build(view.Cancel, () => Ended?.Invoke(this, CompletedOrCanceled.Canceled)); }
//comment out above declaration and uncomment next line to make form noncloseable // public ExternalEventsHandlers ExternalEventsHandlers => ExternalEventsHandlers.Ignore; public SomeForm() { var inp = LocalValueFieldBuilder.Build(_view.Inp, (v, errors) => errors.IfTrueAdd(string.IsNullOrWhiteSpace(v), "Must contain at least one non whitespace character")); var conf = LocalActionBuilder.Build(_view.Confirm, () => Ended?.Invoke(this, CompletedOrCanceled.Completed)); conf.BindEnableAndInitializeAsObserving(x => x.Observes(inp)); }
public EnumChoiceForm( string title, bool isCancelable, T defaultValue, Func <T, string> getLabel, Action <EnumChoiceFormView <T> > postInitialization = null) { Title = title; _isCancelable = isCancelable; _view = new EnumChoiceFormView <T>(defaultValue, getLabel, postInitialization); _chosen = LocalValueFieldBuilder.BuildEnumBasedChoice(defaultValue, _view.Choice); LocalActionBuilder.Build(_view.Confirm, () => Ended?.Invoke(this, CompletedOrCanceled.Completed)); }
public SingleRadioBasedChoiceForm( string title, bool isCancelable, T defaultValue, Func <T, string> getLabel, Func <int, T> intToItem, Func <T, int> itemToInt, Action <SingleRadioBasedChoiceFormView <T> > postInitialization = null) { Title = title; _isCancelable = isCancelable; _getLabel = getLabel; _itemToInt = itemToInt; _view = new SingleRadioBasedChoiceFormView <T>( defaultValue, getLabel, intToItem, itemToInt, postInitialization); _chosen = LocalValueFieldBuilder.BuildGeneralChoice( defaultValue, intToItem, itemToInt, _view.Choice); LocalActionBuilder.Build(_view.Confirm, () => Ended?.Invoke(this, CompletedOrCanceled.Completed)); }
public TextInputForm( TextInputFormView view, string label, string titleOrNull = null, string defaultValue = null, params Validate <string>[] validators) { Title = titleOrNull ?? I18n.Translate("Input"); _view = view; _msg = new LocalValue <string>(label ?? ""); view.Label.BindReadOnlyAndInitialize(_msg); _input = LocalValueFieldBuilder.Build(defaultValue, view.Input, validators); var isFormValid = new AggregatedErrorsValue <bool>(false, x => !x.Errors.Any(), x => x.Observes(_input)); var confirmInput = LocalActionBuilder.Build(view.Confirm, () => Ended?.Invoke(this, CompletedOrCanceled.Completed)); confirmInput.BindEnableAndInitialize(isFormValid); }
public IntroduceItemForm() { _view = new IntroduceItemFormView(); _someText = LocalValueFieldBuilder.Build(_view.SomeText, Validator.IsNotEmptyOrWhitespaceOnly); _someNumber = LocalValueFieldBuilder.BuildInt(_view.SomeNumber, Validator.MustBePositive); _someBool = LocalValueFieldBuilder.Build(_view.SomeBool); _view.SomeTrait.PermittedValues = EnumExtensions.GetEnumValues <SomeTraitType>().Select(x => (SomeTraitType?)x); _someTrait = LocalValueFieldBuilder.Build(_view.SomeTrait, Validator.IsNotNull); var isFormValid = new AggregatedErrorsValue <bool>(false, self => !self.Errors.Any(), x => { x.Observes(_someText); x.Observes(_someNumber); x.Observes(_someBool); x.Observes(_someTrait); }); LocalActionBuilder .Build(_view.Create, () => Ended?.Invoke(this, Outcome.Saved)) .With(x => x.BindEnableAndInitialize(isFormValid)); }
public SseListenerForm( Func <ContinentalSubscriptionRequest, IServerSentEventsSubscriber <ContinentalNotification> > listenerBld) { _listenerBld = listenerBld; _unsubscribe = LocalActionBuilder.Build(_view.Unsubscribe, () => SetupListener(null)); _contToAction.Add(Continent.Africa, LocalActionBuilder.Build(_view.SubscribeAfrica, () => SetupListener(Continent.Africa))); _contToAction.Add(Continent.Antarctica, LocalActionBuilder.Build(_view.SubscribeAntarctica, () => SetupListener(Continent.Antarctica))); _contToAction.Add(Continent.Europe, LocalActionBuilder.Build(_view.SubscribeEurope, () => SetupListener(Continent.Europe))); _contToAction.Add(Continent.NorthAmerica, LocalActionBuilder.Build(_view.SubscribeNorthAmerica, () => SetupListener(Continent.NorthAmerica))); SetupEnablement(); }
//TODO refactor this monster private static Tuple <HTMLElement, DataGridColumnControllerResult <InternalT> > Create <InternalT, OperT, ViewT>( Func <InternalT, OperT> toOper, ITransformationMediator listener, FilterDef <OperT>[] availableFilters, IEnumerable <AggregatorDef <OperT> > rawAvailableAggregators, IEnumerable <GrouperDef <OperT> > rawAvailableGroupers, Func <IReadWriteValue <OperT>, IReadWriteValueView <HTMLElement, ViewT> > paramEditor, OperT initialFilterValue, OperT invalidFilterValue, IComparer <OperT> sortingImpl) { var availableAggregators = rawAvailableAggregators.ToList(); var availableGroupers = rawAvailableGroupers.ToList(); AssureUnique(availableFilters, x => x.Label); AssureUnique(availableAggregators, x => x.Label); AssureUnique(availableGroupers, x => x.Label); LocalValue <AggregatorDef <OperT> > aggregateFunc = null; LocalValue <GrouperDef <OperT> > groupingFunc = null; LocalValue <GroupOrAggregate?> groupOrAggregateChoice = null; FilterDef <OperT> currentFilterImplOrNull = null; var filterLabelToImpl = new Dictionary <string, FilterDef <OperT> >(); availableFilters.ForEach(x => filterLabelToImpl.Add(x.Label, x)); AggregatorDef <OperT> currentAggrImplOrNull = null; var aggregLabelToImpl = new Dictionary <string, AggregatorDef <OperT> >(); availableAggregators.ForEach(x => aggregLabelToImpl.Add(x.Label, x)); GrouperDef <OperT> currentGrouperImplOrNull = null; var grouperLabelToImpl = new Dictionary <string, GrouperDef <OperT> >(); availableGroupers.ForEach(x => grouperLabelToImpl.Add(x.Label, x)); var filterParam = new LocalValue <OperT>(initialFilterValue, invalidFilterValue); HTMLElement controllerElem = new HTMLSpanElement { ClassName = Magics.CssClassFilterMainContainer }; var actionContainer = new HTMLSpanElement { ClassName = Magics.CssClassFilterActionContainer }; controllerElem.AppendChild(actionContainer); var groupOrAggregateChoiceView = new RadioBasedSingleChoice(); Element GetLabelTh() { var filterTh = controllerElem.ParentElement; var filterTr = filterTh.ParentElement; var thead = filterTr.ParentElement; var iCol = filterTr.IndexOfChild(filterTh); var labelTr = thead.GetChildAtOrNull(0); var labelTh = labelTr.GetChildAtOrNull(iCol); return(labelTh); } void MarkAsGrouped(bool activated) { Logger.Debug(typeof(DataGridColumnController), "markAsGrouped({0})", activated); controllerElem.ParentElement.AddOrRemoveClass(activated, Magics.CssClassActive); GetLabelTh().AddOrRemoveClass(activated, Magics.CssClassWithGrouping); controllerElem.ParentElement.AddOrRemoveClass(activated, Magics.CssClassWithGrouping); } void MarkAsAggregated(bool activated) { Logger.Debug(typeof(DataGridColumnController), "markAsAggregated({0})", activated); controllerElem.ParentElement.AddOrRemoveClass(activated, Magics.CssClassActive); GetLabelTh().AddOrRemoveClass(activated, Magics.CssClassWithAggregation); controllerElem.ParentElement.AddOrRemoveClass(activated, Magics.CssClassWithAggregation); } void MarkAsFiltered(bool activated) { Logger.Debug(typeof(DataGridColumnController), "markAsFiltered({0})", activated); controllerElem.ParentElement.AddOrRemoveClass(activated, Magics.CssClassActive); GetLabelTh().AddOrRemoveClass(activated, Magics.CssClassWithFilter); controllerElem.ParentElement.AddOrRemoveClass(activated, Magics.CssClassWithFilter); } var removeFilter = new HTMLAnchorElement { Target = "#", Title = I18n.Translate("Remove filter"), Text = FontAwesomeSolid.IconFilter }; removeFilter.AddClasses(Magics.CssClassFilterRemove, IconFontType.FontAwesomeSolid.ToCssClassName()); actionContainer.AppendChild(removeFilter); var removeFilterActionView = new InputTypeButtonActionView(removeFilter); LocalActionBuilder.Build(removeFilterActionView, () => { currentFilterImplOrNull = null; MarkAsFiltered(false); listener.UserFilterChangedHandler(ChangeOrRemove.Removed); }); var removeGrouping = new HTMLAnchorElement { Target = "#", Title = I18n.Translate("Remove grouping"), Text = FontAwesomeSolid.IconListUl }; removeGrouping.AddClasses(Magics.CssClassGroupingRemove, IconFontType.FontAwesomeSolid.ToCssClassName()); actionContainer.AppendChild(removeGrouping); var removeGroupingActionView = new InputTypeButtonActionView(removeGrouping); LocalActionBuilder.Build(removeGroupingActionView, async() => { currentGrouperImplOrNull = null; MarkAsGrouped(false); await groupOrAggregateChoice.DoChange(null, false, null, false); listener.UserGroupingChangedHandler(ChangeOrRemove.Removed); }); var removeAggregation = new HTMLAnchorElement { ClassName = Magics.CssClassAggregationRemove, Target = "#", Title = I18n.Translate("Remove aggregation"), Text = "Σ" }; actionContainer.AppendChild(removeAggregation); var removeAggregationActionView = new InputTypeButtonActionView(removeAggregation); LocalActionBuilder.Build(removeAggregationActionView, async() => { currentAggrImplOrNull = null; await groupOrAggregateChoice.DoChange(null, false, null, false); MarkAsAggregated(false); listener.UserAggregationChangedHandler(ChangeOrRemove.Removed); }); Action <string> groupingChangedHandler = async labelOrNull => { Logger.Debug(typeof(DataGridColumnController), "Setting grouping programmatically to {0}", labelOrNull); if (labelOrNull == null) { currentGrouperImplOrNull = null; MarkAsGrouped(false); await groupOrAggregateChoice.DoChange(null, false, null, false); return; } GrouperDef <OperT> grouper; if (!grouperLabelToImpl.TryGetValue(labelOrNull, out grouper)) { Logger.Debug(typeof(DataGridColumnController), "No such grouping func when looking by label"); return; } await groupingFunc.DoChange(grouper, false, null, false); currentGrouperImplOrNull = grouper; MarkAsGrouped(true); }; Action <string> aggregationChangedHandler = async labelOrNull => { Logger.Debug(typeof(DataGridColumnController), "Setting aggregation programmatically to {0}", labelOrNull); if (labelOrNull == null) { currentAggrImplOrNull = null; MarkAsAggregated(false); await groupOrAggregateChoice.DoChange(null, false, null, false); listener.UserAggregationChangedHandler(ChangeOrRemove.Removed); return; } if (!aggregLabelToImpl.TryGetValue(labelOrNull, out var aggr)) { Logger.Debug(typeof(DataGridColumnController), "No such aggregation func when looking by label"); return; } await aggregateFunc.DoChange(aggr, false, null, false); currentAggrImplOrNull = aggr; MarkAsAggregated(true); }; listener.InitUserSide(groupingChangedHandler, aggregationChangedHandler); var filterOper = new LocalValue <FilterDef <OperT> >(availableFilters.FirstOrDefault()); var filterOperView = new DropDownSelectBox("") { PermittedValues = filterLabelToImpl.Select(x => Tuple.Create(x.Key, x.Key)) }; filterOperView.BindReadWriteAndInitialize(filterOper, x => x != null ? Tuple.Create(x.Label, x.Label) : Tuple.Create("", ""), x => !string.IsNullOrEmpty(x.Item1) ? filterLabelToImpl[x.Item1] : null); controllerElem.AppendChild(filterOperView.Widget); var val = paramEditor(filterParam); controllerElem.AppendChild(val.Widget); filterParam.Changed += (_, __, newValue, ___, isUserChange) => { if (!isUserChange) { return; } currentFilterImplOrNull = filterOper.Value; MarkAsFiltered(true); listener.UserFilterChangedHandler(ChangeOrRemove.Changed); }; filterOper.Changed += (_, __, newValue, ___, isUserChange) => { if (!isUserChange) { return; } currentFilterImplOrNull = newValue; MarkAsFiltered(true); listener.UserFilterChangedHandler(ChangeOrRemove.Changed); }; { groupOrAggregateChoice = new LocalValue <GroupOrAggregate?>(null); groupOrAggregateChoiceView.Widget.ClassList.Add(Magics.CssClassGroupOrAggregate); groupOrAggregateChoiceView.PermittedValues = EnumExtensions.GetEnumValues <GroupOrAggregate>().Select(x => Tuple.Create(((int)x).ToString(), x.GetUserFriendlyName())); groupOrAggregateChoiceView.BindReadWriteAndInitialize(groupOrAggregateChoice, x => !x.HasValue ? null : Tuple.Create(((int)x).ToString(), x.Value.GetUserFriendlyName()), x => (x == null || string.IsNullOrEmpty(x.Item1)) ? null : (GroupOrAggregate?)Convert.ToInt32(x.Item1)); groupingFunc = new LocalValue <GrouperDef <OperT> >(availableGroupers.FirstOrDefault()); var groupingFuncView = new DropDownSelectBox(I18n.Translate("group by:")); groupingFuncView.Widget.ClassList.Add(Magics.CssClassGroupingFunc); groupingFuncView.PermittedValues = grouperLabelToImpl.Select(x => Tuple.Create(x.Key, x.Key)); groupingFuncView.BindReadWriteAndInitialize(groupingFunc, x => x != null ? Tuple.Create(x.Label, x.Label) : Tuple.Create("", ""), x => !string.IsNullOrEmpty(x.Item1) ? grouperLabelToImpl[x.Item1] : null); aggregateFunc = new LocalValue <AggregatorDef <OperT> >(availableAggregators.FirstOrDefault()); var aggregateFuncView = new DropDownSelectBox(I18n.Translate("aggregate by:")); aggregateFuncView.Widget.ClassList.Add(Magics.CssClassAggregateFunc); aggregateFuncView.PermittedValues = aggregLabelToImpl.Select(x => Tuple.Create(x.Key, x.Key)); aggregateFuncView.BindReadWriteAndInitialize(aggregateFunc, x => x != null ? Tuple.Create(x.Label, x.Label) : Tuple.Create("", ""), x => !string.IsNullOrEmpty(x.Item1) ? aggregLabelToImpl[x.Item1] : null); groupingFunc.Changed += (_, __, newValue, errors, isUserChange) => { if (!isUserChange) { return; } currentGrouperImplOrNull = newValue; MarkAsGrouped(newValue != null); listener.UserGroupingChangedHandler(newValue != null ? ChangeOrRemove.Changed : ChangeOrRemove.Removed); }; aggregateFunc.Changed += (_, __, newValue, errors, isUserChange) => { if (!isUserChange) { return; } currentAggrImplOrNull = newValue; MarkAsAggregated(newValue != null); listener.UserAggregationChangedHandler(newValue != null ? ChangeOrRemove.Changed : ChangeOrRemove.Removed); }; groupOrAggregateChoice.Changed += (_, __, newValue, ___, isUserChange) => { Logger.Debug(typeof(DataGridColumnController), "groupOrAggregateChoice changed to {0} by {1}", newValue, isUserChange); //if (!isUserChange) { // return; //} if (!newValue.HasValue) { return; } switch (newValue.Value) { case GroupOrAggregate.Aggregate: currentAggrImplOrNull = aggregateFunc.Value; MarkAsAggregated(true); listener.UserAggregationChangedHandler(ChangeOrRemove.Changed); break; case GroupOrAggregate.Group: currentGrouperImplOrNull = groupingFunc.Value; MarkAsGrouped(true); listener.UserGroupingChangedHandler(ChangeOrRemove.Changed); break; default: throw new Exception("unsupported GroupOrAggregate"); } }; controllerElem.AppendChild(groupOrAggregateChoiceView.Widget); controllerElem.AppendChild(groupingFuncView.Widget); controllerElem.AppendChild(aggregateFuncView.Widget); } DocumentUtil.AddMouseClickListener(controllerElem, ev => { if (!ev.HasHtmlTarget()) { return; } //find out if clicked item is a descendant of th if (ev.HtmlTarget().IsDescendantOf(controllerElem.ParentElement)) { controllerElem.ParentElement.ClassList.Add(Magics.CssClassActive); return; } controllerElem.ParentElement?.ClassList.Remove(Magics.CssClassActive); }); return(Tuple.Create(controllerElem, new DataGridColumnControllerResult <InternalT> { FilterImpl = x => currentFilterImplOrNull == null || currentFilterImplOrNull.FilterFunc(filterParam.Value, toOper(x)), AggregationImpl = x => currentAggrImplOrNull?.AggregatorFunc(x.Select(toOper)), GroupingImpl = x => currentGrouperImplOrNull?.GroupingFunc(x.Select(toOper)), SortingImpl = new CompareImpl <InternalT>((x, y) => sortingImpl.Compare(toOper(x), toOper(y))), IsGroupingActive = () => currentGrouperImplOrNull != null })); }
() => Ended?.Invoke(this, Outcome.EndRequested));//makes form cancelable public MainForm() { LocalActionBuilder.Build(_view.ShowInfo, () => Ended?.Invoke(this, Outcome.InfoRequested)); LocalActionBuilder.Build(_view.ReplaceMaster, () => Ended?.Invoke(this, Outcome.ReplaceMaster)); }