حالا میخوام ستون تشخیص هم که یه ستون از نوع string هست هم آخرین مقدار اون ستون رو بگیره.
به عنوان مثال در عکس بالا جاهایی که Highlight شده میبایست مقدار "بدهکار" داشته باشد.
آیا باز هم باید از توابع تجمعی سفارشی استفاده کنم؟
حالا میخوام ستون تشخیص هم که یه ستون از نوع string هست هم آخرین مقدار اون ستون رو بگیره.
به عنوان مثال در عکس بالا جاهایی که Highlight شده میبایست مقدار "بدهکار" داشته باشد.
آیا باز هم باید از توابع تجمعی سفارشی استفاده کنم؟
public static string UnicodeFrom(TextEncoding textEncoding, string iranSystemEncodedString) { // وهله سازی از انکودینگ صحیح برای تبدیل رشته ایران سیستم به بایت Encoding encoding = Encoding.GetEncoding((int)textEncoding); // حذف فاصلههای موجود در رشته iranSystemEncodedString = iranSystemEncodedString.Replace(" ", ""); if (iranSystemEncodedString.Length <= 0) return ""; // تبدیل رشته به بایت byte[] stringBytes = encoding.GetBytes(iranSystemEncodedString.Trim()); // تغییر ترتیب بایت هااز آخر به اول در صورتی که رشته تماماً عدد نباشد if (!IsNumber(iranSystemEncodedString)) { stringBytes = stringBytes.Reverse().ToArray(); } // آرایه ای که بایتهای معادل را در آن قرار میدهیم // مجموع تعداد بایتهای رشته + بایتهای اضافی محاسبه شده byte[] newStringBytes = new byte[stringBytes.Length + CountCharactersRequireTwoBytes(stringBytes)]; int index = 0; // بررسی هر بایت و پیدا کردن بایت (های) معادل آن for (int i = 0; i < stringBytes.Length; ++i) { byte charByte = stringBytes[i]; // اگر جز 128 بایت اول باشد که نیازی به تبدیل ندارد چون کد اسکی است if (charByte < 128) { newStringBytes[index] = charByte; } else { // اگر جز حروف یا اعداد بود معادلش رو قرار میدیم if (CharactersMapper.ContainsKey(charByte)) { newStringBytes[index] = CharactersMapper[charByte]; } } // اگر کاراکتر ایران سیستم "لا" بود چون کاراکتر متناظرش در عربی 1256 "ل" است و باید یک "ا" هم بعدش اضافه کنیم if (charByte == 242) { newStringBytes[++index] = 199; } // اگر کاراکتر یکی از انواعی بود که بعدشان باید یک فاصله باشد // و در عین حال آخرین کاراکتر رشته نبود if (charactersWithSpaceAfter.Contains(charByte) && Array.IndexOf(stringBytes, charByte) != stringBytes.Length - 1) { // یک فاصله بعد ان اضافه میکنیم newStringBytes[++index] = 32; } index += 1; } // تبدیل به رشته و ارسال به فراخواننده byte[] unicodeContent = Encoding.Convert(encoding, Encoding.Unicode, newStringBytes); string result = Encoding.Unicode.GetString(unicodeContent).Trim(); result = result.Replace("ڑ", "ء").Replace("ؤ", "ئ"); //در صورتی که عدد داخل رشته نیست نیاز به ادامه کار نمیباشد if (!Regex.IsMatch(result, @"\d")) return result; bool isLastDigit = false; string tempForDigits = ""; string str=""; for (int i = 0; i < result.Length; i++) { if (Regex.IsMatch(result[i].ToString(), @"\d") || (i+1<result.Length && Regex.IsMatch(result[i].ToString() + result[i+1].ToString(), @"/\d"))) { isLastDigit = true; tempForDigits += result[i]; } else { if (isLastDigit && tempForDigits.Length > 0) { str += new string(tempForDigits.Reverse().ToArray()); isLastDigit = false; tempForDigits = ""; } str += result[i]; } if (!String.IsNullOrWhiteSpace(tempForDigits) && i == result.Length - 1) { str += new string(tempForDigits.Reverse().ToArray()); } } return str; }
یک نکتهی تکمیلی: نحوهی نامگذاری ویژهی عناصر در فرمهای جدید Blazor SSR
اگر با نگارشهای دیگر Blazor کار کرده باشید، عموما یک EditForm را به صفحه اضافه کرده و چند المان را به آن اضافه میکنیم و ... کار میکند. حتی اگر کامپوننتهای سفارشی را هم بر این مبنا تهیه کنیم ... بازهم بدون نکتهی خاصی کار میکنند. اما ... در برنامههای Blazor SSR اینطور نیست! زمانیکه برای مثال مدل فرم را به این صورت تعریف میکنیم:
[SupplyParameterFromForm] public OrderPlace? MyModel { get; set; }
و آنرا به نحو متداولی در صفحه نمایش میدهیم:
<InputText @bind-Value="MyModel.City"/>
اگر به المان رندر شدهی در مرورگر مراجعه کنیم، ویژگی name حاصل، با MyModel.City مقدار دهی شدهاست و ... این موضوع درج نام خاصیت مدل (و یا اصطلاحا Html Field Prefix)، برای Blazor SSR بسیار مهم است! تاحدی که اگر از آن آگاه نباشید، ممکن است ساعتی را مشغول دیباگ برنامه شوید که چرا، مقدار نالی را دریافت کردهاید و یا عناصر تعریف شدهی در کامپوننتهای سفارشی، کار نمیکنند و مقدار نمیگیرند!
متاسفانه API بازگشت نام کامل عناصری که توسط Blazor SSR تولید میشود، عمومی نیست و internal است. اگر از کامپوننتهای استاندارد خود Blazor استفاده میکنید، نیازی نیست تا به این موضوع فکر کنید و مدیریت آن خودکار است؛ اما همینکه قصد تولید کامپوننتهای سفارشی مخصوص SSR را داشته باشید، اولین مشکلی را که با آن مواجه خواهید شد، دقیقا همین مسالهی تولید صحیح HtmlFieldPrefixها است.
برای رفع این مشکل و دسترسی به API پشت صحنهی تولید نام فیلدها در Blazor SSR، میتوان از کامپوننت پایهی InputBase خود Blazor ارثبری کرد و به این ترتیب به خاصیت جدید NameAttributeValue آن دسترسی یافت (این خاصیت به داتنت 8 و مخصوص Blazor SSR، اضافه شدهاست) که اینکار در کلاس BlazorHtmlField انجام شدهاست. روش استفادهی از آن هم به صورت زیر است:
private BlazorHtmlField<T?> ValueField => new(ValueExpression ?? throw new InvalidOperationException(message: "Please use @bind-Value here.")); [Parameter] public T? Value { set; get; } [Parameter] public EventCallback<T?> ValueChanged { get; set; } [Parameter] public Expression<Func<T?>> ValueExpression { get; set; } = default!;
زمانیکه میخواهیم در یک کامپوننت سفارشی، خاصیتی bind پذیر را طراحی کنیم، روش کار آن، مانند مثال فوق است که به همراه یک خاصیت، یک EventCallback و یک Expression است تا اعتبارسنجی و انقیاد دوطرفه را فعال کند. اما ... اگر همین Value را مستقیما در فیلدهای کامپوننت استفاده کنیم ... مقدار نمیگیرد؛ چون به همراه نام کامل خاصیت بایند شدهی به آن نیست. برای مثال بجای MyModel.City فقط City درج میشود (که به علت نداشتن .MyModel، سیستم binding از مقدار آن صرفنظر میکند). اکنون با استفاده از BlazorHtmlField فوق، میتوان به نام کامل تولیدی توسط Blazor SSR دسترسی یافت و از آن استفاده کرد:
<input type="text" dir="ltr" name="@ValueField.HtmlFieldName" id="@ValueField.HtmlFieldName" />
HtmlFieldName ای که در اینجا درج میشود، توسط خود Blazor محاسبه شده و با انتظارات موتور binding آن تطابق دارد و دیگر به خواص بایند شدهای که مقدار نمیگیرند، نخواهیم رسید.
public class EntityConfigurations { internal static void LoadEntityConfigurations(Assembly[] asm, DbModelBuilder modelBuilder) { if (asm == null) throw new ArgumentNullException(nameof(asm)); foreach (var configurations in asm.Select(assembly => assembly.GetTypes() .Where( type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)) .ToList())) { configurations.ForEach(type => { dynamic instance = Activator.CreateInstance(type); modelBuilder.Configurations.Add(instance); }); } } }
/// <summary> /// /// </summary> /// <param name="modelBuilder"></param> protected override void OnModelCreating(DbModelBuilder modelBuilder) { EntityConfigurations.LoadEntityConfigurations(AppDomain.CurrentDomain.GetAssemblies(), modelBuilder); }
import Pagination from "./common/pagination";
<Pagination itemsCount={this.state.movies.length} pageSize={this.state.pageSize} onPageChange={this.handlePageChange} />
state = { movies: getMovies(), pageSize: 4 };
handlePageChange = page => { console.log("handlePageChange", page); };
import React, { Component } from "react"; class Pagination extends Component { render() { return ( <nav> <ul className="pagination"> <li className="page-item"> <a className="page-link">1</a> </li> </ul> </nav> ); } } export default Pagination;
class Pagination extends Component { // ... getPageNumbersArray() { const { itemsCount, pageSize } = this.props; const pagesCount = Math.ceil(itemsCount / pageSize); if (pagesCount === 1) { return null; } const pages = new Array(); for (let i = 1; i <= pagesCount; i++) { pages.push(i); } return pages; } }
class Pagination extends Component { render() { const pages = this.getPageNumbersArray(); if (!pages) { return null; } return ( <nav> <ul className="pagination"> {pages.map(page => ( <li key={page} className="page-item"> <a className="page-link">{page}</a> </li> ))} </ul> </nav> ); }
<a onClick={() => this.props.onPageChange(page)} className="page-link" style={{ cursor: "pointer" }} > {page} </a>
<Pagination itemsCount={this.state.movies.length} pageSize={this.state.pageSize} onPageChange={this.handlePageChange} currentPage={this.state.currentPage} />
class Movies extends Component { state = { movies: getMovies(), pageSize: 4, currentPage: 1 };
handlePageChange = page => { console.log("handlePageChange", page); this.setState({currentPage: page}); };
<li key={page} className={ page === this.props.currentPage ? "page-item active" : "page-item" } >
paginate() { const first = (this.state.currentPage - 1) * this.state.pageSize; const last = first + this.state.pageSize; return this.state.movies.slice(first, last); }
render() { const { length: count } = this.state.movies; if (count === 0) return <p>There are no movies in the database.</p>; const movies = this.paginate();
> npm i -g typescript eslint tslint eslint-plugin-react-hooks jshint babel-eslint eslint-plugin-react eslint-plugin-mocha
> npm i prop-types --save
C:/Users/{username}/AppData/Local/Microsoft/TypeScript/3.6/node_modules/@types/prop-types/index
import PropTypes from "prop-types";
Pagination.propTypes = { itemsCount: PropTypes.number.isRequired, pageSize: PropTypes.number.isRequired, currentPage: PropTypes.number.isRequired, onPageChange: PropTypes.func.isRequired }; export default Pagination;
البته این خطا فقط در حالت development مشاهده میشود و در حالت توزیع برنامه، خیر.
private static readonly Regex _htmlRegex = new Regex("<.*?>", RegexOptions.Compiled);
/// <summary>
/// حذف تمامی تگهای موجود
/// </summary>
/// <param name="html">ورودی اچ تی ام ال</param>
/// <returns></returns>
public static string CleanTags(string html)
{
return _htmlRegex.Replace(html, string.Empty);
}
private static readonly Regex _contentRegex = new Regex(@"<\/?script[^>]*?>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>
/// تنها حذف یک تگ ویژه
/// </summary>
/// <param name="html">ورودی اچ تی ام ال</param>
/// <returns></returns>
public static string CleanScriptTags(string html)
{
return _contentRegex.Replace(html, string.Empty);
}
private static readonly Regex _safeStrRegex = new Regex(@"<script[^>]*?>[\s\S]*?<\/script>",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
/// <summary>
/// حذف یک تگ ویژه به همراه محتویات آن
/// </summary>
/// <param name="html">ورودی اچ تی ام ال</param>
/// <returns></returns>
public static string CleanScriptsTagsAndContents(string html)
{
return _safeStrRegex.Replace(html, "");
}
using NUnit.Framework;
namespace testWinForms87
{
[TestFixture]
public class CTestRegExHelper
{
#region Methods (3)
// Public Methods (3)
[Test]
public void TestCleanScriptsTagsAndContents()
{
Assert.AreEqual(
CRegExHelper.CleanScriptsTagsAndContents("data1 <script> ... </script> data2"),
"data1 data2");
}
[Test]
public void TestCleanScriptTags()
{
Assert.AreEqual(
CRegExHelper.CleanScriptTags("<b>data1</b> <script> ... </script> data2"),
"<b>data1</b> ... data2");
}
[Test]
public void TestCleanTags()
{
Assert.AreEqual(
CRegExHelper.CleanTags("<b>data</b>"),
"data");
}
#endregion Methods
}
}
<httpRuntime executionTimeout="1200" maxRequestLength="39936" />
using System;
using System.Configuration;
using System.Web.Configuration;
/// <summary>
/// کلاسی جهت نمایش اندازه مجاز فایل قابل ارسال به سرور
/// </summary>
public class CMaxLimit
{
/// <summary>
/// اندازه مجاز فایل قابل ارسال به سرور
/// </summary>
/// <returns></returns>
public static string MaxFileUploadSizeLimit()
{
//مقدار پیش فرض
int resultKB = 4096;
//machine.config
Configuration mConfig =
WebConfigurationManager.OpenMachineConfiguration();
bool mConfigIsLocked = false;
HttpRuntimeSection section =
mConfig.GetSection("system.web/httpRuntime") as HttpRuntimeSection;
if (section != null)
{
resultKB = section.MaxRequestLength;
mConfigIsLocked = section.ElementInformation.IsLocked;
}
//web.config
if (!mConfigIsLocked)
{
HttpRuntimeSection httpRuntimeSection =
WebConfigurationManager.GetSection("system.web/httpRuntime") as HttpRuntimeSection;
if (httpRuntimeSection != null)
{
resultKB = httpRuntimeSection.MaxRequestLength;
}
}
return
SizeToString(resultKB * 1024);
}
/// <summary>
/// نمایش اندازه یک فایل به صورتی قابل درک
/// </summary>
/// <param name="len">اندازه فایل</param>
/// <returns></returns>
public static string SizeToString(long len)
{
int order = 0;
string[] sizes = new[] { "B", "KB", "MB", "GB" };
while (len >= 1024 && order + 1 < sizes.Length)
{
order++;
len = len / 1024;
}
return String.Format("{0:0.##} {1}", len, sizes[order]);
}
}