- این برنامه برای اجرا نیاز به دات نت فریم ورک 4 دارد. بنابراین بر روی ویندوزهای XP SP3 به بعد قابل اجرا است.
- ضمنا خطاهای برنامه در فایل متنی به نام ErrorsLog.Log در کنار فایل اجرایی برنامه ثبت میشوند.
[Display(Name = "رایانامه")] [Required(AllowEmptyStrings = false, ErrorMessage = "رایانامه خود را وارد کنید.")] [RegularExpression("\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*", ErrorMessage = "نشانی رایانامه پذیرفتنی نمیباشد.")] [ExistField(Action = "EmailExist", Namespace = "Parsnet.Controllers", Controller = "Account", ErrorMessage = "این رایانامه پیشتر به کار گرفته شده است.")] public string Email { get; set; }
@Html.TextBoxFor(m => m.Email, new { @class = "form-control en", placeholder = @Html.DisplayNameFor(m => m.Email) })
<input data-val="true" data-val-existfiledvalidator="این رایانامه پیشتر به کار گرفته شده است." data-val-existfiledvalidator-url="/account/emailexist" data-val-regex="نشانی رایانامه پذیرفتنی نمیباشد." data-val-regex-pattern="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" data-val-required="رایانامه خود را وارد کنید." id="Email" name="Email" placeholder="رایانامه" value="" type="text">
namespace Parsnet { public static MvcHtmlString SpanFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes) { var sb = new StringBuilder(); var span = new TagBuilder("span"); var metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData); var name = ExpressionHelper.GetExpressionText(expression); var fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name); var value = ""; if (metadata.Model != null && metadata.Model.GetType() == typeof(List<IdentityProvider.IdentityRole>)) { var modelList = (List<IdentityProvider.IdentityRole>)metadata.Model; value = String.Join("، ", modelList.Select(r => r.Name)); } else { value = htmlHelper.FormatValue(metadata.Model, null); } span.MergeAttributes<string, object>(((IDictionary<string, object>)HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes))); var fieldName = fullName.Split('.')[1]; span.MergeAttribute("data-name", fieldName, true); span.MergeAttributes<string, object>(htmlHelper.GetUnobtrusiveValidationAttributes(name, metadata)); sb.Append(span.ToString(TagRenderMode.StartTag)); sb.Append(value); sb.Append(span.ToString(TagRenderMode.EndTag)); return new MvcHtmlString(sb.ToString()); } } }
var metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData);
var name = ExpressionHelper.GetExpressionText(expression); var fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
if (metadata.Model != null && metadata.Model.GetType() == typeof(List<IdentityProvider.IdentityRole>)) { var modelList = (List<IdentityProvider.IdentityRole>)metadata.Model; value = String.Join("، ", modelList.Select(r => r.Name)); } else { value = htmlHelper.FormatValue(metadata.Model, null); }
span.MergeAttributes<string, object>(((IDictionary<string, object>)HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)));
span.MergeAttributes<string, object>(htmlHelper.GetUnobtrusiveValidationAttributes(name, metadata));
@Html.SpanFor(m => m.Profile.Email, new { @class = "editor", data_type = "text" })
<span class="editor" data-name="Email" data-type="text" data-val="true" data-val-existfiledvalidator="این رایانامه پیشتر به کار گرفته شده است." data-val-existfiledvalidator-url="/account/emailexist" data-val-regex="نشانی رایانامه پذیرفتنی نمیباشد." data-val-regex-pattern="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" data-val-required="رایانامه خود را وارد کنید.">alireza_s_84@yahoo.com</span>
و پس از ویرایش:
var app = angular.module('myApp', []);
app.directive('angry', function () { return { restrict: 'E', template: '<div style="color:red"> I am angry!</div>' } })
app.directive('happy', function () { return { restrict: 'A', template: '<div style="color:blue"> I am happy!</div>' }; })
<script type="text/javascript" src="~/scripts/Modules/module1.js"></script> <div ng-app="myApp"> <angry></angry> <div happy></div> </div>
<body> <component type="typeof(App)" render-mode="ServerPrerendered" />
<body> <component type="typeof(App)" render-mode="ServerPrerendered" /> <div id="blazor-error-ui"> <environment include="Staging,Production"> An error has occurred. This application may no longer respond until reloaded. </environment> <environment include="Development"> An unhandled exception has occurred. See browser dev tools for details. </environment> <a href="" class="reload">Reload</a> <a class="dismiss">🗙</a> </div> <script src="_framework/blazor.server.js"></script> </body>
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true"> <Found Context="routeData"> <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> </Found> <NotFound> <LayoutView Layout="@typeof(MainLayout)"> <p>Sorry, there's nothing at this address.</p> </LayoutView> </NotFound> </Router>
public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddServerSideBlazor(); services.AddSingleton<WeatherForecastService>(); }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // ... app.UseEndpoints(endpoints => { endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); }); }
namespace BlazorWasmSample { public class Program { public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add<App>("#app"); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); await builder.Build().RunAsync(); } } }
<body> <div id="app">Loading...</div> <div id="blazor-error-ui"> An unhandled error has occurred. <a href="" class="reload">Reload</a> <a class="dismiss">🗙</a> </div> <script src="_framework/blazor.webassembly.js"></script> </body>
سپس روی Web Site ایجادشده راست کلیک کنید و از منوی بازشده Property Pages را انتخاب کنید. روی گزینهی Add Reference کلیک کنید، سپس پروژهی MyNewsWCFLibrary را از قسمت Solution انتخاب کرده و دکمهی OK را بفشارید.
دکمهی OK را بفشارید و از Solution Explorer فایل Web.Config را باز کنید. پیش از تغییرات مد نظر باید چنین محتوایی داشته باشد:
<?xml version="1.0" encoding="utf-8"?> <!-- For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5" /> </system.web> </configuration>
متن آنرا به این صورت تغییر دهید:
<?xml version="1.0" encoding="utf-8"?> <!-- For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5" /> </system.web> <system.serviceModel> <serviceHostingEnvironment> <serviceActivations> <add factory="System.ServiceModel.Activation.ServiceHostFactory" relativeAddress="./HamedService.svc" service="MyNewsWCFLibrary.MyNewsService"/> </serviceActivations> </serviceHostingEnvironment> <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
همانگونه که مشاهده میکنید به وسیلهی تگ add factory سرویسها را به وبسایت معرفی میکنیم. با relativeAddress میتوانیم هر نامی را به عنوان نام سرویس که در URL قرار میگیرد معرفی کنیم. چنانکه من یه جای MyNewsService از نام HamedService استفاده کردم. و در صفت service فضای نام و نام کلاس سرویس را معرفی میکنیم.
اکنون پروژه را اجرا کنید. در مرورگر باید صفحه را به اینصورت مشاهده کنید:
نیازی به یادآوری نیست که شما میتوانید این پروژه را در IIS سرور راهاندازی کنید تا کلیهی مشتریها به آن دسترسی داشته باشند. هرچند پیش از آن باید امنیت را نیز در WCF برقرار کنید.
توجه داشته باشید که روشی که در این بخش به عنوان میزبانی WCF مطرح کردم یکی از روشهای میزبانی WCF است. مثلاً شما میتوانستید به جای ایجاد یک WCFLibrary و یک Web Site به صورت جداگانه یک پروژه از نوع WCF Service و یا Web Site ایجاد میکردید و سرویسها و مدل Entity Framework را به طور مستقیم در آن میافزودید. روشی که در این درس از آن بهره برده ایم البته مزایایی دارد از جمله اینکه خروجی پروژه فقط یک فایل DLL است و با هر بار تغییر فقط کافی است همان فایل را در پوشه Bin از وبسایتی که روی سرور میگذارید کپی کنید.
در بخش هشتم با هم یک پروژهی تحت ویندوز خواهیم ساخت و از سرویس WCF ای که ساخته ایم در آن استفاده خواهیم کرد.
using System.Collections.Generic; using System.IO; using Lucene.Net.Analysis.Standard; using Lucene.Net.Documents; using Lucene.Net.Index; using Lucene.Net.Store; using LuceneSearch.Core.Model; using LuceneSearch.Core.Utils; namespace LuceneSearch.Core { public static class CreateIndex { static readonly Lucene.Net.Util.Version _version = Lucene.Net.Util.Version.LUCENE_30; public static Document MapPostToDocument(Post post) { var postDocument = new Document(); postDocument.Add(new Field("Id", post.Id.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED)); var titleField = new Field("Title", post.Title, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS); titleField.Boost = 3; postDocument.Add(titleField); postDocument.Add(new Field("Body", post.Body.RemoveHtmlTags(), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS)); return postDocument; } public static void CreateFullTextIndex(IEnumerable<Post> dataList, string path) { var directory = FSDirectory.Open(new DirectoryInfo(path)); var analyzer = new StandardAnalyzer(_version); using (var writer = new IndexWriter(directory, analyzer, create: true, mfl: IndexWriter.MaxFieldLength.UNLIMITED)) { foreach (var post in dataList) { writer.AddDocument(MapPostToDocument(post)); } writer.Optimize(); writer.Commit(); writer.Close(); directory.Close(); } } } }
namespace LuceneSearch.Core.Model { public class SearchResult { public int Id { set; get; } public string Title { set; get; } } }
using System.Collections.Generic; using System.IO; using Lucene.Net.Index; using Lucene.Net.Search; using Lucene.Net.Store; using LuceneSearch.Core.Model; using LuceneSearch.Core.Utils; namespace LuceneSearch.Core { public static class AutoComplete { private static IndexSearcher _searcher; /// <summary> /// Get terms starting with the given prefix /// </summary> /// <param name="prefix"></param> /// <param name="maxItems"></param> /// <returns></returns> public static IList<SearchResult> GetTermsScored(string indexPath, string prefix, int maxItems = 10) { if (_searcher == null) _searcher = new IndexSearcher(FSDirectory.Open(new DirectoryInfo(indexPath)), true); var resultsList = new List<SearchResult>(); if (string.IsNullOrWhiteSpace(prefix)) return resultsList; prefix = prefix.ApplyCorrectYeKe(); var results = _searcher.Search(new PrefixQuery(new Term("Title", prefix)), null, maxItems); if (results.TotalHits == 0) { results = _searcher.Search(new PrefixQuery(new Term("Body", prefix)), null, maxItems); } foreach (var doc in results.ScoreDocs) { resultsList.Add(new SearchResult { Title = _searcher.Doc(doc.Doc).Get("Title"), Id = int.Parse(_searcher.Doc(doc.Doc).Get("Id")) }); } return resultsList; } } }
using System.Text; using System.Web.Mvc; using LuceneSearch.Core; using System.Web; namespace LuceneSearch.Controllers { public class HomeController : Controller { static string _indexPath = HttpRuntime.AppDomainAppPath + @"App_Data\idx"; public ActionResult Index(int? id) { if (id.HasValue) { //todo: do something } return View(); //Show the page } public virtual ActionResult ScoredTerms(string q) { if (string.IsNullOrWhiteSpace(q)) return Content(string.Empty); var result = new StringBuilder(); var items = AutoComplete.GetTermsScored(_indexPath, q); foreach (var item in items) { var postUrl = this.Url.Action(actionName: "Index", controllerName: "Home", routeValues: new { id = item.Id }, protocol: "http"); result.AppendLine(item.Title + "|" + postUrl); } return Content(result.ToString()); } } }
@{ ViewBag.Title = "جستجو"; var scoredTermsUrl = Url.Action(actionName: "ScoredTerms", controllerName: "Home"); var bulletImage = Url.Content("~/Content/Images/bullet_shape.png"); } <h2> جستجو</h2> <div align="center"> @Html.TextBox("term", "", htmlAttributes: new { dir = "ltr" }) <br /> جهت آزمایش lu را وارد نمائید </div> @section scripts { <script type="text/javascript"> EnableSearchAutocomplete('@scoredTermsUrl', '@bulletImage'); </script> }
function EnableSearchAutocomplete(url, img) { var formatItem = function (row) { if (!row) return ""; return "<img src='" + img + "' /> " + row[0]; } $(document).ready(function () { $("#term").autocomplete(url, { dir: 'rtl', minChars: 2, delay: 5, mustMatch: false, max: 20, autoFill: false, matchContains: false, scroll: false, width: 300, formatItem: formatItem }).result(function (evt, row, formatted) { if (!row) return; window.location = row[1]; }); }); }
result.AppendLine(item.Title + "|" + postUrl); return Content(result.ToString());
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="LuceneSearch.WebForms.Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>جستجو</title> <link href="Content/Site.css" rel="stylesheet" type="text/css" /> <script src="Scripts/jquery-1.7.1.min.js" type="text/javascript"></script> <script src="Scripts/jquery.autocomplete.js" type="text/javascript"></script> <script src="Scripts/custom.js" type="text/javascript"></script> </head> <body dir="rtl"> <h2> جستجو</h2> <form id="form1" runat="server"> <div align="center"> <asp:TextBox runat="server" dir="ltr" ID="term"></asp:TextBox> <br /> جهت آزمایش lu را وارد نمائید </div> </form> <script type="text/javascript"> EnableSearchAutocomplete('Search.ashx', 'Content/Images/bullet_shape.png'); </script> </body> </html>
using System.Text; using System.Web; using LuceneSearch.Core; namespace LuceneSearch.WebForms { public class Search : IHttpHandler { static string _indexPath = HttpRuntime.AppDomainAppPath + @"App_Data\idx"; public void ProcessRequest(HttpContext context) { string q = context.Request.QueryString["q"]; if (string.IsNullOrWhiteSpace(q)) { context.Response.Write(string.Empty); context.Response.End(); } var result = new StringBuilder(); var items = AutoComplete.GetTermsScored(_indexPath, q); foreach (var item in items) { var postUrl = "Default.aspx?id=" + item.Id; result.AppendLine(item.Title + "|" + postUrl); } context.Response.ContentType = "text/plain"; context.Response.Write(result.ToString()); context.Response.End(); } public bool IsReusable { get { return false; } } } }
result.AppendLine(item.Title + "|" + postUrl); context.Response.Write(result.ToString());
import React, { useState } from "react"; export const Input = () => { const [name, setName] = useState(""); return <input value={name} onChange={(e) => setName(e.target.value)} />; };
const [name, setName] = useState(0);
عنوان میکند که مقدار رشتهای e.target.value، به مقدار عددی name قابل انتساب نیست. به عبارتی TypeScript از قابلیت Type Inference خود در اینجا استفاده میکند. درست است که به ظاهر نوعی را برای useState و خروجی منتسب به آن تعیین نکردهایم، اما بر اساس نوع مقدار پیشفرض آن، نوع name و setName به صورت خودکار مشخص میشوند و نیازی به ذکر صریح این نوع، نیست. برای مثال در حالت اول چون مقدار پیشفرض useState را یک رشتهی خالی معرفی کرده بودیم، نوع name نیز string درنظر گرفته شده بود. در حالت دوم بر اساس مقدار پیشفرض عددی useState، اینبار نوع name نیز یک number خواهد بود و دیگر نمیتوان یک مقدار رشتهای را مانند e.target.value به آن انتساب داد. مزیت کار کردن با TypeScript در اینجا، مشاهدهی آنی خطای یک چنین استفادهها و انتسابهای نادرستی است.
const [name, setName] = useState<string>("");
const [name, setName] = useState("");
const [name, setName] = useState<string | null>(null);
import React, { useRef, useState } from "react"; export const Input = () => { const [name, setName] = useState(""); const inputRef = useRef(null); if (inputRef && inputRef.current) { console.log("ref", inputRef.current.value); } return ( <input ref={inputRef} value={name} onChange={(e) => setName(e.target.value)} /> ); };
interface MutableRefObject<T> { current: T; }
const inputRef = useRef<HTMLInputElement>(null);
//if (inputRef && inputRef.current) { console.log("ref", inputRef.current.value); //}
که برای رفع آن، همانند قبل باید ذکر if بررسی نال بودن inputRef و خاصیت current آنرا اضافه کرد؛ تا دیگر در زمان اجرای برنامه، با شانس نال بودن یکی از ایندو مواجه نشویم و به کیفیت بالاتری در برنامهی خود برسیم.
console.log("ref", inputRef?.current?.value);
node -v npm -v
{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "project1": {
npm outdated -g --depth=0
npm update -g
npm i -g @angular/cli
npm install --save-dev @angular/cli@latest
ng update @angular/cli ng update @angular/core ng update rxjs
DELETE .angular-cli.json CREATE angular.json (4273 bytes) UPDATE karma.conf.js (1008 bytes) UPDATE src/tsconfig.spec.json (322 bytes) UPDATE package.json (2076 bytes) UPDATE tslint.json (3217 bytes)
ng update @angular/material
npm install npm-check-updates -g
ncu -u npm install
ng update @angular/core ng update rxjs
ng config cli.warnings.typescriptMismatch false
{ "devDependencies": { "typescript": "~2.7.2" } }
{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "angular-template-driven-forms-lab": { "configurations": { "production": { "optimization": true, "outputHashing": "all", "sourceMap": false, "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true, "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ] } } },
ng build --env staging
ng build --configuration staging
>ng build --watch Date: 2018-05-05T09:10:50.158Z Hash: a43eab94ff01539b8592 Time: 31733ms chunk {main} main.js, main.js.map (main) 9.38 kB [initial] [rendered] chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 226 kB [initial] [rendered] chunk {runtime} runtime.js, runtime.js.map (runtime) 5.4 kB [entry] [rendered] chunk {styles} styles.js, styles.js.map (styles) 15.6 kB [initial] [rendered] chunk {vendor} vendor.js, vendor.js.map (vendor) 3.05 MB [initial] [rendered]
>ng build --prod --watch Date: 2018-05-05T09:17:01.803Z Hash: f25fd6788a4969c52b70 Time: 73279ms chunk {0} runtime.6afe30102d8fe7337431.js (runtime) 1.05 kB [entry] [rendered] chunk {1} styles.34c57ab7888ec1573f9c.css (styles) 0 bytes [initial] [rendered] chunk {2} polyfills.6c08419970f9e4781b69.js (polyfills) 59.4 kB [initial] [rendered]
ng add @angular/material
ابتدا میخواهیم یک الگو یا Template را درست کنیم و بعدها از روی آن، نامهی جدیدی
را ایجاد کنیم و فیلدهایش را پرکنیم. برای اینکار یک سند جدید را در Word
ایجاد و به سربرگ Mailings مراجعه میکنیم. سپس دکمهی Select Recipients
را بزنید. در ادامه از منوی باز شده، Type a NewList را بزنید. با اینکار پنجرهای باز
میشود. در اینجا دکمهی Customize Columns را بزنید. این پنجره شامل فیلدهایی میشود که
میتوانید از آن استفاده کنید و بر روی سند قرار دهید و داخل برنامه با پیدا کردن
این فیلدها میتوانید بجای آنها، مقدار مورد نظرتان را پاس دهید. حالا شما نیاز
دارید تا از طریق دکمهی Add، تمامی فیلدهای لازم یک نامه را بسازید. پس از این کار، در هر دو پنجره ،
دکمهی OK را بزنید. بدین صورت یک پنجرهی ذخیره برای شما باز میشود تا این فیلدهایی را
که ایجاد کردید، به عنوان یک دیتابیس کوچک ذخیره شود که تمامی فیلدها را
دارا میباشد و هر موقع که خواستید دوباره میتوانید از همین فیلدها استفاده
کنید.
حالا میرسیم به قرار دادن این فیلدها داخل سند. با ذخیره
کردن فیلدها، تمامی گزینههای سربرگ Mailings فعال میشود. شما برای اینکه
فیلدی را بر روی سند قرار دهید، روی Insert Merge Field کلیک و متناسب با نیازتان،
فیلدها را قرار دهید و الگو را طراحی کنید. یک نمونه:
حالا فایل را با پسوند DOT. ذخیره کنید. در ادامه این فایل را در دیتابیس، به این روش ذخیره کنید:
String FilePath = "Template Path" // Converting File to ByteArray byte[] FileBuffer = System.IO.File.ReadAllBytes(FilePath); // Now you can insert this file buffer to DB
الان، الگوی ما آمادهاست و میتوانیم از طریق برنامه، به این الگو دسترسی داشته باشیم و به آن پارامتر ارسال کنیم.
روش ارسال پارامترها به الگوهای Word
حالا
فرضا شما یک فرم دارید که از کاربر، اطلاعاتی را دریافت میکند و میخواهید همین
اطلاعات را به Word ارسال کنید. برای اینکار ابتدا باید
یک نمونه از الگویی را که طراحی کردهایم، داخل سیستم ذخیره کنیم. یعنی باید آنرا از
دیتابیس فراخوانی کنیم و آن آرایهی بایتی را، بر روی سیستم، تبدیل به فایل
کنیم. سپس از سمت برنامه، تمامی فیلدهای موجود در این الگو را خوانده و بجای تک تک آنها، مقدار مناسبی را قرار دهیم. در نهایت این فایل را توسط کدنویسی بر
روی سیستم کاربر ذخیره میکنیم. فایل را تبدیل به آرایه بایتی میکنیم، داخل
دیتابیس درج میکنیم و فایل را از سیستم کاربر حذف میکنیم.
بنابراین در ادامه ابتدا
Assembly مربوط به MicroSoft.Office.Interop.Word را به رفرنسهای پروژه اضافه
میکنیم و سربرگش را هم Using میکنیم.
حالا میرسیم به کد نویسی:
کدهای زیر را به صورت سراسری داخل فرم تعریف میکنیم:
//LOCATION OF THE TEMPLATE FILE ON THE MACHINE; Object oTemplatePath = string.Format("{0}\\NewDocument.dot", Application.StartupPath); //OBJECT OF MISSING "NULL VALUE" Object oMissing = System.Reflection.Missing.Value; //OBJECTS OF FALSE AND TRUE Object oTrue = true; Object oFalse = false; //CREATING OBJECTS OF WORD AND DOCUMENT Microsoft.Office.Interop.Word.Application oWord = null; Microsoft.Office.Interop.Word.Document oWordDoc = null;
// Fetching Template ByteArray From Database => Byte[] YourTemplateByteArray = Fetch Template; System.IO.File.WriteAllBytes(oTemplatePath.ToString(), YourByteArray); oWord = new Microsoft.Office.Interop.Word.Application(); oWordDoc = new Microsoft.Office.Interop.Word.Document(); //Adding A New Document From A Template oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing); int iTotalFields = 0; // Finding Mailmerge Fields foreach(Microsoft.Office.Interop.Word.Field myMergeField in oWordDoc.Fields) { iTotalFields++; Microsoft.Office.Interop.Word.Range rngFieldCode = myMergeField.Code; String fieldText = rngFieldCode.Text; // Only Get The Mailmerge Fields if (fieldText.StartsWith(" MERGEFIELD")) { // Gives The Fieldnames as Entered in .DOT File string fieldName = fieldText.Substring(12, fieldText.IndexOf(" ", 12) - 12); switch (fieldName) { case "Letter_No": myMergeField.Select(); oWord.Selection.TypeText(txtLetterNo.Text); break; case "Letter_Date": myMergeField.Select(); oWord.Selection.TypeText(DateTime.Now); break; case "Letter_Has_Attachment": myMergeField.Select(); oWord.Selection.TypeText("دارد یا ندارد"); break; // And So On default: break; } } } //Showing The Document To The User oWord.Visible = true;
در ادامه یک دکمه را برای ذخیرهی فایل ورد قرار میدهیم. زمانیکه کاربر تایپ کردنش تمام شد و هنوز برنامهی ورد در حال اجراست، این دکمه را اجرا میکند. دقت کنید برنامهی ورد نباید بسته شود؛ باید باز باشد. بعد دکمهی ذخیره را میزنیم. با کدنویسی، برنامهی Word را خودمان میبندیم؛ نیازی به دخالت کاربر نیست.
oWordDoc.Save(); //Closing the file oWordDoc.Close(ref oFalse, ref oMissing, ref oMissing); //Quitting the application oWord.Quit(ref oMissing, ref oMissing, ref oMissing); byte[] FileBuffer = System.IO.File.ReadAllBytes(oTemplatePath.ToString ()); // Now Insert The FileBuffer Into Database as A Letter
خوب؛ کار تمام است! حالا فیلد FileBuffer را باید بسته به کدنویسی خودتان، داخل دیتابیس ذخیره کنید که برای بعدها بتوانید آنرا واکشی کرده و به کاربر نمایش دهید. این هم نمونهی نهایی جایگذاری فیلدها:
این آموزش را خیلی سال پیش در این تاپیک داخل فوروم برنامه نویس نوشته بودم.