2017-04-11 2 views
0

Ich habe eine WPF-Anwendung mit einem TabControl und mehreren TabItems, die jeweils ein UserControl enthalten. Benutzer können Einträge in der Benutzersteuerung ändern, die in dem TabItem enthalten ist, beispielsweise die Anwendung konfigurieren.Ereignis vor Benutzerwechsel TabItem

Ich habe eine Funktion, die prüft, ob es nicht gespeicherte Änderungen in der UserControl gibt. Vor der Benutzer ändert die Registerkarte oder schließt die Anwendung, ich möchte ihm die Möglichkeit geben, entweder zu speichern, verwerfen oder auf der Registerkarte bleiben.

Ist das möglich und wenn ja, wie? Wenn es einige andere Steuerelemente/Strukturen als die TabControl benötigt, die auch funktionieren wouls, weil ich zur Zeit in der Planungsphase bin ...

Vielen Dank im Voraus,
Frank

Antwort

0

Sie können mit Interaktivität mit jedem event.This ist MVVM-Lösung.

<TabControl> 
    <TabItem Header="Configuration"> 
    <views:ConfigurationView x:Name="ConfigurationView_Object" /> 
    <intr:Interaction.Triggers> 
     <intr:EventTrigger EventName="MouseUp"> 
       <intr:InvokeCommandAction Command="{Binding Yourcommand}" CommandParameter="YourCommandParameter"/> 
       </intr:EventTrigger> 
     </intr:Interaction.Triggers> 

+0

xmlns: intr = "clr-namespace: System.Windows.Interactivity; Montage = System.Windows.Interactivity" – leapold

+0

interessante Möglichkeit. Ich bin mir nicht sicher, ob das mouseup-Ereignis ausreichen würde, um alle möglichen Arten des Änderns des Tabs abzudecken, und dann müsste ich noch verhindern, dass sich der Tab ändert ... – Aaginor

0

Wenn Sie es über Ereignisse tun möchten, können Sie Selection Ereignis für die TabControl und der Abschlussveranstaltung für das Fenster verwenden. Etwas wie folgt aus:

XAML:

<Window x:Class="Namespace.View" 
     ..... 
     Closing="Window_Closing"> 
...... 

C#:

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) 
{ 
    if (UnsavedChanges()) 
    { 
     //save changes    
    }   
} 

XAML:

<TabControl SelectionChanged="TabControl_SelectionChanged"> 
    <TabItem Header="Configuration"> 
    <views:ConfigurationView x:Name="ConfigurationView_Object" /> 
</TabItem> 
<TabItem Header="Artist"> 
    ... 
</TabItem> 
</TabControl> 

C#:

private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    if (UnsavedChanges()) 
    { 
     //save changes 
    } 
} 
+0

Danke für Ihre Antwort! Der Punkt ist, dass ich dem Benutzer auch ermöglichen möchte, die Änderung abzubrechen, indem er auf dem ausgewählten Tab bleibt. Von was ich auf Stackoverflow darüber gelesen habe (http://stackoverflow.com/questions/30706758/how-to-cancel-tab-change-in-wpf-tabcontrol) scheint das ziemlich kompliziert zu sein ... – Aaginor

0

Das TabControl hat kein TabChanging-Ereignis. Sie können jedoch das Ereignis .Items.CurrentChanging verwenden. Dies funktioniert nur, wenn Sie setzen IsSynchronizedWithCurrentItem="True" auf dem TabControl

XAML **

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height='1*' /> 
     <RowDefinition Height='Auto' /> 
    </Grid.RowDefinitions> 
    <TabControl x:Name='MainTab' 
       IsSynchronizedWithCurrentItem='True' 
       Grid.Row='0'> 
     <TabItem x:Name='TabTickets' 
       Header='Tickets'> 

      <StackPanel Orientation='Horizontal' > 
      <TextBlock Text='Provide some text:' 
         Margin='10,0' /> 
      <TextBox x:Name='ExampleTextBox' 
        VerticalAlignment='Top' MinWidth='90' /> 
      </StackPanel> 

     </TabItem> 
     <TabItem x:Name='TabCalendar' 
       Header='Calendar' /> 
     <TabItem x:Name='TabAbout' 
       Header='About' /> 
    </TabControl> 

    <TextBlock x:Name='MessageTextBox' 
       Grid.Row='1' /> 

    </Grid> 

-Code

public TabChangingWindow() { 
     InitializeComponent(); 

     MainTab.Items.CurrentChanging += Items_CurrentChanging; 
    } 

    void Items_CurrentChanging(object sender, 
           System.ComponentModel.CurrentChangingEventArgs e) { 
     if (e.IsCancelable) 
     { 
     var fromElement = ((ICollectionView)sender).CurrentItem as FrameworkElement; 
     var toElement = MainTab.SelectedItem as FrameworkElement; 
     if (fromElement!= null && toElement!= null) 
     { 
      if (ExampleTextBox.Text.Length == 0) 
      { 
      e.Cancel = true; 
      MessageTextBox.Text = "Example Text cannot be blank."; 
      MainTab.SelectedItem = fromElement; 
      } 
      else 
      { 
      MessageTextBox.Text = 
      String.Format("Changing from {0} to {1}", fromElement.Name, toElement.Name); 
      } 

     } 

     } 

    } 

Screenshots

Prevent move to another tab

Das Verschieben auf eine andere Registerkarte verhindern, wenn die Daten unvollständig sind.


Allow move to another tab

Umzug in ein anderes Register zulassen, wenn die Daten vollständig sind.

+0

Danke für die Antworten! Das Problem ist, dass diese Lösung funktioniert, solange während der Änderung keine Benutzerinteraktion stattfindet. (siehe http://stackoverflow.com/questions/30706758/how-to-cancel-tab-change-in-wpf-tabcontrol) Aber ich wollte den Benutzer fragen, was er machen will (speichern/diktieren/bleiben)) – Aaginor

+0

Haben Sie den Code versucht? Der Benutzer kann nicht mit anderen Teilen der Benutzeroberfläche interagieren, sie werden zurück an die ursprüngliche Registerkarte gesendet. Wenn das nicht genug ist, können Sie eine Message-Box verwenden, um den Benutzer aufzufordern, und Sie können Schaltflächen im Dialogfeld haben, um Informationen vom Benutzer abzurufen. Es ist modal, der Benutzer wird nicht in der Lage sein, mit der App zu interagieren, bis die Nachricht gelöscht wird. –

+0

Wie man einen Dialog zum Benutzer anzeigt und Resultate erhält, ist eine andere Frage von der, die du fragst. Siehe http://stackoverflow.com/questions/3830228/is-there-a-messagebox-equivalent-in-wpf –

0

Ich resoliere schließlich, um eine einfache tabcontrol selbst zu implementieren, weil ich dann Kontrolle über alles habe.

<WrapPanel x:Name="WrapPanel_Main"> <!-- This is the TabControl --> 
    <Border x:Name="Border_Configuration" Margin="5,5,0,0" BorderThickness="4,4,4,0"> <!-- This is the first tab --> 
    <TextBlock x:Name="TextBlock_Configuration" Text="Configuration" Padding="5" MouseLeftButtonUp="TextBlock_Step_MouseLeftButtonUp"/> 
    </Border> 
    <Border Margin="5,5,0,0" BorderThickness="4,4,4,0"> <!-- This is the second tab --> 
    <TextBlock x:Name="TextBlock_Artists" Text="Artists" Padding="5" MouseLeftButtonUp="TextBlock_Step_MouseLeftButtonUp" /> 
    </Border> 
    <Border Margin="5,5,0,0" BorderThickness="4,4,4,0"> <!-- This is the third tab --> 
    <TextBlock x:Name="TextBlock_ReleaseGroups" Text="Release Groups" Padding="5" MouseLeftButtonUp="TextBlock_Step_MouseLeftButtonUp"/> 
    </Border> 
</WrapPanel> 

<Border x:Name="Border_Placeholder" Grid.Row="1" Margin="5,0,5,5"> <!-- placeholder for the content of each tab --> 
    <ContentControl x:Name="ContentControl_Placeholder" Grid.Row="1" Padding="5" /> 
</Border> 

Und hier die Behandlungsroutine, die Pflege der Maus-Up-Ereignis der "Tabs" nimmt. Ich habe eine Schnittstelle erstellt, jede Benutzersteuerung, die als Inhalt für die Registerkarte verwendet wird, muss implementiert werden. Auf diese Weise kann das Benutzersteuerelement die "Registerkartensteuerung" über nicht gespeicherte Änderungen informieren und entsprechende (vom Benutzer gewählte) Maßnahmen ergreifen. Danach lädt es den neuen Inhalt und ändert das Aussehen der "Tab-Header". Die Menge an mehr Code, die dies verursacht, ist meiner Meinung nach akzeptabel für die volle Kontrolle über Tab-Änderungen.

private void TextBlock_Step_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
{ 
    ICancelUnloading currentElement = ContentControl_Placeholder.Content as ICancelUnloading; 
    if (currentElement != null) 
    { 
    if (currentElement.UnsavedChanges) 
    { 
     MessageBoxResult result = MessageBox.Show("Yes: Save, No: Discard, Cancel: Stay", "Unsaved Changes", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel); 
     if (result == MessageBoxResult.Cancel) 
     return; 
     if (result == MessageBoxResult.Yes) 
     currentElement.Save(); 
    } 
    } 

    TextBlock textBlock = sender as TextBlock; 
    if (textBlock != null) 
    { 
    switch (textBlock.Name) 
    { 
     case "TextBlock_Configuration": 
     ContentControl_Placeholder.Content = new ConfigurationView(); 
     break; 
     case "TextBlock_Artists": 
     ContentControl_Placeholder.Content = new ArtistsView(); 
     break; 
     case "TextBlock_ReleaseGroups": 
     ContentControl_Placeholder.Content = new ReleaseGroupsView(); 
     break; 
    } 

    ActivateTab(textBlock); 
    } 
}