2021年7月4日 星期日

Blazor.WebForm.UI - Blazor Component與WebForm Control

StarRatingComponent.razor

@for (int i = 1; i <= 5; i++)
{
    int rating = i;
    <a style="color: @GetColor(rating);font-size:30px;" href="javascript:" @onclick="() => OnChanged(rating)">★</a>
}

@code {
    [Parameter]
    public int CurrentRating { get; set; }

    [Parameter]
    public EventCallback<int> Changed { get; set; }

    private void OnChanged(int rating)
    {
        this.CurrentRating = rating;
        if (Changed.HasDelegate)
        {
            Changed.InvokeAsync(rating);
        }
    }

    private string GetColor(int rating)
    {
        if (rating <= this.CurrentRating)
        {
            return "#f49813";
        }
        else
        {
            return "#cccccc";
        }
    }
}

StarRatingControl.cs

    public class StarRatingControl : UserControl
    {
        public int CurrentRating { get; set; }

        public event EventHandler Changed;

        protected override void OnInit(EventArgs e)
        {
            for (int i = 1; i <= 5; i++)
            {
                LinkButton linkButton = new LinkButton();
                linkButton.Style[HtmlTextWriterStyle.FontSize] = "30px";
                linkButton.Text = "★";
                linkButton.CommandArgument = i.ToString();
                linkButton.Click += this.LinkButton_Click;
                linkButton.PreRender += this.LinkButton_PreRender;
                this.Controls.Add(linkButton);
            }
            base.OnInit(e);
        }

        private void LinkButton_Click(object sender, EventArgs e)
        {
            LinkButton linkButton = (LinkButton)sender;
            int rating = Convert.ToInt32(linkButton.CommandArgument);
            this.CurrentRating = rating;
            if (Changed != null)
            {
                Changed.Invoke(this, e);
            }
        }

        private void LinkButton_PreRender(object sender, EventArgs e)
        {
            LinkButton linkButton = (LinkButton)sender;
            int rating = Convert.ToInt32(linkButton.CommandArgument);
            if (rating <= this.CurrentRating)
            {
                linkButton.Style[HtmlTextWriterStyle.Color] = "#f49813";
            }
            else
            {
                linkButton.Style[HtmlTextWriterStyle.Color] = "#cccccc";
            }
        }
    }

StarRatingControlInComponent.razor

@using System.Web.UI;
@inherits ControlComponent<StarRatingControl>
@this.RenderControl()
@code {
    [Parameter]
    public int CurrentRating
    {
        get
        {
            return this.Control.CurrentRating;
        }
        set
        {
            this.Control.CurrentRating = value;
        }
    }

    [Parameter]
    public EventCallback<int> Changed { get; set; }

    protected override void OnInitialized()
    {
        this.Control.Changed += this.OnChanged;
    }

    private void OnChanged(object sender, EventArgs e)
    {
        if (Changed.HasDelegate)
        {
            Changed.InvokeAsync(this.CurrentRating);
        }
    }
}

StarRatingComponentInControl.cs

    public class StarRatingComponentInControl : UserControl, IRenderComponentControl
    {
        private StarRatingComponent _starRating;

        public int CurrentRating { get; set; }

        public event EventHandler Changed;

        private void OnChanged()
        {
            this.CurrentRating = _starRating.CurrentRating;
            if (Changed != null)
            {
                Changed.Invoke(this, EventArgs.Empty);
            }
        }

        Type IRenderComponentControl.ComponentType
        {
            get
            {
                return typeof(StarRatingComponent);
            }
        }

        void IRenderComponentControl.ComponentReferenceCapture(object componentReference)
        {
            _starRating = (StarRatingComponent)componentReference;
        }

        void IRenderComponentControl.RenderAttributes(IHtmlAttributesWriter writer)
        {
            writer.AddSingleAttribute(nameof(this.CurrentRating), this.CurrentRating);
            writer.AddEventAttribute<int>(nameof(this.Changed), this, this.OnChanged);
        }

        void IRenderComponentControl.RenderContents(IHtmlContentsWriter writer)
        {

        }
    }

StarRatingList.razor

@using System.Web.UI;
@page "/starrating-list"
@inherits ControlComponent
<h3>StarRating List</h3>

@for (int i = 1; i <= 5; i++)
{
    @i
    <StarRatingControlInComponent CurrentRating="i"></StarRatingControlInComponent>
    <br />
}

<hr />

@this.RenderControl()

@code {
    protected override void OnInitialized()
    {
        for (int i = 1; i <= 5; i++)
        {
            this.Controls.Add(new LiteralControl($"{i}"));

            StarRatingComponentInControl starRating = new StarRatingComponentInControl();
            starRating.CurrentRating = i;
            this.Controls.Add(starRating);

            this.Controls.Add(new LiteralControl("<br />"));
        }
    }
}