features/refactor
stm 2 years ago
parent c3b267dfc4
commit b178bbb9b0

@ -10,176 +10,127 @@ namespace Connected.Components;
public partial class Dialog : UIComponent public partial class Dialog : UIComponent
{ {
protected string ContentClass => new CssBuilder("dialog-content") #region Variables
.AddClass($"dialog-no-side-padding", DisableSidePadding) [CascadingParameter] private DialogInstance DialogInstance { get; set; }
.AddClass(ClassContent) [Inject] public IDialogService DialogService { get; set; }
.Build(); private IDialogReference _reference;
#endregion
protected string ActionClass => new CssBuilder("dialog-actions")
.AddClass(ClassActions) #region Events
.Build(); [Parameter]
[Category(CategoryTypes.Dialog.Behavior)]
[CascadingParameter] private DialogInstance DialogInstance { get; set; } public Action OnBackdropClick { get; set; }
[Inject] public IDialogService DialogService { get; set; } /// <summary>
/// Raised when the inline dialog's display status changes.
/// <summary> /// </summary>
/// Define the dialog title as a renderfragment (overrides GlyphTitle) [Parameter] public EventCallback<bool> IsVisibleChanged { get; set; }
/// </summary> #endregion
[Parameter]
[Category(CategoryTypes.Dialog.Behavior)] #region Content
public RenderFragment TitleContent { get; set; }
/// <summary>
/// <summary> /// Define the dialog title as a renderfragment (overrides GlyphTitle)
/// Define the dialog body here /// </summary>
/// </summary> [Parameter]
[Parameter] [Category(CategoryTypes.Dialog.Behavior)]
[Category(CategoryTypes.Dialog.Behavior)] public DefaultFocus DefaultFocus { get; set; }
public RenderFragment DialogContent { get; set; }
/// <summary>
/// <summary> /// Define the dialog title as a renderfragment (overrides GlyphTitle)
/// Define the action buttons here /// </summary>
/// </summary> [Parameter]
[Parameter] [Category(CategoryTypes.Dialog.Behavior)]
[Category(CategoryTypes.Dialog.Behavior)] public RenderFragment TitleContent { get; set; }
public RenderFragment DialogActions { get; set; }
/// <summary>
/// <summary> /// Define the dialog body here
/// Default options to pass to Show(), if none are explicitly provided. /// </summary>
/// Typically useful on inline dialogs. [Parameter]
/// </summary> [Category(CategoryTypes.Dialog.Behavior)]
[Parameter] public RenderFragment DialogContent { get; set; }
[Category(CategoryTypes.Dialog.Misc)] // Behavior and Appearance
public DialogOptions Options { get; set; } /// <summary>
/// Define the action buttons here
[Parameter] /// </summary>
[Category(CategoryTypes.Dialog.Behavior)] [Parameter]
public Action OnBackdropClick { get; set; } [Category(CategoryTypes.Dialog.Behavior)]
public RenderFragment DialogActions { get; set; }
/// <summary> #endregion
/// No padding at the sides
/// </summary> #region Styling
[Parameter] /// <summary>
[Category(CategoryTypes.Dialog.Appearance)] /// No padding at the sides
public bool DisableSidePadding { get; set; } /// </summary>
[Parameter]
/// <summary> [Category(CategoryTypes.Dialog.Appearance)]
/// CSS class that will be applied to the dialog content public bool DisableSidePadding { get; set; }
/// </summary> /// <summary>
[Parameter] /// CSS class that will be applied to the dialog content
[Category(CategoryTypes.Dialog.Appearance)] /// </summary>
public string ClassContent { get; set; } [Parameter]
[Category(CategoryTypes.Dialog.Appearance)]
/// <summary> public string ClassContent { get; set; }
/// CSS class that will be applied to the action buttons container
/// </summary> /// <summary>
[Parameter] /// CSS class that will be applied to the action buttons container
[Category(CategoryTypes.Dialog.Appearance)] /// </summary>
public string ClassActions { get; set; } [Parameter]
[Category(CategoryTypes.Dialog.Appearance)]
/// <summary> public string ClassActions { get; set; }
/// CSS styles to be applied to the dialog content
/// </summary> /// <summary>
[Parameter] /// CSS styles to be applied to the dialog content
[Category(CategoryTypes.Dialog.Appearance)] /// </summary>
public string ContentStyle { get; set; } [Parameter]
[Category(CategoryTypes.Dialog.Appearance)]
/// <summary> public string ContentStyle { get; set; }
/// Bind this two-way to show and close an inlined dialog. Has no effect on opened dialogs
/// </summary> /// <summary>
[Parameter] /// Bind this two-way to show and close an inlined dialog. Has no effect on opened dialogs
[Category(CategoryTypes.Dialog.Behavior)] /// </summary>
public bool IsVisible [Parameter]
{ [Category(CategoryTypes.Dialog.Behavior)]
get => _isVisible; public bool IsVisible
set {
{ get => _isVisible;
if (_isVisible == value) set
return; {
_isVisible = value; if (_isVisible == value)
IsVisibleChanged.InvokeAsync(value); return;
} _isVisible = value;
} IsVisibleChanged.InvokeAsync(value);
private bool _isVisible; }
}
/// <summary> private bool _isVisible;
/// Raised when the inline dialog's display status changes. protected string ContentClass => new CssBuilder("dialog-content")
/// </summary> .AddClass($"dialog-no-side-padding", DisableSidePadding)
[Parameter] public EventCallback<bool> IsVisibleChanged { get; set; } .AddClass(ClassContent)
.Build();
/// <summary> protected string ActionClass => new CssBuilder("dialog-actions")
/// Define the dialog title as a renderfragment (overrides GlyphTitle) .AddClass(ClassActions)
/// </summary> .Build();
[Parameter] #endregion
[Category(CategoryTypes.Dialog.Behavior)]
public DefaultFocus DefaultFocus { get; set; } #region Behavior
/// <summary>
private bool IsInline => DialogInstance == null; /// Used for forwarding state changes from inlined dialog to its instance
/// </summary>
private IDialogReference _reference; internal void ForceUpdate()
{
/// <summary> StateHasChanged();
/// Show this inlined dialog }
/// </summary>
/// <param name="title"></param> /// <summary>
/// <param name="options"></param> /// Default options to pass to Show(), if none are explicitly provided.
/// <returns></returns> /// Typically useful on inline dialogs.
public IDialogReference Show(string title = null, DialogOptions options = null) /// </summary>
{ [Parameter]
if (!IsInline) [Category(CategoryTypes.Dialog.Misc)] // Behavior and Appearance
throw new InvalidOperationException("You can only show an inlined dialog."); public DialogOptions Options { get; set; }
if (_reference != null)
Close(); /// <summary>
var parameters = new DialogParameters()
{
[nameof(AdditionalClassList)] = AdditionalClassList,
[nameof(Tag)] = Tag,
[nameof(TitleContent)] = TitleContent,
[nameof(DialogContent)] = DialogContent,
[nameof(DialogActions)] = DialogActions,
[nameof(DisableSidePadding)] = DisableSidePadding,
[nameof(ClassContent)] = ClassContent,
[nameof(ClassActions)] = ClassActions,
[nameof(ContentStyle)] = ContentStyle,
};
_reference = DialogService.Show<Dialog>(title, parameters, options ?? Options);
_reference.Result.ContinueWith(t =>
{
_isVisible = false;
InvokeAsync(() => IsVisibleChanged.InvokeAsync(false));
});
return _reference;
}
protected override void OnAfterRender(bool firstRender)
{
if (IsInline)
{
if (_isVisible && _reference == null)
{
Show(); // if isVisible and we don't have any reference we need to call Show
}
else if (_reference != null)
{
if (IsVisible)
(_reference.Dialog as Dialog)?.ForceUpdate(); // forward render update to instance
else
Close(); // if we still have reference but it's not visible call Close
}
}
base.OnAfterRender(firstRender);
}
/// <summary>
/// Used for forwarding state changes from inlined dialog to its instance
/// </summary>
internal void ForceUpdate()
{
StateHasChanged();
}
/// <summary>
/// Close the currently open inlined dialog /// Close the currently open inlined dialog
/// </summary> /// </summary>
/// <param name="result"></param> /// <param name="result"></param>
@ -191,9 +142,69 @@ public partial class Dialog : UIComponent
_reference = null; _reference = null;
} }
protected override void OnInitialized() private bool IsInline => DialogInstance == null;
{
base.OnInitialized(); #endregion
DialogInstance?.Register(this);
} #region Lifecycle
protected override void OnInitialized()
{
base.OnInitialized();
DialogInstance?.Register(this);
}
/// <summary>
/// Show this inlined dialog
/// </summary>
/// <param name="title"></param>
/// <param name="options"></param>
/// <returns></returns>
public IDialogReference Show(string title = null, DialogOptions options = null)
{
if (!IsInline)
throw new InvalidOperationException("You can only show an inlined dialog.");
if (_reference != null)
Close();
var parameters = new DialogParameters()
{
[nameof(AdditionalClassList)] = AdditionalClassList,
[nameof(Tag)] = Tag,
[nameof(TitleContent)] = TitleContent,
[nameof(DialogContent)] = DialogContent,
[nameof(DialogActions)] = DialogActions,
[nameof(DisableSidePadding)] = DisableSidePadding,
[nameof(ClassContent)] = ClassContent,
[nameof(ClassActions)] = ClassActions,
[nameof(ContentStyle)] = ContentStyle,
};
_reference = DialogService.Show<Dialog>(title, parameters, options ?? Options);
_reference.Result.ContinueWith(t =>
{
_isVisible = false;
InvokeAsync(() => IsVisibleChanged.InvokeAsync(false));
});
return _reference;
}
protected override void OnAfterRender(bool firstRender)
{
if (IsInline)
{
if (_isVisible && _reference == null)
{
Show(); // if isVisible and we don't have any reference we need to call Show
}
else if (_reference != null)
{
if (IsVisible)
(_reference.Dialog as Dialog)?.ForceUpdate(); // forward render update to instance
else
Close(); // if we still have reference but it's not visible call Close
}
}
base.OnAfterRender(firstRender);
}
#endregion
} }

@ -12,29 +12,52 @@ namespace Connected.Components;
public partial class DialogInstance : UIComponent, IDisposable public partial class DialogInstance : UIComponent, IDisposable
{ {
#region Variables
private DialogOptions _options = new(); private DialogOptions _options = new();
private string _elementId = "dialog_" + Guid.NewGuid().ToString().Substring(0, 8); private string _elementId = "dialog_" + Guid.NewGuid().ToString().Substring(0, 8);
private IKeyInterceptor _keyInterceptor; private IKeyInterceptor _keyInterceptor;
[Inject] private IKeyInterceptorFactory _keyInterceptorFactory { get; set; } [Inject] private IKeyInterceptorFactory _keyInterceptorFactory { get; set; }
[CascadingParameter(Name = "RightToLeft")] public bool RightToLeft { get; set; }
[CascadingParameter] private DialogProvider Parent { get; set; } [CascadingParameter] private DialogProvider Parent { get; set; }
[CascadingParameter] private DialogOptions GlobalDialogOptions { get; set; } = new DialogOptions(); [CascadingParameter] private DialogOptions GlobalDialogOptions { get; set; } = new DialogOptions();
private Dialog _dialog;
private bool _disposedValue;
#endregion
[Parameter] #region Events
[Category(CategoryTypes.Dialog.Misc)] // Behavior and Appearance private void HandleBackgroundClick()
public DialogOptions Options
{ {
get if (DisableBackdropClick)
return;
if (_dialog?.OnBackdropClick == null)
{ {
if (_options == null) Cancel();
_options = new DialogOptions(); return;
return _options;
} }
set => _options = value;
_dialog?.OnBackdropClick.Invoke();
} }
/// <summary>
/// Cancels all dialogs in dialog provider collection.
/// </summary>
public void CancelAll()
{
Parent?.DismissAll();
}
public void Register(Dialog dialog)
{
if (dialog == null)
return;
_dialog = dialog;
//AdditionalClassList = dialog.AdditionalClassList;
TitleContent = dialog.TitleContent;
StateHasChanged();
}
#endregion
#region Content
[Parameter] [Parameter]
[Category(CategoryTypes.Dialog.Behavior)] [Category(CategoryTypes.Dialog.Behavior)]
public string Title { get; set; } public string Title { get; set; }
@ -46,10 +69,129 @@ public partial class DialogInstance : UIComponent, IDisposable
[Parameter] [Parameter]
[Category(CategoryTypes.Dialog.Behavior)] [Category(CategoryTypes.Dialog.Behavior)]
public RenderFragment Content { get; set; } public RenderFragment Content { get; set; }
[Parameter] [Parameter]
[Category(CategoryTypes.Dialog.Behavior)] [Category(CategoryTypes.Dialog.Behavior)]
public Guid Id { get; set; } public Guid Id { get; set; }
#endregion
#region Styling
public void ForceRender()
{
StateHasChanged();
}
private string SetPosition()
{
DialogPosition position;
if (Options.Position.HasValue)
{
position = Options.Position.Value;
}
else if (GlobalDialogOptions.Position.HasValue)
{
position = GlobalDialogOptions.Position.Value;
}
else
{
position = DialogPosition.Center;
}
return $"dialog-{position.ToDescription()}";
}
private bool SetHideHeader()
{
if (Options.NoHeader.HasValue)
return Options.NoHeader.Value;
if (GlobalDialogOptions.NoHeader.HasValue)
return GlobalDialogOptions.NoHeader.Value;
return false;
}
private bool SetCloseButton()
{
if (Options.CloseButton.HasValue)
return Options.CloseButton.Value;
if (GlobalDialogOptions.CloseButton.HasValue)
return GlobalDialogOptions.CloseButton.Value;
return false;
}
private bool SetDisableBackdropClick()
{
if (Options.DisableBackdropClick.HasValue)
return Options.DisableBackdropClick.Value;
if (GlobalDialogOptions.DisableBackdropClick.HasValue)
return GlobalDialogOptions.DisableBackdropClick.Value;
return false;
}
private bool SetCloseOnEscapeKey()
{
if (Options.CloseOnEscapeKey.HasValue)
return Options.CloseOnEscapeKey.Value;
if (GlobalDialogOptions.CloseOnEscapeKey.HasValue)
return GlobalDialogOptions.CloseOnEscapeKey.Value;
return false;
}
private string SetMaxWidth()
{
MaxWidth maxWidth;
if (Options.MaxWidth.HasValue)
{
maxWidth = Options.MaxWidth.Value;
}
else if (GlobalDialogOptions.MaxWidth.HasValue)
{
maxWidth = GlobalDialogOptions.MaxWidth.Value;
}
else
{
maxWidth = MaxWidth.Small;
}
return $"dialog-width-{maxWidth.ToDescription()}";
}
private bool SetFullWidth()
{
if (Options.FullWidth.HasValue)
return Options.FullWidth.Value;
if (GlobalDialogOptions.FullWidth.HasValue)
return GlobalDialogOptions.FullWidth.Value;
return false;
}
private bool SetFulScreen()
{
if (Options.FullScreen.HasValue)
return Options.FullScreen.Value;
if (GlobalDialogOptions.FullScreen.HasValue)
return GlobalDialogOptions.FullScreen.Value;
return false;
}
protected string Classname =>
new CssBuilder("dialog")
.AddClass(DialogMaxWidth, !FullScreen)
.AddClass("dialog-width-full", FullWidth && !FullScreen)
.AddClass("dialog-fullscreen", FullScreen)
.AddClass("dialog-rtl", RightToLeft)
.AddClass(_dialog?.AdditionalClassList)
.Build();
/// <summary> /// <summary>
/// Custom close icon. /// Custom close icon.
@ -66,35 +208,22 @@ public partial class DialogInstance : UIComponent, IDisposable
private bool CloseButton { get; set; } private bool CloseButton { get; set; }
private bool FullScreen { get; set; } private bool FullScreen { get; set; }
private bool FullWidth { get; set; } private bool FullWidth { get; set; }
[CascadingParameter(Name = "RightToLeft")] public bool RightToLeft { get; set; }
[Parameter]
protected override void OnInitialized() [Category(CategoryTypes.Dialog.Misc)] // Behavior and Appearance
{ public DialogOptions Options
ConfigureInstance();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{ {
if (firstRender) get
{ {
//Since CloseOnEscapeKey is the only thing to be handled, turn interceptor off if (_options == null)
if (CloseOnEscapeKey) _options = new DialogOptions();
{ return _options;
_keyInterceptor = _keyInterceptorFactory.Create();
await _keyInterceptor.Connect(_elementId, new KeyInterceptorOptions()
{
TargetClass = "dialog",
Keys = {
new KeyOptions { Key="Escape", SubscribeDown = true },
},
});
_keyInterceptor.KeyDown += HandleKeyDown;
}
} }
await base.OnAfterRenderAsync(firstRender); set => _options = value;
} }
#endregion
#region Behavior
internal void HandleKeyDown(KeyboardEventArgs args) internal void HandleKeyDown(KeyboardEventArgs args)
{ {
switch (args.Key) switch (args.Key)
@ -175,157 +304,34 @@ public partial class DialogInstance : UIComponent, IDisposable
//AdditionalClassList = Classname; //AdditionalClassList = Classname;
} }
private string SetPosition() #endregion
{
DialogPosition position;
if (Options.Position.HasValue)
{
position = Options.Position.Value;
}
else if (GlobalDialogOptions.Position.HasValue)
{
position = GlobalDialogOptions.Position.Value;
}
else
{
position = DialogPosition.Center;
}
return $"dialog-{position.ToDescription()}";
}
private string SetMaxWidth()
{
MaxWidth maxWidth;
if (Options.MaxWidth.HasValue)
{
maxWidth = Options.MaxWidth.Value;
}
else if (GlobalDialogOptions.MaxWidth.HasValue)
{
maxWidth = GlobalDialogOptions.MaxWidth.Value;
}
else
{
maxWidth = MaxWidth.Small;
}
return $"dialog-width-{maxWidth.ToDescription()}";
}
private bool SetFullWidth()
{
if (Options.FullWidth.HasValue)
return Options.FullWidth.Value;
if (GlobalDialogOptions.FullWidth.HasValue)
return GlobalDialogOptions.FullWidth.Value;
return false;
}
private bool SetFulScreen()
{
if (Options.FullScreen.HasValue)
return Options.FullScreen.Value;
if (GlobalDialogOptions.FullScreen.HasValue)
return GlobalDialogOptions.FullScreen.Value;
return false;
}
protected string Classname =>
new CssBuilder("dialog")
.AddClass(DialogMaxWidth, !FullScreen)
.AddClass("dialog-width-full", FullWidth && !FullScreen)
.AddClass("dialog-fullscreen", FullScreen)
.AddClass("dialog-rtl", RightToLeft)
.AddClass(_dialog?.AdditionalClassList)
.Build();
private bool SetHideHeader()
{
if (Options.NoHeader.HasValue)
return Options.NoHeader.Value;
if (GlobalDialogOptions.NoHeader.HasValue)
return GlobalDialogOptions.NoHeader.Value;
return false;
}
private bool SetCloseButton()
{
if (Options.CloseButton.HasValue)
return Options.CloseButton.Value;
if (GlobalDialogOptions.CloseButton.HasValue)
return GlobalDialogOptions.CloseButton.Value;
return false;
}
private bool SetDisableBackdropClick()
{
if (Options.DisableBackdropClick.HasValue)
return Options.DisableBackdropClick.Value;
if (GlobalDialogOptions.DisableBackdropClick.HasValue)
return GlobalDialogOptions.DisableBackdropClick.Value;
return false; #region Lifecycle
} protected override void OnInitialized()
private bool SetCloseOnEscapeKey()
{ {
if (Options.CloseOnEscapeKey.HasValue) ConfigureInstance();
return Options.CloseOnEscapeKey.Value;
if (GlobalDialogOptions.CloseOnEscapeKey.HasValue)
return GlobalDialogOptions.CloseOnEscapeKey.Value;
return false;
} }
private void HandleBackgroundClick() protected override async Task OnAfterRenderAsync(bool firstRender)
{ {
if (DisableBackdropClick) if (firstRender)
return;
if (_dialog?.OnBackdropClick == null)
{ {
Cancel(); //Since CloseOnEscapeKey is the only thing to be handled, turn interceptor off
return; if (CloseOnEscapeKey)
} {
_keyInterceptor = _keyInterceptorFactory.Create();
_dialog?.OnBackdropClick.Invoke();
}
private Dialog _dialog;
private bool _disposedValue;
public void Register(Dialog dialog)
{
if (dialog == null)
return;
_dialog = dialog;
//AdditionalClassList = dialog.AdditionalClassList;
TitleContent = dialog.TitleContent;
StateHasChanged();
}
public void ForceRender()
{
StateHasChanged();
}
/// <summary> await _keyInterceptor.Connect(_elementId, new KeyInterceptorOptions()
/// Cancels all dialogs in dialog provider collection. {
/// </summary> TargetClass = "dialog",
public void CancelAll() Keys = {
{ new KeyOptions { Key="Escape", SubscribeDown = true },
Parent?.DismissAll(); },
});
_keyInterceptor.KeyDown += HandleKeyDown;
}
}
await base.OnAfterRenderAsync(firstRender);
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
@ -350,4 +356,6 @@ public partial class DialogInstance : UIComponent, IDisposable
Dispose(disposing: true); Dispose(disposing: true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
#endregion
} }

@ -15,94 +15,101 @@ namespace Connected.Components;
public partial class DialogProvider : IDisposable public partial class DialogProvider : IDisposable
{ {
[Inject] private IDialogService DialogService { get; set; }
[Inject] private NavigationManager NavigationManager { get; set; } #region Variables
[Inject] private IDialogService DialogService { get; set; }
[Parameter][Category(CategoryTypes.Dialog.Behavior)] public bool? NoHeader { get; set; } [Inject] private NavigationManager NavigationManager { get; set; }
[Parameter][Category(CategoryTypes.Dialog.Behavior)] public bool? CloseButton { get; set; } [Parameter][Category(CategoryTypes.Dialog.Behavior)] public bool? NoHeader { get; set; }
[Parameter][Category(CategoryTypes.Dialog.Behavior)] public bool? DisableBackdropClick { get; set; } [Parameter][Category(CategoryTypes.Dialog.Behavior)] public bool? CloseButton { get; set; }
[Parameter][Category(CategoryTypes.Dialog.Behavior)] public bool? CloseOnEscapeKey { get; set; } [Parameter][Category(CategoryTypes.Dialog.Behavior)] public bool? DisableBackdropClick { get; set; }
[Parameter][Category(CategoryTypes.Dialog.Appearance)] public bool? FullWidth { get; set; } [Parameter][Category(CategoryTypes.Dialog.Behavior)] public bool? CloseOnEscapeKey { get; set; }
[Parameter][Category(CategoryTypes.Dialog.Appearance)] public DialogPosition? Position { get; set; } [Parameter][Category(CategoryTypes.Dialog.Appearance)] public bool? FullWidth { get; set; }
[Parameter][Category(CategoryTypes.Dialog.Appearance)] public MaxWidth? MaxWidth { get; set; } [Parameter][Category(CategoryTypes.Dialog.Appearance)] public DialogPosition? Position { get; set; }
[Parameter][Category(CategoryTypes.Dialog.Appearance)] public MaxWidth? MaxWidth { get; set; }
private readonly Collection<IDialogReference> _dialogs = new();
private readonly DialogOptions _globalDialogOptions = new(); private readonly Collection<IDialogReference> _dialogs = new();
private readonly DialogOptions _globalDialogOptions = new();
protected override void OnInitialized() #endregion
{
DialogService.OnDialogInstanceAdded += AddInstance; #region Events
DialogService.OnDialogCloseRequested += DismissInstance; private void AddInstance(IDialogReference dialog)
NavigationManager.LocationChanged += LocationChanged; {
_dialogs.Add(dialog);
_globalDialogOptions.DisableBackdropClick = DisableBackdropClick; StateHasChanged();
_globalDialogOptions.CloseOnEscapeKey = CloseOnEscapeKey; }
_globalDialogOptions.CloseButton = CloseButton; internal void DismissInstance(Guid id, DialogResult result)
_globalDialogOptions.NoHeader = NoHeader; {
_globalDialogOptions.Position = Position; var reference = GetDialogReference(id);
_globalDialogOptions.FullWidth = FullWidth; if (reference != null)
_globalDialogOptions.MaxWidth = MaxWidth; DismissInstance(reference, result);
} }
protected override Task OnAfterRenderAsync(bool firstRender) public void DismissAll()
{ {
if (!firstRender) _dialogs.ToList().ForEach(r => DismissInstance(r, DialogResult.Cancel()));
{ StateHasChanged();
foreach (var dialogReference in _dialogs.Where(x => !x.Result.IsCompleted)) }
{
dialogReference.RenderCompleteTaskCompletionSource.TrySetResult(true); private void DismissInstance(IDialogReference dialog, DialogResult result)
} {
} if (!dialog.Dismiss(result)) return;
return base.OnAfterRenderAsync(firstRender); _dialogs.Remove(dialog);
} StateHasChanged();
}
internal void DismissInstance(Guid id, DialogResult result)
{ private IDialogReference GetDialogReference(Guid id)
var reference = GetDialogReference(id); {
if (reference != null) return _dialogs.SingleOrDefault(x => x.Id == id);
DismissInstance(reference, result); }
}
private void LocationChanged(object sender, LocationChangedEventArgs args)
private void AddInstance(IDialogReference dialog) {
{ DismissAll();
_dialogs.Add(dialog); }
StateHasChanged(); #endregion
}
#region Lifecycle
public void DismissAll() protected override void OnInitialized()
{ {
_dialogs.ToList().ForEach(r => DismissInstance(r, DialogResult.Cancel())); DialogService.OnDialogInstanceAdded += AddInstance;
StateHasChanged(); DialogService.OnDialogCloseRequested += DismissInstance;
} NavigationManager.LocationChanged += LocationChanged;
private void DismissInstance(IDialogReference dialog, DialogResult result) _globalDialogOptions.DisableBackdropClick = DisableBackdropClick;
{ _globalDialogOptions.CloseOnEscapeKey = CloseOnEscapeKey;
if (!dialog.Dismiss(result)) return; _globalDialogOptions.CloseButton = CloseButton;
_globalDialogOptions.NoHeader = NoHeader;
_dialogs.Remove(dialog); _globalDialogOptions.Position = Position;
StateHasChanged(); _globalDialogOptions.FullWidth = FullWidth;
} _globalDialogOptions.MaxWidth = MaxWidth;
}
private IDialogReference GetDialogReference(Guid id)
{ protected override Task OnAfterRenderAsync(bool firstRender)
return _dialogs.SingleOrDefault(x => x.Id == id); {
} if (!firstRender)
{
private void LocationChanged(object sender, LocationChangedEventArgs args) foreach (var dialogReference in _dialogs.Where(x => !x.Result.IsCompleted))
{ {
DismissAll(); dialogReference.RenderCompleteTaskCompletionSource.TrySetResult(true);
} }
}
public void Dispose()
{ return base.OnAfterRenderAsync(firstRender);
if (NavigationManager != null) }
NavigationManager.LocationChanged -= LocationChanged;
public void Dispose()
if (DialogService != null) {
{ if (NavigationManager != null)
DialogService.OnDialogInstanceAdded -= AddInstance; NavigationManager.LocationChanged -= LocationChanged;
DialogService.OnDialogCloseRequested -= DismissInstance;
} if (DialogService != null)
} {
DialogService.OnDialogInstanceAdded -= AddInstance;
DialogService.OnDialogCloseRequested -= DismissInstance;
}
}
#endregion
} }

@ -6,7 +6,8 @@ using Microsoft.AspNetCore.Components;
namespace Connected.Components; namespace Connected.Components;
public partial class Divider : UIComponent public partial class Divider : UIComponent
{ {
protected string Classname => #region Styling
protected string Classname =>
new CssBuilder("divider") new CssBuilder("divider")
.AddClass($"divider-absolute", Absolute) .AddClass($"divider-absolute", Absolute)
.AddClass($"divider-flexitem", FlexItem) .AddClass($"divider-flexitem", FlexItem)
@ -50,4 +51,6 @@ public partial class Divider : UIComponent
[Parameter] [Parameter]
[Category(CategoryTypes.Divider.Appearance)] [Category(CategoryTypes.Divider.Appearance)]
public DividerType DividerType { get; set; } = DividerType.FullWidth; public DividerType DividerType { get; set; } = DividerType.FullWidth;
#endregion
} }

@ -7,6 +7,7 @@ namespace Connected.Components;
public partial class Drawer : UIComponent, IDisposable, INavigationEventReceiver public partial class Drawer : UIComponent, IDisposable, INavigationEventReceiver
{ {
#region Variables
private double _height; private double _height;
private ElementReference _contentRef; private ElementReference _contentRef;
private DrawerClipMode _clipMode; private DrawerClipMode _clipMode;
@ -21,8 +22,16 @@ public partial class Drawer : UIComponent, IDisposable, INavigationEventReceiver
private Breakpoint _screenBreakpoint = Breakpoint.None; private Breakpoint _screenBreakpoint = Breakpoint.None;
private Guid _breakpointListenerSubscriptionId; private Guid _breakpointListenerSubscriptionId;
#region EventCallbacks #endregion
#region Events
private void CloseDrawer()
{
if (Open)
{
OpenChanged.InvokeAsync(false);
}
}
[Parameter] public EventCallback<bool> OpenChanged { get; set; } [Parameter] public EventCallback<bool> OpenChanged { get; set; }
@ -351,13 +360,7 @@ public partial class Drawer : UIComponent, IDisposable, INavigationEventReceiver
OpenChanged.InvokeAsync(_open); OpenChanged.InvokeAsync(_open);
} }
} }
private void CloseDrawer()
{
if (Open)
{
OpenChanged.InvokeAsync(false);
}
}
/// <summary> /// <summary>
/// Width of left/right drawer. Only for non-fixed drawers. /// Width of left/right drawer. Only for non-fixed drawers.

@ -6,16 +6,33 @@ namespace Connected.Components;
public partial class DrawerContainer : UIComponent public partial class DrawerContainer : UIComponent
{ {
#region Variables
protected bool Fixed { get; set; } = false; protected bool Fixed { get; set; } = false;
private List<Drawer> _drawers = new(); private List<Drawer> _drawers = new();
#endregion
#region Event callbacks #region Events
internal void FireDrawersChanged() => StateHasChanged(); internal void FireDrawersChanged() => StateHasChanged();
internal void Add(Drawer drawer)
{
if (Fixed && !drawer.Fixed)
return;
_drawers.Add(drawer);
StateHasChanged();
}
internal void Remove(Drawer drawer)
{
_drawers.Remove(drawer);
StateHasChanged();
}
#endregion #endregion
#region Content placeholders #region Content
[CascadingParameter(Name = "RightToLeft")] public bool RightToLeft { get; set; } [CascadingParameter(Name = "RightToLeft")] public bool RightToLeft { get; set; }
@ -83,7 +100,7 @@ public partial class DrawerContainer : UIComponent
#endregion #endregion
#region Styling properties #region Styling
protected virtual CssBuilder CompiledClassList protected virtual CssBuilder CompiledClassList
{ {
@ -142,18 +159,5 @@ public partial class DrawerContainer : UIComponent
#endregion #endregion
internal void Add(Drawer drawer)
{
if (Fixed && !drawer.Fixed)
return;
_drawers.Add(drawer);
StateHasChanged();
}
internal void Remove(Drawer drawer)
{
_drawers.Remove(drawer);
StateHasChanged();
}
} }

@ -4,10 +4,8 @@ using Microsoft.AspNetCore.Components;
namespace Connected.Components; namespace Connected.Components;
public partial class DrawerHeader : UIComponent public partial class DrawerHeader : UIComponent
{ {
#region Event callbacks
#endregion
#region Content placeholders #region Content
/// <summary> /// <summary>
/// If true, compact padding will be used, same as the Appbar. /// If true, compact padding will be used, same as the Appbar.
@ -29,7 +27,7 @@ public partial class DrawerHeader : UIComponent
#endregion #endregion
#region Styling properties #region Styling
/// <summary> /// <summary>
/// A space separated list of class names, added on top of the default class list. /// A space separated list of class names, added on top of the default class list.
@ -37,11 +35,13 @@ public partial class DrawerHeader : UIComponent
[Parameter] [Parameter]
public string? ClassList { get; set; } public string? ClassList { get; set; }
/*
/// <summary> /// <summary>
/// A space separated list of class names, added on top of the default class list. /// A space separated list of class names, added on top of the default class list.
/// </summary> /// </summary>
[Parameter] [Parameter]
public string? StyleList { get; set; } public string? StyleList { get; set; }
*/
protected virtual CssBuilder CompiledClassList protected virtual CssBuilder CompiledClassList
{ {
@ -56,5 +56,4 @@ public partial class DrawerHeader : UIComponent
#endregion #endregion
} }

@ -10,6 +10,13 @@ namespace Connected.Components;
public class DragAndDropIndexChangedEventArgs : EventArgs public class DragAndDropIndexChangedEventArgs : EventArgs
{ {
#region Variables
public string ZoneIdentifier { get; }
public int Index { get; }
public string OldZoneIdentifier { get; }
#endregion
#region Events
public DragAndDropIndexChangedEventArgs(string zoneIdentifier, string oldZoneIdentifier, int index) public DragAndDropIndexChangedEventArgs(string zoneIdentifier, string oldZoneIdentifier, int index)
{ {
ZoneIdentifier = zoneIdentifier; ZoneIdentifier = zoneIdentifier;
@ -17,41 +24,17 @@ public class DragAndDropIndexChangedEventArgs : EventArgs
OldZoneIdentifier = oldZoneIdentifier; OldZoneIdentifier = oldZoneIdentifier;
} }
public string ZoneIdentifier { get; } #endregion
public int Index { get; }
public string OldZoneIdentifier { get; }
} }
/// <summary>
/// Used to encapsulate data for a drag and drop transaction
/// </summary>
/// <typeparam name="T"></typeparam>
public class DragAndDropItemTransaction<T> public class DragAndDropItemTransaction<T>
{ {
#region Variables
private Func<Task> _commitCallback; private Func<Task> _commitCallback;
private Func<Task> _cancelCallback; private Func<Task> _cancelCallback;
#endregion
/// <summary> #region Events
/// The Item that is dragged during the transaction
/// </summary>
public T Item { get; init; }
/// <summary>
/// The index of the item in the current drop zone
/// </summary>
public int Index { get; private set; }
/// <summary>
/// The index of the item when the transaction started
/// </summary>
public int SourceIndex { get; private set; }
/// <summary>
/// Identifier for drop zone where the transaction started
/// </summary>
public string SourceZoneIdentifier { get; init; }
public string CurrentZone { get; private set; }
/// <summary> /// <summary>
/// create a new instance of a drag and drop transaction encapsulating the item and source /// create a new instance of a drag and drop transaction encapsulating the item and source
@ -101,248 +84,293 @@ public class DragAndDropItemTransaction<T>
Index = -1; Index = -1;
return true; return true;
} }
}
/// <summary> #endregion
/// Record encaplusalting data regaring a completed transaction
/// </summary>
/// <typeparam name="T">Type of dragged item</typeparam>
/// <param name="Item">The dragged item during the transaction</param>
/// <param name="DropzoneIdentifier">Identifier of the zone where the transaction started</param>
/// <param name="IndexInZone">The index of the item within in the dropzone</param>
public record ItemDropInfo<T>(T Item, string DropzoneIdentifier, int IndexInZone);
public class DragAndDropTransactionFinishedEventArgs<T> : EventArgs
{
public DragAndDropTransactionFinishedEventArgs(DragAndDropItemTransaction<T> transaction) :
this(string.Empty, false, transaction)
{
}
public DragAndDropTransactionFinishedEventArgs(string destinationDropzoneIdentifier, bool success, DragAndDropItemTransaction<T> transaction) #region Content
{
Item = transaction.Item;
Success = success;
OriginatedDropzoneIdentifier = transaction.SourceZoneIdentifier;
DestinationDropzoneIdentifier = destinationDropzoneIdentifier;
OriginIndex = transaction.SourceIndex;
DestinationIndex = transaction.Index;
}
public T Item { get; }
public bool Success { get; }
public string OriginatedDropzoneIdentifier { get; }
public string DestinationDropzoneIdentifier { get; }
public int OriginIndex { get; }
public int DestinationIndex { get; }
}
/// <summary>
/// The container of a drag and drop zones
/// </summary>
/// <typeparam name="T">Datetype of items</typeparam>
public partial class DropContainer<T> : UIComponent
{
private DragAndDropItemTransaction<T> _transaction;
protected string Classname =>
new CssBuilder("drop-container")
.AddClass(AdditionalClassList)
.Build();
/// <summary>
/// Child content of component. This should include the drop zones
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Appearance)]
public RenderFragment ChildContent { get; set; }
/// <summary> /// <summary>
/// The items that can be drag and dropped within the container /// The Item that is dragged during the transaction
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Items)]
public IEnumerable<T> Items { get; set; }
/// <summary>
/// The render fragment (template) that should be used to render the items within a drop zone
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Items)]
public RenderFragment<T> ItemRenderer { get; set; }
/// <summary>
/// The method is used to determinate if an item can be dropped within a drop zone
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Items)]
public Func<T, string, bool> ItemsSelector { get; set; }
/// <summary>
/// Callback that indicates that an item has been dropped on a drop zone. Should be used to update the "status" of the data item
/// </summary> /// </summary>
[Parameter] public T Item { get; init; }
[Category(CategoryTypes.DropZone.Items)]
public EventCallback<ItemDropInfo<T>> ItemDropped { get; set; }
/// <summary> /// <summary>
/// The method is used to determinate if an item can be dropped within a drop zone /// The index of the item in the current drop zone
/// </summary> /// </summary>
[Parameter] public int Index { get; private set; }
[Category(CategoryTypes.DropZone.DropRules)]
public Func<T, string, bool> CanDrop { get; set; }
/// <summary> /// <summary>
/// The CSS class(es), that is applied to drop zones that are a valid target for drag and drop transaction /// The index of the item when the transaction started
/// </summary> /// </summary>
[Parameter] public int SourceIndex { get; private set; }
[Category(CategoryTypes.DropZone.DropRules)]
public string CanDropClass { get; set; }
/// <summary> /// <summary>
/// The CSS class(es), that is applied to drop zones that are NOT valid target for drag and drop transaction /// Identifier for drop zone where the transaction started
/// </summary> /// </summary>
[Parameter] public string SourceZoneIdentifier { get; init; }
[Category(CategoryTypes.DropZone.DropRules)]
public string NoDropClass { get; set; }
/// <summary> public string CurrentZone { get; private set; }
/// If true, drop classes CanDropClass <see cref="CanDropClass"/> or NoDropClass <see cref="NoDropClass"/> or applied as soon, as a transaction has started
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.DropRules)]
public bool ApplyDropClassesOnDragStarted { get; set; } = false;
/// <summary> #endregion
/// The method is used to determinate if an item should be disabled for dragging. Defaults to allow all items
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Disabled)]
public Func<T, bool> ItemIsDisabled { get; set; }
/// <summary> #region Styling
/// If a drop item is disabled (determinate by <see cref="ItemIsDisabled"/>). This class is applied to the element #endregion
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Disabled)]
public string DisabledClass { get; set; } = "disabled";
/// <summary> #region Behavior
/// An additional class that is applied to the drop zone where a drag operation started #endregion
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.DraggingClass)]
public string DraggingClass { get; set; }
/// <summary> #region Lifecycle
/// An additional class that is applied to an drop item, when it is dragged #endregion
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.DraggingClass)]
public string ItemDraggingClass { get; set; }
public event EventHandler<DragAndDropItemTransaction<T>> TransactionStarted;
public event EventHandler<DragAndDropIndexChangedEventArgs> TransactionIndexChanged;
public event EventHandler<DragAndDropTransactionFinishedEventArgs<T>> TransactionEnded; }
public event EventHandler RefreshRequested;
public void StartTransaction(T item, string identifier, int index, Func<Task> commitCallback, Func<Task> cancelCallback) /// <summary>
{ /// Used to encapsulate data for a drag and drop transaction
_transaction = new DragAndDropItemTransaction<T>(item, identifier, index, commitCallback, cancelCallback); /// </summary>
TransactionStarted?.Invoke(this, _transaction); /// <typeparam name="T"></typeparam>
}
public T GetTransactionItem() => _transaction.Item;
public bool TransactionInProgress() => _transaction != null; /// <summary>
public string GetTransactionOrignZoneIdentiifer() => _transaction?.SourceZoneIdentifier ?? string.Empty; /// Record encaplusalting data regaring a completed transaction
public string GetTransactionCurrentZoneIdentiifer() => _transaction?.CurrentZone ?? string.Empty; /// </summary>
public bool IsTransactionOriginatedFromInside(string identifier) => _transaction.SourceZoneIdentifier == identifier; /// <typeparam name="T">Type of dragged item</typeparam>
/// <param name="Item">The dragged item during the transaction</param>
/// <param name="DropzoneIdentifier">Identifier of the zone where the transaction started</param>
/// <param name="IndexInZone">The index of the item within in the dropzone</param>
public record ItemDropInfo<T>(T Item, string DropzoneIdentifier, int IndexInZone);
public int GetTransactionIndex() => _transaction?.Index ?? -1; public class DragAndDropTransactionFinishedEventArgs<T> : EventArgs
public bool IsItemMovedDownwards() => _transaction.Index > _transaction.SourceIndex;
public bool HasTransactionIndexChanged()
{ {
if (_transaction == null) public DragAndDropTransactionFinishedEventArgs(DragAndDropItemTransaction<T> transaction) :
this(string.Empty, false, transaction)
{ {
return false;
} }
if (_transaction.CurrentZone != _transaction.SourceZoneIdentifier) public DragAndDropTransactionFinishedEventArgs(string destinationDropzoneIdentifier, bool success, DragAndDropItemTransaction<T> transaction)
{ {
return true; Item = transaction.Item;
Success = success;
OriginatedDropzoneIdentifier = transaction.SourceZoneIdentifier;
DestinationDropzoneIdentifier = destinationDropzoneIdentifier;
OriginIndex = transaction.SourceIndex;
DestinationIndex = transaction.Index;
} }
return _transaction.Index != _transaction.SourceIndex; public T Item { get; }
public bool Success { get; }
public string OriginatedDropzoneIdentifier { get; }
public string DestinationDropzoneIdentifier { get; }
public int OriginIndex { get; }
public int DestinationIndex { get; }
} }
public bool IsOrign(int index, string identifier)
/// <summary>
/// The container of a drag and drop zones
/// </summary>
/// <typeparam name="T">Datetype of items</typeparam>
public partial class DropContainer<T> : UIComponent
{ {
if (_transaction == null) private DragAndDropItemTransaction<T> _transaction;
protected string Classname =>
new CssBuilder("drop-container")
.AddClass(AdditionalClassList)
.Build();
/// <summary>
/// Child content of component. This should include the drop zones
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Appearance)]
public RenderFragment ChildContent { get; set; }
/// <summary>
/// The items that can be drag and dropped within the container
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Items)]
public IEnumerable<T> Items { get; set; }
/// <summary>
/// The render fragment (template) that should be used to render the items within a drop zone
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Items)]
public RenderFragment<T> ItemRenderer { get; set; }
/// <summary>
/// The method is used to determinate if an item can be dropped within a drop zone
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Items)]
public Func<T, string, bool> ItemsSelector { get; set; }
/// <summary>
/// Callback that indicates that an item has been dropped on a drop zone. Should be used to update the "status" of the data item
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Items)]
public EventCallback<ItemDropInfo<T>> ItemDropped { get; set; }
/// <summary>
/// The method is used to determinate if an item can be dropped within a drop zone
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.DropRules)]
public Func<T, string, bool> CanDrop { get; set; }
/// <summary>
/// The CSS class(es), that is applied to drop zones that are a valid target for drag and drop transaction
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.DropRules)]
public string CanDropClass { get; set; }
/// <summary>
/// The CSS class(es), that is applied to drop zones that are NOT valid target for drag and drop transaction
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.DropRules)]
public string NoDropClass { get; set; }
/// <summary>
/// If true, drop classes CanDropClass <see cref="CanDropClass"/> or NoDropClass <see cref="NoDropClass"/> or applied as soon, as a transaction has started
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.DropRules)]
public bool ApplyDropClassesOnDragStarted { get; set; } = false;
/// <summary>
/// The method is used to determinate if an item should be disabled for dragging. Defaults to allow all items
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Disabled)]
public Func<T, bool> ItemIsDisabled { get; set; }
/// <summary>
/// If a drop item is disabled (determinate by <see cref="ItemIsDisabled"/>). This class is applied to the element
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.Disabled)]
public string DisabledClass { get; set; } = "disabled";
/// <summary>
/// An additional class that is applied to the drop zone where a drag operation started
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.DraggingClass)]
public string DraggingClass { get; set; }
/// <summary>
/// An additional class that is applied to an drop item, when it is dragged
/// </summary>
[Parameter]
[Category(CategoryTypes.DropZone.DraggingClass)]
public string ItemDraggingClass { get; set; }
public event EventHandler<DragAndDropItemTransaction<T>> TransactionStarted;
public event EventHandler<DragAndDropIndexChangedEventArgs> TransactionIndexChanged;
public event EventHandler<DragAndDropTransactionFinishedEventArgs<T>> TransactionEnded;
public event EventHandler RefreshRequested;
public void StartTransaction(T item, string identifier, int index, Func<Task> commitCallback, Func<Task> cancelCallback)
{ {
return false; _transaction = new DragAndDropItemTransaction<T>(item, identifier, index, commitCallback, cancelCallback);
TransactionStarted?.Invoke(this, _transaction);
} }
if (identifier != _transaction.SourceZoneIdentifier) public T GetTransactionItem() => _transaction.Item;
public bool TransactionInProgress() => _transaction != null;
public string GetTransactionOrignZoneIdentiifer() => _transaction?.SourceZoneIdentifier ?? string.Empty;
public string GetTransactionCurrentZoneIdentiifer() => _transaction?.CurrentZone ?? string.Empty;
public bool IsTransactionOriginatedFromInside(string identifier) => _transaction.SourceZoneIdentifier == identifier;
public int GetTransactionIndex() => _transaction?.Index ?? -1;
public bool IsItemMovedDownwards() => _transaction.Index > _transaction.SourceIndex;
public bool HasTransactionIndexChanged()
{ {
return false; if (_transaction == null)
} {
return false;
}
return _transaction.SourceIndex == index || _transaction.SourceIndex - 1 == index; if (_transaction.CurrentZone != _transaction.SourceZoneIdentifier)
} {
return true;
}
public async Task CommitTransaction(string dropzoneIdentifier, bool reorderIsAllowed) return _transaction.Index != _transaction.SourceIndex;
{ }
await _transaction.Commit();
var index = -1; public bool IsOrign(int index, string identifier)
if (reorderIsAllowed == true)
{ {
index = GetTransactionIndex() + 1; if (_transaction == null)
if (_transaction.SourceZoneIdentifier == _transaction.CurrentZone && IsItemMovedDownwards() == true) {
return false;
}
if (identifier != _transaction.SourceZoneIdentifier)
{ {
index -= 1; return false;
} }
return _transaction.SourceIndex == index || _transaction.SourceIndex - 1 == index;
} }
await ItemDropped.InvokeAsync(new ItemDropInfo<T>(_transaction.Item, dropzoneIdentifier, index)); public async Task CommitTransaction(string dropzoneIdentifier, bool reorderIsAllowed)
var transactionFinishedEventArgs = new DragAndDropTransactionFinishedEventArgs<T>(dropzoneIdentifier, true, _transaction); {
_transaction = null; await _transaction.Commit();
TransactionEnded?.Invoke(this, transactionFinishedEventArgs); var index = -1;
} if (reorderIsAllowed == true)
{
index = GetTransactionIndex() + 1;
if (_transaction.SourceZoneIdentifier == _transaction.CurrentZone && IsItemMovedDownwards() == true)
{
index -= 1;
}
}
public async Task CancelTransaction() await ItemDropped.InvokeAsync(new ItemDropInfo<T>(_transaction.Item, dropzoneIdentifier, index));
{ var transactionFinishedEventArgs = new DragAndDropTransactionFinishedEventArgs<T>(dropzoneIdentifier, true, _transaction);
await _transaction.Cancel(); _transaction = null;
var transactionFinishedEventArgs = new DragAndDropTransactionFinishedEventArgs<T>(_transaction); TransactionEnded?.Invoke(this, transactionFinishedEventArgs);
_transaction = null; }
TransactionEnded?.Invoke(this, transactionFinishedEventArgs);
}
public void UpdateTransactionIndex(int index) public async Task CancelTransaction()
{ {
var changed = _transaction.UpdateIndex(index); await _transaction.Cancel();
if (changed == false) { return; } var transactionFinishedEventArgs = new DragAndDropTransactionFinishedEventArgs<T>(_transaction);
_transaction = null;
TransactionEnded?.Invoke(this, transactionFinishedEventArgs);
}
TransactionIndexChanged?.Invoke(this, new DragAndDropIndexChangedEventArgs(_transaction.CurrentZone, _transaction.CurrentZone, _transaction.Index)); public void UpdateTransactionIndex(int index)
} {
var changed = _transaction.UpdateIndex(index);
if (changed == false) { return; }
internal void UpdateTransactionZone(string identifier) TransactionIndexChanged?.Invoke(this, new DragAndDropIndexChangedEventArgs(_transaction.CurrentZone, _transaction.CurrentZone, _transaction.Index));
{ }
var oldValue = _transaction.CurrentZone;
var changed = _transaction.UpdateZone(identifier);
if (changed == false) { return; }
TransactionIndexChanged?.Invoke(this, new DragAndDropIndexChangedEventArgs(_transaction.CurrentZone, oldValue, _transaction.Index)); internal void UpdateTransactionZone(string identifier)
} {
var oldValue = _transaction.CurrentZone;
var changed = _transaction.UpdateZone(identifier);
if (changed == false) { return; }
TransactionIndexChanged?.Invoke(this, new DragAndDropIndexChangedEventArgs(_transaction.CurrentZone, oldValue, _transaction.Index));
}
/// <summary>
/// Refreshes the dropzone and all items within. This is neded in case of adding items to the collection or changed values of items /// <summary>
/// </summary> /// Refreshes the dropzone and all items within. This is neded in case of adding items to the collection or changed values of items
public void Refresh() => RefreshRequested?.Invoke(this, EventArgs.Empty); /// </summary>
public void Refresh() => RefreshRequested?.Invoke(this, EventArgs.Empty);
} }

Loading…
Cancel
Save