myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Gemeinschaft » .NET-Komponenten und C#-Snippets » WPF - Ribbon mit MVVM-Pattern nutzen
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

WPF - Ribbon mit MVVM-Pattern nutzen

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
trashkid2000 trashkid2000 ist männlich
myCSharp.de-Mitglied

Dabei seit: 27.12.2010
Beiträge: 156


trashkid2000 ist offline

WPF - Ribbon mit MVVM-Pattern nutzen

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hi,

ich dachte mir mal, ich poste mal ein Tutorial.
Und das für die Verwendung des WPF - Ribbon unter der Verwendung des MVVM-Pattern.

Vorwort: Es gibt von Microsoft ein paar Samples zu diesem Thema, eine Suche nach 'MicrosoftRibbonForWPFSourceAndSamples' findet diese.

Soweit so gut, aber dies ist nicht das, nach dem ich suchte...
In den Samples werden (umfangreiche) Objekte im ViewModel zusammengebaut. Aber MVVM-konform ist das nicht. Es ist so einfach nicht möglich, das ganze Konstrukt einfach umzubiegen...

Beruflich habe ich eine Umsetzung benötigt, in der wie gewöhnt, einfach ein ViewModel und das entsprechende DataTemplate definiert werden kann.

Also, nach ein paar fails hier eine Lösung des Ganzen.
Überschrieben wurde dabei die Definition, wie Das jeweilige ItemsControl seine Items erzeugt.

Bei dem Ribbon ist es das ControlTemplate, was bei der Erzeugung der Tabs überschrieben wurde.
Bei dem ApplicationMenu einfach der Container, der zur Anzeige eines Items erzeugt wird.

C#-Code:
public class CustomRibbon : Ribbon
{
   /// <summary>
   /// Bereitet den RibbonTab so vor, dass der Content auf das Item gesetzt wird und ein definiertes DataTemplate zur Anzeige genutzt wird
    /// </summary>
    /// <param name="element">Der Tab, der zur Anzeige vorbereitet werden soll</param>
    /// <param name="item">Objekt, das als Content gesetzt wird</param>
    protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        var tab = (RibbonTab)element;

        var controlTemplate = new ControlTemplate(typeof(RibbonTab));
        var contentControlFactory = new FrameworkElementFactory(typeof(ContentControl));
        contentControlFactory.SetBinding(ContentControl.ContentProperty, new Binding() { Source = item });

        contentControlFactory.SetBinding(VisibilityProperty, new Binding()
        {
            UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, Source = tab,
            Path = new PropertyPath(nameof(tab.IsSelected)), Converter = new BooleanToValueConverter() { FalseValue = Visibility.Collapsed, TrueValue = Visibility.Visible }
        });

        controlTemplate.VisualTree = contentControlFactory;
        contentControlFactory.SetValue(IsTabStopProperty, false);
        tab.Template = controlTemplate;

        tab.Header = item;
   }
}

C#-Code:
public class CustomRibbonApplicationMenu : RibbonApplicationMenu
{
   /// <summary>
   /// Erstellt einen neuen Container für einen Eintrag im Menü
   /// </summary>
    /// <returns>Den erstellten Container</returns>
   protected override DependencyObject GetContainerForItemOverride()
   {
      return new ContentControl() { IsTabStop = false };
   }

   /// <summary>
   /// Bereitet den Menüeintrag für die Anzeige vor
   /// </summary>
   /// <param name="element">Das <see cref="ContentControl"/>, das als Container genutzt wird</param>
   /// <param name="item">Der Content</param>
   protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
   {
       var contentControl = ((ContentControl)element);
       contentControl.Content = item;
    }

   /// <summary>
   /// Behebt das Verhalten, dass das Menü geschlossen wird, wenn ein Menuitem, das disabled ist, angeklickt wird.
   /// </summary>
   /// <param name="e">Die <see cref="MouseButtonEventArgs"/></param>
   protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
   {
      if (e.OriginalSource is ContentPresenter applicationMenuItemContentPresenter)
      {
         if (VisualTreeHelper.GetChild(applicationMenuItemContentPresenter, 0) is RibbonApplicationMenuItem applicationMenuItem)
         {
            if (!applicationMenuItem.IsEnabled)
            {
                e.Handled = true;
             }
          }
       }

       base.OnPreviewMouseLeftButtonUp(e);
   }

   /// <summary>
   /// Behebt das Verhalten, dass in dem Menü manchmal direkt das ContentControl des ContainerForItemOverride angesprungen wurden und das AppMenuItem dann nicht fokussiert wurde. Gerade bei Up und Down war das aufgefallen.
    /// </summary>
    /// <param name="e">Die <see cref="KeyboardFocusChangedEventArgs"/></param>
    protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
    {
        if (e.OriginalSource is ContentControl contentControl)
        {
            var applicationMenuItem = (UIElement)contentControl.FindVisualChildren<DependencyObject>().FirstOrDefault(x => x.GetType().GetProperty(nameof(QuickAccessToolBarId)) != null);
            if (applicationMenuItem != null)
            {
                applicationMenuItem.Focus();
             }
         }

         base.OnGotKeyboardFocus(e);
     }
}

Eingebunden wird dies dann wie folgt:

XML-Code:
<Controls:CustomRibbon ItemsSource="{Binding RibbonTabItems}">
   <Controls:CustomRibbon.ApplicationMenu>
      <Controls:CustomRibbonApplicationMenu ItemsSource="{Binding ApplicationMenuItems}" FooterPaneContent="{Binding CloseApplicationFooterPaneContent}" AuxiliaryPaneContent="{Binding AuxiliaryPaneContent}"/>
   </Controls:CustomRibbon.ApplicationMenu>
</Controls:CustomRibbon>

Ein Sample-Projekt kann unter
 https://drive.google.com/file/d/1d2OckuDTLwnZ86p50Keyh_67zz2eWwFC/view?usp=sharing
heruntergeladen werden.

Viel Spaß damit,
Marko
04.12.2019 22:18 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als ein Monat.
Der letzte Beitrag ist älter als ein Monat.
Antwort erstellen


© Copyright 2003-2020 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 28.01.2020 05:38