Разрешить только одно редактируемое поле одновременно в пользовательском компоненте - PullRequest
1 голос
/ 21 марта 2019

Я работаю в веб-формах, и у меня есть ряд полей для ввода с одинаковым шаблоном. У них есть метка для отображения текста, который может переключаться в текстовое поле одним нажатием кнопки, сохраняя его.

Я хочу, чтобы пользователь редактировал только одно поле одновременно, так что если он начнет редактировать второе поле, первое поле будет сохранено.

Мой код как есть:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace vk_HVK_Web.User_Controls
{
    [ValidationProperty("Text")]
    [ToolboxData("<{0}:EditableLabel runat=server></{0}:EditableLabel>")]
    public partial class EditableLabel : System.Web.UI.UserControl
    {
        public event EventHandler OnSave;
        public static EditableLabel CurrentEditing;
        public string DisplayText { get
            {
                return this.Text.ToUpper();
            }
        }
        public string Text { get => txtInput.Text; set => txtInput.Text = value; }

        public bool Editable { get => txtInput.Visible; set => txtInput.Visible = value; }

        protected void Page_PreRender(object sender, EventArgs e)
        {
            if (Editable)
            {
                txtInput.Visible = true;
                lblText.Visible = false;
                btnEditSave.CssClass = "fas fa-save";
                sectionEditable.CssClass = "col";
            }
            else
            {
                lblText.Visible = true;
                txtInput.Visible = false;
                btnEditSave.CssClass = "fas fa-pencil-alt";
                sectionEditable.CssClass = "col col-form-label text-left";
            }
            lblText.Text = DisplayText;
        }
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void txtInput_TextChanged(object sender, EventArgs e)
        {
            this.Text = txtInput.Text;
        }

        protected void btnEditSave_Click(object sender, EventArgs e)
        {
            if (Editable)
            {
                Save();
            } else
            {
                Edit();
            }

        }

        public void Edit()
        {
            if (CurrentEditing != null && CurrentEditing != this && CurrentEditing.Editable)
                CurrentEditing.Save();
            CurrentEditing = this;
            Editable = true;
        }
        public void Save()
        {
            Editable = false;
            if (OnSave != null)
                OnSave(this, EventArgs.Empty);
        }
    }
}

Я не верю, что код из дизайна полезен, но в любом случае вот он:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="EditableLabel.ascx.cs" Inherits="vk_HVK_Web.User_Controls.EditableLabel" %>
<div class="row">
                    <div class="col-12">
                        <div class="row">
                            <div class="col-4 col-form-label text-right">Start Date: </div>
                            <asp:Panel runat="server" id="sectionEditable">
                                <asp:Label ID="lblText" runat="server" Text="" ></asp:Label>
                                <asp:TextBox Visible="false" ID="txtInput" runat="server" Text="" OnTextChanged="txtInput_TextChanged" CssClass="form-control" ></asp:TextBox>
                            </asp:Panel>
                            <div class="col-4 col-form-label">
                                <span><asp:LinkButton ID="btnEditSave" runat="server" OnClick="btnEditSave_Click" /></span>
      </div>

    </div>
  </div>
</div>

Как вы можете видеть, когда они нажимают кнопку для редактирования, первое, что она делает, это проверяет, редактируется ли что-то еще, и если это так, чтобы сохранить это. Метод save изменяет состояние компонента и делает его больше недоступным для редактирования.

Как и в стенде, переключение само по себе прекрасно работает, но вызов метода Save() статической переменной, похоже, никак не влияет на его состояние.

Помощь будет принята с благодарностью. Я очень плохо знаком с веб-формами, поэтому, если я делаю неправильное управление состоянием, подскажите, пожалуйста, как это сделать правильно. Спасибо.

1 Ответ

0 голосов
/ 23 марта 2019

Хорошо, это заняло у меня 2 дня, но я знаю, что хорошо разбираюсь в ASP.NET.

Мое решение было двукратным, во-первых, я почему-то думал, что статические времена жизни для каждого пользователя, как в интерфейсных средах, что не так. Это означало, что оно было доступно всем пользователям и всем страницам. Не хорошо, правда?

Так как я хотел, чтобы это было на странице, я использовал ViewState. У пользовательских элементов управления есть свои ViewState, и мне нужны были Page, но это был protected, и мне было запрещено его использовать.

Я выставил ViewState, используя следующий класс расширения:

    public static class SharedViewStateExtension
    {
        public static StateBag GetProtectedViewState(this Page page)
        {
            var viewStateField = typeof(Page).GetProperty("ViewState", BindingFlags.NonPublic | BindingFlags.Instance);
            return (StateBag) viewStateField.GetValue(page);
        }
    }

Конечно, все, что вы помещаете в ViewState, должно быть сериализуемым, и я не мог этого сделать. Поэтому я сохранил EditableLabels в словаре уровня сеанса, где ключом является GUID, сохраненный в ViewState.

Вторая проблема заключается в том, что ControlFromPriviousPageLoad != ControlFromNextPageLoad. Новые компоненты генерируются для каждой загрузки страницы. Вместо этого я прибегаю к сравнению идентификаторов, которые в любом случае должны быть уникальными для каждой страницы.

Я знаю, что все это звучит странно, но ASP.NET отвратителен, поэтому давайте просто остановимся.

Результирующий класс: https://paste.rs/9bU.cs

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...