مشاركة عبر


تخصيص مظهر عنصر تحكم موجود قبل إنشاء ControlTemplate

ControlTemplate تعيّن البنية المرئية في والسلوك المرئي لعنصر التحكم. يمكنك تخصيص مظهر عنصر التحكم بإعطائه ControlTemplateجديد . عند إنشاء ControlTemplate ، تستبدل مظهر عنصر تحكم موجود دون تغيير وظيفته. على سبيل المثال، يمكنك جعل الأزرار الموجودة في التطبيق الخاص بك مستديرة بدلاً من الشكل المربع الافتراضى، ولكن الزر سوف لا يزال يرفع حدث Click.

يشرح هذا الموضوع الأجزاء المختلفة من ControlTemplate ، يوضح إنشاء ControlTemplate بسيطة للحصول على Button ، وتشرح كيفية فهم عقد التحكم لعنصر التحكم بحيث يمكنك تخصيص المظهر الخاص به. لأن إنشاء ControlTemplate في XAML ، يمكنك تغيير مظهر عنصر التحكم بدون كتابة أية تعليمة برمجية. يمكنك أيضاً استخدام مصمم، كمزيج تعبير Microsoft ، لإنشاء قوالب تحكم مخصصة. يوضح هذا الموضوع أمثلة في XAML التي تخصص مظهر Button وتسرد المثال الكامل في نهاية الموضوع. لمزيد من المعلومات حول استخدام "مزيج التعبير" راجع تنسيق عنصر تحكم يعتمد القوالب .

تُظهر التوضيحات التالية Button الذي يستخدم ControlTemplate التي يتم إنشاؤها في هذا الموضوع.

زر يستخدم قالب تحكم مخصص

زر له قالب تحكم مخصص.

الزر الذي يستخدم قالب عنصر تحكم مخصص ولديه مؤشر الماوس فوقه

زر له حد أحمر.

يشتمل هذا الموضوع على الأقسام التالية.

  • المتطلبات الأساسية
  • عندما يجب أن تقوم بإنشاء ControlTemplate
  • تغيير في البنية المرئية لأحد عناصر التحكم
  • تغيير مظهر التحكم اعتماداً على حالته
  • تحديد سلوك عنصر التحكم متى ينتقل بين الحالات
  • تخصيص عناصر التحكم أخرى عن طريق فهم اتفاق التحكم
  • مثال كامل
  • موضوعات ذات صلة

المتطلبات الأساسية

هذا الموضوع يفترض فهم كيفية إنشاء و استخدام عناصر تحكم وأنماط كما تمت مناقشته في نظرة عامة حول عناصر التحكم. المفاهيم تمت مناقشتها في هذا الموضوع تطبيق على عناصر ترث من فئةControl ، فيما عدا UserControl. لا يمكن تطبيق ControlTemplate على UserControl.

عندما يجب أن تقوم بإنشاء ControlTemplate

يكون لعناصر التحكم العديد من الخصائص مثل Background ، Foreground ، و FontFamily ، التي يمكنك تعيينها لتحديد أوجه مختلفة من مظهر عنصر التحكم، ولكن التغييرات التي يمكنك إجراؤها بواسطة تعيين هذه الخصائص محدودة. على سبيل المثال، إذا قمت بتعيين خاصية Foreground إلى أزرق FontStyle إلى مائل على CheckBox .

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

تقوم بإنشاء ControlTemplateعندما تريد يخصص المظهر عنصر التحكم بعد ما هي الإعداد غير ذلك الخصائص تشغيل عنصر التحكم سوف do. In the مثال of the CheckBox, suppose that you want the content of the فحص صندوق إلى be above the تحديد مؤشر و you want an X إلى indicate that the CheckBox هو selected. تحديد هذه التغييرات في ControlTemplate من CheckBox.

يبين التوضيح التالي CheckBox الذى يستخدم ControlTemplate افتراضي.

CheckBox يستخدم قالب التحكم الافتراضي

خانة اختيار بقالب تحكم افتراضي.

يبين التوضيح التالي CheckBox الذي يستخدم ControlTemplateمخصص لوضع محتوى CheckBox أعلى مؤشر التحديد و تعرض X عند يكون CheckBox محدداً.

CheckBox يستخدم قالب تحكم مخصص

خانة اختيار لها قالب تحكم مخصص.

ControlTemplate الخاص ب CheckBox في هذا النموذج هو نسبياً معقد بحيث يستخدم هذا الموضوع مثال أسهل من إنشاء ControlTemplate للحصول على Button.

تغيير في البنية المرئية لأحد عناصر التحكم

في WPF ، غالباً ما يكون عنصر التحكم كائنات FrameworkElement مركّبة . عند إنشاء ControlTemplate ، تدمج كائنات FrameworkElement لإنشاء عنصر تحكم واحد. ControlTemplate يجب أن يكون له FrameworkElement واحد فقط كـعنصر جذرى. يحتوى العنصرالجذر عادةً على الكائنات FrameworkElement الأخرى . تركيبة الكائنات تنشئ البنية المرئية لعنصر التحكم .

يقوم المثال التالي بإنشاء ControlTemplate مخصصة إلى Button. ControlTemplate ينشئ البنية 
المرئية لل Button. لا يقوم هذا المثال بتغيير مظهر الزر عند انتقال مؤشر الماوس فوقها أو النقر فوقه. تغيير مظهر الزر عندما يكون في حالة مختلفة ستتم مناقشته لاحقاً في هذا الموضوع.

في هذا المثال، تتكون البنية البصرية من الأجزاء التالية:

<ControlTemplate TargetType="Button">
  <Border Name="RootElement">

    <!--Create the SolidColorBrush for the Background 
        as an object elemment and give it a name so 
        it can be referred to elsewhere in the
        control template.-->
    <Border.Background>
      <SolidColorBrush x:Name="BorderBrush" Color="Black"/>
    </Border.Background>

    <!--Create a border that has a different color
        by adding smaller grid. The background of 
        this grid is specificied by the button's 
        Background property.-->
    <Grid Margin="4" Background="{TemplateBinding Background}">

      <!--Use a ContentPresenter to display the Content of
          the Button.-->
      <ContentPresenter
        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
        Margin="4,5,4,4" />
    </Grid>

  </Border>
</ControlTemplate>

مع الاحتفاظ بوظائف خصائص عناصر التحكم باستخدام TemplateBinding

عند إنشاءControlTemplate جديد، فقد تزال محتاجاً لاستخدام الخصائص العامة لتغيير مظهر عنصر التحكم. ملحق العلامات TemplateBinding يربط خاصية العنصرالتى تكون في ControlTemplate إلى خاصية عامة معرفة بواسطة عنصر التحكم. يكرر المثال التالي الجزء من المثال السابق الذي يستخدم ملحق العلامات TemplateBinding لربط خصائص العناصر في ControlTemplate إلى خصائص عمومية معرفة بواسطة الزر.

<Grid Margin="4" Background="{TemplateBinding Background}">

  <!--Use a ContentPresenter to display the Content of
      the Button.-->
  <ContentPresenter
    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
    Margin="4,5,4,4" />
</Grid>

في هذا المثال، Grid لديه قالب الخاصية Panel.Background مرتبطاً ب Control.Background. لأن Panel.Background هو قالب منضم ، يمكنك إنشاء أزرار متعددة تستخدم نفس ControlTemplate وتعيين Control.Background إلى قيم مختلفة لكل زر. إذا كان Control.Backgroundقالب غير منضم إلى خاصية عنصر في ControlTemplate ، معداً Control.Background للزر لكى لا يؤثر على مظهر الزر.

لاحظ أن إسمين الخاصيتين لا يحتاجان أن يكونا متطابقان. في المثال السابق، خاصية Control.HorizontalContentAlignment الخاصة ب Buttonمرتبطة القالب بخاصية FrameworkElement.HorizontalAlignment الخاصة ب ContentPresenter. يتيح هذا المحتوى butإلىn إلى وضعه أفقياً. ContentPresenterغير خاصية مسماةHorizontalContentAlignment، ولكنControl.HorizontalContentAlignmentيمكن أن يكون منضماً إلىFrameworkElement.HorizontalAlignment. عند ربط قالب إلى خاصية ، تأكد من أن خصائص الهدف والمصدرمن نفس النوع.

فئةControl تعرف العديد من الخصائص التي يجب أن يتم استخدامها من قبل قالب عنصر التحكم ليكون لها تأثير على عنصر التحكم عندما تعين. كيفية استخدام ControlTemplate لخاصية يعتمد على الخاصية. ControlTemplate يجب أن يستخدم الخاصية بإحدى الطرق التالية:

يسرد الجدول التالي الخصائص المرئية الموروثة من قبل عنصر التحكم من فئةControl. يشير ذلك أيضاً إلى ما إذا كان قالب عنصر التحكم الافتراضي يستخدم القيمة الموروثة أو إذا كان يجب أن يكون منضم القالب.

الخصائص

أسلوب الاستخدام

Background

ربط القالب

BorderThickness

ربط القالب

BorderBrush

ربط القالب

FontFamily

ميراث الخاصية أو ربط القالب

FontSize

ميراث الخاصية أو ربط القالب

FontStretch

ميراث الخاصية أو ربط القالب

FontWeight

ميراث الخاصية أو ربط القالب

Foreground

ميراث الخاصية أو ربط القالب

HorizontalContentAlignment

ربط القالب

Padding

ربط القالب

VerticalContentAlignment

ربط القالب

يسرد الجدول الخصائص المرئية فقط الموروثة من فئة Control . بعيداً عن الخصائص المذكورة في الجدول، قد يرث عنصر التحكم أيضاً DataContext ، Language ، وخصائص TextDecorations من إطار عمل العنصر الأصل.

أيضاً، إذا ContentPresenter في ControlTemplate من ContentControl ، ستربط ContentPresenter تلقائياً إلى ContentTemplate و خصائص Content . وبالمثل، ItemsPresenter في ControlTemplate من ItemsControl سيتم تلقائياً ربط Items و خصائص ItemsPresenter .

يقوم المثال التالي بإنشاء زرين يستخدمان ControlTemplate المعرفة في المثال السابق. يعين المثال Background ، Foreground ، و خصائص FontSize لكل زر. إعداد خاصيةBackground له تأثير لأنه منضم في القالب فى ControlTemplate. بالرغم من أن Foreground و الخصائص FontSize غير منضمة القالب ،تعيينهم له تأثير لأن قيمهم موروثة .

<StackPanel>
  <Button Style="{StaticResource newTemplate}" 
          Background="Navy" Foreground="White" FontSize="14"
          Content="Button1"/>

  <Button Style="{StaticResource newTemplate}" 
          Background="Purple" Foreground="White" FontSize="14"
          Content="Button2" HorizontalContentAlignment="Left"/>
</StackPanel>

المثال السابق ينتج مخرج مشابه للرسم التوضيحي التالي.

زرين

زران، أحدهما أزرق والآخر أرجواني.

تغيير مظهر التحكم اعتماداً على حالته

الفرق بين زر بالمظهر الافتراضي و زر في المثال السابق هو أنه الزرالافتراضي يتغير ببساطة عندما يكون في حالات مختلفة. على سبيل المثال، يتغيير المظهر الافتراضي للزر عند الضغط على الزر, أو عندما يكون مؤشر الماوس فوقه. على الرغم من أن ControlTemplate لا يغير وظيفة التحكم ،فإنه يغير سلوك عنصر التحكم المرئي. يصف السلوك المرئي مظهر عنصر التحكم عندما يكون فى حالة معينة . لفهم الفرق بين وظائف والسلوك المرئي لعنصر التحكم خذ بعين الاعتبار مثال الزر. وظيفة الزر هى رفع الحدث Click عندما يتم النقر فوقه ولكن سلوكه المرئى لتغيير مظهره عندما يكون مشار إليه أو مضغوط.

يمكنك استخدام كائناتVisualState لتحديد مظهر عنصر التحكم عندما يكون فى حالة معينة . VisualState يحتوي على Storyboard يغيرات مظهر العناصر الموجودة في ControlTemplate. لا يلزم كتابة أية تعليمات برمجية لجعل هذا يحدث بسبب تغيير منطق عنصر التحكم الحالة باستخدام VisualStateManager. عندما يدخل عنصر التحكم الحالة المحددة بواسطة خاصية VisualState.Name ، تبدأStoryboard . عندما يخرج عنصر التحكم من الحالة ، يتوقف Storyboard .

يظهر المثال التالي VisualState الذي يغير من مظهر Button عندما يكون المؤشر فوقه . Storyboard يغير لون حد الزر عن طريق تغيير لون BorderBrush. إذا قمت بالإشارة إلى مثال ControlTemplate في بداية هذا الموضوع، سيتم استدعاء أن BorderBrush هو اسم SolidColorBrush التي تم تعيينها إلى Background من Border.

<!--Change the border of the button to red when the
    mouse is over the button.-->
<VisualState x:Name="MouseOver">
  <Storyboard>
    <ColorAnimation Storyboard.TargetName="BorderBrush"     
                    Storyboard.TargetProperty="Color"
                    To="Red" />

  </Storyboard>
</VisualState>

يكون عنصر التحكم هو المسؤول عن تعريف الحالات كجزء من عقده الذي تمت مناقشته بالتفاصيل في تخصيص عناصر أخرى عن طريق فهم "عقد التحكم" لاحقًا في هذا الموضوع. يسرد الجدول التالى الحالات المحددة للButton.

اسم VisualState

اسم VisualStateGroup

الوصف

Normal

CommonStates

الحالة الافتراضية.

MouseOver

CommonStates

وضع مؤشر الماوس على عنصر التحكم.

مضغوط

CommonStates

عنصر التحكم مضغوط.

معطل

CommonStates

عنصر التحكم معطّل.

مركز

FocusStates

عنصر التحكم عليه التركيز.

غير مركز

FocusStates

عنصر التحكم ليس عليه التركيز.

Button يعرّف مجموعتين من الحالات: تحتوي مجموعةCommonStates على Normal ، MouseOver ، Pressed ، و حالاتDisabled . تحتوي مجموعةFocusStates على Focused ، Unfocused ، ، و حالات . الحالات في نفس مجموعة الحالة تبادليتان بوجه عام. يكون عنصر التحكم دائماً في حالة واحدة لكل مجموعة. على سبيل المثال، Button يمكن أن يكون يركز حتى في حالة كون مؤشر الماوس فوقه, لذلك Button في حالةFocused يمكن أن يكون في MouseOver ، Pressed, أو حالة Normal .

اضافة كائنات VisualState إلى كائنات VisualStateGroup . إضافة كائنات VisualStateGroup إلى خاصية VisualStateManager.VisualStateGroups المرفقة التي تعينها على اجذر FrameworkElement من ControlTemplate. يحدد المثال التالي كائنات VisualState للحصول Normal ، MouseOver ، و حالاتPressed التي تكون كافة في مجموعة CommonStates . Name لكل VisualState تطابق الاسم الموجود في الجدول السابق. حالةDisabled والحالات في مجموعة FocusStates يتم حذفها للاحتفاظ بالمثال قصير, ولكن يتم تضمينها في المثال بأكمله في نهاية هذا الموضوع.

<ControlTemplate TargetType="Button">
  <Border Name="RootElement">

    <VisualStateManager.VisualStateGroups>

      <!--Define the states and transitions for the common states.
          The states in the VisualStateGroup are mutually exclusive to
          each other.-->
      <VisualStateGroup Name="CommonStates">

        <!--The Normal state is the state the button is in
            when it is not in another state from this VisualStateGroup.-->
        <VisualState Name="Normal" />

        <!--Change the SolidColorBrush, BorderBrush, to red when the
            mouse is over the button.-->
        <VisualState Name="MouseOver">
          <Storyboard>
            <ColorAnimation Storyboard.TargetName="BorderBrush" 
                            Storyboard.TargetProperty="Color" 
                            To="Red" />
          </Storyboard>
        </VisualState>

        <!--Change the SolidColorBrush, BorderBrush, to Transparent when the
            button is pressed.-->
        <VisualState Name="Pressed">
          <Storyboard>
            <ColorAnimation Storyboard.TargetName="BorderBrush" 
                            Storyboard.TargetProperty="Color"
                            To="Transparent"/>
          </Storyboard>
        </VisualState>

        <!--The Disabled state is omitted for brevity.-->
      </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <Border.Background>
      <SolidColorBrush x:Name="BorderBrush" Color="Black"/>
    </Border.Background>

    <Grid Background="{TemplateBinding Background}" Margin="4">
      <ContentPresenter
        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
        Margin="4,5,4,4" />
    </Grid>
  </Border>
</ControlTemplate>

المثال السابق ينتج مخرج مشابه للرسم التوضيحي التالي.

زر يستخدم قالب عنصر تحكم مخصص في الحالة العادية

زر له قالب تحكم مخصص.

زر يستخدم قالب عنصر تحكم مخصص في الحالة العادية

زر له حد أحمر.

زر يستخدم قالب عنصر تحكم مخصص في الحالة المضغوطة

الحد شفاف على زر مضغوط.

تحديد سلوك عنصر التحكم متى ينتقل بين الحالات

في المثال السابق، مظهر الزر أيضاً إلى يتغير عند قيام المستخدم بالنقر فوقه ولكن ما لم يظل الضغط ثانية كاملة, لا يرى المستخدم التأثير. بشكل افتراضي، تأخذ الحركة ثانية واحدة لكى تحدث. لأنه من المحتمل أن نقر و تحرير المستخدمين للزر يكون في وقت أقل بكثير، الملاحظات المرئية لن تصبح سارية المفعول إذا تركت في ControlTemplate في الحالة الافتراضية.

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

  • الوقت المستغرق بين الحالات للحدوث.

  • تغييرات إضافية في مظهر عنصر التحكم التي تحدث في وقت الانتقال.

  • حيث توضح أن VisualTransition يتم تطبيقها.

تحديد مدة الانتقال

يمكنك تحديد المدة التى يأخذها الانتقال بواسطة إعداد خاصية GeneratedDuration . يحتوي المثال السابق VisualState التي تحدد أن حد الزر يصبح شفافاً عند الضغط ولكن الحركة تأخذ فترة طويلة جداً بحيث لا يمكن أن تلاحظ إذا تم الضغط بشكل سريع وأصدر. يمكنك استخدام VisualTransition لتحديد مقدار الوقت الذى يستغرقه عنصر التحكم فى الانتقال الى حالة الضغط عليه. يحدد المثال التالي أن عنصر التحكم يأخذ مئوي واحد من الثانية فى الانتقال إلى حالة الضغط عليه .

<!--Take one hundredth of a second to transition to the
    Pressed state.-->
<VisualTransition To="Pressed" 
                  GeneratedDuration="0:0:0.01" />

تحديد التغييرات لمظهر عنصر التحكم أثناء الانتقال

VisualTransition يحتوي على Storyboard التي يبدأ عندما ينتقل بين الحالات. على سبيل المثال، يمكنك تحديد أن حركة معينة تحدث عند انتقال عنصر التحكم من حالةMouseOver إلى حالة Normal. يقوم المثال التالي بإنشاء VisualTransition التي تعيّن أن عندما يقوم المستخدم بتحريك مؤشر الماوس بعيداً عن الزر يتغير حد الزر إلى الأزرق ، ثم إلى الأصفر ثم إلى اللون الأسود في 1.5 ثانية.

<!--Take one and a half seconds to transition from the
    MouseOver state to the Normal state. 
    Have the SolidColorBrush, BorderBrush, fade to blue, 
    then to yellow, and then to black in that time.-->
<VisualTransition From="MouseOver" To="Normal" 
                      GeneratedDuration="0:0:1.5">
  <Storyboard>
    <ColorAnimationUsingKeyFrames
      Storyboard.TargetProperty="Color"
      Storyboard.TargetName="BorderBrush"
      FillBehavior="HoldEnd" >

      <ColorAnimationUsingKeyFrames.KeyFrames>

        <LinearColorKeyFrame Value="Blue" 
          KeyTime="0:0:0.5" />
        <LinearColorKeyFrame Value="Yellow" 
          KeyTime="0:0:1" />
        <LinearColorKeyFrame Value="Black" 
          KeyTime="0:0:1.5" />

      </ColorAnimationUsingKeyFrames.KeyFrames>
    </ColorAnimationUsingKeyFrames>
  </Storyboard>
</VisualTransition>

تحديد عند تطبيق VisualTransition

VisualTransition يمكن تقييدهم للتطبيق لحالات معينة أو أنه يتم تطبيقهم فى أي وقت ينتقل عنصر التحكم بين الحالات. في المثال السابق، VisualTransition يتم تطبيقه عند انتقال عنصر التحكم من حالة MouseOver إلى حالة Normal ; في المثال قبل ذلك، VisualTransition يتم تطبيق عندما يذهب عنصر التحكم فى حالةPressed . التقييد عندما VisualTransition يطبق بواسطة تعيين To و خصائص From . يصف الجدول التالي مستويات التقييد من الأكثر تقييداً إلى الأقل تقييداً.

نوع التقييد

قيمة فى شكل

قيمة ل

من حالة محددة إلى أخرى غير محددة

اسم VisualState

اسم VisualState

من أي حالة إلى حالة محددة

غير معين

اسم VisualState

من أي حالة إلى حالة محددة

اسم VisualState

غير معين

من أي حالة إلي أى حالة أخرى

غير معين

غير معين

يمكن أن يكون لديك عدة VisualTransition كائنات في VisualStateGroup التي تشير إلى نفس الحالة ، ولكن سيتم استخدام بالترتيب الذي يحدده الجدول السابق. في الأمثلة التالية يوجد كائنين VisualTransition عندما اينتقل عنصر التحكم من حالة Pressed إلى حالة MouseOver ، تسنخدم VisualTransition التى تحتوي على كلاً من From و مجموعة To . عندما ينتقل عنصر التحكم من حالة وهو ليس Pressed إلى حالة MouseOver ، تستخدم الحالة الأخرى.

<!--Take one half second to trasition to the MouseOver state.-->
<VisualTransition To="MouseOver" 
                  GeneratedDuration="0:0:0.5" />

<!--Take one hundredth of a second to transition from the
    Pressed state to the MouseOver state.-->
<VisualTransition From="Pressed" To="MouseOver" 
                  GeneratedDuration="0:0:0.01" />

VisualStateGroup يحتوي على خاصية Transitions التي تحتوي على كائنات VisualTransition التي تنطبق على كائنات VisualState في VisualStateGroup. كمؤلف ControlTemplate يمكنك إن شئت تضمين أي VisualTransition تريده. ومع ذلك، إذا تم تعيين To و خصائص From إلى أسماء الحالة غير الموجودة في VisualStateGroup ،يتم تجاهل VisualTransition .

المثال التالي يوضح VisualStateGroup لـCommonStates. يحدد المثال VisualTransition لكل من انتقالات الزر التالية .

  • إلى حالة Pressed .

  • إلى حالة MouseOver .

  • من حالة Pressed إلى حالة MouseOver .

  • من حالة MouseOver إلى حالة Normal .

<VisualStateGroup Name="CommonStates">

  <!--Define the VisualTransitions that
      can be used when the control transitions 
      between VisualStates that are defined in the
      VisualStatGroup.-->
  <VisualStateGroup.Transitions>

    <!--Take one hundredth of a second to 
        transition to the Pressed state.-->
    <VisualTransition To="Pressed" 
                      GeneratedDuration="0:0:0.01" />

    <!--Take one half second to trasition 
        to the MouseOver state.-->
    <VisualTransition To="MouseOver" 
                      GeneratedDuration="0:0:0.5" />

    <!--Take one hundredth of a second to transition from the
        Pressed state to the MouseOver state.-->
    <VisualTransition From="Pressed" To="MouseOver" 
                      GeneratedDuration="0:0:0.01" />

    <!--Take one and a half seconds to transition from the
        MouseOver state to the Normal state. 
        Have the SolidColorBrush, BorderBrush, fade to blue, 
        then to yellow, and then to black in that time.-->
    <VisualTransition From="MouseOver" To="Normal" 
                      GeneratedDuration="0:0:1.5">
      <Storyboard>
        <ColorAnimationUsingKeyFrames
          Storyboard.TargetProperty="Color"
          Storyboard.TargetName="BorderBrush"
          FillBehavior="HoldEnd" >

          <ColorAnimationUsingKeyFrames.KeyFrames>
            <LinearColorKeyFrame Value="Blue" 
              KeyTime="0:0:0.5" />
            <LinearColorKeyFrame Value="Yellow" 
              KeyTime="0:0:1" />
            <LinearColorKeyFrame Value="Black" 
              KeyTime="0:0:1.5" />

          </ColorAnimationUsingKeyFrames.KeyFrames>
        </ColorAnimationUsingKeyFrames>
      </Storyboard>
    </VisualTransition>
  </VisualStateGroup.Transitions>

  <!--The remainder of the VisualStateGroup is the
      same as the previous example.-->

  <VisualState Name="Normal" />

  <VisualState Name="MouseOver">
    <Storyboard>
      <ColorAnimation 
        Storyboard.TargetName="BorderBrush" 
        Storyboard.TargetProperty="Color" 
        To="Red" />

    </Storyboard>
  </VisualState>

  <VisualState Name="Pressed">
    <Storyboard>
      <ColorAnimation 
        Storyboard.TargetName="BorderBrush" 
        Storyboard.TargetProperty="Color" 
        To="Transparent"/>
    </Storyboard>
  </VisualState>

  <!--The Disabled state is omitted for brevity.-->

</VisualStateGroup>

تخصيص عناصر التحكم أخرى عن طريق فهم اتفاق التحكم

عنصر تحكم يستخدم ControlTemplate لتحديد البنية البصرية الخاصة به (باستخدام كائناتFrameworkElement ) والسلوك المرئي (باستخدام كائنات VisualState ) يستخدم أجزاء طراز التحكم . العديد من عناصر التحكم التي تم تضمينها مع WPF 4 تستخدم هذا الطراز. الأجزاء التي يحتاجها كاتبControlTemplate ليكون على علم، يتم اتصالها أن خلال اتفاق عنصر التحكم . عند فهم أجزاء اتفاق عنصر التحكم ، يمكنك تخصيص مظهر أي عنصر تحكم يستخدم نموذج التحكم بالأجزاء.

يحتوي عقد عناصر التحكم ثلاثة عناصر:

  • العناصر المرئية التي يستخدمها منطق عنصر التحكم.

  • حالات التحكم و المجموعة التى تنتمي اليها كل حالة.

  • الخصائص العامة التي تؤثر على عنصر التحكم بشكل مرئي.

العناصر المرئية الموجودة في اتفاق عنصر التحكم

في بعض الأحيان يتفاعل منطق عنصر التحكم مع FrameworkElement الموجود في ControlTemplate. على سبيل المثال، قد يعالج حدث أحد عناصره. عندما يتوقع عنصر التحكم العثور علىFrameworkElement معينة في ControlTemplate, فإنه يجب نقل هذه المعلومات الى ControlTemplate الكاتب. يستخدم عنصر التحكم TemplatePartAttribute لنقل نوع العنصر المتوقع و ما يجب أن يكون اسم العنصر. Button ليس لديه أجزاء FrameworkElement في اتفاق عنصر التحكم الخاص به ، ولكن عناصر تحكم أخرى، مثل ComboBox و نفذ.

يظهر المثال التالي كائناتTemplatePartAttribute فى فئة ComboBox. منطق ComboBox يتوقع العثور على TextBox باسم PART_EditableTextBox و Popup باسم PART_Popup في ControlTemplate الخاص به.

<TemplatePartAttribute(Name:="PART_EditableTextBox", Type:=GetType(TextBox))> _
<TemplatePartAttribute(Name:="Part_Popup", Type:=GetType(Popup))> _
Public Class ComboBox
    Inherits ItemsControl

End Class
[TemplatePartAttribute(Name = "PART_EditableTextBox", Type = typeof(TextBox))]
[TemplatePartAttribute(Name = "PART_Popup", Type = typeof(Popup))]
public class ComboBox : ItemsControl
{
}

يظهر المثال التالي ControlTemplateمبسطة للحصول على ComboBox التي تتضمن العناصر المحددة حسب الكائنات TemplatePartAttributeفى فئة ComboBox.

<ControlTemplate TargetType="ComboBox">
  <Grid>
    <ToggleButton x:Name="DropDownToggle"
      HorizontalAlignment="Stretch" VerticalAlignment="Stretch"  
      Margin="-1" HorizontalContentAlignment="Right"
      IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,
                  RelativeSource={RelativeSource TemplatedParent}}">
      <Path x:Name="BtnArrow" Height="4" Width="8" 
        Stretch="Uniform" Margin="0,0,6,0"  Fill="Black"
        Data="F1 M 300,-190L 310,-190L 305,-183L 301,-190 Z " />
    </ToggleButton>
    <ContentPresenter x:Name="ContentPresenter" Margin="6,2,25,2"
      Content="{TemplateBinding SelectionBoxItem}"
      ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
      ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}">
    </ContentPresenter>
    <TextBox x:Name="PART_EditableTextBox"
      Style="{x:Null}"
      Focusable="False"
      Background="{TemplateBinding Background}"
      HorizontalAlignment="Left" 
      VerticalAlignment="Center" 
      Margin="3,3,23,3"
      Visibility="Hidden"
      IsReadOnly="{TemplateBinding IsReadOnly}"/>

    <Popup x:Name="PART_Popup"
      IsOpen="{TemplateBinding IsDropDownOpen}">
      <Border x:Name="PopupBorder" 
        HorizontalAlignment="Stretch" Height="Auto" 
        MinWidth="{TemplateBinding ActualWidth}"
        MaxHeight="{TemplateBinding MaxDropDownHeight}"
        BorderThickness="{TemplateBinding BorderThickness}" 
        BorderBrush="Black" Background="White" CornerRadius="3">
        <ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1">
          <ItemsPresenter/>
        </ScrollViewer>
      </Border>
    </Popup>

  </Grid>
</ControlTemplate>

الحالات في اتفاق عنصرالتحكم

حالات عنصر التحكم هى أيضاً جزء من اتفاق عنصر التحكم . مثال على إنشاء ControlTemplate للحصول Button يُظهر كيفية تحديد مظهر Button اعتماداً على الحالات الخاص به. لعناصر التحكم التي تم تضمينها مع WPF ، يمكنك العثور على الحالات المرئية التي تم تضمينها في عقد عنصر التحكم بواسطة النظر إلى الموضوع المرجع لعنصر التحكم. يجب تحديد عناصر التحكم بواسطة الجهة الخارجية الحالات عن طريق استخدام TemplateVisualStateAttribute. إنشاء VisualState لكل حالة معينة ووضع كافة كائنات VisualState التى اتشارك GroupName في VisualStateGroup ، كما هو موضح في تغيير مظهر عنصر التحكم اعتماداً على حالته مسبقاً في هذا الموضوع.

الخصائص في اتفاق عنصر التحكم

الخصائص العامة التي تؤثر بشكل مرئي فى عنصر التحكم مضمنة أيضاً في العقد. يمكنك تعيين هذه الخصائص لتغيير مظهر عنصر التحكم دون إنشاء ControlTemplateجديد . يمكنك أيضاً استخدام ملحق العلامات TemplateBinding لربط خصائص العناصر في ControlTemplate لخصائص عامة معرفة بواسطة Button.

عند إنشاء ControlTemplate ، غالباً يكون أسهل بالبدء ب ControlTemplate موجودةوإجراء تغييرات له. يمكنك القيام بواحد مما يلي لتغيير ControlTemplateموجودة :

مثال كامل

يظهر المثال التالي ButtonControlTemplate الكامل الذي تمت مناقشتها في هذا الموضوع.

<StackPanel>
  <StackPanel.Resources>
    <Style TargetType="Button" x:Key="newTemplate">
      <!--Set the Background, Foreground, FontSize, Width, 
                  Height, Margin, and Template properties for
                  the Button.-->
      <Setter Property="Background" Value="Navy"/>
      <Setter Property="Foreground" Value="White"/>
      <Setter Property="FontSize" Value="14"/>
      <Setter Property="Width" Value="100"/>
      <Setter Property="Height" Value="40"/>
      <Setter Property="Margin" Value="10"/>
      <Setter Property="HorizontalContentAlignment" Value="Center"/>
      <Setter Property="VerticalContentAlignment" Value="Center"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="Button">
            <Border x:Name="RootElement">
              <VisualStateManager.VisualStateGroups>

                <!--Define the states and transitions for the common states.
                    The states in the VisualStateGroup are mutually exclusive to
                    each other.-->
                <VisualStateGroup Name="CommonStates">

                  <!--Define the VisualTransitions that can be used when the control
                      transitions between VisualStates that are defined in the
                      VisualStatGroup.-->
                  <VisualStateGroup.Transitions>

                    <!--Take one hundredth of a second to transition to the
                        Pressed state.-->
                    <VisualTransition To="Pressed" 
                                      GeneratedDuration="0:0:0.01" />

                    <!--Take one half second to trasition to the MouseOver state.-->
                    <VisualTransition To="MouseOver" 
                                      GeneratedDuration="0:0:0.5" />

                    <!--Take one hundredth of a second to transition from the
                        Pressed state to the MouseOver state.-->
                    <VisualTransition From="Pressed" To="MouseOver" 
                                      GeneratedDuration="0:0:0.01" />

                    <!--Take one and a half seconds to transition from the
                        MouseOver state to the Normal state. 
                        Have the SolidColorBrush, BorderBrush, fade to blue, 
                        then to yellow, and then to black in that time.-->
                    <VisualTransition From="MouseOver" To="Normal" 
                                          GeneratedDuration="0:0:1.5">
                      <Storyboard>
                        <ColorAnimationUsingKeyFrames
                          Storyboard.TargetProperty="Color"
                          Storyboard.TargetName="BorderBrush"
                          FillBehavior="HoldEnd" >

                          <ColorAnimationUsingKeyFrames.KeyFrames>

                            <LinearColorKeyFrame Value="Blue" 
                              KeyTime="0:0:0.5" />
                            <LinearColorKeyFrame Value="Yellow" 
                              KeyTime="0:0:1" />
                            <LinearColorKeyFrame Value="Black" 
                              KeyTime="0:0:1.5" />

                          </ColorAnimationUsingKeyFrames.KeyFrames>
                        </ColorAnimationUsingKeyFrames>
                      </Storyboard>
                    </VisualTransition>
                  </VisualStateGroup.Transitions>

                  <!--The Normal state is the state the button is in
                      when it is not in another state from this VisualStateGroup.
                      There is no special visual behavior for this state, but
                      the VisualState must be defined in order for the button
                      to return to its initial state.-->
                  <VisualState x:Name="Normal" />

                  <!--Change the border of the button to red when the
                      mouse is over the button.-->
                  <VisualState x:Name="MouseOver">
                    <Storyboard>
                      <ColorAnimation Storyboard.TargetName="BorderBrush"     
                                      Storyboard.TargetProperty="Color"
                                      To="Red" />

                    </Storyboard>
                  </VisualState>

                  <!--Change the border of the button to Transparent when the
                      button is pressed.-->
                  <VisualState x:Name="Pressed">
                    <Storyboard >
                      <ColorAnimation Storyboard.TargetName="BorderBrush" 
                                      Storyboard.TargetProperty="Color" 
                                      To="Transparent" 
                                      />
                    </Storyboard>
                  </VisualState>

                  <!--Show the DisabledRect when the IsEnabled property on
                      the button is false.-->
                  <VisualState x:Name="Disabled">
                    <Storyboard>
                      <DoubleAnimation Storyboard.TargetName="DisabledRect" 
                                       Storyboard.TargetProperty="Opacity"
                                       To="1" Duration="0" />
                    </Storyboard>
                  </VisualState>
                </VisualStateGroup>

                <!--Define the states and transitions for the focus states.
                    The states in the VisualStateGroup are mutually exclusive to
                    each other.-->
                <VisualStateGroup x:Name="FocusStates">

                  <!--Define the VisualStates in this VistualStateGroup.-->
                  <VisualState x:Name="Focused">
                    <Storyboard>
                      <ObjectAnimationUsingKeyFrames 
                        Storyboard.TargetName="FocusVisual" 
                        Storyboard.TargetProperty="Visibility" Duration
                        ="0">

                        <DiscreteObjectKeyFrame KeyTime="0">
                          <DiscreteObjectKeyFrame.Value>
                            <Visibility>Visible</Visibility>
                          </DiscreteObjectKeyFrame.Value>
                        </DiscreteObjectKeyFrame>
                      </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                  </VisualState>
                  <VisualState x:Name="Unfocused">
                    <Storyboard>
                      <ObjectAnimationUsingKeyFrames 
                        Storyboard.TargetName="FocusVisual" 
                        Storyboard.TargetProperty="Visibility"
                        Duration="0">

                        <DiscreteObjectKeyFrame KeyTime="0">
                          <DiscreteObjectKeyFrame.Value>
                            <Visibility>Collapsed</Visibility>
                          </DiscreteObjectKeyFrame.Value>
                        </DiscreteObjectKeyFrame>
                      </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                  </VisualState>
                </VisualStateGroup>
              </VisualStateManager.VisualStateGroups>

              <!--Create the SolidColorBrush for the Background 
                  as an object elemment and give it a name so 
                  it can be referred to elsewhere in the control template.-->
              <Border.Background>
                <SolidColorBrush x:Name="BorderBrush" Color="Black"/>
              </Border.Background>

              <!--Create a border that has a different color by adding smaller grid.
                  The background of this grid is specified by the button's Background
                  property.-->
              <Grid Background="{TemplateBinding Background}" Margin="4">

                <!--Create a Rectangle that indicates that the
                    Button has focus.-->
                <Rectangle Name="FocusVisual" 
                           Visibility="Collapsed" Margin="2" 
                           Stroke="{TemplateBinding Foreground}" 
                           StrokeThickness="1" 
                           StrokeDashArray="1.5 1.5"/>

                <!--Use a ContentPresenter to display the Content of
                    the Button.-->
                <ContentPresenter
                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                  Margin="4,5,4,4" />

                <!--Create a rectangle that causes the button to appear
                    grayed out when it is disabled.-->
                <Rectangle x:Name="DisabledRect" 
                         Fill="#A5FFFFFF"
                         Opacity="0" IsHitTestVisible="false" />
              </Grid>
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

  </StackPanel.Resources>

  <Button Style="{StaticResource newTemplate}" 
          Content="Button1"/>

  <Button Style="{StaticResource newTemplate}"
          Background="Purple" 
          Content="Button2" />
</StackPanel>

راجع أيضًا:

المبادئ

التنسيق و القولبة