سؤال

ماذا أفعل خطأ هنا؟:

 <GridViewColumn>
    <GridViewColumn.CellTemplate>
       <DataTemplate>
          <Button>
            <Button.ToolTip>
              <TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource AncestorType=Window}}" />

هذا مجرد مثال مبسط ، لا يعمل على أي حال :) في الواقع أحتاج إلى الحصول على قيمة من خاصية أخرى في نطاق DataContext للنافذة.

مساعدتي الثابتة والمتنقلة.

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

المحلول

هذا أمر صعب لأن تلميح الأدوات ليس جزءًا من VisualTree. هنا ترى حلًا رائعًا لنفس المشكلة مع ContextMenus. بنفس الطريقة التي يمكنك بها الذهاب إلى تلميح الأدوات.

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

هناك طريقة لطيفة للقيام بذلك ، وهي توفير المثيل المطلوب (مثل ViewModel) ضمن علامة العلامة الخاصة بـ PlacementTarget. المثال التالي يقوم بذلك للوصول إلى عملية قيادة من ViewModel:

<Button Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=Self}}">
  <Button.ContextMenu>
    <ContextMenu>
       <MenuItem Command="{Binding PlacementTarget.Tag.DesiredCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" .../>
    <ContextMenu>
  </Button.ContextMenu>
</Button>

لم أختبرها ووقت طويل فعلت هذا في المرة الأخيرة. يرجى الإدلاء بتعليق إذا لم ينجح ذلك من أجلك.

تحديث 2

نظرًا لأن الرابط الأصلي الذي كتب عنه هذا الإجابة قد ولت ، فقد ضربت Archive.org و وجدت إدخال المدونة الأصلي. هنا ، حرفيًا من المدونة:

نظرًا لأن ContextMenu في WPF غير موجود داخل الشجرة المرئية للصفحة/النافذة/التحكم في حد ذاتها ، فقد يكون ربط البيانات أمرًا صعبًا بعض الشيء. لقد بحثت في عالية ومنخفضة عبر الويب لهذا ، ويبدو أن الإجابة الأكثر شيوعًا هي "فقط القيام بذلك في الكود". خاطئ - ظلم - يظلم! لم آتي إلى عالم XAML الرائع لأعود لفعل الأشياء في الكود.

فيما يلي مثالي على ذلك سيسمح لك بالربط بسلسلة موجودة كخاصية لنافذتك.

public partial class Window1 : Window
{
    public Window1()
    {
        MyString = "Here is my string";
    }

    public string MyString
    {
        get;
        set;

    }
}


<Button Content="Test Button" 
     Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
  <Button.ContextMenu>
    <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, 
          RelativeSource={RelativeSource Self}}" >
      <MenuItem Header="{Binding MyString}"/>
    </ContextMenu>
  </Button.ContextMenu>   
</Button>

الجزء المهم هو العلامة الموجودة على الزر (على الرغم من أنه يمكنك بسهولة تعيين DataContext للزر). هذا يخزن إشارة إلى النافذة الأصل. ContextMenu قادر على الوصول إلى هذا من خلال خاصية PlacementTarget. يمكنك بعد ذلك تمرير هذا السياق من خلال عناصر القائمة الخاصة بك.

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

نصائح أخرى

لكل أدناه:
PlacementTarget هو عنصر التحكم الذي يمتلك ContextMenu (على سبيل المثال: DataGrid). لا حاجة إلى خاصية "علامة".

يرتبط isEnabled بقيمة "myProperty" الخاصة بـ DataGrid.

لقد اختبرت هذا وهو يعمل. كان وجود مشكلة مماثلة مع الربط.

<ContextMenu
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}"
IsEnabled="{Binding myProperty}"  
>

لان ContextMenu ليس في الشجرة المرئية ، ولن يعمل الربط. الحل البسيط هو استخدام نمط الوكيل ، يمكنك إنشاء فئة غلاف ترث من DependencyObject ولديه DependencyProperty من شأنه أن يحتفظ DataContext من الخاص بك Window, ، ثم يمكنك الحصول على مورد للوكيل في XAML وأخيراً ربطك MenuItem أمر إلى الأمر المطلوب عبر كائن الوكيل.
عينة الوكيل:

Public class ProxyClass : DependencyObject
{
    Public object Data {get; set;}
   public static readonly DependencyProperty DataProperty = DependencyProperty.Register("DataProperty", typeof(object), typeof(ProxyClass), new FrameworkPropertyMetadata(null));

}

كيفية استخدام في XAML:

<Window DataContext="{Binding MyViewModel}">
...
<Window.Resources>
    <ProxyClass Data={Binding} x:Key="BindingProxy"/>

</Window.Resources>
...  
<MenuItem Command="{Binding Source={StaticResource BindingProxy}, Path=Data.MyDesiredCommand"/>
...
</Window>

ماذا يحدث؟
Data ممتلكات ProxyClass سوف يرتبط DataContext من Window, ، ثم يحتوي على كل من comamnds وخصائصك ViewModel داخل ProxyClass مورد.
فائدة أخرى لهذا النهج هي قابلية النقل وإعادة استخدامها في وجهات نظر ومشاريع متعددة.

أعتقد أنه ينبغي القيام به مثل هذا:

{Binding Path=Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top