2009-03-03 5 views
51

Ich habe eine WPF-Anwendung mit diesen drei Arten von Dingen bekam ...WPF: Wie setze ich das Besitzerfenster eines Dialogs, der von einem UserControl angezeigt wird?

  • WindowMain
  • UserControlZack
  • WindowModal

UserControlZack1 sitzt auf meinem WindowMain ...

<Window x:Class="WindowMain" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:ProjectName" 
     ... 
     Name="WindowMain"> 
    <Grid> 
     ... 
     <local:UserControlZack x:Name="UserControlZack1" ... /> 
     ... 
    </Grid> 
</Window> 

UserControlZack1 zeigt eine WindowModal-Dialogbox an ...

 
Partial Public Class UserControlZack 

    ... 

    Private Sub SomeButton_Click(...) 
     'instantiate the dialog box and open modally... 
     Dim box As WindowModal = New WindowModal() 
     box.Owner = ????? 
     box.ShowDialog() 
     'process data entered by user if dialog box is accepted... 
     If (box.DialogResult.GetValueOrDefault = True) Then 
      _SomeVar = box.SomeVar 
      ... 
     End If 
    End Sub 

End Class 

Wie kann ich box.Owner auf das richtige Fenster, meine laufenden Instanz WindowMain eingestellt?

Ich kann box.Owner = Me.Owner nicht verwenden, weil "'Besitzer' kein Mitglied von 'ProjectName.UserControlZack' ist."

Ich kann box.Owner = Me.Parent nicht verwenden, weil das ein Raster zurückgibt, nicht das Fenster.

Ich kann box.Owner = WindowMain nicht verwenden, weil "'WindowMain' ein Typ ist und nicht als Ausdruck verwendet werden kann."

+1

Eine korrekte, akzeptable Antwort wurde wahrscheinlich schon eingereicht. Basierend ausschließlich auf den Stimmen sollte Martins wohl angenommen werden. – Emyr

Antwort

0

habe ich es kriechend den ganzen Weg zurück durch meine XAML ...

 
box.Owner = DirectCast(DirectCast(DirectCast(Me.Parent, Grid).Parent, Grid).Parent, Window) 

zu arbeiten, aber das scheint ziemlich unelegant. Gibt es einen besseren Weg?

+0

Siehe unten auf einen RoutedUICommand, den ich denke, ist der elegantere Weg. Entschuldigung für die C#, ich bin kein VB-Typ! –

0

Wie wäre es, den Namen des Fensters zu WindowMain1 oder etwas zu ändern und den Besitzer darauf einzustellen?

+0

"Name 'WindowMain1' ist nicht deklariert." –

+0

Ah, ich sehe, die Frage nicht sorgfältig genug gelesen, Sie tun dies innerhalb der Benutzersteuerungsklasse statt der Hauptformklasse – Davy8

5

Aktualisierung zu versuchen und Greg aus den Kommentaren zu helfen. Der Befehl funktioniert im Hauptfenstermenü, der Schaltfläche im Benutzersteuerelement und dem Kontextmenü im Benutzersteuerelement.

Ich würde es mit Befehlen tun. So habe eine Klasse Commands.cs so etwas wie:

public static class Commands 
{ 
    public static RoutedUICommand TestShowDialogCommand = new RoutedUICommand("Test command", "TestShowDialog", typeof(Commands)); 
} 

registrieren diese in Ihrem Hauptfenster: (Sie brauchen nicht die canshow es standardmäßig true)

public Window1() 
    { 
     InitializeComponent(); 

     CommandManager.RegisterClassCommandBinding(typeof(System.Windows.Controls.Control), 
      new CommandBinding(Commands.TestShowDialogCommand, ShowDialogCommand, CanShowDialogCommand)); 
    } 

    private void ShowDialogCommand(object sender, ExecutedRoutedEventArgs e) 
    { 
     var box = new Window(); 
     box.Owner = this; 
     box.ShowDialog(); 

    } 

    private void CanShowDialogCommand(object sender, CanExecuteRoutedEventArgs e) 
    { 
     e.CanExecute = true; 
    } 

Das ist mein XAML für die Hauptfenster:

<Window x:Class="WpfApplication1.Window1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:WpfApplication1="clr-namespace:WpfApplication1" 
Title="Window1" Height="300" Width="322"> 
<Grid> 
    <StackPanel> 
     <Menu> 
      <MenuItem Header="Test"> 
       <MenuItem Header="ShowDialog" Command="{x:Static WpfApplication1:Commands.TestShowDialogCommand}"/> 
      </MenuItem> 
     </Menu> 
     <WpfApplication1:BazUserControl /> 
    </StackPanel> 
</Grid> 
</Window> 

Dies ist das xAML für meine Benutzersteuerung (Standard-Code hinter nur)

<UserControl x:Class="WpfApplication1.BazUserControl" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:WpfApplication1="clr-namespace:WpfApplication1" 
Height="300" Width="300"> 
<Grid> 
    <StackPanel> 
     <Button Command="{x:Static WpfApplication1:Commands.TestShowDialogCommand}" Content="ClickMe" ></Button> 
     <TextBox> 
      <TextBox.ContextMenu> 
       <ContextMenu> 
        <MenuItem Header="ShowDialog" Command="{x:Static WpfApplication1:Commands.TestShowDialogCommand}" /> 
       </ContextMenu> 
      </TextBox.ContextMenu> 
     </TextBox> 
    </StackPanel> 
</Grid> 
</UserControl> 

Sie könnten es ein wenig weiter und behandeln Sie den Befehl in einer Controller-Klasse statt und machen es ein bisschen mehr MVC.

+0

Wenn ich diese Technik verwenden, wird das CanExecute-Ereignis nicht für die Referenz von der aufgerufen Nutzerkontrolle. CanExecute scheint standardmäßig auf "false" zu setzen und deaktiviert das Element, auf dem der Befehl ausgeführt wird (in meinem Fall ein Kontextmenüelement). Ein MenuItem im übergeordneten Fenster hat keine Probleme und ist aktiviert. –

+0

Es hat etwas mit dem Befehl Routing zu tun. Mein UserControl erhält keinen Fokus, hat aber ein Kontextmenü. Wenn kein Element ausgewählt/fokussiert ist, wenn ich versuche, das Kontextmenü des Benutzersteuerelements anzuzeigen, wird das Befehlsereignis nicht weitergeleitet. –

+0

Wenn du mehr Informationen in einer Frage posten willst, werde ich sehen, ob ich dir helfen kann. Ich benutze Befehle in der ganzen WPF-App, die ich mache, und ich liebe sie im Moment wirklich. –

37

Um die Top-Level-Fenster erhalten Sie Ihre Steuerung in ist, vorausgesetzt, man ist:

(Window)PresentationSource.FromVisual(this).RootVisual 

das Hauptfenster zu gelangen:

Application.Current.MainWindow 
+2

Application.Current.MainWindow gab mir genau das, was ich brauchte. Ich muss auf die Steuerelemente im übergeordneten Fenster von einem unterordneten Fenster zugreifen, das mit ShowDialog() geöffnet wird. –

112

Try

.Owner = Window.GetWindow(this) 
+3

Funktioniert gut, danke. Und ist genau die Antwort auf diese Frage :-). –

8
MyWpfDialog dialog = new MyWpfDialog(); 

//remember, this is WinForms UserControl and its Handle property is 
//actually IntPtr containing Win32 HWND. 

new System.Windows.Interop.WindowInteropHelper(dialog).Owner = this.Handle; 

dialog.ShowDialog(); 
zu verwenden
+0

Vorsicht mit diesem. Ich hatte seltsame Probleme, wenn ich in 'VMWare Fusion' auf einem' Macintosh' lief - das Fenster erschien für eine Sekunde und verschwand dann. – itsho

+0

Heads-up: Wenn Sie ein anderes Fenster (Splash-Fenster, etc.) angezeigt haben - müssen Sie ** auch den 'Owner' dafür einstellen! sonst werden Sie einige seltsame Verhaltensweisen bekommen - Ihr Hauptfenster wird nicht 'OnActivated' Event bekommen/wird im Hintergrund bleiben/wird plötzlich verschwinden, etc. – itsho