نمایش نتایج 1 تا 10 از 10

نام تاپیک: مقالات آموزشی و کاربردی در زمینه WPF

  1. #1

    مقالات آموزشی و کاربردی در زمینه WPF

    با سلام
    در این تاپیک دوستان می توانند، مقالات مختلف آموزشی و کاربردی در زمینه WPF را قرار دهند.
    توجه به ذکر چند نکته می تواند در روند کاربردی بودن این تاپیک موثر باشد.
    1) از قرار دادن مقالاتی که جنبه تئوریک دارد، در این تاپیک خود داری کنید و آن ها در بخش های مربوطه ارسال نمایید.
    2) سعی شود، مطالب به صورت روان و ساده بیان شود.
    3) سعی شود، مطالب همراه با نمونه کد و حتی المقدور همراه با نمونه برنامه تست شده و مطمئن (پیوست شده با مقاله) باشد.
    4)مطالب نوشته شده توسط خودتان و یا ترجمه شده باشد. از فرستادن پست هایی که صرفا لینک به یک مقاله دیگر می باشد، در این تاپیک خود داری نمایید.
    5)چنانچه مطالب ترجمه، یک مقاله دیگر می باشد، لینک منبع را نیز در پایان مقاله ذکر نمایید.
    6)حتی المقدور، مقالات را در قالب pdf در پایان پست خود ضمیمه کنید.
    7)هنگام لینک دادن به عکس های آپلود شده در سایتهای دیگر، ساز عکس را متناسب با صفحه در نظر بگیرید.
    8)عنوان مناسبی برای پست های خود انتخاب کنید، تا در فهرست بندی مطالب در آینده، مشکلی پیش نیاید.

    با تشکر./
    مهدی کیانی

    پ و:
    به لطف خدا، تاپیک مربوط به آموزش WPF نیز در آینده ای نزدیک مجددا ادامه داده خواهد شد.
    آخرین ویرایش به وسیله Mahdi.Kiani : سه شنبه 24 دی 1387 در 00:19 صبح

    مجموعه آموزشی Asp.Net Core Mvc کاملا به زبان فارسی(21 ماژول و 15 ساعت فیلم آموزشی همراه با سورس کامل تمرینات و پروژه عملی انجام شده در طول آموزشی)
    مشاهده جزئیات در آدرس http://www.mkiani.ir/blog/content/53084


    وب سایت : http://www.mkiani.ir
    پست الکترونیک : mkiani3000@gmail.com

    موفق و پیروز باشید.
    مهدی کیانی


  2. #2

    ايجاد و ساخت دکمه سفارشي در WPF

    نمونه کد : دارد
    فرمت pdf : دارد

    مقدمه:
    در ادامه مقالات آموزشي WPF ، در اين مقاله، نحوه ساخت دکمه هاي سفارشي را در تکنولوژي WPF به صورت ساده و روان آموزش خواهم داد. براي فهم مطالب اين مقاله و استفاده و بهره وري از آن، نيازمند است تا خواننده با مفاهيم کلي WPF از جمله تعريف Brush ها، Style ها، نحوه ايجاد Resource ها و استفاده از آن ها، آشنايي داشته باشد. در اين مقاله از Microsoft Visual Studio.Net 2008 ، نسخه Professional به روز رساني شده با Service Pack1 استفاده شده است.

    ايجاد پروژه:
    در جهت سهولت ياد گيري کاربر، سعي کرده ام که به ساده ترين شکل ممکن، اين آموزش را در اختيار شما قرار دهم.
    يک پروژه از نوع WPF Application ايجاد کنيد. نام دلخواهي را براي آن انتخاب نماييد. من در پروژه خودم آن را CustomButton ناميدم. در پنجره Solution Explorer بر روي Window1 راست کليلک نماييد و گزينه View Designer را کليک نماييد. مطمئن شويد که در قسمت کدهاي XAML مربوط به Window1 هستيد.
    کد XAML مربوط به Window1 به صورت زير مي باشد:





    <Window x:Class="CustomButton.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>

    </Grid>
    </Window>




    قبل ازتعريف <Grid> کد هاي زير را وارد نماييد.


    <Window.Resources>

    </Window.Resources>



    کدهايي که براي ساخت دکمه خواهيم نوشت، در قسمت مربوط به Resource هاي Window1 قرار خواهند گرفت.(به نکته 1 آخر مقاله توجه نماييد.)
    براي ساخت دکمه سفارشي يک Style جديد ايجاد خواهيم کرد، و سپس با تعريف خاصيت Template، شکل و حالت دلخواه خود را به دکمه خواهيم داد. اما قبل از ايجادStyle جديد، تعاريف مربوط به Brush ها را خواهيم آورد. در قسمت Resource ها، کد هاي زير را وارد نماييد.





    <!-- ************************************************** * -->
    <!-- DefaultBackBrush -->
    <!-- ************************************************** * -->
    <LinearGradientBrush x:Key="DefaultBackBrush" StartPoint="0.5,0" EndPoint="0.5,1">
    <GradientStop Color="#FF2e2e2e" Offset="0"/>
    <GradientStop Color="#FF606984" Offset="0.025"/>
    <GradientStop Color="#FF3a404d" Offset="0.475"/>
    <GradientStop Color="#FF2e2e2e" Offset="0.5"/>
    </LinearGradientBrush>
    <!-- ************************************************** * -->







    <!-- ************************************************** * -->

    <!-- HighLightBackBrush -->
    <!-- ************************************************** * -->
    <LinearGradientBrush x:Key="HighLightBackBrush" StartPoint="0.5,0" EndPoint="0.5,1">
    <GradientStop Color="#FF2e2e2e" Offset="0"/>
    <GradientStop Color="#FF8a9ac6" Offset="0.025"/>
    <GradientStop Color="#FF3a404d" Offset="0.475"/>
    <GradientStop Color="#FF2e2e2e" Offset="0.5"/>
    </LinearGradientBrush>
    <!-- ************************************************** * -->

    <!-- ************************************************** * -->
    <!-- DisabledBackBrush -->
    <!-- ************************************************** * -->
    <LinearGradientBrush x:Key="DisabledBackBrush" StartPoint="0.5,0" EndPoint="0.5,1">
    <GradientStop Color="#FF3f3c3c" Offset="0"/>
    <GradientStop Color="#FF74798a" Offset="0.025"/>
    <GradientStop Color="#FF5e6168" Offset="0.475"/>
    <GradientStop Color="#FF3f3c3c" Offset="0.5"/>
    </LinearGradientBrush>
    <!-- ************************************************** * -->


    <!-- ************************************************** * -->
    <!-- IsDefaultedBorderColor -->
    <!-- ************************************************** * -->
    <SolidColorBrush x:Key="IsDefaultedBorderColor" Color="#FF2362ff"/>
    <!-- ************************************************** * -->

    <!-- ************************************************** * -->
    <!-- IsCancelBorderColor -->
    <!-- ************************************************** * -->
    <SolidColorBrush x:Key="IsCancelBorderColor" Color="#FFFF0000"/>
    <!-- ************************************************** * -->


    <!-- ************************************************** * -->
    <!-- FocusedBorderColor -->
    <!-- ************************************************** * -->
    <SolidColorBrush x:Key="FocusedBorderColor" Color="#FFbdccef"/>
    <!-- ************************************************** * -->


    <!-- ************************************************** * -->
    <!-- DisabledForeColor -->
    <!-- ************************************************** * -->
    <SolidColorBrush x:Key="DisabledForeColor" Color="#FFc3c3c3"/>
    <!-- ************************************************** * -->

    <!-- ************************************************** * -->
    <!-- DefaultForeColor -->
    <!-- ************************************************** * -->
    <SolidColorBrush x:Key="DefaultForeColor" Color="#FFFFFFFF"/>
    <!-- ************************************************** * -->


    <!-- ************************************************** * -->
    <!-- DefaultBorderColor -->
    <!-- ************************************************** * -->
    <SolidColorBrush x:Key="DefaultBorderColor" Color="#FF000000"/>
    <!-- ************************************************** * -->


    <!-- ************************************************** * -->
    <!-- ButtonRotater -->
    <!-- ************************************************** * -->
    <RotateTransform x:Key="ButtonRotater" Angle="180" />
    <!-- ************************************************** * -->



    امي که براي هر آيتم تعيين گرديده است، به خوبي بيانگر عملکر آن آيتم نيز ميباشد. به عنوان مثال، آيتم DisabledForeColor ، رنگ مربوط به دکمه را، در زماني که دکمه، در حالت Disable مي باشد، مشخص مي نماييد. به آيتم ButtonRotater توجه نماييد. اين آيتم يک RotateTransform مي باشد، که در زماني که دکمه توسط کاربر فشرده مي شود، باعث چرخش 180 درجه اي Border مربوط به دکمه مي شود که اين امر باعث مي شود، فشرده شدن دکمه توسط کاربر به خوبي مشخص شود و هنگام فشرده شدن، ظاهر دکمه با حالت پيش فرض آن متفاوت باشد. (قبل از خواند ادامه مطالب به نکته شماره 2 آخر مقاله توجه کنيد.)
    حال تعاريف مربوط به Style دکمه را در ادامه کد هاي فوق بنويسيد:




    <!-- ************************************************** * -->
    <!-- CustomButton -->
    <!-- ************************************************** * -->
    <Style TargetType="{x:Type Button}">
    <Setter Property="OverridesDefaultStyle" Value="True"/>
    <Setter Property="Foreground" Value="{StaticResource DefaultForeColor}"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="Template">
    <Setter.Value>
    <ControlTemplate TargetType="{x:Type Button}">
    <Grid
    Margin="0"
    Background="Transparent"
    >
    <Border
    x:Name="ButtonBorder"
    Background="{StaticResource DefaultBackBrush}"
    BorderBrush="{StaticResource DefaultBorderColor}"
    CornerRadius="4"
    BorderThickness="1"
    Padding="2"
    Margin="0"/>

    <ContentPresenter
    SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
    Margin="{TemplateBinding Padding}"
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
    RecognizesAccessKey="True"


    />

    </Grid>

    <ControlTemplate.Triggers>
    <Trigger Property="IsFocused" Value="True">
    <Setter
    TargetName="ButtonBorder"
    Property="BorderBrush"
    Value="{StaticResource FocusedBorderColor}"/>
    </Trigger>

    <Trigger Property="IsDefaulted" Value="True">
    <Setter TargetName="ButtonBorder" Property="BorderBrush" Value="{StaticResource IsDefaultedBorderColor}"/>
    </Trigger>
    <Trigger Property="IsCancel" Value="True">
    <Setter TargetName="ButtonBorder" Property="BorderBrush" Value="{StaticResource IsCancelBorderColor}"/>
    </Trigger>

    <Trigger Property="IsMouseOver" Value="True">
    <Setter TargetName="ButtonBorder" Property="Background" Value="{StaticResource HighLightBackBrush}"/>
    </Trigger>
    <Trigger Property="IsPressed" Value="True">
    <Setter TargetName="ButtonBorder" Property="Background" Value="{StaticResource DefaultBackBrush}"/>
    <Setter TargetName="ButtonBorder" Property="LayoutTransform" Value="{StaticResource ButtonRotater}"/>
    </Trigger>

    <Trigger Property="IsEnabled" Value="False">
    <Setter TargetName="ButtonBorder" Property="Background" Value="{StaticResource DisabledBackBrush}"/>
    <Setter Property="Foreground" Value="{StaticResource DisabledForeColor}"/>

    </Trigger>

    </ControlTemplate.Triggers>

    </ControlTemplate>
    </Setter.Value>
    </Setter>
    </Style>
    <!-- ************************************************** * -->



    همانطور که در مقدمه مقاله آورده شد، خواننده بايد با مطالب تعريف Style ها، Trigger ها و ... آشنايي داشته باشد. به همين دليل در اين موارد توضيحي نخواهم داد. فقط به ذکر چند نکته در اکتفا خواهم کرد.

    هنکام تعاريف Style ها معمولا يک Key براي آن در نظر خواهيم گرفت. که با دستور زير مشخص مي شود:



    x:Key="[style key name]"



    اما در Style فوق، من کليدي براي آن تعريف نکرده ام. اما تعريفي با عنوان



    TargetType="{x:Type Button}"


    را آورده ام. در واقع با اين عمل، Style مربوطه به تمامي دکمه هاي درون Window1 (و اگر Style در app.xaml تعريف شده باشد؛ به تمام دکمه هاي به کار رفته در همه Window هاي برنامه) اعمال خواهد شد و نيازي به مقدار دهي خاصيت Style دکمه ها، نخواهد بود.

    براي کنترل رفتار دکمه، در حالت هاي مختلف، از Trigger ها و خواص مربوطه استفاده شده است. به عنوان مثال با تعريف Trigger زير



    <Trigger Property="IsEnabled" Value="False">
    <Setter TargetName="ButtonBorder" Property="Background" Value="{StaticResource DisabledBackBrush}"/>
    <Setter Property="Foreground" Value="{StaticResource DisabledForeColor}"/>



    رنگ پس زمينه و پيش زمينه دکمه در حالتي که دکمه به صورت Disable ميباشد را به رنگ هاي متناسب و تعريف شده در بالاي Style نسبت مي دهد.


    نکته 1:
    چنانچه بخواهيد، از دکمه سفارشي، در همه Windows هاي برنامه استفاده نماييد، تعاريف مربوطه را در قسمت Resource ها فايل App.xaml قرار دهيد. علاوه براين مي توانيد يک Resource Dictionary ايجاد کرده و توسط دستور Merge Dictionaries ، آن را به Resource هاي برنامه اضافه نماييد. من در برنامه هاييم اغلب ازاين حالت استفاده مي کنم به اين دليل که قابليت Reusable بودن بالايي را به همراه خواهد داشت.
    نکته 2:
    مي توانيد، براي ايجاد Brush ها نيز يک Resource Dictionary در نظر بگيريد، تعاريف مربوط به Brush ها و عناصري را که در قسمت هاي مختلف ساخت کنترل هاي سفارشي شما، مشترک مي باشند را در آن نوشته و سپس آن را هنکام ايجاد کنترل هاي سفارشي، به آنها اضافه نماييد. اين عمل در هنگام تعريف و ساخت Style ها که در آن ها اغلي عناصر از رنگ هاي يکساني بهره مي برند، باعث صرفه جويي در وقت و کئ نويسي سريع و همچنين خوانا تر مي شود و از نوشتن کد هاي تکراري جلوگيري مي کند.

    نکته3:
    دقت کنيد که زماني که يک Style جديد براي يکي از عنصرهاي موجود در Visual Studio تعريف مي نماييد، تمامي کنترل آن عنصر در اختيار شما خواهد بود و در واقع مي توانيد عناصر و کنترل هاي جديد با ظاهر دلخواه خود را به وجود آوريد.

    تبريک!!!
    شما اولين کنترل سفارشي خود را با موفقيت ايجاد کرديد و مي توانيد از ان در برنامه هايتان استفاده نماييد.
    شکل زير، نمونه هايي از دکمه ايجاد شده را در حالت هاي مختلف نشان مي دهد.








    اميدوارم که اين مقاله نيز، کمکي در جهت ارتقاء سطح دانش شما درزمينه برنامه نويسي و استفاده از تکنولوژي WPF در برنامه هايتان نمايد.
    خواهشمند است نظرات ،انتقادات و پيشنهادات خود را در رابطه با مقاله فوق از طريق ايميل با بنده در ميان گذاريد.
    عکس های ضمیمه عکس های ضمیمه
    فایل های ضمیمه فایل های ضمیمه

    مجموعه آموزشی Asp.Net Core Mvc کاملا به زبان فارسی(21 ماژول و 15 ساعت فیلم آموزشی همراه با سورس کامل تمرینات و پروژه عملی انجام شده در طول آموزشی)
    مشاهده جزئیات در آدرس http://www.mkiani.ir/blog/content/53084


    وب سایت : http://www.mkiani.ir
    پست الکترونیک : mkiani3000@gmail.com

    موفق و پیروز باشید.
    مهدی کیانی


  3. #3
    VIP آواتار Amir Oveisi
    تاریخ عضویت
    اسفند 1384
    محل زندگی
    هر جا که حال کنم - فعلا یزد
    پست
    2,604

    Post WPFMessageBox، یک Messagebox فارسی-انگلیسی با قابلیت تغییر Theme

    نمونه کد : دارد
    pdf : فعلا ندارد

    مقدمه:
    چند روز پیش دیدم که خیلیا دنبال Messagebox‌ فارسی و Customize‌شده هستند، گفتم یکی با WPF بنویسم تا دوستان با WPF‌و قابلیت هاش بیشتر آشنا بشن و ببینن چقدر لذت بخشه کار با WPF!

    توضیحات:
    این MessageBox هم میتونه فارسی باشه هم انگلیسی (پیش فرضش انگلیسی هست) و تقریبا همه قابلیت های Messagebox استاندارد رو داره + امکان تغییر Style‌همه قسمت هاش.

    چند نمونه عکس ازش:





    برای تغییر اسکین :

    WPFMessageBox.BackgroundBrush
    WPFMessageBox.BorderBrush
    WPFMessageBox.ButtonsStyle
    WPFMessageBox.TitleTextStyle
    WPFMessageBox.MessageTextStyle

    قبل از Show کردن، با مقدار دهی به هر کدوم از ویژگی های بالا میتونین اسکین اونو تغییر بدید.



    برای فارسی کردن :

    WPFMessageBox.IsPersian = true;


    و بعد Show میکنید.



    اینا هم دو تا style‌ مختلف که کد XAML‌ ش تو فایل ضمیمه هم موجوده:





    (به دلیل محدودیت سایز سایت، مچبور شدم یه جا دیگه upload کنم)

    دانلود سورس

    موفق باشید
    اویسی

  4. #4
    VIP آواتار Amir Oveisi
    تاریخ عضویت
    اسفند 1384
    محل زندگی
    هر جا که حال کنم - فعلا یزد
    پست
    2,604

    Post نمونه برنامه ساده با استفاده از الگوی طراحی MVVM و Entity Framework در WPF برای کار با دیتابیس

    نمونه کد: دارد
    pdf:فعلا ندارد

    مقدمه

    یک نمونه برنامه ساده با استفاده از الگوی طراحی MVVM و Entity Framework در WPF برای کار با دیتابیس، که اعمال Select, Insert, Update و Delete را با استفاده از ساختار های الگوی MVVM انجام می دهد.
    در صورتی که با الگوی MVVM آشنا نیستید مطالبی را که جناب آقای نصیری که در سایت شخصیشون در مورد MVVM قرار داده اند، مطالعه نمایید.



    توضیحات


    شمای کلی برنامه بصورت زیر است که نمایانگر لایه های مختلف MVVM می باشد.

    لایه DataAccess:
    شامل فایل دیتابیس است که یک جدول به نام Employee، دارای دو فیلد نام و ID می باشد. در این لایه می توان از انواع data source ها نظیر فایل های xml و ... نیز استفاده نمود.
    البته توجه داشته باشید که چنین لایه ای در الگوی MVVM نامبرده نشده است اما برای شفافیت بیشتر کدنویسی معمولا برنامه نویسانی که با MVVM سر و کار دارند، چنین اقدامی می کنند!

    لایه Model:
    در این لایه باید مدلی از داده ای که در DataAccess وجود دارد، ایجاد کنیم. با استفاده از Entity Framework، یک Entity Data Model خواهیم داشت که به عنوان مدلی آماده از لایه DataAccess می توان از آن نام برد. زیرا کدهای مورد نیاز برای ایجاد کلاس های Model را بصورت خودکار تولید می کند.

    [assembly: EdmSchemaAttribute()]

    namespace MVVM_EntityFramework.Model
    {
    #region Contexts

    /// <summary>
    /// No Metadata Documentation available.
    /// </summary>
    public partial class EmployeeRepository : ObjectContext
    {
    #region Constructors

    /// <summary>
    /// Initializes a new EmployeeRepository object using the connection string found in the 'EmployeeRepository' section of the application configuration file.
    /// </summary>
    public EmployeeRepository() : base("name=EmployeeRepository", "EmployeeRepository")
    {
    this.ContextOptions.LazyLoadingEnabled = true;
    OnContextCreated();
    }

    /// <summary>
    /// Initialize a new EmployeeRepository object.
    /// </summary>
    public EmployeeRepository(string connectionString) : base(connectionString, "EmployeeRepository")
    {
    this.ContextOptions.LazyLoadingEnabled = true;
    OnContextCreated();
    }

    /// <summary>
    /// Initialize a new EmployeeRepository object.
    /// </summary>
    public EmployeeRepository(EntityConnection connection) : base(connection, "EmployeeRepository")
    {
    this.ContextOptions.LazyLoadingEnabled = true;
    OnContextCreated();
    }

    #endregion

    #region Partial Methods

    partial void OnContextCreated();

    #endregion

    #region ObjectSet Properties

    /// <summary>
    /// No Metadata Documentation available.
    /// </summary>
    public ObjectSet<Employee> Employees
    {
    get
    {
    if ((_Employees == null))
    {
    _Employees = base.CreateObjectSet<Employee>("Employees");
    }
    return _Employees;
    }
    }
    private ObjectSet<Employee> _Employees;

    #endregion
    #region AddTo Methods

    /// <summary>
    /// Deprecated Method for adding a new object to the Employees EntitySet. Consider using the .Add method of the associated ObjectSet&lt;T&gt; property instead.
    /// </summary>
    public void AddToEmployees(Employee employee)
    {
    base.AddObject("Employees", employee);
    }

    #endregion
    }


    #endregion

    #region Entities

    /// <summary>
    /// No Metadata Documentation available.
    /// </summary>
    [EdmEntityTypeAttribute(NamespaceName="dbModel", Name="Employee")]
    [Serializable()]
    [DataContractAttribute(IsReference=true)]
    public partial class Employee : EntityObject
    {
    #region Factory Method

    /// <summary>
    /// Create a new Employee object.
    /// </summary>
    /// <param name="id">Initial value of the id property.</param>
    public static Employee CreateEmployee(global::System.Int32 id)
    {
    Employee employee = new Employee();
    employee.id = id;
    return employee;
    }

    #endregion
    #region Primitive Properties

    /// <summary>
    /// No Metadata Documentation available.
    /// </summary>
    [EdmScalarPropertyAttribute(EntityKeyProperty=false , IsNullable=true)]
    [DataMemberAttribute()]
    public global::System.String Name
    {
    get
    {
    return _Name;
    }
    set
    {
    OnNameChanging(value);
    ReportPropertyChanging("Name");
    _Name = StructuralObject.SetValidValue(value, true);
    ReportPropertyChanged("Name");
    OnNameChanged();
    }
    }
    private global::System.String _Name;
    partial void OnNameChanging(global::System.String value);
    partial void OnNameChanged();

    /// <summary>
    /// No Metadata Documentation available.
    /// </summary>
    [EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
    [DataMemberAttribute()]
    public global::System.Int32 id
    {
    get
    {
    return _id;
    }
    set
    {
    if (_id != value)
    {
    OnidChanging(value);
    ReportPropertyChanging("id");
    _id = StructuralObject.SetValidValue(value);
    ReportPropertyChanged("id");
    OnidChanged();
    }
    }
    }
    private global::System.Int32 _id;
    partial void OnidChanging(global::System.Int32 value);
    partial void OnidChanged();

    #endregion

    }

    #endregion

    }


    لایه View:

    برای View یک user control به نام EmployeeListView داریم که دارای یک DataGrid برای نمایش اطلاعات مشتریان، دو TextBox برای ورود اطلاعات و سه Button برای اعمال Insert و Update و Delete است. برای این کار از Command استفاده شده است.
    برای کد XAML آن به این شکل است: (به Binding ها دقت کنید)

    <UserControl x:Class="MVVM_EntityFramework.View.EmployeeListVie w"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="300">


    <Grid>
    <Grid.InputBindings>
    <KeyBinding Key="I" Modifiers="Control" Command="{Binding InsertCommand}"/>
    <KeyBinding Key="U" Modifiers="Control" Command="{Binding UpdateCommand}"/>
    <KeyBinding Key="D" Modifiers="Control" Command="{Binding DeleteCommand}"/>
    </Grid.InputBindings>
    <StackPanel Margin="5" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
    <DataGrid ItemsSource="{Binding AllEmployees}" AutoGenerateColumns="False" Margin="5" AlternatingRowBackground="#FFD2CECE" Background="{x:Null}" HorizontalGridLinesBrush="#FFC6C6C6" VerticalGridLinesBrush="#FFC6C6C6" BorderBrush="#FFA3A3A3">
    <DataGrid.Columns>
    <DataGridTemplateColumn Header="Name">
    <DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
    <TextBlock Text="{Binding Name}"/>
    </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    <DataGridTemplateColumn Header="ID">
    <DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
    <TextBlock Text="{Binding id}"/>
    </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    </DataGrid.Columns>
    </DataGrid>
    <StackPanel Orientation="Horizontal" Margin="5" DataContext="{Binding NewEmployee}">
    <TextBlock Text="Name:" Margin="5"/>
    <TextBox Width="70" Margin="5" Text="{Binding Path=Name, Mode=OneWayToSource}"/>
    <TextBlock Text="ID:" Margin="5"/>
    <TextBox Width="70" Margin="5" Text="{Binding Path=id, Mode=OneWayToSource}"/>
    </StackPanel>
    <StackPanel Margin="5" Orientation="Horizontal">
    <Button Content="Insert" Command="{Binding InsertCommand}" Margin="5" Width="50"/>
    <Button Content="Update" Command="{Binding UpdateCommand}" Margin="5" Width="50"/>
    <Button Content="Delete" Command="{Binding DeleteCommand}" Margin="5" Width="50"/>
    </StackPanel>
    <TextBlock Margin="10" Foreground="DarkGray" Text="Shortcut Keys: Insert = Ctrl+I , Update = Ctrl+U , Delete = Ctrl+D" TextWrapping="Wrap"/>
    </StackPanel>
    </Grid>
    </UserControl>


    لایه ViewModel:
    بطور کلی برای هر View یک ViewModel باید باشد تا منطق آن را تولید نماید.
    در اینجا ما دو View داریم، user control و main wondow.
    کار main window نمایش View های دیگر در داخل خود است به همین دلیل جزو لایه View محسوب نمی شود. اما برای کنترل منطق آن باید یک ViewModel برای آن نیز داشته باشیم تا بتوانیم قابلیت نمایش View های مختلف در داخل آن را بوجود بیاوریم.
    کلاس ViewModelBase را نیز برای داشتن یک چارجوب کلی برای تمام ViewModel ایجاد می کنیم و همه ViewModel های موجود از آن ارث خواهند برد.

    ViewModelBase

    namespace MVVM_EntityFramework.ViewModel
    {
    public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
    {
    protected ViewModelBase()
    {
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
    PropertyChangedEventHandler handler = this.PropertyChanged;
    if (handler != null)
    {
    var e = new PropertyChangedEventArgs(propertyName);
    handler(this, e);
    }
    }

    public void Dispose()
    {
    this.OnDispose();
    }

    protected virtual void OnDispose()
    {
    }
    }
    }


    MainWindowViewModel


    namespace MVVM_EntityFramework.ViewModel
    {
    public class MainWindowViewModel : ViewModelBase
    {
    readonly EmployeeRepository _employeeRepository;

    ObservableCollection<ViewModelBase> _viewModels;

    public MainWindowViewModel()
    {
    _employeeRepository = new EmployeeRepository();
    EmployeeListViewModel viewModel = new EmployeeListViewModel(_employeeRepository);
    this.ViewModels.Add(viewModel);
    }

    public ObservableCollection<ViewModelBase> ViewModels
    {
    get
    {
    if (_viewModels == null)
    {
    _viewModels = new ObservableCollection<ViewModelBase>();
    }
    return _viewModels;
    }
    }
    }
    }



    EmployeeListViewModel
    به تعاریف Command ها توجه نمایید.


    namespace MVVM_EntityFramework.ViewModel
    {
    class EmployeeListViewModel : ViewModelBase
    {


    readonly EmployeeRepository _employeeRepository;

    RelayCommand _insertCommand;
    RelayCommand _updateCommand;
    RelayCommand _deleteCommand;

    public Employee NewEmployee { get; set; }

    public ObservableCollection<Employee> AllEmployees
    {
    get;
    private set;
    }

    public EmployeeListViewModel(EmployeeRepository employeeRepository)
    {
    if (NewEmployee == null)
    NewEmployee = new Employee();
    if (employeeRepository == null)
    {
    throw new ArgumentNullException("employeeRepository");
    }
    _employeeRepository = employeeRepository;
    var tmp = from o in employeeRepository.Employees

    select o;
    this.AllEmployees = new ObservableCollection<Employee>(tmp.ToList());
    }

    protected override void OnDispose()
    {
    this.AllEmployees.Clear();
    }



    public ICommand InsertCommand
    {
    get
    {
    if (_insertCommand == null)
    {
    _insertCommand = new RelayCommand(param => this.InsertCommandExecute(), param => this.InsertCommandCanExecute);
    }
    return _insertCommand;
    }
    }

    public ICommand UpdateCommand
    {
    get
    {
    if (_updateCommand == null)
    {
    _updateCommand = new RelayCommand(param => this.UpdateCommandExecute(), param => this.UpdateCommandCanExecute);
    }
    return _updateCommand;
    }
    }

    public ICommand DeleteCommand
    {
    get
    {
    if (_deleteCommand == null)
    {
    _deleteCommand = new RelayCommand(param => this.DeleteCommandExecute(), param => this.DeleteCommandCanExecute);
    }
    return _deleteCommand;
    }
    }

    void InsertCommandExecute()
    {
    Employee emp = Employee.CreateEmployee(NewEmployee.id);
    emp.Name = NewEmployee.Name;
    _employeeRepository.Employees.AddObject(emp);
    _employeeRepository.SaveChanges();
    var tmp = from o in _employeeRepository.Employees

    select o;
    this.AllEmployees = new ObservableCollection<Employee>(tmp.ToList());
    OnPropertyChanged("AllEmployees");
    }


    bool InsertCommandCanExecute
    {
    get
    {
    var tmp = from o in _employeeRepository.Employees
    where o.id == NewEmployee.id
    select o;
    if (tmp != null && tmp.Count() > 0)
    {
    return false;
    }
    return true;
    }
    }

    void UpdateCommandExecute()
    {
    var tmp = from o in _employeeRepository.Employees
    where o.id == NewEmployee.id
    select o;
    tmp.First().Name = NewEmployee.Name;
    _employeeRepository.SaveChanges();
    var tmp2 = from o in _employeeRepository.Employees
    select o;
    this.AllEmployees = new ObservableCollection<Employee>(tmp2.ToList());
    OnPropertyChanged("AllEmployees");
    }


    bool UpdateCommandCanExecute
    {
    get
    {
    var tmp = from o in _employeeRepository.Employees
    where o.id == NewEmployee.id
    select o;
    if (tmp != null && tmp.Count() > 0)
    {
    return true;
    }
    return false;
    }
    }

    void DeleteCommandExecute()
    {
    var tmp = _employeeRepository.Employees.Single(o => o.id == NewEmployee.id);
    _employeeRepository.Employees.DeleteObject(tmp);
    _employeeRepository.SaveChanges();
    var tmp2 = from o in _employeeRepository.Employees
    select o;
    this.AllEmployees = new ObservableCollection<Employee>(tmp2.ToList());
    OnPropertyChanged("AllEmployees");
    }


    bool DeleteCommandCanExecute
    {
    get
    {
    var tmp = from o in _employeeRepository.Employees
    where o.id == NewEmployee.id
    select o;
    if (tmp != null && tmp.Count() > 0)
    {
    return true;
    }
    return false;
    }
    }
    }
    }


    نکته :
    فایل App.cs را بصورت زیر تغییر می دهیم تا در زمان لود برنامه، محتوی main window را مشخص کنیم. main window قابلیت نمایش هر ViewModel ای را دارد و هر ViewModel دارای یک View است که در نهایت آن View دز main window نمایش داده می شود.

    namespace MVVM_EntityFramework
    {
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
    protected override void OnStartup(StartupEventArgs e)
    {
    base.OnStartup(e);
    MainWindow window = new MainWindow();
    var viewModel = new MainWindowViewModel();
    window.DataContext = viewModel;
    window.Show();
    }

    }
    }


    دقت کنید که در بخش XAML کلاس App قسمت مربوط به StaurtupUri را حذف کنید.

    و در آخر، کد XAML مربوط به MainWindow به شکل زیر خواهد بود:
    (به Resource های آن و Binding مربوط به ItemsSource دقت نمایید)


    <Window x:Class="MVVM_EntityFramework.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:MVVM_EntityFramework.ViewModel"
    xmlns:vw="clr-namespace:MVVM_EntityFramework.View"
    Title="MainWindow" Height="350" Width="525" Background="#FFBCB4B4">
    <Window.Resources>
    <DataTemplate DataType="{x:Type vm:EmployeeListViewModel}">
    <vw:EmployeeListView />
    </DataTemplate>

    </Window.Resources>
    <Grid Margin="4">
    <Border BorderBrush="#FFA3A0A0" BorderThickness="1" CornerRadius="5">
    <Border.Background>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
    <GradientStop Color="#FFD6D2D2" Offset="0"/>
    <GradientStop Color="White" Offset="1"/>
    </LinearGradientBrush>
    </Border.Background>
    <ItemsControl ItemsSource="{Binding ViewModels}" Margin="4" />
    </Border>
    </Grid>
    </Window>


    نتیجه:
    MainWindow را به گونه ای طراحی کردیم که قادر به نمایش دادن ViewModel های مختلف باشد. هر ViewModel نیز یک منطق است که داده ها را از Model (یا DataAccess) گرفته و با استفاده از یک View، در MainWindow نمایش می دهد. توجه داشته باشید که هیچ کدام از فایل های XAML، دارای کدنویسی در Code-behind خود نیستند (به جز کد های پیش فرض خودشان) و این امر سبب می شود به راحتی بتوانید View های خود را به دلخواه و بدون نگرانی از به هم ریختن کدها تغییر دهید. تنها کار لازم، اعمال Binding ها در کد XAML است!
    برای پرسش، بحث و تبادل نظر به لینک زیر مراجعه کنید:
    https://barnamenevis.org/showthread.php?t=196333
    فایل های ضمیمه فایل های ضمیمه

  5. #5

    اجرای فقط یک نمونه از برنامه در WPF

    کد دارد
    PDF ندارد
    منبع : Aliaghdam.blogspot.com

    در بعضی برنامه های بنا به دلایلی برای توسعه دهنده هیچ اهمیتی ندارد که کاربر چند نمونه از برنامه را اجرا کند ولی اگر زمانی اجرای برنامه محدود بشود (به یک فرم )،برای این جور برنامه ها 3 نوع سناریو وجود دارد که به شرح آنها می پردازیم.
    اولین سناریو را می توان نرافزاری در نظر گرفت که فقط یک نمونه از آن اجرا می شود (فقط یک پنجره اصلی) و می تواند پارامتر های را در هنگام اجرا بپذیرد به طور مثال برنامه ی مثل ویندوز مدیا پلیر و سناریو دیگر این است که در واقع از نرم افزار فقط یک نمونه اجرا می شود ولی دارای تعدادی پنجره مختلف است (Document Base) از این برنامه ها می توان MS Word رو مثال زد که کاربر شاید فکر بکند چند نمونه از برنامه را اجرا کرده در صورتی که فقط یک نمونه از برنامه اجرا شده و پنجره های مختلف را مدیریت می کند که از افزوده شدن سربار اضافی به سیستم جلوگیری می کند و سناریو آخری که می توان در نظر داشت برنامه ای که فقط یک نمونه از ان اجرا می شود (فقط یک پنجره اصلی) و هیچ پارامتر ورودی نمی پذیرد.البته سناریوهای دیگری را نیز می توان نام برد ولی ما به همین سه سناریو اکتفا می کنیم


    برای پیاده سازی این قبیل نرم افزار ها راه حل های زیادی وجود دارد که هر کدام کم وبیش این قابلیت را به ما می دهند ولی ما قصد بررسی روشی رو داریم که در آن بتوان هر سه سناریو را پیاده سازی کرد


    مثلا برای این منظور از Mutex استفاده می کنند که در آن نمی توان سناریویی اول و دوم را پیاده سازی کرد و یا پردازش ها بررسی می کنند که باز هم شامل سناریویی 1و2 نمی شود

    public partial class App : Application
    {
    protected override void OnStartup(StartupEventArgs e)
    {
    // Get Reference to the current Process
    Process thisProc = Process.GetCurrentProcess();
    // Check how many total processes have the same name as the current one
    if (Process.GetProcessesByName(thisProc.ProcessName). Length > 1)
    {
    // If ther is more than one, than it is already running.
    MessageBox.Show("Application is already running.");
    Application.Current.Shutdown();
    return;
    }

    base.OnStartup(e);
    }
    }
    با ارائه شدن WPF توسط مایکرسافت برای این منظور در C#‎‎ هیچ تمهیداتی پیش بینی نشده بود ولی تیم توسعه VB.NET این امکان را فراهم کرده بودند که ما نیز قصد استفاده از آن را در C#‎‎ داریم

    در VB.NET در فضای نام کلاسی وجود دارد به نام Microsoft.VisualBasic.ApplicationServices که این امکان را برای ما فراهم می کندو ما با مشتق کردن کلاسی از این کلاس می توانیم موفق به پیاده سازی هر سه سناریو بشویم.
    این کلاس سه عضو را پیاده سازی می کند که از آنها برای این منظور استفاده می کنیم


    • IsSingleInstance : یک خصیصه است و مشخص می کند که آیا از این برنامه فقط یک نمونه اجرا بشود یا نه؟ که ما آن را در سازنده کلاس با true مقدار دهی می کنیم.
    • OnStartup : این رویداد زمانی رخ می دهد که اولین نمونه از برنامه در حال ساخته شدن است و می توانیم به آرگومان های ورودی دسترسی داشته باشیم( StartupEventArgs ).
    • OnStartupNextInstance : همانطور که از نامش پیداست این زمانی رخ می دهد که نمونه دیگری از برنامه در حال ساخته شدن باشد.در این رویداد نیز می توان به آرگومان های ورودی دسترسی داشته باشیم ( StartupNextInstanceEventArgs )

    خوب برای این که بتوانید به این کلاس دسترسی پیدا کنید با ید یک ارجاع به اسمبلی Microsoft.VisuaBasic.dllدر پروژه داشته باشید.

    در اینجا ما سناریوی دوم را بررسی می کنیم که مشکلترین آنهاست و توسعه دهندگان اکثرا با پیاده سازی آن مشکل دارند
    ابتدا یک کلاس را از WindowsFormsApplicationBase مشتق می کنیم و پیاده سازی زیر را انجام می دهیم

    using Microsoft.VisualBasic.ApplicationServices;

    public class SingleInstanceManager : WindowsFormsApplicationBase
    {
    public App app { get; private set; }

    public SingleInstanceManager()
    {
    this.IsSingleInstance = true;
    }

    protected override bool OnStartup(StartupEventArgs e)
    {
    // First time app is launched
    app = new App();
    app.Run();

    return false;
    }

    protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
    {
    app.MyWindow.Activate();

    app.ProcessArgs(eventArgs.CommandLine.ToArray(), false);

    }
    }
    این کلاس یک نمونه از شی Application مورد نظر ما را نگهداری می کند (App) و در رویداد OnStartup یک نمونه از شی Application ساخته می شود و در رویداد OnStartNextInstance پنجره اصلی برنامه با نام MyWindow فعال می شود و سپس آرگومان های ورودی پردازش می شوند .توجه کنید که این قاعده کلی است و اگر این قسمت را متوجه شوید 70% راه را طی نموده اید.
    حال ما قسمت کد نویسی شی Application را بررسی می کنیم (نه کد XAML)

    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
    public MainWindow MyWindow { get; private set; }

    protected override void OnStartup(StartupEventArgs e)
    {
    base.OnStartup(e);

    // Create and show the application's main window
    MyWindow = new MainWindow();
    MyWindow.Show();

    //cache Arguments
    ProcessArgs (e.Args, true);
    }

    //cache Arguments
    public void ProcessArgs(string[] args, bool firstInstance)
    {
    if (firstInstance )
    {
    MyWindow.ProcessArgs(args, true );
    }else
    //cache Arguments
    MyWindow.ProcessArgs(args, false);
    }


    }
    در این کلاس تابع ProcessArgs آرگومان های ورودی را گرفته و تجزیه می کند سپس اطلاعات را به تابعی با همین نام در شئ MyWindow تحویل می دهد (ورودی ها در ادامه بررسی خواهند شد)

    حال نگاهی به پیاده سازی MyWindow می اندازیم


    public MainWindow()
    {
    InitializeComponent();
    }

    //Parse Arguments
    public void ProcessArgs(string[] args, bool firstInstance)
    {
    if (!firstInstance)
    {
    Block.Text += "Other try" + Environment.NewLine; ;
    if (args.Length >= 1)
    {
    string temp = "With Argument" + Environment.NewLine;

    for (int i = 0; i <args.Length ; i++)
    {
    temp += "args " + i + " = " + args[i] + Environment.NewLine;
    }

    this.Block.Text += temp;
    }

    }
    else
    {
    Block.Text = "First Instance" + Environment.NewLine; ;
    if (args.Length >= 1)
    {
    string temp = "With Arguments" + Environment.NewLine;

    for (int i = 0; i < args.Length; i++)
    {
    temp += "args " + i + " = " + args[i] + Environment.NewLine;
    }
    this.Block.Text += temp;
    }

    }
    }
    در این پنجره که به عنوان پنجره اصلی برنامه است شما می بایست آرگومان های ورودی را بررسی (Parse) کنید و نمایش صحیحی رو بسته به برنامه در اختیار کاربر قرار دهید که ما در اینجا وقت به نمایش آرگومان های ورودی بسنده می کنیم.
    ورودی اول آرگومتن های ورودی است و ورودی دوم مشخص می کند که آیا نمونه اول و اصلی است یا نمونه دیگر (اجرای اول با دیگر)

    توجه کنید که تا این جا این راه حل برای یک Build از برنامه کار می کند واگر بخواهید که برای انواع Build های نرم افزار در یک سیستم جواب بدهد باید در فایل Assembly.cs پروژه خود یک اتریبیوت به نام GuidAttribute را بیفزایید چون اگر Guidرو مقداردهی نکنید دات نت در هر بار Build یک Guid به آن اختصاص می دهدو در Build های مختلف برنامه نمی توانید یک فرم واحد داشته باشید.

    [assembly: GuidAttribute("67ab3432-7388-4f47-af08-edabe2306cfd")]
    حاصل برنامه بالا با توجه به ورودی های مختلف در تصویر زیر مشخص است


    منابع : من اول این نکته رو در کتاب Pro WPF in C#‎‎ 2008" by Matthew MacDonald خوندم بعد از MSDNتکمیلش کردم.

    فایل پروژه را می توانید از { اینجا } دریافت کنید.


  6. #6
    VIP آواتار Amir Oveisi
    تاریخ عضویت
    اسفند 1384
    محل زندگی
    هر جا که حال کنم - فعلا یزد
    پست
    2,604

    Post BeRMOoDA File Encrypter

    نرم افزار رمز نگاری فایل

    امکانات برنامه:
    • رمزنگاری فایل بر اساس کلمه عبوری که به آن داده میشود و با الگوریتمAES، بطوریکه فقط با همان کلمه عبور، رمز گشایی خواهد شد.
    • قابلیت رمزنگاری محتویات فولدر ها بصورت تو در تو (همراه با زیرفولدر ها)
    • امکان رمزنگاری و رمزگشایی بصورت همزمان و با Thread های مجزا، بدون کاهش سرعت
    • محاسبه Elapsed Time و Remaining Time با استفاده از Thread مجزا


    ویژگی های فنی:
    • استفاده از تکنولوژی WPF
    • کاملا Multi Thread
    • طراحی شده با معماری MVVM
    • استفاده از Aero Glass Theme ویندوز 7
    • با استفاده از Visula Studio 2010 و .NET Framework 3.5 نوشته شده است.




    چند نکته که بر عهده شما خواهد بود:

    Exception Handling ها اعمال نشده اند.
    Validation ها در رویداد CanExecute برای Command ها، اعمال نشده اند.
    گزینه On The Fly Encryption در نسخه open source فعال نمی باشد.

    لینک دریافت برنامه همراه با سورس

    توضیحات:

    من این برنامه رو چند سال پیش نوشته بودم ولی معماری خاصی نداشت و تقریبا spaghetti code بود.
    چند روز پیش تصمیم گرفتم این برنامه را با معماری MVVM بنویسم تا ببینم از نظر performance چه تغییراتی اتفاق میفتد. نتیجه خیلی جالب بود، اعمال رمزنگاری و رمزگشایی نزدیک 30% سریع تر انجام شدند!

    ساختار پروژه:


    کلاس های داخل فولدر Converters، کلاس هایی هستند که در Binding ها استفاده می شوند. کاربرد آن زمانی است که مقداری که Bind می شود باید تغییراتی (از نظر نوع داده یا فرمت نمایش) بکند. به عنوان مثال کلاس زیر برای NOT کردن مقدار یک متغیر bool در کد Xaml را ممکن می سازد:
     [ValueConversion(typeof(bool), typeof(bool))]
    public class XamlNotOperatorConverter : IValueConverter
    {

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {

    return !(bool)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
    return !(bool)value;
    }
    }


    سپس برای استفاده از این کلاس در کد Xaml باید یک object از آن در resource های کنترل مورد نظر تعریف کرد و آن را به عنوان مقدار پارامتر Converter برای Binding قرار داد:

     <UserControl.Resources>
    <project:XamlNotOperatorConverter x:Key="NotOperatorConverter"/>
    </UserControl.Resources>


     <Expander IsExpanded="{Binding ElementName=expanderDecrypt, Path=IsExpanded, Converter={StaticResource NotOperatorConverter}}" />


    با این کار، بدون نوشتن کد برای event handling، زمانی که یکی از expander ها باز شود، expander دیگر بصورت خودکار بسته خواهد شد.

    لایه Model
    در فولدر Model، مدل داده ای که قرار است در برنامه با آن سر و کار داشته باشیم تعریف شده است. در برنامه قصد نمایش اطلاعات مربوط به فایل ها را داریم و میخواهیم نام، سایز و وضعیت یک فایل را نشان دهیم. وضعیت یک فایل می تواند نرمال، در حال پردازش و پردازش شده باشد که هر کدام با یک رنگ مشخص می شود. به همین دلیل نوع داده فیلد Status از نوع Brush در نظر گرفته شده است.

    لایه View
    فولدر View شامل یک user control است که در واقع قرار است در داخل MainWindow نمایش داده شود. اما بر اساس قوانین MVVM، هیچ منطقی را شامل نمی شود د دارای code behind نیست. منطق مورد نیاز برنامه بصورت کامل در لایه ViewModel پیاده سازس خواهد شد.

    لایه ViewModel
    فولدر ViewModels شامل کلاس هایی است که منطق برنامه را فراهم می کنند. یک کلاس پایه وجود دارد که هر ViewModel ای از آن ارث می برد. یک ViewModel برای MainWindow و یک ViewModel برای user control ایجاد شده است. در حالت کلی، برای هر View، یک ViewModel وجود خواهد داشت.

    کلاس PasswordHelper:
    فیلد Password در کنترل PasswordBox یک DependencyProperty نیست و به همین دلیل (و نیز دلایل امنیتی) امکان Bind آن وجود ندارد. برای حل این مسئله یک کلاس طراحی شده که یک Attached Property به PasswordBox اضافه می کند و می توان مقدار آن را Bind کرد.

    کلاس AeroGlassProvider:
    این کلاس با استفاده از API های ویندوز 7 یا وسیتا، قابلیت استفاده از Aero Theme ویندوز را در برنامه فراهم می کند.

    کلاس Crypto:
    این کلاس هم لایه ارتباط با فایل است که می توان آن را لایه Data Access هم در نظر گرفت. در این کلاس با استفاده از الگوریتم AES اعمال رمزنگاری و رمزگشایی انجام می شوند.

    کلاس RelayCommand:
    آقای Josh Smith این کلاس را نوشته اند که امکان استفاده ساده از Action ها و Predicate ها را به برنامه نویسان می دهد.

    توضیحات کامل در مورد معماری MVVM بزودی با استفاده از یک پروژه ساده ارائه خواهد شد.


  7. #7
    VIP آواتار Amir Oveisi
    تاریخ عضویت
    اسفند 1384
    محل زندگی
    هر جا که حال کنم - فعلا یزد
    پست
    2,604

    ايجاد برنامه هاي چند زبانه در WPF با قابليت افزودن زبان هاي جديد در زمان اجرا

    PDF‌:‌دارد
    نمونه کد: دارد

    مقدمه
    با گسترش استفاده از كامپيوتر در بسياري از امور روزمره انسان ها سازگار بودن برنامه ها با سليقه كاربران به يكي از نياز هاي اصلي برنامه هاي كامپيوتري تبديل شده است. بدون شك زبان و فرهنگ يكي از مهم ترين عوامل در ايجاد ارتباط نزديك بين برنامه و كاربر به شمار مي رود و نقشي غير قابل انكار در ميزان موفقيت يك برنامه به عهده دارد. از اين رو در اين نوشته تلاش بر آن است تا يكي از ساده ترين و در عين حال كارا ترين راه هاي ممكن براي ايجاد برنامه هاي چند زبانه با استفاده از تكنولوژي WPF آموزش داده شود.

    مروري بر روش هاي موجود
    همواره روش هاي مختلفي براي پياده سازي يك ايده در دنياي نرم افزار وجود دارد كه هر روش را مي توان بر حسب نياز مورد استفاده قرار داد. در برنامه هاي مبتني بر WPF معمولا از دو روش عمده براي اين منظور استفاده مي شود:
    1- استفاده از فايل هاي .resx
    در اين روش كه براي Win App نيز استفاده مي شود، اطلاعات مورد نياز براي هر زبان به شكل جدول هايي داراي كليد و مقدار در داخل يك فايل .resx نگهداري مي شود و در زمان اجراي برنامه بر اساس انتخاب كاربر اطلاعات زبان مورد نظر از داخل فايل .resx load شده و نمايش داده مي شود. يكي از ضعف هايي كه اين روش در عين ساده بودن دارد اين است كه همه اطلاعات مورد نياز داخل assembly اصلي برنامه قرار مي گيرد و امكان افزودن زبان هاي جديد بدون تغيير دادن برنامه اصلي ممكن نخواهد بود.
    2- استفاده از فايل هاي .csv كه به فايل هاي .dll تبديل مي شوند
    در اين روش كه مختص برنامه هاي WPF مي باشد با استفاده از ابزار هاي موجود در كامپايلر WPF براي هر كنترل يك property به نام Uid ايجاد شده و مقدار دهي مي شود. سپس با ابزار ديگري ( كه جزو ابزار هاي كامپايلر محسوب نمي شود ) از فايل .csproj پروژه يك خروجي اكسل با فرمت .csv ايجاد مي شود كه شامل Uid هاي كنترل ها و مقادير آن ها است. پس از ترجمه متون مورد نظر به زبان مقصد با كمك ابزار ديگري فايل اكسل مورد نظر به يك .net assembly تبديل مي شود و داخل پوشه اي با نام culture استاندارد ذخيره مي شود. ( مثلا براي زبان فارسي نام پوشه fa-IR خواهد بود ). زماني كه برنامه اجرا مي شود بر اساس culture اي كه در سيستم عامل انتخاب شده است و در صورتي كه براي آن culture فايل .dll اي موجود باشد، زبان مربوط به آن culture را load خواهد كرد. با وجود اين كه اين روش مشكل روش قبلي را ندارد و بيشتر با ويژگي هاي WPF سازگار است اما پروسه اي طولاني براي انجام كار ها دارد و به ازاي هر تغييري بايد كل مراحل هر بار تكرار شوند. همچنين مشكلاتي در نمايش برخي زبان ها ( از جمله فارسي ) در اين روش مشاهده شده است.

    روش سوم!
    روش سوم اما كاملا بر پايه WPF و در اصطلاح WPF-Native مي باشد. ايده از آنجا ناشي شده است كه براي ايجاد skin در برنامه هاي WPF استفاده مي شود. در ايجاد برنامه هاي Skin-Based به اين شيوه عمل مي شود كه skin هاي مورد نظر به صورت style هايي در داخل resource dictionary ها قرار مي گيرند. سپس آن resource dictionary به شكل .dll كامپايل مي شود. در برنامه اصلي نيز همه كنترل ها style هايشان را به شكل dynamic resource از داخل يك resource dictionary مشخص شده load مي كنند. حال كافي است براي تغيير skin، resource dictionary مورد نظر از .dll مشخص load شود و resource dictionary اي كه در حال حاضر در برنامه از آن استفاده مي شود با resource dictionary اي كه load شده جايگزين شود. كنترل ها مقادير جديد را از resource dictionary جديد به شكل كاملا خودكار دريافت خواهند كرد.
    خوب! به سادگي مي توان از اين روش براي تغيير زبان برنامه نيز استفاده كرد.

    پياده سازي
    در اين قسمت نحوه پياده سازي اين روش با ايجاد يك نمونه برنامه ساده كه داراي دو زبان انگليسي و فارسي خواهد بود آموزش داده مي شود.
    ابتدا يك پروژه WPF Application در Visual Studio 2010 ايجاد كنيد. در MainWindow سه كنترل Button قرار دهيد و يك ComboBox كه قرار است زبان هاي موجود را نمايش دهد و با انتخاب يك زبان، نوشته هاي درون Button ها متناسب با آن تغيير خواهند كرد.


    توجه داشته باشيد كه براي Button ها نبايد به صورت مستقيم مقداري به Content شان داده شود. بلكه بايد مقدار مورد نظر از داخل resource dictionary كه خواهيم ساخت به شكل dynamic گرفته خواهد شد. پس در اين مرحله يك ResourceDictionary به پروژه اضافه خواهيم كرد و در آن resource هايي به شكل string ايجاد خواهيم كرد. هر resource داراي يك Key مي باشد كه بر اساس آن، Button مورد نظر مقدار آن Resource را load خواهد كرد. فايل ResourceDictionary را Culture_en-US.xaml نامگذاري كنيد و مقادير مورد نظر را به آن اضافه نماييد.
    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <system:String x:Key="button1">Hello!</system:String>
    <system:String x:Key="button2">How Are You?</system:String>
    <system:String x:Key="button3">Are You OK?</system:String>

    </ResourceDictionary>


    دقت كنيد كه namespace اي كه كلاس string در آن قرار دارد به فايل xaml اضافه شده است.

    پس از اين كار فايل App.xaml به اين شكل خواهد بود:
    <Application x:Class="BeRMOoDA.WPF.LocalizationSample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="MainWindow.xaml">
    <Application.Resources>

    <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="Culture_en-US.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>

    </Application.Resources>
    </Application>


    براي استفاده از اين resource ها به عنوان Content براي Button ها نيز آن ها را به صورت DynamicResource، load خواهيم كرد:
    <Button Content="{DynamicResource ResourceKey=button1}" />
    <Button Content="{DynamicResource ResourceKey=button2}" />
    <Button Content="{DynamicResource ResourceKey=button3}" />


    بسيار خوب! اكنون بايد شروع به ايجاد يك ResourceDictionary براي زبان فارسي كنيم و آن را به صورت يك فايل .dll كامپايل نماييم.
    براي اين كار يك پروژه جديد در قسمت WPF از نوع User control ايجاد مي كنيم و نام آن را Culture_fa-IR_Farsi قرار مي دهيم. لطفا شيوه نامگذاري را رعايت كنيد چرا كه در ادامه به آن نياز خواهيم داشت.
    پس از ايجاد پروژه فايل UserControl1.xaml را از پروژه حذف كنيد و يك ResourceDictionary با نام Culture_fa-IR.xaml اضافه كنيد. محتواي آن را پاك كنيد و محتواي فايل Culture_en-US.xaml را از پروژه قبلي به صورت كامل در فايل جديد كپي كنيد. دو فايل بايد ساختار كاملا يكساني از نظر key براي resource هاي موجود داشته باشند. حالا زمان ترجمه فرا رسيده است! رشته هاي دلخواه را ترجمه كنيد و پروژه را build نماييد.
    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="Culture_fa-IR_Farsi.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <system:String x:Key="button1">سلام!</system:String>
    <system:String x:Key="button2">حالت چطوره؟</system:String>
    <system:String x:Key="button3">خوبی؟</system:String>
    </ResourceDictionary>


    خروجي يك فايل با نام Culture_fa-IR_Farsi.dll خواهد بود.

    در اين مرحله كاري كه بايد انجام دهيم چيست؟
    راهكاري ارئه دهيم تا بتوان فايل هاي .dll مربوط به زبان ها را در زمان اجراي برنامه load كرده و نام زبان ها را در داخل ComboBox اي كه داريم نشان دهد. سپس با انتخاب هر زبان در ComboBox، محتواي Button ها بر اساس زبان انتخاب شده تغيير كند.
    براي سهولت كار، نام فايل ها را به گونه اي انتخاب كرديم كه بتوانيم ساده تر به اين هدف برسيم. نام هر فايل از سه بخش تشكيل شده است:
    Culture_[standard culture notation]_[display name for this culture].dll
    يعني اگر فايل Culture_fa-IR_Farsi.dll را در نظر بگيريم، Culture نشان دهنده اين است كه اين فايل مربوط به يك culture مي باشد. fa-IR نمايش استاندارد culture براي كشور ايران و زبان فارسي است و Farsi هم مقداري است كه مي خواهيم در ComboBox براي اين زبان نمايش داده شود.
    پوشه اي با نام Languages در كنار فايل .exe برنامه ايجاد كنيد و فايل Culture_fa-IR_Farsi.dll را درون آن كپي كنيد. تصميم داريم همه .dll هاي مربوط به زبان ها را داخل اين پوشه قرار دهيم تا مديريت آن ها ساده تر شود.
    براي مديريت بهتر فايل هاي مربوط به زبان ها يك كلاس با نام CultureAssemblyModel خواهيم ساخت كه هر object از آن نشانگر يك فايل زبان خواهد بود. يك كلاس با اين نام به پروژه اضافه كنيد و property هاي زير را در آن تعريف نماييد:
    public class CultureAssemblyModel
    {
    //the text will be displayed to user as language name (like Farsi)
    public string DisplayText { get; set; }
    //name of .dll file (like Culture_fa-IR_Farsi.dll)
    public string Name { get; set; }
    //standar notation of this culture (like fa-IR)
    public string Culture { get; set; }
    //name of resource dictionary file name inside the loaded .dll (like Culture_fa-IR.xaml)
    public string XamlFileName { get; set; }
    }


    براي ComboBox نيز يك DataTemplate تعريف مي كنيم تا فقط فيلد DisplayText از اين كلاس را نمايش دهد:
    <ComboBox HorizontalAlignment="Left" Margin="10" VerticalAlignment="Top" MinWidth="100" Name="comboboxLanguages">
    <ComboBox.ItemTemplate>
    <DataTemplate>
    <Label Content="{Binding DisplayText}"/>
    </DataTemplate>
    </ComboBox.ItemTemplate>
    </ComboBox>


    براي load كردن نام فايل هاي .dll مربوط به زبان ها متدي تعريف مي كنيم به اسم LoadCultureAssmeblies به شكل زير:
    //will keep information about loaded assemblies
    public List<CultureAssemblyModel> CultureAssemblies { get; set; }

    //loads assmeblies in languages folder and adds their info to list
    void LoadCultureAssemblies()
    {
    //we should be sure that list is empty before adding info (do u want to add some cultures more than one? of course u dont!)
    CultureAssemblies.Clear();
    //creating a directory represents applications directory\languages
    DirectoryInfo dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirector y + "\\languages");
    //getting all .dll files in the language folder and its sub dirs. (who knows? maybe someone keeps each culture file in a seperate folder!)
    var assemblies = dir.GetFiles("*.dll", SearchOption.AllDirectories);
    //for each found .dll we will create a model and set its properties and then add to list for (int i = 0; i < assemblies.Count(); i++)
    {
    CultureAssemblyModel model = new CultureAssemblyModel() { DisplayText = assemblies[i].Name.Split('.', '_')[2], Culture = assemblies[i].Name.Split('.', '_')[1], Name = assemblies[i].Name, XamlFileName =assemblies[i].Name.Substring(0, assemblies[i].Name.LastIndexOf(".")) + ".xaml" };
    CultureAssemblies.Add(model);
    }
    }


    اطلاعات مورد نياز از فايل هاي .dll خوانده شده و در ليست نگهداري مي شوند. براي نمايش دادن نام زبان ها در ComboBox كافي است اين ليست را به عنوان ItemsSource قرار دهيم:
    comboboxLanguages.ItemsSource = CultureAssemblies;


    با handle كردن رويداد selectionChanged مربوط به ComboBox زبان انتخاب شده را به متد LoadCulture كه در فايل App.cs (كلاس اصلي برنامه) تعريف كرده ايم ارسال مي كنيم:
    //loads selected culture
    public void LoadCulture(CultureAssemblyModel culture)
    {
    //setting current culture of applpications main thread to selected one.
    System.Threading.Thread.CurrentThread.CurrentUICul ture = new System.Globalization.CultureInfo(culture.Culture);
    System.Threading.Thread.CurrentThread.CurrentCultu re = new System.Globalization.CultureInfo(culture.Culture);
    //creating a FileInfo object represents .dll file of selected cultur
    FileInfo assemblyFile = new FileInfo("languages\\" + culture.Name);
    //loading .dll into memory as a .net assembly
    var assembly = Assembly.LoadFile(assemblyFile.FullName);
    //getting .dll file name
    var assemblyName = assemblyFile.Name.Substring(0, assemblyFile.Name.LastIndexOf("."));
    //creating string represents structure of a pack uri (something like this: /{myassemblyname;component/myresourcefile.xaml}
    string packUri = string.Format(@"/{0};component/{1}", assemblyName, culture.XamlFileName);
    //creating a pack uri
    Uri uri = new Uri(packUri, UriKind.Relative);
    //now we have created a pack uri that represents a resource object in loaded assembly
    //and its time to load that as a resource dictionary (do u remember that we had resource dictionary in culture assemblies? don't u?)
    var dic = Application.LoadComponent(uri) as ResourceDictionary;
    dic.Source = uri;
    //here we will remove current merged dictionaries in our resource dictionary and add recently-loaded resource dictionary as e merged dictionary
    var mergedDics = this.Resources.MergedDictionaries;
    if (mergedDics.Count > 0)
    mergedDics.Clear();
    mergedDics.Add(dic);
    }


    void comboboxLanguages_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
    var selectedCulture = (CultureAssemblyModel)comboboxLanguages.SelectedIt em;
    App app = Application.Current as App;
    app.LoadCulture(selectedCulture);
    }



    متد LoadCulture با گرفتن مشخصات زبان ارسال شده، culture سيستم را به زبان مورد نظر تغيير داده و resource dictionary مربوط به آن را از داخل فايل .dll آن زبان load كرده و آن را با resource dictionary فعلي برنامه جايگزين مي كند. Button ها كه محتواي خود را به شكل dynamic از داخل اين resource dictionary دريافت مي كردند حالا از داخل فايل جايگزين شده خواهند گرفت.

    كار انجام شد!
    از مزيت هاي اين روش مي توان به WPF-Native بودن، سادگي در پياده سازي، قابليت load كردن هر زبان جديدي در زمان اجرا بدون نياز به كوچك ترين تغيير در برنامه اصلي و همچنين پشتيباني كامل از نمايش زبان هاي مختلف از جمله فارسي اشاره كرد.

    لینک اول PDF و لینک دوم نمونه برنامه هستند.
    فایل های ضمیمه فایل های ضمیمه

  8. #8
    کاربر دائمی آواتار morteza_carefree
    تاریخ عضویت
    فروردین 1389
    محل زندگی
    رو به غروب CPU
    پست
    144

    نقل قول: ايجاد برنامه هاي چند زبانه در WPF با قابليت افزودن زبان هاي جديد در زمان اجرا

    دوست عزیز ممنون از آموزش خوبت واقعا عالی بود
    امکانش هست مال skin هارم بگی ؟

  9. #9
    کاربر دائمی آواتار morteza_carefree
    تاریخ عضویت
    فروردین 1389
    محل زندگی
    رو به غروب CPU
    پست
    144

    نقل قول: ايجاد برنامه هاي چند زبانه در WPF با قابليت افزودن زبان هاي جديد در زمان اجرا

    نقل قول نوشته شده توسط Amir Oveisi مشاهده تاپیک
    PDF‌:‌دارد
    نمونه کد: دارد

    مقدمه
    با گسترش استفاده از كامپيوتر در بسياري از امور روزمره انسان ها سازگار بودن برنامه ها با سليقه كاربران به يكي از نياز هاي اصلي برنامه هاي كامپيوتري تبديل شده است. بدون شك زبان و فرهنگ يكي از مهم ترين عوامل در ايجاد ارتباط نزديك بين برنامه و كاربر به شمار مي رود و نقشي غير قابل انكار در ميزان موفقيت يك برنامه به عهده دارد. از اين رو در اين نوشته تلاش بر آن است تا يكي از ساده ترين و در عين حال كارا ترين راه هاي ممكن براي ايجاد برنامه هاي چند زبانه با استفاده از تكنولوژي WPF آموزش داده شود.

    مروري بر روش هاي موجود
    همواره روش هاي مختلفي براي پياده سازي يك ايده در دنياي نرم افزار وجود دارد كه هر روش را مي توان بر حسب نياز مورد استفاده قرار داد. در برنامه هاي مبتني بر WPF معمولا از دو روش عمده براي اين منظور استفاده مي شود:
    1- استفاده از فايل هاي .resx
    در اين روش كه براي Win App نيز استفاده مي شود، اطلاعات مورد نياز براي هر زبان به شكل جدول هايي داراي كليد و مقدار در داخل يك فايل .resx نگهداري مي شود و در زمان اجراي برنامه بر اساس انتخاب كاربر اطلاعات زبان مورد نظر از داخل فايل .resx load شده و نمايش داده مي شود. يكي از ضعف هايي كه اين روش در عين ساده بودن دارد اين است كه همه اطلاعات مورد نياز داخل assembly اصلي برنامه قرار مي گيرد و امكان افزودن زبان هاي جديد بدون تغيير دادن برنامه اصلي ممكن نخواهد بود.
    2- استفاده از فايل هاي .csv كه به فايل هاي .dll تبديل مي شوند
    در اين روش كه مختص برنامه هاي WPF مي باشد با استفاده از ابزار هاي موجود در كامپايلر WPF براي هر كنترل يك property به نام Uid ايجاد شده و مقدار دهي مي شود. سپس با ابزار ديگري ( كه جزو ابزار هاي كامپايلر محسوب نمي شود ) از فايل .csproj پروژه يك خروجي اكسل با فرمت .csv ايجاد مي شود كه شامل Uid هاي كنترل ها و مقادير آن ها است. پس از ترجمه متون مورد نظر به زبان مقصد با كمك ابزار ديگري فايل اكسل مورد نظر به يك .net assembly تبديل مي شود و داخل پوشه اي با نام culture استاندارد ذخيره مي شود. ( مثلا براي زبان فارسي نام پوشه fa-IR خواهد بود ). زماني كه برنامه اجرا مي شود بر اساس culture اي كه در سيستم عامل انتخاب شده است و در صورتي كه براي آن culture فايل .dll اي موجود باشد، زبان مربوط به آن culture را load خواهد كرد. با وجود اين كه اين روش مشكل روش قبلي را ندارد و بيشتر با ويژگي هاي WPF سازگار است اما پروسه اي طولاني براي انجام كار ها دارد و به ازاي هر تغييري بايد كل مراحل هر بار تكرار شوند. همچنين مشكلاتي در نمايش برخي زبان ها ( از جمله فارسي ) در اين روش مشاهده شده است.

    روش سوم!
    روش سوم اما كاملا بر پايه WPF و در اصطلاح WPF-Native مي باشد. ايده از آنجا ناشي شده است كه براي ايجاد skin در برنامه هاي WPF استفاده مي شود. در ايجاد برنامه هاي Skin-Based به اين شيوه عمل مي شود كه skin هاي مورد نظر به صورت style هايي در داخل resource dictionary ها قرار مي گيرند. سپس آن resource dictionary به شكل .dll كامپايل مي شود. در برنامه اصلي نيز همه كنترل ها style هايشان را به شكل dynamic resource از داخل يك resource dictionary مشخص شده load مي كنند. حال كافي است براي تغيير skin، resource dictionary مورد نظر از .dll مشخص load شود و resource dictionary اي كه در حال حاضر در برنامه از آن استفاده مي شود با resource dictionary اي كه load شده جايگزين شود. كنترل ها مقادير جديد را از resource dictionary جديد به شكل كاملا خودكار دريافت خواهند كرد.
    خوب! به سادگي مي توان از اين روش براي تغيير زبان برنامه نيز استفاده كرد.

    پياده سازي
    در اين قسمت نحوه پياده سازي اين روش با ايجاد يك نمونه برنامه ساده كه داراي دو زبان انگليسي و فارسي خواهد بود آموزش داده مي شود.
    ابتدا يك پروژه WPF Application در Visual Studio 2010 ايجاد كنيد. در MainWindow سه كنترل Button قرار دهيد و يك ComboBox كه قرار است زبان هاي موجود را نمايش دهد و با انتخاب يك زبان، نوشته هاي درون Button ها متناسب با آن تغيير خواهند كرد.


    توجه داشته باشيد كه براي Button ها نبايد به صورت مستقيم مقداري به Content شان داده شود. بلكه بايد مقدار مورد نظر از داخل resource dictionary كه خواهيم ساخت به شكل dynamic گرفته خواهد شد. پس در اين مرحله يك ResourceDictionary به پروژه اضافه خواهيم كرد و در آن resource هايي به شكل string ايجاد خواهيم كرد. هر resource داراي يك Key مي باشد كه بر اساس آن، Button مورد نظر مقدار آن Resource را load خواهد كرد. فايل ResourceDictionary را Culture_en-US.xaml نامگذاري كنيد و مقادير مورد نظر را به آن اضافه نماييد.
    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <system:String x:Key="button1">Hello!</system:String>
    <system:String x:Key="button2">How Are You?</system:String>
    <system:String x:Key="button3">Are You OK?</system:String>

    </ResourceDictionary>


    دقت كنيد كه namespace اي كه كلاس string در آن قرار دارد به فايل xaml اضافه شده است.

    پس از اين كار فايل App.xaml به اين شكل خواهد بود:
    <Application x:Class="BeRMOoDA.WPF.LocalizationSample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="MainWindow.xaml">
    <Application.Resources>

    <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="Culture_en-US.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>

    </Application.Resources>
    </Application>


    براي استفاده از اين resource ها به عنوان Content براي Button ها نيز آن ها را به صورت DynamicResource، load خواهيم كرد:
    <Button Content="{DynamicResource ResourceKey=button1}" />
    <Button Content="{DynamicResource ResourceKey=button2}" />
    <Button Content="{DynamicResource ResourceKey=button3}" />


    بسيار خوب! اكنون بايد شروع به ايجاد يك ResourceDictionary براي زبان فارسي كنيم و آن را به صورت يك فايل .dll كامپايل نماييم.
    براي اين كار يك پروژه جديد در قسمت WPF از نوع User control ايجاد مي كنيم و نام آن را Culture_fa-IR_Farsi قرار مي دهيم. لطفا شيوه نامگذاري را رعايت كنيد چرا كه در ادامه به آن نياز خواهيم داشت.
    پس از ايجاد پروژه فايل UserControl1.xaml را از پروژه حذف كنيد و يك ResourceDictionary با نام Culture_fa-IR.xaml اضافه كنيد. محتواي آن را پاك كنيد و محتواي فايل Culture_en-US.xaml را از پروژه قبلي به صورت كامل در فايل جديد كپي كنيد. دو فايل بايد ساختار كاملا يكساني از نظر key براي resource هاي موجود داشته باشند. حالا زمان ترجمه فرا رسيده است! رشته هاي دلخواه را ترجمه كنيد و پروژه را build نماييد.
    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="Culture_fa-IR_Farsi.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <system:String x:Key="button1">سلام!</system:String>
    <system:String x:Key="button2">حالت چطوره؟</system:String>
    <system:String x:Key="button3">خوبی؟</system:String>
    </ResourceDictionary>


    خروجي يك فايل با نام Culture_fa-IR_Farsi.dll خواهد بود.

    در اين مرحله كاري كه بايد انجام دهيم چيست؟
    راهكاري ارئه دهيم تا بتوان فايل هاي .dll مربوط به زبان ها را در زمان اجراي برنامه load كرده و نام زبان ها را در داخل ComboBox اي كه داريم نشان دهد. سپس با انتخاب هر زبان در ComboBox، محتواي Button ها بر اساس زبان انتخاب شده تغيير كند.
    براي سهولت كار، نام فايل ها را به گونه اي انتخاب كرديم كه بتوانيم ساده تر به اين هدف برسيم. نام هر فايل از سه بخش تشكيل شده است:
    Culture_[standard culture notation]_[display name for this culture].dll
    يعني اگر فايل Culture_fa-IR_Farsi.dll را در نظر بگيريم، Culture نشان دهنده اين است كه اين فايل مربوط به يك culture مي باشد. fa-IR نمايش استاندارد culture براي كشور ايران و زبان فارسي است و Farsi هم مقداري است كه مي خواهيم در ComboBox براي اين زبان نمايش داده شود.
    پوشه اي با نام Languages در كنار فايل .exe برنامه ايجاد كنيد و فايل Culture_fa-IR_Farsi.dll را درون آن كپي كنيد. تصميم داريم همه .dll هاي مربوط به زبان ها را داخل اين پوشه قرار دهيم تا مديريت آن ها ساده تر شود.
    براي مديريت بهتر فايل هاي مربوط به زبان ها يك كلاس با نام CultureAssemblyModel خواهيم ساخت كه هر object از آن نشانگر يك فايل زبان خواهد بود. يك كلاس با اين نام به پروژه اضافه كنيد و property هاي زير را در آن تعريف نماييد:
    public class CultureAssemblyModel
    {
    //the text will be displayed to user as language name (like Farsi)
    public string DisplayText { get; set; }
    //name of .dll file (like Culture_fa-IR_Farsi.dll)
    public string Name { get; set; }
    //standar notation of this culture (like fa-IR)
    public string Culture { get; set; }
    //name of resource dictionary file name inside the loaded .dll (like Culture_fa-IR.xaml)
    public string XamlFileName { get; set; }
    }


    براي ComboBox نيز يك DataTemplate تعريف مي كنيم تا فقط فيلد DisplayText از اين كلاس را نمايش دهد:
    <ComboBox HorizontalAlignment="Left" Margin="10" VerticalAlignment="Top" MinWidth="100" Name="comboboxLanguages">
    <ComboBox.ItemTemplate>
    <DataTemplate>
    <Label Content="{Binding DisplayText}"/>
    </DataTemplate>
    </ComboBox.ItemTemplate>
    </ComboBox>


    براي load كردن نام فايل هاي .dll مربوط به زبان ها متدي تعريف مي كنيم به اسم LoadCultureAssmeblies به شكل زير:
    //will keep information about loaded assemblies
    public List<CultureAssemblyModel> CultureAssemblies { get; set; }

    //loads assmeblies in languages folder and adds their info to list
    void LoadCultureAssemblies()
    {
    //we should be sure that list is empty before adding info (do u want to add some cultures more than one? of course u dont!)
    CultureAssemblies.Clear();
    //creating a directory represents applications directory\languages
    DirectoryInfo dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirector y + "\\languages");
    //getting all .dll files in the language folder and its sub dirs. (who knows? maybe someone keeps each culture file in a seperate folder!)
    var assemblies = dir.GetFiles("*.dll", SearchOption.AllDirectories);
    //for each found .dll we will create a model and set its properties and then add to list for (int i = 0; i < assemblies.Count(); i++)
    {
    CultureAssemblyModel model = new CultureAssemblyModel() { DisplayText = assemblies[i].Name.Split('.', '_')[2], Culture = assemblies[i].Name.Split('.', '_')[1], Name = assemblies[i].Name, XamlFileName =assemblies[i].Name.Substring(0, assemblies[i].Name.LastIndexOf(".")) + ".xaml" };
    CultureAssemblies.Add(model);
    }
    }


    اطلاعات مورد نياز از فايل هاي .dll خوانده شده و در ليست نگهداري مي شوند. براي نمايش دادن نام زبان ها در ComboBox كافي است اين ليست را به عنوان ItemsSource قرار دهيم:
    comboboxLanguages.ItemsSource = CultureAssemblies;


    با handle كردن رويداد selectionChanged مربوط به ComboBox زبان انتخاب شده را به متد LoadCulture كه در فايل App.cs (كلاس اصلي برنامه) تعريف كرده ايم ارسال مي كنيم:
    //loads selected culture
    public void LoadCulture(CultureAssemblyModel culture)
    {
    //setting current culture of applpications main thread to selected one.
    System.Threading.Thread.CurrentThread.CurrentUICul ture = new System.Globalization.CultureInfo(culture.Culture);
    System.Threading.Thread.CurrentThread.CurrentCultu re = new System.Globalization.CultureInfo(culture.Culture);
    //creating a FileInfo object represents .dll file of selected cultur
    FileInfo assemblyFile = new FileInfo("languages\\" + culture.Name);
    //loading .dll into memory as a .net assembly
    var assembly = Assembly.LoadFile(assemblyFile.FullName);
    //getting .dll file name
    var assemblyName = assemblyFile.Name.Substring(0, assemblyFile.Name.LastIndexOf("."));
    //creating string represents structure of a pack uri (something like this: /{myassemblyname;component/myresourcefile.xaml}
    string packUri = string.Format(@"/{0};component/{1}", assemblyName, culture.XamlFileName);
    //creating a pack uri
    Uri uri = new Uri(packUri, UriKind.Relative);
    //now we have created a pack uri that represents a resource object in loaded assembly
    //and its time to load that as a resource dictionary (do u remember that we had resource dictionary in culture assemblies? don't u?)
    var dic = Application.LoadComponent(uri) as ResourceDictionary;
    dic.Source = uri;
    //here we will remove current merged dictionaries in our resource dictionary and add recently-loaded resource dictionary as e merged dictionary
    var mergedDics = this.Resources.MergedDictionaries;
    if (mergedDics.Count > 0)
    mergedDics.Clear();
    mergedDics.Add(dic);
    }


    void comboboxLanguages_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
    var selectedCulture = (CultureAssemblyModel)comboboxLanguages.SelectedIt em;
    App app = Application.Current as App;
    app.LoadCulture(selectedCulture);
    }



    متد LoadCulture با گرفتن مشخصات زبان ارسال شده، culture سيستم را به زبان مورد نظر تغيير داده و resource dictionary مربوط به آن را از داخل فايل .dll آن زبان load كرده و آن را با resource dictionary فعلي برنامه جايگزين مي كند. Button ها كه محتواي خود را به شكل dynamic از داخل اين resource dictionary دريافت مي كردند حالا از داخل فايل جايگزين شده خواهند گرفت.

    كار انجام شد!
    از مزيت هاي اين روش مي توان به WPF-Native بودن، سادگي در پياده سازي، قابليت load كردن هر زبان جديدي در زمان اجرا بدون نياز به كوچك ترين تغيير در برنامه اصلي و همچنين پشتيباني كامل از نمايش زبان هاي مختلف از جمله فارسي اشاره كرد.

    لینک اول PDF و لینک دوم نمونه برنامه هستند.
    دوست عزیز من تو پروژه خودم تو این خط به مشکل بر میخورم
    var dic = Application.LoadComponent(uri) as ResourceDictionary;

    StackOverflowException

  10. #10
    کاربر دائمی آواتار morteza_carefree
    تاریخ عضویت
    فروردین 1389
    محل زندگی
    رو به غروب CPU
    پست
    144

    نقل قول: ايجاد برنامه هاي چند زبانه در WPF با قابليت افزودن زبان هاي جديد در زمان اجرا

    نقل قول نوشته شده توسط Amir Oveisi مشاهده تاپیک
    PDF‌:‌دارد
    نمونه کد: دارد

    مقدمه
    با گسترش استفاده از كامپيوتر در بسياري از امور روزمره انسان ها سازگار بودن برنامه ها با سليقه كاربران به يكي از نياز هاي اصلي برنامه هاي كامپيوتري تبديل شده است. بدون شك زبان و فرهنگ يكي از مهم ترين عوامل در ايجاد ارتباط نزديك بين برنامه و كاربر به شمار مي رود و نقشي غير قابل انكار در ميزان موفقيت يك برنامه به عهده دارد. از اين رو در اين نوشته تلاش بر آن است تا يكي از ساده ترين و در عين حال كارا ترين راه هاي ممكن براي ايجاد برنامه هاي چند زبانه با استفاده از تكنولوژي WPF آموزش داده شود.

    مروري بر روش هاي موجود
    همواره روش هاي مختلفي براي پياده سازي يك ايده در دنياي نرم افزار وجود دارد كه هر روش را مي توان بر حسب نياز مورد استفاده قرار داد. در برنامه هاي مبتني بر WPF معمولا از دو روش عمده براي اين منظور استفاده مي شود:
    1- استفاده از فايل هاي .resx
    در اين روش كه براي Win App نيز استفاده مي شود، اطلاعات مورد نياز براي هر زبان به شكل جدول هايي داراي كليد و مقدار در داخل يك فايل .resx نگهداري مي شود و در زمان اجراي برنامه بر اساس انتخاب كاربر اطلاعات زبان مورد نظر از داخل فايل .resx load شده و نمايش داده مي شود. يكي از ضعف هايي كه اين روش در عين ساده بودن دارد اين است كه همه اطلاعات مورد نياز داخل assembly اصلي برنامه قرار مي گيرد و امكان افزودن زبان هاي جديد بدون تغيير دادن برنامه اصلي ممكن نخواهد بود.
    2- استفاده از فايل هاي .csv كه به فايل هاي .dll تبديل مي شوند
    در اين روش كه مختص برنامه هاي WPF مي باشد با استفاده از ابزار هاي موجود در كامپايلر WPF براي هر كنترل يك property به نام Uid ايجاد شده و مقدار دهي مي شود. سپس با ابزار ديگري ( كه جزو ابزار هاي كامپايلر محسوب نمي شود ) از فايل .csproj پروژه يك خروجي اكسل با فرمت .csv ايجاد مي شود كه شامل Uid هاي كنترل ها و مقادير آن ها است. پس از ترجمه متون مورد نظر به زبان مقصد با كمك ابزار ديگري فايل اكسل مورد نظر به يك .net assembly تبديل مي شود و داخل پوشه اي با نام culture استاندارد ذخيره مي شود. ( مثلا براي زبان فارسي نام پوشه fa-IR خواهد بود ). زماني كه برنامه اجرا مي شود بر اساس culture اي كه در سيستم عامل انتخاب شده است و در صورتي كه براي آن culture فايل .dll اي موجود باشد، زبان مربوط به آن culture را load خواهد كرد. با وجود اين كه اين روش مشكل روش قبلي را ندارد و بيشتر با ويژگي هاي WPF سازگار است اما پروسه اي طولاني براي انجام كار ها دارد و به ازاي هر تغييري بايد كل مراحل هر بار تكرار شوند. همچنين مشكلاتي در نمايش برخي زبان ها ( از جمله فارسي ) در اين روش مشاهده شده است.

    روش سوم!
    روش سوم اما كاملا بر پايه WPF و در اصطلاح WPF-Native مي باشد. ايده از آنجا ناشي شده است كه براي ايجاد skin در برنامه هاي WPF استفاده مي شود. در ايجاد برنامه هاي Skin-Based به اين شيوه عمل مي شود كه skin هاي مورد نظر به صورت style هايي در داخل resource dictionary ها قرار مي گيرند. سپس آن resource dictionary به شكل .dll كامپايل مي شود. در برنامه اصلي نيز همه كنترل ها style هايشان را به شكل dynamic resource از داخل يك resource dictionary مشخص شده load مي كنند. حال كافي است براي تغيير skin، resource dictionary مورد نظر از .dll مشخص load شود و resource dictionary اي كه در حال حاضر در برنامه از آن استفاده مي شود با resource dictionary اي كه load شده جايگزين شود. كنترل ها مقادير جديد را از resource dictionary جديد به شكل كاملا خودكار دريافت خواهند كرد.
    خوب! به سادگي مي توان از اين روش براي تغيير زبان برنامه نيز استفاده كرد.

    پياده سازي
    در اين قسمت نحوه پياده سازي اين روش با ايجاد يك نمونه برنامه ساده كه داراي دو زبان انگليسي و فارسي خواهد بود آموزش داده مي شود.
    ابتدا يك پروژه WPF Application در Visual Studio 2010 ايجاد كنيد. در MainWindow سه كنترل Button قرار دهيد و يك ComboBox كه قرار است زبان هاي موجود را نمايش دهد و با انتخاب يك زبان، نوشته هاي درون Button ها متناسب با آن تغيير خواهند كرد.


    توجه داشته باشيد كه براي Button ها نبايد به صورت مستقيم مقداري به Content شان داده شود. بلكه بايد مقدار مورد نظر از داخل resource dictionary كه خواهيم ساخت به شكل dynamic گرفته خواهد شد. پس در اين مرحله يك ResourceDictionary به پروژه اضافه خواهيم كرد و در آن resource هايي به شكل string ايجاد خواهيم كرد. هر resource داراي يك Key مي باشد كه بر اساس آن، Button مورد نظر مقدار آن Resource را load خواهد كرد. فايل ResourceDictionary را Culture_en-US.xaml نامگذاري كنيد و مقادير مورد نظر را به آن اضافه نماييد.
    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <system:String x:Key="button1">Hello!</system:String>
    <system:String x:Key="button2">How Are You?</system:String>
    <system:String x:Key="button3">Are You OK?</system:String>

    </ResourceDictionary>


    دقت كنيد كه namespace اي كه كلاس string در آن قرار دارد به فايل xaml اضافه شده است.

    پس از اين كار فايل App.xaml به اين شكل خواهد بود:
    <Application x:Class="BeRMOoDA.WPF.LocalizationSample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="MainWindow.xaml">
    <Application.Resources>

    <ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="Culture_en-US.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>

    </Application.Resources>
    </Application>


    براي استفاده از اين resource ها به عنوان Content براي Button ها نيز آن ها را به صورت DynamicResource، load خواهيم كرد:
    <Button Content="{DynamicResource ResourceKey=button1}" />
    <Button Content="{DynamicResource ResourceKey=button2}" />
    <Button Content="{DynamicResource ResourceKey=button3}" />


    بسيار خوب! اكنون بايد شروع به ايجاد يك ResourceDictionary براي زبان فارسي كنيم و آن را به صورت يك فايل .dll كامپايل نماييم.
    براي اين كار يك پروژه جديد در قسمت WPF از نوع User control ايجاد مي كنيم و نام آن را Culture_fa-IR_Farsi قرار مي دهيم. لطفا شيوه نامگذاري را رعايت كنيد چرا كه در ادامه به آن نياز خواهيم داشت.
    پس از ايجاد پروژه فايل UserControl1.xaml را از پروژه حذف كنيد و يك ResourceDictionary با نام Culture_fa-IR.xaml اضافه كنيد. محتواي آن را پاك كنيد و محتواي فايل Culture_en-US.xaml را از پروژه قبلي به صورت كامل در فايل جديد كپي كنيد. دو فايل بايد ساختار كاملا يكساني از نظر key براي resource هاي موجود داشته باشند. حالا زمان ترجمه فرا رسيده است! رشته هاي دلخواه را ترجمه كنيد و پروژه را build نماييد.
    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="Culture_fa-IR_Farsi.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <system:String x:Key="button1">سلام!</system:String>
    <system:String x:Key="button2">حالت چطوره؟</system:String>
    <system:String x:Key="button3">خوبی؟</system:String>
    </ResourceDictionary>


    خروجي يك فايل با نام Culture_fa-IR_Farsi.dll خواهد بود.

    در اين مرحله كاري كه بايد انجام دهيم چيست؟
    راهكاري ارئه دهيم تا بتوان فايل هاي .dll مربوط به زبان ها را در زمان اجراي برنامه load كرده و نام زبان ها را در داخل ComboBox اي كه داريم نشان دهد. سپس با انتخاب هر زبان در ComboBox، محتواي Button ها بر اساس زبان انتخاب شده تغيير كند.
    براي سهولت كار، نام فايل ها را به گونه اي انتخاب كرديم كه بتوانيم ساده تر به اين هدف برسيم. نام هر فايل از سه بخش تشكيل شده است:
    Culture_[standard culture notation]_[display name for this culture].dll
    يعني اگر فايل Culture_fa-IR_Farsi.dll را در نظر بگيريم، Culture نشان دهنده اين است كه اين فايل مربوط به يك culture مي باشد. fa-IR نمايش استاندارد culture براي كشور ايران و زبان فارسي است و Farsi هم مقداري است كه مي خواهيم در ComboBox براي اين زبان نمايش داده شود.
    پوشه اي با نام Languages در كنار فايل .exe برنامه ايجاد كنيد و فايل Culture_fa-IR_Farsi.dll را درون آن كپي كنيد. تصميم داريم همه .dll هاي مربوط به زبان ها را داخل اين پوشه قرار دهيم تا مديريت آن ها ساده تر شود.
    براي مديريت بهتر فايل هاي مربوط به زبان ها يك كلاس با نام CultureAssemblyModel خواهيم ساخت كه هر object از آن نشانگر يك فايل زبان خواهد بود. يك كلاس با اين نام به پروژه اضافه كنيد و property هاي زير را در آن تعريف نماييد:
    public class CultureAssemblyModel
    {
    //the text will be displayed to user as language name (like Farsi)
    public string DisplayText { get; set; }
    //name of .dll file (like Culture_fa-IR_Farsi.dll)
    public string Name { get; set; }
    //standar notation of this culture (like fa-IR)
    public string Culture { get; set; }
    //name of resource dictionary file name inside the loaded .dll (like Culture_fa-IR.xaml)
    public string XamlFileName { get; set; }
    }


    براي ComboBox نيز يك DataTemplate تعريف مي كنيم تا فقط فيلد DisplayText از اين كلاس را نمايش دهد:
    <ComboBox HorizontalAlignment="Left" Margin="10" VerticalAlignment="Top" MinWidth="100" Name="comboboxLanguages">
    <ComboBox.ItemTemplate>
    <DataTemplate>
    <Label Content="{Binding DisplayText}"/>
    </DataTemplate>
    </ComboBox.ItemTemplate>
    </ComboBox>


    براي load كردن نام فايل هاي .dll مربوط به زبان ها متدي تعريف مي كنيم به اسم LoadCultureAssmeblies به شكل زير:
    //will keep information about loaded assemblies
    public List<CultureAssemblyModel> CultureAssemblies { get; set; }

    //loads assmeblies in languages folder and adds their info to list
    void LoadCultureAssemblies()
    {
    //we should be sure that list is empty before adding info (do u want to add some cultures more than one? of course u dont!)
    CultureAssemblies.Clear();
    //creating a directory represents applications directory\languages
    DirectoryInfo dir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirector y + "\\languages");
    //getting all .dll files in the language folder and its sub dirs. (who knows? maybe someone keeps each culture file in a seperate folder!)
    var assemblies = dir.GetFiles("*.dll", SearchOption.AllDirectories);
    //for each found .dll we will create a model and set its properties and then add to list for (int i = 0; i < assemblies.Count(); i++)
    {
    CultureAssemblyModel model = new CultureAssemblyModel() { DisplayText = assemblies[i].Name.Split('.', '_')[2], Culture = assemblies[i].Name.Split('.', '_')[1], Name = assemblies[i].Name, XamlFileName =assemblies[i].Name.Substring(0, assemblies[i].Name.LastIndexOf(".")) + ".xaml" };
    CultureAssemblies.Add(model);
    }
    }


    اطلاعات مورد نياز از فايل هاي .dll خوانده شده و در ليست نگهداري مي شوند. براي نمايش دادن نام زبان ها در ComboBox كافي است اين ليست را به عنوان ItemsSource قرار دهيم:
    comboboxLanguages.ItemsSource = CultureAssemblies;


    با handle كردن رويداد selectionChanged مربوط به ComboBox زبان انتخاب شده را به متد LoadCulture كه در فايل App.cs (كلاس اصلي برنامه) تعريف كرده ايم ارسال مي كنيم:
    //loads selected culture
    public void LoadCulture(CultureAssemblyModel culture)
    {
    //setting current culture of applpications main thread to selected one.
    System.Threading.Thread.CurrentThread.CurrentUICul ture = new System.Globalization.CultureInfo(culture.Culture);
    System.Threading.Thread.CurrentThread.CurrentCultu re = new System.Globalization.CultureInfo(culture.Culture);
    //creating a FileInfo object represents .dll file of selected cultur
    FileInfo assemblyFile = new FileInfo("languages\\" + culture.Name);
    //loading .dll into memory as a .net assembly
    var assembly = Assembly.LoadFile(assemblyFile.FullName);
    //getting .dll file name
    var assemblyName = assemblyFile.Name.Substring(0, assemblyFile.Name.LastIndexOf("."));
    //creating string represents structure of a pack uri (something like this: /{myassemblyname;component/myresourcefile.xaml}
    string packUri = string.Format(@"/{0};component/{1}", assemblyName, culture.XamlFileName);
    //creating a pack uri
    Uri uri = new Uri(packUri, UriKind.Relative);
    //now we have created a pack uri that represents a resource object in loaded assembly
    //and its time to load that as a resource dictionary (do u remember that we had resource dictionary in culture assemblies? don't u?)
    var dic = Application.LoadComponent(uri) as ResourceDictionary;
    dic.Source = uri;
    //here we will remove current merged dictionaries in our resource dictionary and add recently-loaded resource dictionary as e merged dictionary
    var mergedDics = this.Resources.MergedDictionaries;
    if (mergedDics.Count > 0)
    mergedDics.Clear();
    mergedDics.Add(dic);
    }


    void comboboxLanguages_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
    var selectedCulture = (CultureAssemblyModel)comboboxLanguages.SelectedIt em;
    App app = Application.Current as App;
    app.LoadCulture(selectedCulture);
    }



    متد LoadCulture با گرفتن مشخصات زبان ارسال شده، culture سيستم را به زبان مورد نظر تغيير داده و resource dictionary مربوط به آن را از داخل فايل .dll آن زبان load كرده و آن را با resource dictionary فعلي برنامه جايگزين مي كند. Button ها كه محتواي خود را به شكل dynamic از داخل اين resource dictionary دريافت مي كردند حالا از داخل فايل جايگزين شده خواهند گرفت.

    كار انجام شد!
    از مزيت هاي اين روش مي توان به WPF-Native بودن، سادگي در پياده سازي، قابليت load كردن هر زبان جديدي در زمان اجرا بدون نياز به كوچك ترين تغيير در برنامه اصلي و همچنين پشتيباني كامل از نمايش زبان هاي مختلف از جمله فارسي اشاره كرد.

    لینک اول PDF و لینک دوم نمونه برنامه هستند.
    دوست عزیز کلا این قسمت رو از فایل های xaml زبون ها وردار
    <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="Culture_fa-IR_Farsi.xaml"/>
    </ResourceDictionary.MergedDictionaries>

قوانین ایجاد تاپیک در تالار

  • شما نمی توانید تاپیک جدید ایجاد کنید
  • شما نمی توانید به تاپیک ها پاسخ دهید
  • شما نمی توانید ضمیمه ارسال کنید
  • شما نمی توانید پاسخ هایتان را ویرایش کنید
  •