با تشکر
<Routes> <Route path="/product/list" element={<ProductList/>} /> <Route path="/product/new" element={<NewProduct/>} /> </Routes>
<Routes> <Route path="/post" element={<Posts/>}> <Route path="images" element={<Images />} /> <Route path="text" element={<Text />} /> <Route path="/post" element={<Text />} /> </Route> </Routes>
<div className="list-group"> <Link to="/post/images" className="list-group-item list-group-item-action active" aria-current="true"> Images Post </Link> <Link to="/post/text" className="list-group-item list-group-item-action">Text Post</Link> </div> <Outlet />
<div className="list-group"> <Link to="images" className="list-group-item list-group-item-action active" aria-current="true"> Images Post </Link> <Link to="text" className="list-group-item list-group-item-action">Text Post</Link> </div> <Outlet />
<Routes> <Route path="/post" element={<Posts/>}> <Route path="images" element={<Images />} /> <Route path="text" element={<Text />} /> <Route path="/post" element={<Text />} /> </Route> </Routes>
<Routes> <Route path="/product/list" element={<ProductList/>} /> <Route path="/product/new" element={<NewProduct/>} /> <Route path="/post" element={<Posts/>}> <Route path="images" element={<Images />} /> <Route path="text" element={<Text />} /> <Route path="/post" element={<Text />} /> </Route> <Route path="*" element={<NotFound />} /> </Routes>
زمین بازی برای Nginx
یک زمین بازی ساده با امکانات ابتدایی برای Nginx
در صورتیکه فایلهای شما برای انشار نهایی آماده هستند، پروژه خود را در لیست سمت چپ برنامه انتخاب کنید تا در بالا و سمت راست برنامه، گزینهی Publish Repository دیده شود و با انتخاب آن، یک نام را که قبلا وارد کرده اید و یک توضیح مختصر را از شما میخواهد. به صورت پیش فرض انتشارها عمومی و رایگان هستند. در صورتی که اگر بخواهید این انتشار را تنها برای خود و به صورت احتصاصی انجام دهید، باید هزینه آن را پرداخت کنید.
در صورتیکه دوست دارید در پروژهای مشارکت داشته باشید، ابتدا پروژه مورد نظر را در سایت گیت هاب Fork کنید و سپس از طریق گزینهی Add در برنامه عمل کنید و اینبار در سربرگهای بالا، به جای Create گزینهی Clone را انتخاب نمایید. در این حالت لیستی از پروژههای Fork شده نمایش داده میشوند و با انتخاب هر کدام، پروژه بر روی سیستم شما کپی خواهد شد.
بعد از انتخاب گزینهی Clone، از شما محل ذخیرهی پروژه را خواهد پرسید و بعد از تایید آن، مقدار زمان کمی برای کپی کردن پروژه خواهد خواست. پس از آن لیستی از همهی تغییرات و مشارکتها به شما نمایش داده میشود و در صورتیکه دوست دارید به تغییری در قبل برگردید تا کارتان را از آن شروع کنید، میتوانید از گزینهی Revert استفاده کنید. برای یادگیری سایر اصطلاحات فنی گیت و گیتهاب میتوانید از مسیرهای آموزشی آن استفاده کنید.
حال با خیال راحت روی پروژه کار کنید و تغییرات را روی آن اعمال کنید و بعد از اینکه کارتان تمام شد، دوباره به برنامه باز گردید و پروژه را در لیست انتخاب کرده و در سمت راست بالای صفحه، گزینهی Sync Now را انتخاب کنید تا مشارکت جدید شما به سیستم گیت هاب اعمال شود و حالا اگر به صفحهی پروژه در سایت گیت هاب بروید، میبینید که شما به عنوان یک مشارکت کنندهی جدید اضافه شدهاید. پس با هر بار تغییر نسخهی پروژه میتوانید آن را با سیستم گیت سینک نمایید.
گزینهی تنظیمات که در کنار عبارت Sync Now قرار دارد و با رنگ آبی در شکل مشخص شده است نیز به شما اجازهی تغییر فایلهای تنظیماتی از قبیل gitignore یا gitattribute را میدهد.
در صورتی که برای پروژهای در گیت هاب شاخهها یا branches تعریف شده باشند، در اینجا هم میتوانید شاخهی مورد نظر را انتخاب کنید:
Ubuntu is distributed on two types of images described below.
Desktop image
The desktop image allows you to try Ubuntu without changing your
computer at all, and at your option to install it permanently later.
This type of image is what most people will want to use. You will need
at least 384MiB of RAM to install from this image.
Server install image
The server install image allows you to install Ubuntu permanently on a
computer for use as a server. It will not install a graphical user
interface.
ListBox
در مورد لیست، ما قبلا نام کشورها را با استفاده از تگ ListBoxItem به طور دستی اضافه میکردیم و هر گونه ویرایش و اضافه کردن عکس و دیگر اشیاء را داخل این تگ برای هر آیتم جداگانه انجام میدادیم؛ مثل تصویر زیر که هر آیتم شامل یک تگ تصویر و دو تگ TextBlock است که یکی از آنها رنگی شده است. کد هر آیتم به طور جداگانه و دستی اضافه شده است.
<ListBox Grid.Row="3" Name="MyListBox" Grid.Column="1" Margin="10" Height="80" > <ListBox.ItemTemplate> <DataTemplate> <WrapPanel> <Image Width="24" Height="24" Source="{Binding Flag}"></Image> <TextBlock Padding="5 5 0 0" Text="{Binding Name}"></TextBlock> </WrapPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
ارائه این نکته ضروری است که همه اشیاء خصوصیت DataContext را دارند و ما در مثال قبلی DataContext ریشه یا والد اشیاء را پر کردیم. اگر مقاله "ساختار سلسله مراتبی " را به یاد بیاورید، گفتیم که هر شیء در صورتیکه خصوصیت وابستهای برایش تعریف نشده باشد، به سمت اشیاء والد حرکت میکند، به این جهت بود که همهی کنترلها به منبع دادهها دسترسی داشتند. پس ما اگر DataContext لیست را پر کنیم، لیست دلیلی برای دسترسی به DataContext اشیاء والد ندارد و خصوصیت پر شدهی خودش را در نظر میگیرد. پس بیایید این مورد را امتحان کنیم:
من کلاس زیر را جهت ارسال لیستی از کشورها به همراه آدرس پرچمشان، بر میگردانم:
دلیل استفاده از کلاس ObservableCollection در کد زیر به جای استفاده از اشیایی چون Ilist و ... این بود که این کلاس به اینترفیس هایی چون INotifyPropertyChanged مزین گشته و هر گونه تغییری در این مجموعه، از قبیل حذف و اضافه را اطلاع رسانی کرده و مدل تغییر یافته را به سمت ویو هدایت میکند.
using System.Collections.ObjectModel; namespace test { public class Country { public string Flag { get { return "Images/flags/" + Name + ".png"; } } public string Name { get; set; } public int Id { get; set; } public ObservableCollection<Country> GetCountries() { var countries = new ObservableCollection<Country>(); countries.Add(new Country(){Id =1,Name = "Afghanistan"}); countries.Add(new Country() { Id = 2, Name = "Albania" }); countries.Add(new Country() { Id = 3, Name = "Angola" }); countries.Add(new Country() { Id = 4, Name = "Bahrain" }); countries.Add(new Country() { Id = 5, Name = "Bermuda" }); countries.Add(new Country() { Id =6, Name = "Iran" }); return countries; } } }
دلیل این مشکل این است که DataContext برای نمایش یک Object تهیه شده است و در مورد دادههای لیستی باید از خصوصیتی به نام ItemsSource استفاده کرد که برای دادههای لیستی IEnumerables، بهینه شده است.
پس به این ترتیب مینویسیم :
public MainWindow() { InitializeComponent(); person = Person.GetPerson(); DataContext = person; //خط جدید MyListBox.ItemsSource = new Country().GetCountries(); }
شکلهای زیر یک نمودار از ارتباط با Object برای واکشی داده هاست:
نمودار زیر هم دسترسی به مجموعه ای از دادههای لیستی است که از طریق ItemsSource خوانده میشوند:
کد زیر همچنین برای اتصال به کار میرود:
public MainWindow() { InitializeComponent(); person = Person.GetPerson(); DataContext = person; //خط جدید MyListBox.DataContext = new Country().GetCountries(); MyListBox.SetBinding(ItemsControl.ItemsSourceProperty, new Binding()); }
پی نوشت : روشهای دیگر بایند کردن همچون استفاده از منابع یا ریسورسها یا استفاده از ViewModelها هم هستند که در آینده در مورد آنها بیشتر صحبت خواهیم کرد.
حال که توانستیم لیست را پر کنیم باید کشوری را که در رکورد واکشی شده آمده است، در لیست انتخاب کنیم.
توجه داشته باشید که باید لیست را از طریق خصوصیت ItemsSource پر کرده باشید و DataContext را دستکاری نکرده باشید.
خصوصیت Country در کلاس Person میتواند به دو صورت زیر باشد:
public int Country { get; set; } public Country Country { get; set; }
<ListBox Grid.Row="3" Name="MyListBox" Grid.Column="1" Margin="10" Height="80" SelectedValuePath="Id" SelectedValue="{Binding Country}" > <ListBox Grid.Row="3" Name="MyListBox" Grid.Column="1" Margin="10" Height="80" SelectedValuePath="Id" SelectedValue="{Binding Country.Id}" >
خصوصیتهای دیگر یک شیء لیستی چون ListBox و ComboBox و ... SelectedIndex است که اندیس یک آیتم انتخابی را بازگردانده یا جهت انتخاب یک آیتم، اندیس آن را دریافت میکند. SelectedItem و SelectedItems هم شیء یا شیءهایی از مدل را (در اینجا Country) که در لیست انتخاب شدهاند، بر میگرداند (فقط خواندنی).
در تصویر بالا دو مسیر با آدرسهای : ShowPage1/ و ShowPage2/ تعریف شده است که هر کدام به یک view مشخص و یک Controller برای مدیریت آن اشاره میکند.
زمانی که ما از تزریق وابستگیها در AngularJs استفاده میکنیم و یک شیء را به کنترلر تزریق میکنیم، Angular توسط Injector$ سعی در پیدا کردن وابستگی مربوطه و سپس تزریق آن به کنترلر را انجام میدهد. برای استفاده از امکان مسیریابی Route ، ما نیز باید از پروایدر مخصوص آن برای تزریق استفاده کنیم. در Angular مسیرهای برنامه توسط پروایدری به نام routeProvider$ شناسایی میشود که خدمات مسیریابی را به ما ارائه میدهد. این سرویس به ما کمک میکند تا بتوانیم اتصال بین کنترلر ها، ویوها و آدرس URL جاری مرورگرها را به آسانی برقرار کنیم.
بهتر است کار را شروع کنیم . یک فایل JS ایجاد و سپس محتویات زیر را در آن قرار دهید :
var myFirstRoute = angular.module('myFirstRoute', []); myFirstRoute.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/pageOne', { templateUrl: 'templates/page_one.html', controller: 'ShowPage1Controller' }). when('/pageTwo', { templateUrl: 'templates/page_two.html', controller: 'ShowPage2Controller' }). otherwise({ redirectTo: '/pageOne' }); }]); myFirstRoute.controller('ShowPage1Controller', function($scope) { $scope.message = 'Content of page-one.html'; }); myFirstRoute.controller('ShowPage2Controller', function($scope) { $scope.message = 'Content of page-two.html'; });
در کدهای بالا ابتدا یک ماژول تعریف کرده ایم و سپس توسط ()config. تنظیمات مربوط به مسیریابی را انجام داده ایم. با استفاده از متدهای when. و otherwise. میتوانیم مسیرها را تعریف کنیم. برای هر مسیر دو پارامتر وجود دارد که اولین پارامتر نام مسیر و دومین پارامتر شامل 2 قسمت میشود که templateUrl آن آدرسی که باز خواهد شد و controller نیز نام کنترلری که ویو را مدیریت میکند.
توسط otherwise میتوانیم مسیر پیشفرض را نیز تعریف کنیم تا درصورتی که مسیری با آدرسهای بالای آن مطابقت نداشت به این آدرس منتقل شود.
در قطعه کد بالا همچنین دو مسیر با نامهای pageOne/ و pageTwo/ تعریف کرده ایم که هر کدام به ترتیب به Viewهای : templates/page_one.html و templates/page_two.html مرتبط شده اند. همچنین دو کنترلر برای مدیریت ویوها نیز تعریف شده است.
زمانی که ما آدرس http://appname/#pageOne را در نوار آدرس مرورگر وارد میکنیم، Angular به صورت اتوماتیک آدرس URL را با تنظیماتی که ما در اینجا تعریف کرده ایم مطابقت میدهد و در صورت وجود چنین آدرسی ، view مربوطه را بارگزاری میکند و در این مثال نیز مطابق با تنظیمات بالا، صفحهی templates/page_one.html برای ما بارگزاری و سپس کنترلر ShowPage1Controller را فراخوانی میکند ، جایی که ما منطق کار را در آن قرار میدهیم.
محتویات فایل main.html :
<body ng-app="app"> <div> <div> <div> <ul> <li><a href="#pageOne"> Show page one </a></li> <li><a href="#pageTwo"> Show page two </a></li> </ul> </div> <div> <div ng-view></div> </div> </div> </div> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="app.js"></script> </body>
در قطعه کد بالا دو لینک تعریف شده است که ویژگی href از علامت هش و نام صفحه تشکیل شده است. یکی از چیزهایی که شایان ذکر است ، دایرکتیو ng-view است. مکانی برای بارگزاری صفحات در آن.
ما میتوانیم این تگ را به سه شکل زیر نیز استفاده کنیم :
<div ng-view></div> .. <ng-view></ng-view> .. <div class="ng-view"></div>
محتویات صفحه templates/page_one.html :
<h2>Page One</h2> {{ message }}
محتویات صفحه templates/page_two.html :
<h2>Page Two</h2> {{ message }}
حال اگر پروژه را اجرا کنید و به کنسول مرور گر خود نگاه کنید متوجه میشوید که مسیریاب از مسیر پیشفرض استفاده کرده است و صفحهی page_one.html را به صورت ایجکسی فراخوانی کرده است :
و اگر روی لینک Show Page two کلیک کنید ، صفحهی page_two.html نیز به صورت ایجکسی فراخوانی میشود.
دوباره بر روی لینک Show page one کلیک کنید. بله. هیچ درخواستی به سمت سرور ارسال نشد و صفحهی page_one.html به خوبی نمایش داده شد. یکی از مزیتهای سیستم مسیریابی قابلیت کش کردن صفحات است تا در صورت فراخوانی مجدد، درخواستی به سمت سرور ارسال نشود و خیلی سریع به شما نمایش داده شود.
مثال این مطلب : RouteExample.zip
ادامه دارد ...
<?xml version="1.0" encoding="utf-8"?> <AccountingApplication> <Version>1.5.2</Version> <URL>http://www.myappsupport.ir</URL> </AccountingApplication>
... using System.Xml; namespace CheckUpdateApplication { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void CheckUpdate_Click(object sender, EventArgs e) { Version NewVersion = null; string DownloadPath = ""; try { XmlTextReader xmlRead = new XmlTextReader("http://www.myappsupport.ir/AccUpdateVersion.xml"); xmlRead.MoveToContent(); string elmName = ""; if ((xmlRead.NodeType == XmlNodeType.Element) && (xmlRead.Name == "AccountingApplication")) { while (xmlRead.Read()) { if (xmlRead.NodeType == XmlNodeType.Element) { elmName = xmlRead.Name; } else { if ((xmlRead.NodeType == XmlNodeType.Text) && (xmlRead.HasValue)) { switch (elmName) { case "Version": NewVersion = new Version(xmlRead.Value); break; case "URL": DownloadPath = xmlRead.Value; break; } } } } } Version AppVertion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; if (AppVertion.CompareTo(NewVersion) < 0) { DialogResult Result = MessageBox.Show("نسخه " + NewVersion.Major.ToString() + "." + NewVersion.Minor.ToString() + "." + NewVersion.Build.ToString() + " در دسترس میباشد مایل به دانلود هستید؟", "نسخه جدید", MessageBoxButtons.YesNo,MessageBoxIcon.Question); if (Result == DialogResult.Yes) { System.Diagnostics.Process.Start(DownloadPath); } } else { MessageBox.Show("نرم افزار بروز میباشد"); } } catch (Exception E) { MessageBox.Show(E.Message); } } } }
به روش زیر هم نسخه اسمبلی برنامه را میشود تغییر داد.
برای متغیرهای سراسری که در طول اجرای برنامه لازم است مقدار آنها حفظ شود کدام یک را پیشنهاد میکنید
مثلا نگهداری سال مالی جاری در یک سیستم مالی