Skip to content

Lose focus not trigger when click on form #37

@SMAH1

Description

@SMAH1

When edit textbox then click on form (Not button/textbox/...), LoseFus not work.
Add TODO in below code:

using Aprillz.MewUI;
using Aprillz.MewUI.Controls;

Window window = null!;
TextBox inputTextBox = null!;
StackPanel itemsPanel = null!;
List<TodoItem> items = new();

if (OperatingSystem.IsWindows())
{
    Application.DefaultGraphicsBackend = GraphicsBackend.Direct2D;
}
else
{
    Application.DefaultGraphicsBackend = GraphicsBackend.OpenGL;
}

var root = new Window()
    .Ref(out window)
    .Title("Editable List Demo")
    .Resizable(600, 500)
    .Padding(20)
    .Content(
        new DockPanel()
            .LastChildFill()
            .Children(
                CreateInputSection().DockTop(),
                CreateListSection()
            )
    );

Application.Run(root);

FrameworkElement CreateInputSection()
{
    return new StackPanel()
        .Orientation(Orientation.Vertical)
        .Spacing(10)
        .Margin(0, 0, 0, 20)
        .Children(
            new Grid()
                .Columns("Auto,*,Auto")
                .Rows("Auto")
                .Spacing(8)
                .Children(
                    new Label()
                        .Text("Your Data")
                        .FontSize(16)
                        .Bold(),
                    new TextBox()
                        .Ref(out inputTextBox)
                        .Placeholder("Type something...")
                        .OnKeyDown((e) =>
                        {
                            if (e.Key == Key.Enter)
                            {
                                AddItem();
                            }
                        }),
                    new Button()
                        .Content("Add")
                        .Width(80)
                        .OnClick(AddItem)
                )
        );
}

FrameworkElement CreateListSection()
{
    return new Border()
        .BorderThickness(1)
        .Padding(10)
        .Apply(b =>
        {
            b.CornerRadius = 8;
            b.Child = new ScrollViewer()
            .VerticalScroll(ScrollMode.Auto)
            .Content(
                new StackPanel()
                    .Ref(out itemsPanel)
                    .Orientation(Orientation.Vertical)
                    .Spacing(5)
            );
        });
}

void AddItem()
{
    var text = inputTextBox.Text?.Trim();
    if (string.IsNullOrEmpty(text))
        return;

    var item = new TodoItem(text);
    items.Add(item);

    var itemElement = CreateItemElement(item);
    itemsPanel.Children(itemElement);

    inputTextBox.Text = string.Empty;
}

FrameworkElement CreateItemElement(TodoItem item)
{
    Label label = null!;
    TextBox editBox = null!;
    Border itemBorder = null!;
    StackPanel contentStack = null!;

    var labelElement = new Label()
        .Ref(out label)
        .Text(item.Text)
        .FontSize(14)
        .Padding(5)
        .OnMouseDoubleClick((e) =>
        {
            StartEdit(item);
            e.Handled = true;
        });

    var editElement = new TextBox()
        .Ref(out editBox)
        .Text(item.Text)
        .OnKeyDown((e) =>
        {
            if (e.Key == Key.Enter)
            {
                FinishEdit(item, editBox.Text ?? string.Empty);
            }
            else if (e.Key == Key.Escape)
            {
                CancelEdit(item);
            }
        })
        .OnLostFocus(() =>
        {
            // TODO: Lose focus not trigger when click on form
            if (item.IsEditing)
            {
                FinishEdit(item, editBox.Text ?? string.Empty);
            }
        });

    item.Label = label;
    item.EditBox = editBox;

    var deleteButton = new Button()
        .Content("Delete")
        .Width(70)
        .FontSize(12)
        .OnClick(() =>
        {
            if (item.IsEditing)
            {
                FinishEdit(item, editBox.Text ?? string.Empty);
            }
            DeleteItem(item);
        });

    var contentPanel = new DockPanel()
        .Spacing(10)
        .Children(
            deleteButton.DockRight(),
            new StackPanel()
                .Ref(out contentStack)
                .Orientation(Orientation.Vertical)
                .Children(labelElement)  // Start with only label visible
        );

    itemBorder = new Border()
        .BorderBrush(Color.FromRgb(100, 100, 100))
        .Padding(8)
        .BorderThickness(1)
        .Apply(b =>
        {
            b.CornerRadius = 6;
            b.Child = contentPanel;
        });

    item.Container = itemBorder;
    item.ContentStack = contentStack;

    return itemBorder;
}

void StartEdit(TodoItem item)
{
    item.IsEditing = true;

    // Replace label with editbox in the content stack
    if (item.ContentStack != null && item.EditBox != null)
    {
        item.EditBox.Text = item.Text;
        item.ContentStack.Clear();
        item.ContentStack.Children(item.EditBox);
        item.EditBox.Focus();
    }
}

void FinishEdit(TodoItem item, string newText)
{
    newText = newText.Trim();
    if (!string.IsNullOrEmpty(newText))
    {
        item.Text = newText;
        if (item.Label != null)
            item.Label.Text(newText);
    }

    item.IsEditing = false;

    // Replace editbox with label in the content stack
    if (item.ContentStack != null && item.Label != null)
    {
        item.ContentStack.Clear();
        item.ContentStack.Children(item.Label);
    }
}

void CancelEdit(TodoItem item)
{
    item.IsEditing = false;

    // Replace editbox with label in the content stack
    if (item.ContentStack != null && item.Label != null)
    {
        item.ContentStack.Children(item.Label);
    }
}

void DeleteItem(TodoItem item)
{
    items.Remove(item);

    // Remove from UI by rebuilding without this item
    var remainingElements = new List<FrameworkElement>();
    foreach (var todoItem in items)
    {
        if (todoItem.Container != null)
        {
            remainingElements.Add(todoItem.Container);
        }
    }

    itemsPanel.Clear();
    itemsPanel.Children(remainingElements.ToArray());
}

class TodoItem
{
    public string Text { get; set; }
    public bool IsEditing { get; set; }
    public Label? Label { get; set; }
    public TextBox? EditBox { get; set; }
    public Border? Container { get; set; }
    public StackPanel? ContentStack { get; set; }

    public TodoItem(string text)
    {
        Text = text;
        IsEditing = false;
    }
}

Sample Run:

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions