2014-10-15 8 views
7

Ich muss Standard ContextMenu von TextBox deaktivieren. Ich habe ein neues WPF-Projekt erstellt und addierten die folgenden:WPF ContextMenu = {x: Null} aber zeigt immer noch Menü in ContentControl

<Window x:Class="WpfApplication3.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <ContentControl> 
      <ContentControl.ContentTemplate> 
       <DataTemplate> 
        <TextBox ContextMenu="{x:Null}" VerticalAlignment="Top" HorizontalAlignment="Left" Width="50"></TextBox> 
       </DataTemplate> 
      </ContentControl.ContentTemplate> 
     </ContentControl> 
    </Grid> 
</Window> 

Aber das ist, was ich bekommen:

enter image description here

Der folgende Code funktioniert:

<Grid> 
    <TextBox ContextMenu="{x:Null}" VerticalAlignment="Top" HorizontalAlignment="Left" Width="50"></TextBox> 
</Grid> 

Warum passiert das?

Aktualisierung.

Nach der akzeptierten Antwort habe ich eine Klasse von TextBox abgeleitet, um Eltern ContextMenu zeigen zu können.

public class TextBoxNoMenu: TextBox 
    { 
     public TextBoxNoMenu() 
     { 
      ContextMenu = null; 
     } 
    } 

Antwort

3

Warum ist das passiert?

Dies ist ein interessanter Fall, in dem sich das Verhalten eines Steuerelements abhängig davon ändert, wo/wie eine Eigenschaft festgelegt ist.

TextBox verfügt standardmäßig über ein eigenes Kontextmenü. Die nur Zeit wird es nicht tun, wenn Sie den lokalen Wert von ContextMenu auf null explizit festlegen. Dies geschieht in Ihrem einfachen Beispiel, wo die TextBox direkt in der Grid ist.

Wenn Sie jedoch eine Eigenschaft in einer Vorlage festlegen, legen Sie nicht tatsächlich einen lokalen Wert fest; Sie legen einen Wert für "Elternvorlage" fest. Wenn Sie den Wert mit DependencyPropertyHelper.GetValueSource() überprüfen, sehen Sie, dass die Basiswertquelle ParentTemplate anstelle von Local ist. Somit wird das Menü immer noch überschrieben.

Weitere Informationen zu den verschiedenen Arten von Wertquellen für Abhängigkeitseigenschaften finden Sie unter Dependency Property Value Precedence.

@ OmegaMan's Vorschlag, ein 'verstecktes' Kontextmenü zuzuweisen, scheint ziemlich gut zu funktionieren.

+0

Mein ursprüngliches Ziel war, das ContextMenu der Eltern zu öffnen. Zusammenfallen löst also das eigentliche Problem nicht. Wie auch immer, als ich sah, dass du antwortest, habe ich eine Klasse TextBoxNoMenu erstellt, die von TextBox abgeleitet wurde und das Kontextmenü aufgeblendet hat. –

1

Beachten Sie, dass, während Sie die ContextMenu auf TextBox deaktiviert mayhave, wenn es in einem anderen Steuerelement ist, die Sie tatsächlich sein kann, die ContextMenu eines solchen Wrapper zu sehen. Versuchen Sie Snooping, um diese Art von Verhalten genauer zu sehen.

Beachten Sie auch, dass viele der Standardsteuervorlagen in WPF solche Probleme verursachen können, indem Sie ihre eigenen untergeordneten Objekte hinzufügen. Wenn Sie default template for TextBoxBorder und dann <ScrollViewer Margin="0" x:Name="PART_ContentHost" /> verwenden, sehen Sie wahrscheinlich das ContextMenu eines untergeordneten Objekts in TextBox.

+0

Code oben ist alles, was ich in der Lösung habe. Der einzige Wrapper ist also ContentControl. Außerdem, wenn ich ContextMenu des ContentControl auf null setze, bekomme ich das gleiche falsche Verhalten. –

+0

Angenommen, Sie suchen nicht in der TextBox und fügen eigene Kinder hinzu. Aktualisierung meiner Antwort entsprechend. – David

1

Dies scheint ein laufendes Problem zu sein, bei dem X: Null das Standardkontextmenü nicht "ausschaltet". Ein besserer Weg wäre es visiblity zu ändern:

<TextBox.ContextMenu> 
    <ContextMenu Visibility="Collapsed"/> 
</TextBox.ContextMenu> 
0

Ich hatte ein ähnliches Problem, aber ich habe meine Steuerelemente programmgesteuert generiert, und meine Elternsteuerung ist ein Dockpanel. Basierend auf der angenommenen Antwort, entschied ich, den Nullwert im Code hinter zu setzen.

 <Grid> 
      <DockPanel> 
       <TextBox Name="txtBox" VerticalAlignment="Top" HorizontalAlignment="Left" Width="50"></TextBox> 
      </DockPanel> 
     </Grid> 

und dann

  private void Window_Loaded(object sender, RoutedEventArgs e) 
      { 
       txtBox.ContextMenu = null; 
      } 

EDIT: Ich fühlte dies war eine Art willkürlicher Antwort, ebenso wie es nicht vollständig oder direkt auf diese Frage zu lösen. Ich habe etwas gegraben und wenn Sie die Methode implementieren, die in der Antwort auf This Question gefunden wird, können Sie die Textbox im Code-behind finden.

Also, wenn Sie diesen

haben
 <Grid> 
      <ContentControl> 
       <ContentControl.ContentTemplate> 
       <DataTemplate> 
        <TextBox Name="txtBox" VerticalAlignment="Top" HorizontalAlignment="Left" Width="50"></TextBox> 
       </DataTemplate> 
       </ContentControl.ContentTemplate> 
      </ContentControl> 
     </Grid> 

Dann sollten Sie in der Lage sein, Ihre Textbox mit Namen zu finden (txtBox in diesem Fall) und das Kontextmenü gesetzt

   TextBox myTextBox = FindChild<TextBox>(Application.Current.MainWindow, "txtBox"); 

       myTextBox.ContextMenu = null; 

Persönlich mich auf null Ich würde es vorziehen, eine neue Klasse mit Vererbung zu erstellen, aber was auch immer für Sie funktioniert. Dies beantwortet immer noch nicht: "Warum passiert das?" aber ich denke, die akzeptierte Antwort macht einen guten Job.