This article is currently in the process of being translated into Arabic (~97% done).
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 : مصادر ثابتة VS مصادر متغيرة
في الأمثلة حتى الآن ، استخدمت تمديد العلامات StaticResource للإشارة إلى مورد. ومع ذلك ، يوجد بديل ، في شكل DynamicResource.
والفرق الرئيسي هو أن المورد الثابت (StaticResource) يستخدم لمرة واحدة فقط كحل عند نقطة تحميل XAML. لكن إذا تم تغيير المورد فيما بعد ، فلن يتم عكس هذا التغيير في المكان الذي استخدمت فيه StaticResource.
يتم حل DynamicResource من ناحية أخرى بمجرد الحاجة الفعلية ، ثم مرة أخرى إذا تغير المورد. فكر في الأمر على أنه ربط لقيمة ثابتة مقابل الربط بوظيفة تراقب هذه القيمة وترسلها إليك في كل مرة يتم تغييرها - إنها ليست طريقة عملها بالضبط ، ولكن يمكن أن تعطيك فكرة أفضل عن وقت استخدام ما. تسمح لك الموارد الديناميكية أيضًا باستخدام الموارد التي يمكن ألا توجد وقت التصميم ، على سبيل المثال ، إذا قمت بإضافتها من Code-behind أثناء بدء تشغيل التطبيق.
مشاركة سلسلة بسيطة كان أمرًا سهلاً ، ولكن يمكنك فعل المزيد. في المثال التالي ، سأقوم أيضًا بتخزين مجموعة كاملة من السلاسل ، إلى جانب فرشاة متدرجة لاستخدامها في الخلفية. من المفترض أن يمنحك ذلك فكرة جيدة عن مدى ما يمكنك فعله بالموارد:
كانت مشاركة سلسلة بسيطة أمرًا سهلاً ، ولكن يمكنك فعل المزيد. في المثال التالي ، سأخزن أيضًا مجموعة كاملة من الأوتار ، جنبًا إلى جنب مع فرشاة متدرجة لاستخدامها في الخلفية. يجب أن يمنحك هذا فكرة جيدة عن مقدار ما يمكنك فعله بالموارد
<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). أدواة اخرى ضمن لوحة التكديس كانت قد تستطيع استخدامه كما هو الحال للأدوات الفرعية ضمن هذه الأدوات. الأدوات التي تقع خارج لوحة التكديس لا تستطيع استخدام تلك الموارد.
اذا كنت بحاجة قدرة الوصول الى مصدر ما من عدة نوافذ, هذا ممكن أيضاً. ملف "App.xaml" ممكن ان يحتوي مصادر مثل النافذة(window) او اي أداة من أدوات(WPF), وعندما تحفظهم في, سيكونوا قابلين للوصول من كل نوافذ و كل أدوات المشروع. تعمل بالظبط كما عندما تقوم بحفظهم و استخدامهم من نافذة ما.
<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>
استخدامه هو نفسه أيضًا - سيقوم WPF تلقائيًا بالانتقال إلى أعلى النطاق ، من عنصر التحكم المحلي إلى window ثم إلى App.xaml ، للعثور على مورد معين:
<Label Content="{StaticResource ComboBoxTitle}" />
Resources from Code-behind
وصلنا حتى الآن إلى جميع مواردنا مباشرة من XAML ، باستخدام امتداد الترميز. ومع ذلك ، يمكنك بالطبع الوصول إلى مواردك من الخلفية أيضًا ، وهذا مفيد في العديد من المواقف. في المثال السابق ، رأينا كيف يمكننا تخزين الموارد في عدة أماكن مختلفة ، لذلك في هذا المثال ، سنصل إلى ثلاثة موارد مختلفة من الخلفية، كل منها مخزن في نطاق مختلف:
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());
}
}
}
لذا ، كما ترون ، نقوم بتخزين ثلاث رسائل مختلفة من "Hello، world!" : واحدة في App.xaml ، وواحدة داخل النافذة ، وواحدة محليًا في اللوحة الرئيسية. تتكون الواجهة من زر وصندوق قائمة.
في الخلفية نتعامل مع حدث النقر على الزر ، حيث نضيف كل سلسلة نصية إلى ListBox ، كما هو موضح في لقطة الشاشة. نستخدم طريقة FindResource () ، والتي ستعيد المورد ككائن (إن وجد) ، ثم نحوله إلى السلسلة خلال باستخدام طريقة ToString ().
لاحظ كيف نستخدم طريقة FindResource () في نطاقات مختلفة - أولاً على اللوحة ، ثم على النافذة ثم على كائن Application الحالي. من المنطقي البحث عن المورد حيث نعلم أنه موجود ، ولكن كما ذكرنا سابقًا ، إذا لم يتم العثور على المورد ، فإن يتقدم البحث في التسلسل الهرمي ، لذلك من حيث المبدأ ، كان بإمكاننا استخدام طريقة FindResource () على اللوحة في جميع الحالات الثلاث ، نظرًا لأنه سيكون استمر حتى النافذة ولاحقًا حتى مستوى التطبيق ، إذا لم يتم العثور عليه
الشيء نفسه ليس صحيحًا بالعكس - البحث لا يتنقل إلى أسفل الشجرة ، لذلك لا يمكنك البدء في البحث عن مورد على مستوى التطبيق ، إذا تم تحديده محليًا للتحكم أو للنافذة