TOC

This article is currently in the process of being translated into Arabic (~50% done).

تطبيق WPF:

Resources

WPF يقدم مفهوم مفيد جدا: القدرة علي تخزين البيانات كمصادر(resource) ، اما محليا(locally) لعنصر تحكم ، محليا للإطار بأكمله أو عاما للتطبيق بأكمله. قد تكون البيانات اي شئ تريده ، من المعلومات الفعلية إلى التسلسل الهرمي لعناصر تحكم WPF. هذا يسمح لك بوضع البيانات في مكان واحد ومن ثم استخدامه فى أماكن مختلفة، وهو أمر مفيد جدا

يتم استخدام المفهوم كثيرًا للأنماط والقوالب ، والتي سنناقشها لاحقًا في هذا البرنامج التعليمي ، ولكن كما هو موضح في هذا الفصل ، يمكنك استخدامه للعديد من الأشياء الأخرى أيضًا. اسمح لي أن أثبت ذلك بمثال بسيط:

<Window x:Class="WpfTutorialSamples.WPF_Application.ResourceSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="ResourceSample" Height="150" Width="350">
    <Window.Resources>
        <sys:String x:Key="strHelloWorld">Hello, world!</sys:String>
    </Window.Resources>
    <StackPanel Margin="10">
        <TextBlock Text="{StaticResource strHelloWorld}" FontSize="56" />
        <TextBlock>Just another "<TextBlock Text="{StaticResource strHelloWorld}" />" example, but with resources!</TextBlock>
    </StackPanel>
</Window>

يتم إعطاء الموارد مفتاحًا ، باستخدام السمة x: Key ، والتي تتيح لك الاشارة اليها من أجزاء من التطبيق باستخدام هذا المفتاح مقترنا باضافة العلامة StaticResource. في هذا المثال ، أقوم فقط بتخزين سلسلة بسيطة و يمكنني استخدامها بعد ذلك من عنصري تحكم TextBlock مختلفين.

StaticResource vs. DynamicResource

في الأمثلة حتى الآن ، استخدمت تمديد العلامات StaticResource للإشارة إلى مورد. ومع ذلك ، يوجد بديل ، في شكل DynamicResource.

والفرق الرئيسي هو أن المورد الثابت (StaticResource) يستخدم لمرة واحدة فقط كحل عند نقطة تحميل XAML. لكن إذا تم تغيير المورد فيما بعد ، فلن يتم عكس هذا التغيير في المكان الذي استخدمت فيه StaticResource.

يتم حل DynamicResource من ناحية أخرى بمجرد الحاجة الفعلية ، ثم مرة أخرى إذا تغير المورد. فكر في الأمر على أنه ربط لقيمة ثابتة مقابل الربط بوظيفة تراقب هذه القيمة وترسلها إليك في كل مرة يتم تغييرها - إنها ليست طريقة عملها بالضبط ، ولكن يمكن أن تعطيك فكرة أفضل عن وقت استخدام ما. تسمح لك الموارد الديناميكية أيضًا باستخدام الموارد التي يمكن ألا توجد وقت التصميم ، على سبيل المثال ، إذا قمت بإضافتها من Code-behind أثناء بدء تشغيل التطبيق.

مشاركة سلسلة بسيطة كان أمرًا سهلاً ، ولكن يمكنك فعل المزيد. في المثال التالي ، سأقوم أيضًا بتخزين مجموعة كاملة من السلاسل ، إلى جانب فرشاة متدرجة لاستخدامها في الخلفية. من المفترض أن يمنحك ذلك فكرة جيدة عن مدى ما يمكنك فعله بالموارد:

Sharing a simple string was easy, but you can do much more. In the next example, I'll also store a complete array of strings, along with a gradient brush to be used for the background. This should give you a pretty good idea of just how much you can do with resources:

<Window x:Class="WpfTutorialSamples.WPF_Application.ExtendedResourceSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="ExtendedResourceSample" Height="160" Width="300"
        Background="{DynamicResource WindowBackgroundBrush}">
    <Window.Resources>
        <sys:String x:Key="ComboBoxTitle">Items:</sys:String>

        <x:Array x:Key="ComboBoxItems" Type="sys:String">
            <sys:String>Item #1</sys:String>
            <sys:String>Item #2</sys:String>
            <sys:String>Item #3</sys:String>
        </x:Array>

        <LinearGradientBrush x:Key="WindowBackgroundBrush">
            <GradientStop Offset="0" Color="Silver"/>
            <GradientStop Offset="1" Color="Gray"/>
        </LinearGradientBrush>
    </Window.Resources>
    <StackPanel Margin="10">
        <Label Content="{StaticResource ComboBoxTitle}" />
        <ComboBox ItemsSource="{StaticResource ComboBoxItems}" />
    </StackPanel>
</Window>

هذه المرة, لقد أضفنا موردين اثنين, هكذا ستحتوي النافذة على سلسلة محرفية بسيطة, مصفوفة من السلاسل المحرفية, وتلوين بلون منحدر (LinearGradientBrush). السلسلة المحرفية مستخدمة للعنوان, مصفوفة السلاسل المحرفية مستخدمة للصندوق متعدد الخيارات و اللون المنحدر مستخدم لتلوين كامل خلفية النافذة. كما ترا هنا, أي شيء تقريبا يمكن تخزينة كمورد.

الموارد المحلية والموارد على كامل نطاق البرنامج

حتى الآن, لقد قمنا بتخزين الموارد على نطاق النافذة, هذا يعني انه يمكنك الوصول لهذه الموارد من كامل مجال النافذة

إذا كنت تحتاج لربط مورد ب أداة محددة, يمكنك جعلها محلية النطاق أكثر عن طريق اضافتها للأداة المحددة. وتعمل تماما بنفس الطريقة, الفرق الوحيد هنا أنه لايمكنك الوصول لذلك المورد الا من ضمن نطاق الأداة التي وضعتا بها.

<StackPanel Margin="10">
    <StackPanel.Resources>
        <sys:String x:Key="ComboBoxTitle">Items:</sys:String>
    </StackPanel.Resources>
    <Label Content="{StaticResource ComboBoxTitle}" />
</StackPanel>

في هذه الحالة, نضيف المورد ل لوحة التكديس ثم نقوم باستخدامه من أداة فرعية لها (child control) والتي هي العنوان (Label). أدواة اخرى ضمن لوحة التكديس كانت قد تستطيع استخدامه كما هو الحال للأدوات الفرعية ضمن هذه الأدوات. الأدوات التي تقع خارج لوحة التكديس لا تستطيع استخدام تلك الموارد.

If you need the ability to access the resource from several windows, this is possible as well. The App.xaml file can contain resources just like the window and any kind of WPF control, and when you store them in App.xaml, they are globally accessible in all of windows and user controls of the project. It works exactly the same way as when storing and using from a Window:

<Application x:Class="WpfTutorialSamples.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             StartupUri="WPF application/ExtendedResourceSample.xaml">
    <Application.Resources>
        <sys:String x:Key="ComboBoxTitle">Items:</sys:String>
    </Application.Resources>
</Application>

Using it is also the same - WPF will automatically go up the scope, from the local control to the window and then to App.xaml, to find a given resource:

<Label Content="{StaticResource ComboBoxTitle}" />

Resources from Code-behind

So far, we've accessed all of our resources directly from XAML, using a markup extension. However, you can of course access your resources from Code-behind as well, which can be useful in several situations. In the previous example, we saw how we could store resources in several different places, so in this example, we'll be accessing three different resources from Code-behind, each stored in a different scope:

App.xaml:

<Application x:Class="WpfTutorialSamples.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             StartupUri="WPF application/ResourcesFromCodeBehindSample.xaml">
    <Application.Resources>
        <sys:String x:Key="strApp">Hello, Application world!</sys:String>
    </Application.Resources>
</Application>

Window:

<Window x:Class="WpfTutorialSamples.WPF_Application.ResourcesFromCodeBehindSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="ResourcesFromCodeBehindSample" Height="175" Width="250">
    <Window.Resources>
        <sys:String x:Key="strWindow">Hello, Window world!</sys:String>
    </Window.Resources>
    <DockPanel Margin="10" Name="pnlMain">
        <DockPanel.Resources>
            <sys:String x:Key="strPanel">Hello, Panel world!</sys:String>
        </DockPanel.Resources>

        <WrapPanel DockPanel.Dock="Top" HorizontalAlignment="Center" Margin="10">
            <Button Name="btnClickMe" Click="btnClickMe_Click">Click me!</Button>
        </WrapPanel>

        <ListBox Name="lbResult" />
    </DockPanel>
</Window>

Code-behind:

using System;
using System.Windows;

namespace WpfTutorialSamples.WPF_Application
{
	public partial class ResourcesFromCodeBehindSample : Window
	{
		public ResourcesFromCodeBehindSample()
		{
			InitializeComponent();
		}

		private void btnClickMe_Click(object sender, RoutedEventArgs e)
		{
			lbResult.Items.Add(pnlMain.FindResource("strPanel").ToString());
			lbResult.Items.Add(this.FindResource("strWindow").ToString());
			lbResult.Items.Add(Application.Current.FindResource("strApp").ToString());
		}
	}
}

So, as you can see, we store three different "Hello, world!" messages: One in App.xaml, one inside the window, and one locally for the main panel. The interface consists of a button and a ListBox.

In Code-behind, we handle the click event of the button, in which we add each of the text strings to the ListBox, as seen on the screenshot. We use the FindResource() method, which will return the resource as an object (if found), and then we turn it into the string that we know it is by using the ToString() method.

Notice how we use the FindResource() method on different scopes - first on the panel, then on the window and then on the current Application object. It makes sense to look for the resource where we know it is, but as already mentioned, if a resource is not found, the search progresses up the hierarchy, so in principal, we could have used the FindResource() method on the panel in all three cases, since it would have continued up to the window and later on up to the application level, if not found.

The same is not true the other way around - the search doesn't navigate down the tree, so you can't start looking for a resource on the application level, if it has been defined locally for the control or for the window.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!