به مثال زیر توجه کنید:
class EventSource : System.Progress<int> { public async System.Threading.Tasks.Task<int> PerformExpensiveCalculation() { var sum = 0; for (var i = 0; i < 100; i++) { await System.Threading.Tasks.Task.Delay(100); sum += i; this.OnReport(sum); } return sum; } } static class Program { static void Main(string[] args) { var source = new EventSource(); System.EventHandler<int> handler = (_, progress) => System.Console.WriteLine(progress); source.ProgressChanged += handler; System.Console.WriteLine(source.PerformExpensiveCalculation().Result); source.ProgressChanged -= handler; source.ProgressChanged += ProgressChangedMethod; System.Console.WriteLine(source.PerformExpensiveCalculation().Result); source.ProgressChanged -= ProgressChangedMethod; } private static void ProgressChangedMethod( object sender, int e ) { System.Console.WriteLine(e); } }
خوب؛ برای اندازه گیری کارآیی این دو روش باید کمی فکر کنیم که چه چیزی کارآیی این دو روش را تغییر میدهد؟
آیا پردازش event با اضافه کردن و حذف کردن event handler؟ و یا پردازش درون event باعث تغییر در کارآیی میشود؟
این، سوال مهمی در تست کارآیی این دو روش مختلف است. اگر پردازش درون event باعث ایجاد تفاوت کارآیی میشود، با استفاده از این برنامه میتوان آن را اندازه گیری کرد. با این حال اگر تفاوت کارآیی با اضافه کردن و حذف کردن event handler اتفاق میافتد، با این برنامه بعید است بتوان این روش را تست کرد چرا که فقط یکبار این عمل انجام میشود.
قبل از شروع به اندازه گیری کارآیی این دو روش، اجازه بدهید ابتدا به کد IL آنها نگاهی کنیم. (روش اول با استفاده از Lambda syntax)
IL_0007: ldsfld class [mscorlib]System.EventHandler`1<int32> LambdaPerformance.Program/'<>c'::'<>9__0_0' IL_000c: dup IL_000d: brtrue.s IL_0026 IL_000f: pop IL_0010: ldsfld class LambdaPerformance.Program/'<>c' LambdaPerformance.Program/'<>c'::'<>9' IL_0015: ldftn instance void LambdaPerformance.Program/'<>c'::'<Main>b__0_0'(object, int32) IL_001b: newobj instance void class [mscorlib]System.EventHandler`1<int32>::.ctor(object, native int) IL_0020: dup IL_0021: stsfld class [mscorlib]System.EventHandler`1<int32> LambdaPerformance.Program/'<>c'::'<>9__0_0' IL_0026: stloc.1 IL_0027: ldloc.0 IL_0028: ldloc.1 IL_0029: callvirt instance void class [mscorlib]System.Progress`1<int32>::add_ProgressChanged(class [mscorlib]System.EventHandler`1<!0>) IL_002e: nop IL_002f: ldloc.0 IL_0030: callvirt instance class [mscorlib]System.Threading.Tasks.Task`1<int32> LambdaPerformance.EventSource::PerformExpensiveCalculation() IL_0035: callvirt instance !0 class [mscorlib]System.Threading.Tasks.Task`1<int32>::get_Result() IL_003a: call void [mscorlib]System.Console::WriteLine(int32) IL_003f: nop IL_0040: ldloc.0 IL_0041: ldloc.1 IL_0042: callvirt instance void class [mscorlib]System.Progress`1<int32>::remove_ProgressChanged(class [mscorlib]System.EventHandler`1<!0>)
قبل از شروع مقایسه، کد IL روش دوم را نیز بررسی میکنیم:
IL_004a: ldftn void LambdaPerformance.Program::ProgressChangedMethod(object, int32) IL_0050: newobj instance void class [mscorlib]System.EventHandler`1<int32>::.ctor(object, native int) IL_0055: callvirt instance void class [mscorlib]System.Progress`1<int32>::add_ProgressChanged(class [mscorlib]System.EventHandler`1<!0>) IL_005a: nop IL_005b: ldloc.0 IL_005c: callvirt instance class [mscorlib]System.Threading.Tasks.Task`1<int32> LambdaPerformance.EventSource::PerformExpensiveCalculation() IL_0061: callvirt instance !0 class [mscorlib]System.Threading.Tasks.Task`1<int32>::get_Result() IL_0066: call void [mscorlib]System.Console::WriteLine(int32) IL_006b: nop IL_006c: ldloc.0 IL_006d: ldnull IL_006e: ldftn void LambdaPerformance.Program::ProgressChangedMethod(object, int32) IL_0074: newobj instance void class [mscorlib]System.EventHandler`1<int32>::.ctor(object, native int) IL_0079: callvirt instance void class [mscorlib]System.Progress`1<int32>::remove_ProgressChanged(class [mscorlib]System.EventHandler`1<!0>)
برای اندازه گیری دقیق، برنامهی بالا را کمی تغییر میدهیم. ما میزان اضافه و حذف شدن event handler را میخواهیم اندازهگیری کنیم و کاری به زمان اجرای یک عملیات نداریم. بنابراین فراخوانی ()PerformExpensiveCalculation را comment کرده و به صورت خیلی ساده فقط handler را اضافه و حذف میکنیم.
static class Program { static void Main(string[] args) { for (var repeats = 10; repeats <= 1000000; repeats *= 10) { VersionOne(repeats); VersionTwo(repeats); } } private static void VersionOne(int repeats) { var timer = new System.Diagnostics.Stopwatch(); timer.Start(); var source = new EventSource(); for (var i = 0; i < repeats; i++) { System.EventHandler<int> handler = (_, progress) => System.Console.WriteLine(progress); source.ProgressChanged += handler; // Console.WriteLine(source.PerformExpensiveCalculation().Result); source.ProgressChanged -= handler; } timer.Stop(); System.Console.WriteLine($"Version one: {repeats} add/remove takes {timer.ElapsedMilliseconds}ms"); } private static void VersionTwo(int repeats) { var timer = new System.Diagnostics.Stopwatch(); timer.Start(); var source = new EventSource(); for (var i = 0; i < repeats; i++) { source.ProgressChanged += ProgressChangedMethod; // Console.WriteLine(source.PerformExpensiveCalculation().Result); source.ProgressChanged -= ProgressChangedMethod; } timer.Stop(); System.Console.WriteLine($"Version two: {repeats} add/remove takes {timer.ElapsedMilliseconds}ms"); } private static void ProgressChangedMethod(object sender, int e) { System.Console.WriteLine(e); } }
Version one: 10 add/remove takes 0ms Version two: 10 add/remove takes 0ms Version one: 100 add/remove takes 0ms Version two: 100 add/remove takes 0ms Version one: 1000 add/remove takes 0ms Version two: 1000 add/remove takes 0ms Version one: 10000 add/remove takes 0ms Version two: 10000 add/remove takes 1ms Version one: 100000 add/remove takes 8ms Version two: 100000 add/remove takes 13ms Version one: 1000000 add/remove takes 93ms Version two: 1000000 add/remove takes 121ms
توجه: اگر در برنامهی شما یک میلیون بار event handler اضافه و حذف میشوند، نیاز به بازنگری مجدد در طراحی کلی برنامه تان دارد.
یک اشتباه بزرگ
با ایجاد یک تغییر در روش اول (Lambda syntax)، ممکن است تاثیر بسیار زیادی را در عملکرد برنامه مشاهده کنید:private static void VersionOne(int repeats) { var timer = new System.Diagnostics.Stopwatch(); timer.Start(); var source = new EventSource(); for (var i = 0; i < repeats; i++) { // System.EventHandler<int> handler = (_, progress) => System.Console.WriteLine(progress); source.ProgressChanged += (_, progress) => System.Console.WriteLine(progress); // Console.WriteLine(source.PerformExpensiveCalculation().Result); source.ProgressChanged -= (_, progress) => System.Console.WriteLine(progress); } timer.Stop(); System.Console.WriteLine($"Version one: {repeats} add/remove takes {timer.ElapsedMilliseconds}ms"); }
Version one: 10 add/remove takes 0ms Version two: 10 add/remove takes 0ms Version one: 100 add/remove takes 1ms Version two: 100 add/remove takes 0ms Version one: 1000 add/remove takes 102ms Version two: 1000 add/remove takes 0ms Version one: 10000 add/remove takes 10509ms Version two: 10000 add/remove takes 1ms Version one: 100000 add/remove takes 1039014ms Version two: 100000 add/remove takes 11ms
IL_0018: nop IL_0019: ldloc.1 IL_001a: ldsfld class [mscorlib]System.EventHandler`1<int32> LambdaPerformance.Program/'<>c'::'<>9__1_0' IL_001f: dup IL_0020: brtrue.s IL_0039 IL_0022: pop IL_0023: ldsfld class LambdaPerformance.Program/'<>c' LambdaPerformance.Program/'<>c'::'<>9' IL_0028: ldftn instance void LambdaPerformance.Program/'<>c'::'<VersionOne>b__1_0'(object, int32) IL_002e: newobj instance void class [mscorlib]System.EventHandler`1<int32>::.ctor(object, native int) IL_0033: dup IL_0034: stsfld class [mscorlib]System.EventHandler`1<int32> LambdaPerformance.Program/'<>c'::'<>9__1_0' IL_0039: callvirt instance void class [mscorlib]System.Progress`1<int32>::add_ProgressChanged(class [mscorlib]System.EventHandler`1<!0>) IL_003e: nop IL_003f: ldloc.1 IL_0040: ldsfld class [mscorlib]System.EventHandler`1<int32> LambdaPerformance.Program/'<>c'::'<>9__1_1' IL_0045: dup IL_0046: brtrue.s IL_005f IL_0048: pop IL_0049: ldsfld class LambdaPerformance.Program/'<>c' LambdaPerformance.Program/'<>c'::'<>9' IL_004e: ldftn instance void LambdaPerformance.Program/'<>c'::'<VersionOne>b__1_1'(object, int32) IL_0054: newobj instance void class [mscorlib]System.EventHandler`1<int32>::.ctor(object, native int) IL_0059: dup IL_005a: stsfld class [mscorlib]System.EventHandler`1<int32> LambdaPerformance.Program/'<>c'::'<>9__1_1' IL_005f: callvirt instance void class [mscorlib]System.Progress`1<int32>::remove_ProgressChanged(class [mscorlib]System.EventHandler`1<!0>) IL_0064: nop IL_0065: nop IL_0066: ldloc.2 IL_0067: stloc.3 IL_0068: ldloc.3 IL_0069: ldc.i4.1 IL_006a: add IL_006b: stloc.2 IL_006c: ldloc.2 IL_006d: ldarg.0 IL_006e: clt IL_0070: stloc.s V_4 IL_0072: ldloc.s V_4 IL_0074: brtrue.s IL_0018
ممکن است شما به این نتیجه رسیده باشید که استفاده از Lambda syntax برای اضافه و حذف کردن event handler آهستهتر از، استفاده از متد جدا است، این یک اشتباه بزرگ است. در صورتی که شما اضافه و حذف کردن event handler را با استفاده از Lambda syntax به شکل صحیح انجام ندهید، به سرعت، در معیارهای کارآیی خود را نشان میدهد.
دانلود برنامه بالا
jQuery 3.5.0 منتشر شد
The main change in this release is a security fix, and it’s possible you
will need to change your own code to adapt. Here’s why: jQuery used a
regex in its jQuery.htmlPrefilter
method to ensure that all closing tags were XHTML-compliant when passed
to methods. For example, this prefilter ensured that a call like jQuery("<div class='hot' />")
is actually converted to jQuery("<div class='hot'></div>")
. Recently, an issue was reported that demonstrated the regex could introduce a cross-site scripting (XSS) vulnerability.
مصاحبه با خالق ++C
مطالبی که در این ویدئو به آن پرداخته میشود :
What is the keynote about? How do we write modern C++ code? Guideline support library and Static analysis Call to action for the C++ community! Enhancing productivity by eliminating whole classes of bugs Extending the C++ core guidelines What do you expect from these static analysis checkers? How can I get started?
This is the first of an eight part series where I am joined by Phil Japikse to discuss design patterns. A design pattern is a best practice you can use in your code to solve a common problem. In this episode, Phil demonstrates the Command and Memento patterns.
Episodes in this series:
- Command/Memento patterns (this episode)
- Strategy pattern
- Template Method pattern (to be published 7/20)
- Observer/Publish-Subscribe patterns (to be published 7/25)
- Singleton pattern (to be published 8/8)
- Factory patterns (to be published 8/10)
- Adapter/Facade patterns (to be published 8/15)
- Decorator pattern (to be published 8/17)
Fixed In This Release of Visual Studio 2019 version 16.5
- Modified the find "List View" to work with the VsColorOutput extension.
- Fixed a regression introduced with version 16.5 where use of default indexed properties with value-types caused an internal compiler error.
- Modified find in files to preserve user settings between Visual Studio 2019 sessions.
- Fixed an issue where Goto next/previous entry failed to work in the find results list when "preview selected files in find results" is turned off.
- Fixed an issue with find when doing a regex search a pattern that did not contain regex special characters.
- Fixed the button placement in find in files tool window when its in a docked position. Changed alignments for better experience in docked mode.
- Fixed an issue where the find list view did not navigate to results when enter was hit.
- Fixed an issue where Goto next/previous entry failed to work in the find results list when "preview selected files in find results" is turned off.
Security Advisory Notice
CVE-2020-0899 Microsoft Visual Studio Elevation of Privilege Vulnerability
CVE-2020-0900 Visual Studio Extension Installer Service Elevation of Privilege Vulnerability
CVE-2020-5260 Git for Visual Studio Credential Leak Vulnerability due to insufficient validation on URLs
پروژهی WpfDesigner
What I've learned from 20 years of programming in C# with Joe Albahari with Q&A session - YouTube
In April 2001, I wrote and published my first C# program. Join me in discovering the most valuable principles that I've learned in the 20 years of C# programming that followed. We'll cover a range of topics, with plenty of samples and useful code that you can take away.
00:00 - Introduction
01:04 - Types
18:55 - Functional Programming
19:43 - What Defines Functional Programming?
33:26 - Lazy Values
36:20 - Cache a function - Memoizer
41:49 - Using a Closure instead of a Class
43:24 - Memoizer example
45:07 - Asynchronous Programming
47:58 - How do we abstract around Futures?
53:54 - Asynchronous locking
58:04 - Implementing A-synch lock with Semaphore
01:09:48 - Await inside a UI method vs a library method
01:18:04 - Using Exceptions
01:36:18 - Implementing a Retry
01:39:02 - IEither interface
01:39:58 - Downloading samples on LINQPad
01:40:27 - Q&A Session
زمانی که سیستم عامل های GUI مثل ویندوز به بازار آمدند، یکی از قسمتهای گرافیکی آنها AddressBar نام داشت که مسیر حرکت آنها را در فایل سیستم نشان میداد و در سیستم عاملهای متنی CLI با دستور cd یا pwd انجام میشد. بعدها در وب هم همین حرکت با نام BreadCrumb صورت گرفت که به عنوان مثال مسیر رسیدن به صفحهی یک محصول یا یک مقاله را نشان میداد. در یک پروژهی اندرویدی نیاز بود تا یک ساختار درختی را پیاده سازی کنم، ولی در برنامههای اندروید ایجاد یک درخت، کار هوشمندانه و مطلوبی نیست و روش کار به این صورت است که یک لیست از گروههای والد را نمایش داده و با انتخاب هر آیتم لیست به آیتمهای فرزند تغییر میکند. حالا مسئله این بود که کاربر باید مسیر حرکت خودش را بشناسد. به همین علت مجبور شدم یک BreadCrumb را برای آن طراحی کنم که در زیر تصویر آن را مشاهده میکنید.
از نکات جالب توجه در مورد این ماژول میتوان گفت که قابلیت این را دارد تا تصمیمات خود را بر اساس اندازههای مختلف صفحه نمایش بگیرد. به عنوان مثال اگر آیتمهای بالا بیشتر از سه عدد باشد و در صفحه جا نشود از یک مسیر جعلی استفاده میکند و همهی آیتمها با اندیس شماره 1 تا index-3 را درون یک آیتم با عنوان (...) قرار میدهد که من به آن میگویم مسیر جعلی. به عنوان نمونه مسیر تصویر بالا در صفحه جا شده است و نیازی به این کار دیده نشده است. ولی تصویر زیر از آن جا که مسیر، طول width صفحه نمایش رد کرده است، نیاز است تا چنین کاری انجام شود. موقعیکه کاربر آیتم ... را کلیک کند، مسیر باز شده و به محل index-3 حرکت میکند. یعنی دو مرحله به عقب باز میگردد.
نگاهی به کارکرد ماژول
قبل از توضیح در مورد سورس، اجازه دهید نحوهی استفاده از آن را ببینیم.
این سورس شامل دو کلاس است که سادهترین کلاس آن AndBreadCrumbItem میباشد که مشابه کلاس ListItem در بخش وب دات نت است و دو مقدار، یکی متن و دیگری Id را میگیرد:
سورس:
public class AndBreadCrumbItem { private int Id; private String diplayText; public AndBreadCrumbItem(int Id, String displayText) { this.Id=Id; this.diplayText=displayText; } public String getDiplayText() { return diplayText; } public void setDiplayText(String diplayText) { this.diplayText = diplayText; } public int getId() { return Id; } public void setId(int id) { Id = id; } }
به عنوان مثال میخواهیم یک breadcrumb را با مشخصات زیر بسازیم:
AndBreadCrumbItem itemhome=new AndBreadCrumbItem(0,"Home"); AndBreadCrumbItem itemproducts=new AndBreadCrumbItem(12,"Products"); AndBreadCrumbItem itemdigital=new AndBreadCrumbItem(15,"Digital"); AndBreadCrumbItem itemhdd=new AndBreadCrumbItem(56,"Hard Disk Drive");
AndBreadCrumb breadCrumb=new AndBreadCrumb(this); breadCrumb.AddNewItem(itemhome); breadCrumb.AddNewItem(itemproducts); breadCrumb.AddNewItem(itemdigital); breadCrumb.AddNewItem(itemhdd);
breadCumb.setContext(this);
پس از افزودن آیتم ها، تنظیمات زیر را اعمال نمایید:
LinearLayout layout=(LinearLayout)getActivity().findViewById(R.id.breadcumblayout); layout.setPadding(8, 8, 8, 8); breadCrumb.setLayout(layout); breadCrumb.SetTinyNextNodeImage(R.drawable.arrow); breadCrumb.setTextSize(25); breadCrumb.SetViewStyleId(R.drawable.list_item_style);
حال برای رسم آن متد UpdatePath را صدا میزنیم:
breadCrumb.UpdatePath();
الان اگر برنامه اجرا شود باید breadcrumb از چپ به راست رسم گردد. برای استفادههای فارسی، راست به چپ میتوانید از متد زیر استفاده کنید:
breadCrumb.setRTL(true);
در صورتیکه قصد دارید تنظیمات بیشتری چون رنگ متن، فونت متن و ... را روی هر المان اعمال کنید، از رویداد زیر استفاده کنید:
breadCrumb.setOnTextViewUpdate(new ITextViewUpdate() { @Override public TextView UpdateTextView(Context context, TextView tv) { tv.setTextColor(...); tv.setTypeface(...); return tv; } });
همچنین در صورتیکه میخواهید بدانید کاربر بر روی چه عنصری کلیک کرده است، از رویداد زیر استفاده کنید:
breadCumb.setOnClickListener(new IClickListener() { @Override public void onClick(int position, int Id) { //... } });
آخرین متد موجود که کمترین استفاده را دارد، متد SetNoResize است. در صورتیکه این متد با True مقداردهی گردد، عملیات تنظیم بر اساس صفحهی نمایش لغو میشود. این متد برای زمانی مناسب است که به عنوان مثال شما از یک HorozinalScrollView استفاده کرده باشید. در این حالت layout شما هیچ گاه به پایان نمیرسد و بهتر هست عملیات اضافه را لغو کنید.
نگاهی به سورس
کلاس زیر شامل بخشهای زیر است:
فیلدهای خصوصی
//=-=--=-=-=-=-=-=-=-=-=-=-=- Private Properties -=-=-=-=-=-=-=--=-=-= private List<AndBreadCrumbItem> items=null; private List<TextView> textViews; private int tinyNextNodeImage; private int viewStyleId; private Context context; private boolean RTL; private float textSize=20; private boolean noResize=false; LinearLayout layout; IClickListener clickListener; ITextViewUpdate textViewUpdate; LinearLayout.LayoutParams params ;
اینترفیسها هم با حرف I شروع و برای تعریف رویدادها ایجاد شدهاند. در ادامه از تعدادی متد get و Set برای مقدار دهی بعضی از فیلدهای خصوصی بالا استفاده شده است:
//=-=---=-=-=-=-- Constructor =--=-=-=-=-=--=-=- public AndBreadCrumb(Context context) { this.context=context; params = new LinearLayout.LayoutParams (LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); } //=-=-=--=--=-=-=-=-=-=-=-=- Public Properties --=-=-=-=-=-=--=-=-=-=-=-=- //each category would be added to create path public void AddNewItem(AndBreadCrumbItem item) { if(items==null) items=new ArrayList<>(); items.add(item); } // if you want a pointer or next node between categories or textviews public void SetTinyNextNodeImage(int resId) {this.tinyNextNodeImage=resId;} public void SetViewStyleId(int resId) {this.viewStyleId=resId;} public void setTextSize(float textSize) {this.textSize = textSize;} public boolean isRTL() { return RTL; } public void setRTL(boolean RTL) { this.RTL = RTL; } public void setLayout(LinearLayout layout) { this.layout = layout; } public void setContext(Context context) { this.context = context; } public boolean isNoResize() { return noResize; } public void setNoResize(boolean noResize) { this.noResize = noResize; }
بعد از آن به متدهای خصوصی میرسیم که متد زیر، متد اصلی ما برای ساخت breadcrumb است:
//primary method for render objects on layout private void DrawPath() { //stop here if essentail elements aren't present if (items == null) return ; if (layout == null) return; if (items.size() == 0) return; //we need to get size of layout,so we use the post method to run this thread when ui is ready layout.post(new Runnable() { @Override public void run() { //textviews created here one by one int position = 0; textViews = new ArrayList<>(); for (AndBreadCrumbItem item : items) { TextView tv = MakeTextView(position, item.getId()); tv.setText(item.getDiplayText()); textViews.add(tv); position++; } //add textviews on layout AddTextViewsOnLayout(); //we dont manage resizing anymore if(isNoResize()) return; //run this code after textviews Added to get widths of them TextView last_tv=textViews.get(textViews.size()-1); last_tv.post(new Runnable() { @Override public void run() { //define width of each textview depend on screen width BatchSizeOperation(); } }); } }); }
TextView tv=new TextView(this); tv.getWidth(); //return 0 layout.add(tv); tv.getWidth(); //return 0
TextView tv=new TextView(this); tv.post(new Runnable() { @Override public void run() { tv.getWidth(); //return x } });
باز میگردیم به متد DrawPath و داخل متد post
در اولین خط این پروسه به ازای هر آیتم، یک TextView توسط متد MakeTextView ساخته میشود که شامل کد زیر است:
private TextView MakeTextView(final int position, final int Id) { //settings for cumbs TextView tv=new TextView(this.context); tv.setEllipsize(TextUtils.TruncateAt.END); tv.setSingleLine(true); tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); tv.setBackgroundResource(viewStyleId); /*call custom event - this event will be fired when user click on one of textviews and returns position of textview and value that user sat as id */ tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SetPosition(position); clickListener.onClick(position, Id); } }); //if user wants to update each textviews if(textViewUpdate!=null) tv=textViewUpdate.UpdateTextView(context,tv); if(isRTL()) tv.setRotationY(180); return tv; }
در خطوط اولیه، یک Textview ساخته و متد Ellipsize را با Truncate.END مقداردهی مینماید. این مقدار دهی باعث میشود اگر متن، در Textview جا نشد، ادامهی آن با ... مشخص شود. در خط بعدی Textview را تک خطه معرفی میکنیم. در خط بعدی اندازهی قلم را بر اساس آنچه کاربر مشخص کرده است، تغییر میدهیم و بعد هم استایل را برای آن مقداردهی میکنیم. بعد از آن رویداد کلیک را برای آن مشخص میکنیم تا اگر کاربر بر روی آن کلیک کرد، رویداد اختصاصی خودمان را فراخوانی کنیم.
در خط بعدی اگر rtl با true مقدار دهی شده باشد، textview را حول محور Y چرخش میدهد تا برای زبانهای راست به چپ چون فارسی آماده گردد و در نهایت Textview ساخته شده و به سمت متد DrawPath باز میگرداند.
بعد از ساخته شدن TextViewها، وقت آن است که به Layout اضافه شوند که وظیفهی اینکار بر عهدهی متد AddTextViewOnLayout است:
//this method calling by everywhere to needs add textviews on the layout like master method :drawpath private void AddTextViewsOnLayout() { //prepare layout //remove everything on layout for recreate it layout.removeAllViews(); layout.setOrientation(LinearLayout.HORIZONTAL); layout.setVerticalGravity(Gravity.CENTER_VERTICAL); if(isRTL()) layout.setRotationY(180); //add textviews one by one int position=0; for (TextView tv:textViews) { layout.addView(tv,params); //add next node image between textviews if user defined a next node image if(tinyNextNodeImage>0) if(position<(textViews.size()-1)) { layout.addView(GetNodeImage(), params); position++; } } }
تا به اینجا کار چیدمان به ترتیب انجام شده است ولی از آنجا که اندازهی Layout در هر گوشی و در دو حالت حالت افقی یا عمودی نگه داشتن گوشی متفاوت است، نمیتوان به این چینش اعتماد کرد که به چه نحوی عناصر نمایش داده خواهند شد و این مشکل توسط متد BatchSizeOperation (تغییر اندازه دسته جمعی) حل میگردد. در اینجا هم باز متد post به آخرین textview اضافه شده است. به این علت که موقعیکه همهی textviewها در ui جا خوش کردند، بتوانیم به خاصیتهای ui آنها دستیابی داشته باشیم. حالا بعد از ترسیم باید اندازه آنها را اصلاح کنیم. قدم به قدم متد BatchSizeOperation را بررسی میکنیم:
//set textview width depend on screen width private void BatchSizeOperation() { //get width of next node between cumbs Bitmap tinyBmap = BitmapFactory.decodeResource(context.getResources(), tinyNextNodeImage); int tinysize=tinyBmap.getWidth(); //get sum of nodes tinysize*=(textViews.size()-1); ... }
//get width size of screen(layout is screen here) int screenWidth=GetLayoutWidthSize(); //get sum of arrows and cumbs width int sumtvs=tinysize; for (TextView tv : textViews) { int width=tv.getWidth(); sumtvs += width; }
private int GetLayoutWidthSize() { int width=layout.getWidth(); int padding=layout.getPaddingLeft()+layout.getPaddingRight(); width-=padding; return width; }
private void BatchSizeOperation() { .... //if sum of cumbs is less than screen size the state is good so return same old textviews if(sumtvs<screenWidth) return ; if(textViews.size()>3) { //make fake path MakeFakePath(); //clear layout and add textviews again AddTextViewsOnLayout(); } //get free space without next nodes -> and spilt rest of space to textviews count to get space for each textview int freespace =screenWidth-tinysize; int each_width=freespace/textViews.size(); //some elements have less than each_width,so we should leave size them and calculate more space again int view_count=0; for (TextView tv:textViews) { if (tv.getWidth()<=each_width) freespace=freespace-tv.getWidth(); else view_count++; } if (view_count==0) return; each_width=freespace/view_count; for (TextView tv:textViews) { if (tv.getWidth()>each_width) tv.setWidth(each_width); } }
اگر آیتمها بیشتر از سه عدد باشند، میتوانیم از حالت مسیر جعلی استفاده کنیم که توسط متد MakeFakePath انجام میشود. البته بعد از آن هم باید دوباره viewها را چینش کنیم تا مسیر جدید ترسیم گردد، چون ممکن است بعد از آن باز هم جا نباشد یا آیتمها بیشتر از سه عدد نیستند. در این حالت، حداقل کاری که میتوانیم انجام دهیم این است که فضای موجود را بین آنها تقسیم کنیم تا همهی کاسه، کوزهها سر آیتم آخر نشکند و متنش به ... تغییر یابد و حداقل از هر آیتم، مقداری از متن اصلی نمایش داده شود. پس میانگین فضای موجود را گرفته و بر تعداد المانها تقسیم میکنیم. البته این را هم باید در نظر گرفت که در تقسیم بندی، بعضی آیتمها آن مقدار پهنا را نیاز ندارند و با پهنای کمتر هم میشود کل متنشان را نشان داد. پس یک کار اضافهتر این است که مقدار پهنای اضافی آنها را هم حساب کنیم و فقط آیتمهایی را پهنا دهیم که به مقدار بیشتری از این میانگین احتیاج دارند. در اینجا کار به پایان میرسد و مسیر نمایش داده میشود.
نحوهی کارکرد متد MakeFakePath بدین صورت است که 4 عدد TextView را ایجاد کرده که المانهای با اندیس 0 و 2 و 3 به صورت نرمال و عادی ایجاد شده و همان کارکرد سابق را دارند. ولی المان شماره دو با اندیس 1 با متن ... نمایندهی آیتمهای میانی است و رویدادکلیک آن به شکل زیر تحریف یافته است:
//if elements are so much(mor than 3),we make a fake path to decrease elements private void MakeFakePath() { //we make 4 new elements that index 1 is fake element and has a rest of real path in its heart //when user click on it,path would be opened textViews=new ArrayList<>(4); TextView[] tvs=new TextView[4]; int[] positions= {0,items.size()-3,items.size()-2,items.size()-1}; for (int i=0;i<4;i++) { //request for new textviews tvs[i]=MakeTextView(positions[i],items.get(positions[i]).getId()); if(i!=1) tvs[i].setText(items.get(positions[i]).getDiplayText()); else { tvs[i].setText("..."); //override click event and change it to part of code to open real path by call setposition method and redraw path tvs[i].setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int pos = items.size() - 3; int id = items.get(pos).getId(); SetPosition(items.size() - 3); clickListener.onClick(pos, id); } }); } textViews.add(tvs[i]); } }
NHibernate 5.0 منتشر شد
** Highlights
* IO bound methods have gained an async counterpart. Not intended for parallelism, make sure to await each
call before further interacting with a session and its queries.
* Strongly typed DML operation (insert/update/delete) are now available as Linq extensions on queryables.
* Entities collections can be queried with .AsQueryable() Linq extension without being fully loaded.
* Reference documentation has been curated and completed, notably with a Linq section.