لماذا تم تعطيل عنصر قائمة السياق المرتبط بـ WPF RoutedCommand؟

StackOverflow https://stackoverflow.com/questions/455551

  •  19-08-2019
  •  | 
  •  

سؤال

ما زلت أتخبط في طريقي حول WPF في الوقت الحالي، ولا أستطيع معرفة سبب تعطيل عنصر قائمة السياق هذا:

<Window x:Class="DisabledMenuItemProblem.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DisabledMenuItemProblem"
        Title="Window1" Height="300" Width="300">
    <TextBlock Text="fooooobaaaaaar">
        <TextBlock.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Foo" Command="{x:Static local:MyCommands.FooBar}" />
            </ContextMenu>
        </TextBlock.ContextMenu>
    </TextBlock>
</Window>

using System.Windows;
using System.Windows.Input;

namespace DisabledMenuItemProblem
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            CommandBindings.Add(new CommandBinding(MyCommands.FooBar, FooExecuted, CanFooExecute));
        }

        public void FooExecuted(object sender, ExecutedRoutedEventArgs e)
        { MessageBox.Show("Foo!"); }

        public void CanFooExecute(object sender, CanExecuteRoutedEventArgs e)
        { e.CanExecute = true; }
    }

    public static class MyCommands
    { 
        public static RoutedCommand FooBar = new RoutedCommand(); 
    }
}

ماذا ينقصني؟

ما يحيرني أيضًا هو أنه إذا قمت برمي زر في النافذة وقمت بتعيين الأمر الخاص به على FooBar، فإنه يعمل، وبمجرد تنفيذه، يتم تمكين قائمة السياق!

هتاف الرجال ، كريس.

هل كانت مفيدة؟

المحلول

هنا هو النمط العام الذي أستخدمه ....

أولاً، احتفظ بأوامرك في فئتها الثابتة، وهذا يشجع على إعادة الاستخدام، وما إلى ذلك....

public static class MyCommands
{
    public static RoutedUICommand CmdFoo = new RoutedUICommand("CmdFoo", 
                                                               "CmdFoo", 
                                                               typeof(MyCommands));
}

ثانيًا، قم بتسجيل الأمر في عنصر التحكم/النافذة/إلخ.تريد استخدامه في المُنشئ عادةً

public MyControl
{
    public MyControl()
    {
        CommandBindings.Add( 
            new CommandBinding( MyCommands.CmdFoo,   // this is the command object
                                XCutFooCommand,      // execute
                                CanXCuteFooCommand));// can execute?
    }

ثالثًا، قم بإنشاء معالجاتك في عنصر التحكم/النافذة/إلخ .....

  public void CanExecuteRerollCommand(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;  // can this command be executed?
        e.Handled = true;     // has this event been handled?
    }
    public void ExecuteRerollCommand(object sender, ExecutedRoutedEventArgs e)
    {
    // do stuff
    }
}

وأخيرًا، يجب أن يبدو ملف xaml الخاص بك كما يلي:

    <ContextMenu>
        <ContextMenu.CommandBindings>
            <CommandBinding Command="foo:MyCommands.CmdFoo" 
                            CanExecute="CanExecuteRerollCommand" 
                            Executed="ExecuteRerollCommand" />
        </ContextMenu.CommandBindings>
        <MenuItem Header="Reroll"  Command="foo:MyCommands.CmdFoo"/>
    </ContextMenu>

لاحظ أنه لا يوجد ملزمة.لاحظ أيضًا <CommandBinding> في ال <ContextMenu>.هنا مرجع....http://www.wiredprairie.us/journal/2007/04/commandtarget_menuitem_context.html

يتم معالجة الأمر الذي تم تعطيله على هذا الموقع

نصائح أخرى

لأي شخص يبحث عن إجابة لهذه المشكلة - بعد البحث في الإنترنت، وجدت أن الإجابة الأكثر فعالية هي تضمين ما يلي في أي إعلان لعنصر MenuItem الذي يحتاج إلى سماع أوامره من قبل "مالكه".

في شروط الشخص العادي.إذا كنت تريد أن يتم سماع أوامر قائمة السياق الخاصة بك من خلال الشيء الذي تنقر عليه بزر الماوس الأيمن.أضف هذا الكود:

CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}"

مثال:

    <ContextMenu>
        <MenuItem Header="Close" Command="Application.Close" CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
    </ContextMenu>

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

يحتوي كل FrameworkElement على DataContext وهو كائن عشوائي.المصدر الافتراضي لربط البيانات هو DataContext.يمكنك استخدام RelativeSource.Self لتغيير مصدر الارتباط بـ FrameworkElement نفسه بدلاً من DataContext الخاص به.لذا فإن الجزء RelativeSource ينقلك "مستوى واحد لأعلى" من DataContext الخاص بـ FrameworkElement إلى FrameworkElement نفسه.بمجرد وصولك إلى FrameworkElement، يمكنك تحديد مسار لأي من خصائصه.إذا كان FrameworkElement عبارة عن نافذة منبثقة، فستحتوي على خاصية PlacementTarget وهي عنصر FrameworkElement الآخر الذي تم وضع النافذة المنبثقة بالنسبة إليه.

باختصار، إذا كان لديك نافذة منبثقة موضوعة بالنسبة إلى TextBox على سبيل المثال، فإن هذا التعبير يعين DataContext الخاص بالنافذة المنبثقة إلى TextBox ونتيجة لذلك فإن {Binding Text} في مكان ما في نص النافذة المنبثقة سوف يرتبط بنص TextBox .

آمل بصدق أن تنقذ هذه المعلومات أي شخص جديد في WPF من الصداع الذي مررت به في نهاية هذا الأسبوع ...على الرغم من أنه علمني الكثير!

ستيف

بقدر ما أفهم هذا هو ما يحدث.عندما يتم عرض قائمة السياق، يتم عرضها في نافذة منبثقة وهي في الأساس نافذة منفصلة.لا تنتمي النافذة المنبثقة إلى نفس الشجرة المرئية التي ينتمي إليها المحتوى الرئيسي في نافذتك، وبالتالي لا "يظهر" الأمر في نافذتك الرئيسية.ولهذا السبب لا يتم استدعاء أسلوب CanExecute مطلقًا.على سبيل المثال، إذا قمت بإرفاق CommandBindings في قائمة السياق نفسها، فسيتم استدعاء CanExecute بشكل صحيح.

ومع ذلك، أتذكر أنني قرأت في مكان ما أن النافذة المنبثقة في بعض الحالات يجب ألا تتصرف مثل النافذة العادية وأن بعض الأشياء يجب أن "تظهر فقاعة".

أعتقد أنه يجب أن يكون هناك بعض السحر الداخلي يحدث.إذا قمت ببساطة بتغيير TextBlock إلى TextBox على سبيل المثال، يبدو أنه يعمل.أراهن أن برنامج Reflector سيُظهر لك بعض المنطق الإضافي في TextEditorBase أو شيء من هذا القبيل.

إذا كنت حقًا بحاجة إلى استخدام TextBlock، فمن المحتمل أن أقوم بإضافة CommandBinding يدويًا إلى قائمة السياق نفسها بدلاً من إضافتها إلى النافذة.

لقد وجدت أن أسهل طريقة للتغلب على هذه المشكلة هي نقل قائمة السياق إلى مورد النافذة والرجوع إليها من هناك

<ContextMenu x:Key="ControlContextMenu">
    <ContextMenu.CommandBindings>
        <CommandBinding Command="{StaticResource CloseCommand}" Executed="CloseExecuted" CanExecute="CloseCanExecute" />
    </ContextMenu.CommandBindings>          
    <MenuItem Command="{StaticResource CloseCommand}" />
</ContextMenu>

ثم على UIElement فقط قم بتعيين خاصية contextMenu

<TextBlock ContextMenu="{StaticResource ControlContextMenu}"/>

الإجابة الأبسط هي إضافة مكالمة إلى ركز() في منشئ النافذة.لقد اصطدمت بهذه المشكلة بالأمس وأمضيت وقتًا طويلاً في معرفة ما يحدث.أنا كتبت عن ذلك هنا: http://cebla5.spaces.live.com/blog/cns!1B8262ED00250003!206.entry

سوف يشرح منشور المدونة سبب الاتصال ركز() في أعمال البناء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top