2014-10-15 14 views
7

Potrzebuję wyłączyć standardowe menu kontekstowe TextBox. I utworzeniu nowego projektu WPF i dodawali następujący:WPF ContextMenu = {x: Null}, ale nadal pokazuje menu wewnątrz 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> 

Ale to, co otrzymuję:

enter image description here

Poniższy kod działa poprawnie:

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

Dlaczego czy to się dzieje?

Aktualizacja.

Zgodnie z zaakceptowaną odpowiedzą utworzyłem klasę wywodzącą się z TextBox, aby móc pokazać rodzicom ContextMenu.

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

Odpowiedz

3

Dlaczego tak się dzieje?

Jest to interesujący przypadek zmiany zachowania się kontrolki w zależności od miejsca/sposobu ustawiania właściwości.

TextBox domyślnie udostępnia własne menu kontekstowe. W takim przypadku nie zostanie to zrobione, gdy zostanie jawnie ustawiona lokalna wartość o wartości z ContextMenu na null. Oto, co dzieje się w twoim prostym przykładzie, gdzie TextBox znajduje się bezpośrednio w Grid.

Jednak po ustawieniu właściwości w szablonie, w rzeczywistości nie ustawia się wartości lokalnej; ustawiasz wartość "szablonu nadrzędnego". Jeśli sprawdzisz wartość za pomocą DependencyPropertyHelper.GetValueSource(), zobaczysz, że źródłem wartości podstawowej jest ParentTemplate zamiast Local. W związku z tym menu jest nadal nadpisywane.

Aby uzyskać więcej informacji na temat różnych rodzajów źródeł wartości właściwości zależności, zobacz numer Dependency Property Value Precedence.

@ Sugestia OmegaMan o przypisaniu "ukrytego" menu kontekstowego wydaje się działać całkiem dobrze.

+0

Moim początkowym celem było otwarcie Parent ContextMenu. Tak więc, zwijanie nie rozwiązuje rzeczywistego problemu. Jednak gdy zobaczyłem twoją odpowiedź, stworzyłem klasę TextBoxNoMenu wyprowadzoną z TextBox i nulled jej menu kontekstowe. –

1

Należy pamiętać, że podczas mayhave ty wyłączył ContextMenu na TextBox, jeśli jest w innej kontroli, może być rzeczywiście widząc ContextMenu takiej owijki. Wypróbuj Snooping, aby zobaczyć bardziej szczegółowo tego rodzaju zachowanie.

Należy również zauważyć, że wiele domyślnych szablonów kontrolnych w całej WPF może powodować takie problemy, dodając własne obiekty podrzędne. Widok default template for TextBox używa Border, a następnie <ScrollViewer Margin="0" x:Name="PART_ContentHost" />, prawdopodobnie widzisz ContextMenu obiektu podrzędnego, jeśli TextBox.

+0

Powyższy kod jest wszystkim, co mam w rozwiązaniu. Zatem jedynym opakowaniem jest ContentControl. Co więcej, jeśli ustawię ContextMenu ContentControl na wartość null, otrzymam takie samo błędne zachowanie. –

+0

Zakładając, że nie patrzysz na TextBox, dodając własne dzieci. Odpowiednio aktualizuję moją odpowiedź. – David

1

Wydaje się, że to działający problem, w którym X: Null nie "wyłącza" domyślnego menu kontekstowego. Lepszym sposobem byłoby zmienić to visiblity:

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

Miałem podobny problem, ale programistycznie generowałem kontrolki, a moją kontrolą nadrzędną jest dockpanel. Na podstawie przyjętej odpowiedzi zdecydowałem ustawić wartość pustą w kodzie.

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

a następnie

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

EDIT: Czułem to był rodzaj przypadkowy odpowiedź, ponieważ nie w pełni lub bezpośrednio rozwiązać tę kwestię. Zrobiłem trochę kopania i jeśli zaimplementujesz metodę znalezioną w odpowiedzi na This Question możesz znaleźć pole tekstowe z tyłu kodu.

Tak więc, jeśli masz ten

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

Następnie powinieneś być w stanie znaleźć pole tekstowe po nazwie (txtBox w tym przypadku) i ustawić menu kontekstowego null

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

       myTextBox.ContextMenu = null; 

Osobiście wolałby to tworzyć nową klasę z dziedziczeniem, ale cokolwiek działa dla ciebie. To nadal nie odpowiada "Dlaczego tak się dzieje?" ale myślę, że zaakceptowana odpowiedź dobrze to rozumie.

Powiązane problemy