"ডাব্লুপিএফ-এ আমি কীভাবে একাধিক শৈলী সেট করতে পারি?" শিরোনামে বি স্টলনিটসের একটি মার্কআপ এক্সটেনশন ব্যবহার সম্পর্কে একটি ভাল ব্লগ পোস্ট ছিল ?
সেই ব্লগটি এখন মারা গেছে, তাই আমি এখানে পোস্টটি পুনরায় প্রজনন করছি
ডাব্লুপিএফ এবং সিলভারলাইট উভয়ই "বেসডন" সম্পত্তির মাধ্যমে অন্য স্টাইলের থেকে একটি স্টাইল প্রাপ্ত করার ক্ষমতা সরবরাহ করে। এই বৈশিষ্ট্যটি বিকাশকারীদের বর্গ উত্তরাধিকারের মতো একই শ্রেণিবিন্যাস ব্যবহার করে তাদের স্টাইলগুলি সংগঠিত করতে সক্ষম করে। নিম্নলিখিত শৈলী বিবেচনা করুন:
<Style TargetType="Button" x:Key="BaseButtonStyle">
<Setter Property="Margin" Value="10" />
</Style>
<Style TargetType="Button" x:Key="RedButtonStyle" BasedOn="{StaticResource BaseButtonStyle}">
<Setter Property="Foreground" Value="Red" />
</Style>
এই সিনট্যাক্সের সাহায্যে, একটি বোতাম যা রেডবটনস্টাইল ব্যবহার করে তার ফোরগ্রাউন্ড সম্পত্তি রেডে সেট করবে এবং এর মার্জিন সম্পত্তিটি 10 এ সেট থাকবে।
এই বৈশিষ্ট্যটি দীর্ঘকাল ধরে ডাব্লুপিএফ-এ রয়েছে এবং সিলভারলাইট 3 এ এটি নতুন।
আপনি যদি কোনও উপাদানটিতে একাধিক স্টাইল সেট করতে চান তবে কী হবে? ডাব্লুপিএফ বা সিলভারলাইট উভয়ই বাক্সের বাইরে এই সমস্যার সমাধান করতে পারে না। ভাগ্যক্রমে ডাব্লুপিএফ এ আচরণ বাস্তবায়নের উপায় আছে যা আমি এই ব্লগ পোস্টে আলোচনা করব discuss
ডাব্লুপিএফ এবং সিলভারলাইট মানগুলি সরবরাহের জন্য মার্কআপ এক্সটেনশানগুলি ব্যবহার করে যার জন্য কিছু যুক্তির প্রয়োজন। এক্সএএমএলে তাদের চারপাশে কোঁকড়ানো বন্ধনী উপস্থিতি দ্বারা মার্কআপ এক্সটেনশনগুলি সহজেই সনাক্তযোগ্য recogn উদাহরণস্বরূপ, {বাইন্ডিং} মার্কআপ এক্সটেনশনে কোনও ডেটা উত্স থেকে কোনও মূল্য আনতে এবং পরিবর্তনগুলি ঘটে যখন তা আপডেট করার জন্য যুক্তিযুক্ত থাকে; {স্ট্যাটিক রিসোর্স} মার্কআপ এক্সটেনশনে একটি কী এর উপর ভিত্তি করে রিসোর্স ডিকশনারি থেকে একটি মান ধরার জন্য যুক্তি রয়েছে। সৌভাগ্যক্রমে আমাদের জন্য, ডাব্লুপিএফ ব্যবহারকারীদের নিজস্ব কাস্টম মার্কআপ এক্সটেনশন লিখতে দেয় write এই বৈশিষ্ট্যটি এখনও সিলভারলাইটে উপস্থিত নেই, সুতরাং এই ব্লগে সমাধানটি কেবল ডাব্লুপিএফের জন্য প্রযোজ্য।
অন্যরা মার্কআপ এক্সটেনশানগুলি ব্যবহার করে দুটি স্টাইলকে একত্রিত করার দুর্দান্ত সমাধান লিখেছেন। যাইহোক, আমি এমন একটি সমাধান চেয়েছিলাম যা সীমাহীন সংখ্যক শৈলীর একত্রীকরণের ক্ষমতা সরবরাহ করেছিল যা কিছুটা জটিল।
মার্কআপ এক্সটেনশন লেখা সহজবোধ্য। প্রথম পদক্ষেপটি এমন একটি ক্লাস তৈরি করা যা মার্কআপএক্সটেনশন থেকে উদ্ভূত হয় এবং মার্কআপএক্সটেনশান রিটারনটাইপ বৈশিষ্ট্যটি ব্যবহার করে এটি নির্দেশ করে যে আপনি নিজের মার্কআপ এক্সটেনশান থেকে প্রত্যাবর্তিত মানটি টাইপের ধরণের হতে চান।
[MarkupExtensionReturnType(typeof(Style))]
public class MultiStyleExtension : MarkupExtension
{
}
মার্কআপ এক্সটেনশনে ইনপুট নির্দিষ্ট করে
আমরা আমাদের মার্কআপ এক্সটেনশনের ব্যবহারকারীদের শৈলগুলি মার্জ করার জন্য নির্দিষ্ট করার একটি সহজ উপায় দিতে চাই। মূলত দুটি উপায় রয়েছে যার মাধ্যমে ব্যবহারকারী একটি চিহ্নআপ এক্সটেনশনের ইনপুট নির্দিষ্ট করতে পারে। ব্যবহারকারীর বৈশিষ্ট্য নির্ধারণ করতে বা নির্মাণকারীর কাছে পরামিতিগুলি পাস করতে পারেন। যেহেতু এই দৃশ্যে ব্যবহারকারীর সীমাহীন সংখ্যক শৈলী নির্দিষ্টকরণের দক্ষতার প্রয়োজন হয়, তাই আমার প্রথম পদ্ধতিটি ছিল এমন একটি কনস্ট্রাক্টর তৈরি করা যা "প্যারাম" কীওয়ার্ডটি ব্যবহার করে যে কোনও সংখ্যক স্ট্রিং নেয়:
public MultiStyleExtension(params string[] inputResourceKeys)
{
}
আমার লক্ষ্যটি ছিল ইনপুটগুলি নিম্নরূপে লিখতে পারা:
<Button Style="{local:MultiStyle BigButtonStyle, GreenButtonStyle}" … />
বিভিন্ন স্টাইল কীগুলি আলাদা করে কমাটি দেখুন। দুর্ভাগ্যক্রমে, কাস্টম মার্কআপ এক্সটেনশানগুলি সীমাহীন সংখ্যক কনস্ট্রাক্টর প্যারামিটার সমর্থন করে না, সুতরাং এই পদ্ধতির ফলে একটি সংকলন ত্রুটির ফলস্বরূপ। আমি যদি জানতাম যে আমি কয়টি শৈলীর একত্রীকরণ করতে চাইছিলাম তবে আমি কনস্ট্রাক্টরের পছন্দসই সংখ্যক স্ট্রিং গ্রহণ করে একই এক্সএএমএল সিনট্যাক্সটি ব্যবহার করতে পারতাম:
public MultiStyleExtension(string inputResourceKey1, string inputResourceKey2)
{
}
কার্যকারণ হিসাবে, আমি সিদ্ধান্ত নিয়েছি যে কনস্ট্রাক্টর পরামিতিটি একটি একক স্ট্রিং নেবে যা শৈলীর নামগুলি ফাঁক দিয়ে পৃথক করে। বাক্য গঠন খুব খারাপ নয়:
private string[] resourceKeys;
public MultiStyleExtension(string inputResourceKeys)
{
if (inputResourceKeys == null)
{
throw new ArgumentNullException("inputResourceKeys");
}
this.resourceKeys = inputResourceKeys.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (this.resourceKeys.Length == 0)
{
throw new ArgumentException("No input resource keys specified.");
}
}
মার্কআপ এক্সটেনশনের আউটপুট গণনা করা হচ্ছে
মার্কআপ এক্সটেনশনের আউটপুট গণনা করতে, আমাদের "প্রোভাইডভ্যালু" নামক মার্কআপএক্সটেনশন থেকে একটি পদ্ধতি ওভাররাইড করতে হবে। এই পদ্ধতি থেকে প্রত্যাবর্তিত মানটি মার্কআপ এক্সটেনশনের লক্ষ্যে সেট করা হবে।
আমি স্টাইলের জন্য একটি এক্সটেনশন পদ্ধতি তৈরি করে শুরু করেছি যা কীভাবে দুটি শৈলীর একত্রীকরণ করতে জানে। এই পদ্ধতির কোডটি বেশ সহজ:
public static void Merge(this Style style1, Style style2)
{
if (style1 == null)
{
throw new ArgumentNullException("style1");
}
if (style2 == null)
{
throw new ArgumentNullException("style2");
}
if (style1.TargetType.IsAssignableFrom(style2.TargetType))
{
style1.TargetType = style2.TargetType;
}
if (style2.BasedOn != null)
{
Merge(style1, style2.BasedOn);
}
foreach (SetterBase currentSetter in style2.Setters)
{
style1.Setters.Add(currentSetter);
}
foreach (TriggerBase currentTrigger in style2.Triggers)
{
style1.Triggers.Add(currentTrigger);
}
// This code is only needed when using DynamicResources.
foreach (object key in style2.Resources.Keys)
{
style1.Resources[key] = style2.Resources[key];
}
}
উপরের যুক্তি দিয়ে, দ্বিতীয় শৈলীতে সমস্ত তথ্য অন্তর্ভুক্ত করতে প্রথম স্টাইলটি সংশোধন করা হয়েছে। যদি দ্বন্দ্ব হয় (যেমন উভয় শৈলীর একই সম্পত্তির জন্য একটি সেটর রয়েছে), দ্বিতীয় শৈলীতে জয়ী হয়। লক্ষ্য করুন যে শৈলী এবং ট্রিগারগুলি অনুলিপি করা বাদ দিয়ে আমি দ্বিতীয় লক্ষ্য অনুসারে টার্গেটটাইপ এবং বেসডন মানগুলিও গ্রহণ করেছি any মার্জ করা শৈলীর টার্গেটটাইপের জন্য, আমি যে কোনও প্রকারের ব্যবহার আরও বেশি প্রাপ্ত। যদি দ্বিতীয় শৈলীর ভিত্তিভিত্তিক শৈলী থাকে তবে আমি এর শৈলীর স্তরক্রমকে পুনরাবৃত্তভাবে মার্জ করি। যদি এর সংস্থান থাকে তবে আমি এগুলি প্রথম স্টাইলে অনুলিপি করব। যদি সেই সংস্থানগুলি {স্ট্যাটিক রিসোর্স using ব্যবহার করে উল্লেখ করা হয়, তবে এই মার্জ কোডটি কার্যকর করার আগে এগুলি স্থিতিশীলভাবে সমাধান করা হয়েছে, এবং সেজন্য এগুলি সরানোর প্রয়োজন হয় না। আমরা এই কোডটি যুক্ত করেছিলাম যদি আমরা ডায়নামিক রিসোর্স ব্যবহার করি।
উপরে প্রদর্শিত এক্সটেনশন পদ্ধতিটি নিম্নলিখিত সিনট্যাক্সটিকে সক্ষম করে:
style1.Merge(style2);
ProvideValue এর মধ্যে আমার উভয় শৈলীর উদাহরণ রয়েছে এই সংশ্লেষটি কার্যকর। ভাল, আমি না। কনস্ট্রাক্টরের কাছ থেকে আমি যা পেয়েছি তা হ'ল স্টাইলগুলির স্ট্রিং কীগুলির একটি তালিকা। কনস্ট্রাক্টর প্যারামিটারগুলিতে যদি প্যারামগুলির জন্য সমর্থন থাকত তবে আমি প্রকৃত শৈলীর উদাহরণগুলি পেতে নিম্নলিখিত সিনট্যাক্সটি ব্যবহার করতে পারতাম:
<Button Style="{local:MultiStyle {StaticResource BigButtonStyle}, {StaticResource GreenButtonStyle}}" … />
public MultiStyleExtension(params Style[] styles)
{
}
কিন্তু এটি কাজ করে না। এমনকি যদি প্যারামগুলির সীমাবদ্ধতা না উপস্থিত থাকে তবে আমরা সম্ভবত মার্কআপ এক্সটেনশনের আরও একটি সীমাবদ্ধতা আঘাত করব, যেখানে স্থির সংস্থানগুলি নির্দিষ্ট করার জন্য বৈশিষ্ট্য সিনট্যাক্সের পরিবর্তে আমাদের সম্পত্তি-উপাদান সিনট্যাক্স ব্যবহার করতে হবে, যা ভার্জোজ এবং জটিল ( আগের ব্লগ পোস্টে বাগ আরও ভাল )। এবং এই উভয় সীমাবদ্ধতা না থাকলেও আমি কেবল তাদের নাম ব্যবহার করে শৈলীর তালিকা লিখব - এটি প্রত্যেকের স্ট্যাটিক রিসোর্সের চেয়ে ছোট এবং সহজ পড়া is
সমাধানটি হ'ল কোড ব্যবহার করে একটি স্ট্যাটিক রিসোর্স এক্সটেনশন তৈরি করা। টাইপ স্ট্রিংয়ের একটি স্টাইল কী এবং একটি পরিষেবা সরবরাহকারীর দেওয়া, আমি প্রকৃত শৈলীর উদাহরণ পুনরুদ্ধার করতে স্ট্যাটিক রিসোর্সএক্সটেনশনটি ব্যবহার করতে পারি। এখানে বাক্য গঠন:
Style currentStyle = new StaticResourceExtension(currentResourceKey).ProvideValue(serviceProvider) as Style;
ProvideValue পদ্ধতিটি লেখার জন্য এখন আমাদের কাছে সমস্ত টুকরো রয়েছে:
public override object ProvideValue(IServiceProvider serviceProvider)
{
Style resultStyle = new Style();
foreach (string currentResourceKey in resourceKeys)
{
Style currentStyle = new StaticResourceExtension(currentResourceKey).ProvideValue(serviceProvider) as Style;
if (currentStyle == null)
{
throw new InvalidOperationException("Could not find style with resource key " + currentResourceKey + ".");
}
resultStyle.Merge(currentStyle);
}
return resultStyle;
}
এখানে মাল্টিস্টাইল মার্কআপ এক্সটেনশনের ব্যবহারের সম্পূর্ণ উদাহরণ রয়েছে:
<Window.Resources>
<Style TargetType="Button" x:Key="SmallButtonStyle">
<Setter Property="Width" Value="120" />
<Setter Property="Height" Value="25" />
<Setter Property="FontSize" Value="12" />
</Style>
<Style TargetType="Button" x:Key="GreenButtonStyle">
<Setter Property="Foreground" Value="Green" />
</Style>
<Style TargetType="Button" x:Key="BoldButtonStyle">
<Setter Property="FontWeight" Value="Bold" />
</Style>
</Window.Resources>
<Button Style="{local:MultiStyle SmallButtonStyle GreenButtonStyle BoldButtonStyle}" Content="Small, green, bold" />