2016-09-22 5 views
0

Je développe une application WPF en utilisant des contrôles DevExpress, tels que le contrôle du ruban. Je veux pouvoir placer des boutons sur le ruban dynamiquement. Je voudrais être en mesure de prendre en charge les boutons réguliers et les boutons déroulants.BarButtonItems et BarSubItems sur Bound RibbonControl

Je pensais quelque chose de similaire à ci-dessous.

WPF Vue:

<UserControl.Resources> 
    <DataTemplate x:Key="RibbonCommandTemplate"> 
     <ContentControl> 
      <dxb:BarButtonItem RibbonStyle="All" Content="{Binding Caption}" 
           Command="{Binding (dxr:RibbonControl.Ribbon).DataContext.MenuExecuteCommand, 
             RelativeSource={RelativeSource Self}}" 
           CommandParameter="{Binding}" /> 
     </ContentControl> 
    </DataTemplate> 
</UserControl.Resources> 

<Grid> 
    <DockPanel> 
     <dxr:RibbonControl DockPanel.Dock="Top" RibbonStyle="Office2010"> 
      <dxr:RibbonDefaultPageCategory> 
       <dxr:RibbonPage Caption="Home"> 
        <dxr:RibbonPageGroup Caption="Dynamic Commands" 
             ItemLinksSource="{Binding DynamicCommands}" 
             ItemTemplate="{StaticResource RibbonCommandTemplate}" /> 
       </dxr:RibbonPage> 
      </dxr:RibbonDefaultPageCategory> 
     </dxr:RibbonControl> 
     <Grid/> 
    </DockPanel> 
</Grid> 

Voir Modèle:

public class RibbonCommand 
{ 
    public string Caption { get; set; } 
    public int CommandCode { get; set; } 

    public ObservableCollection<RibbonCommand> SubItems { get; set; } 

    public bool HasSubItems 
    { 
     get 
     { 
      if (SubItems != null) 
       return (SubItems.Count > 0); 
      else 
       return false; 
     } 
    } 
} 

[POCOViewModel] 
public class MainViewModel 
{ 
    public ObservableCollection<RibbonCommand> DynamicCommands { get; set; } 

    public MainViewModel() 
    { 
     DynamicCommands = new ObservableCollection<RibbonCommand>(); 

     // Regular buttons. 
     DynamicCommands.Add(new RibbonCommand() { Caption = "Button 1", CommandCode = 1 }); 
     DynamicCommands.Add(new RibbonCommand() { Caption = "Button 2", CommandCode = 2 }); 

     // Drop-down button. 
     RibbonCommand dropDownCommand = new RibbonCommand() { Caption = "Drop-Down", CommandCode = 3 }; 
     dropDownCommand.SubItems = new ObservableCollection<RibbonCommand>(); 
     dropDownCommand.SubItems.Add(new RibbonCommand() { Caption = "Sub-Item 1", CommandCode = 31 }); 
     dropDownCommand.SubItems.Add(new RibbonCommand() { Caption = "Sub-Item 2", CommandCode = 32 }); 
     dropDownCommand.SubItems.Add(new RibbonCommand() { Caption = "Sub-Item 3", CommandCode = 33 }); 
     DynamicCommands.Add(dropDownCommand); 
    } 

    public void MenuExecute(RibbonCommand command) 
    { 
     MessageBox.Show(string.Format("You clicked command with ID: {0} (\"{1}\").", 
         command.CommandCode, command.Caption), "Bound Ribbon Control"); 
    } 
} 

Ce code ne remplit avec succès le ruban avec des articles que j'ai ajouté dans ma collection de DynamicCommands, mais je voudrais soutenir des boutons déroulants pour les éléments avec n'importe quoi dans la collection SubItems (le troisième bouton de mon exemple ci-dessus).

Existe-t-il un moyen de modifier de manière conditionnelle le type de contrôle affiché dans un DataTemplate. Si HasSubItems de l'objet est true, j'aimerais qu'un objet BarSubItem soit placé sur le ruban. Si c'est faux, je garderai le BarButtonItem.

Répondre

0

Si cela est WPF régulière plutôt que UWP, et si les DataContexts de vos sous-éléments sont de différents types, vous pouvez définir plusieurs DataTemplates avec DataType attributs dans les ressources du RibbonPageGroup (où ils ne seront pas dans la portée de tout ce qui doesn « t besoin d'eux), et de se débarrasser de cet attribut ItemTemplate:

<dxr:RibbonPageGroup 
    Caption="Dynamic Commands" 
    ItemLinksSource="{Binding DynamicCommands}"> 
    <dxr:RibbonPageGroup.Resources> 
     <DataTemplate DataType="{x:Type local:RibbonCommand}"> 
      <!-- XAML stuff --> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type local:SpecialRibbonCommand}"> 
      <!-- Totally different XAML stuff --> 
     </DataTemplate> 
    </dxr:RibbonPageGroup.Resources> 

    <!-- etc --> 

pour une autre option, vous devriez être en mesure d'écrire un DataTemplateSelector et donner à la RibbonControl's ToolbarItemTemplateSelector property ou la propriété RibbonPageGroup's ItemTemplateSelector.

Enfin, écrivez un complexe DataTemplate avec plusieurs contrôles enfants superposés dans un Grid, et une série de déclencheurs qui ne montrent que celui approprié en fonction des propriétés du DataContext. Si vous n'avez que deux options différentes à gérer, cela peut être l'itinéraire le plus rapide et le plus facile.

<DataTemplate x:Key="RibbonCommandTemplate"> 
    <Grid> 
     <Label x:Name="OneThing" /> 
     <Label x:Name="AnotherThing" /> 
    </Grid> 
    <DataTemplate.Triggers> 
     <DataTrigger Binding="{Binding HasSubItems}" Value="True"> 
      <Setter TargetName="OneThing" Property="Visibility" Value="Collapsed" /> 
      <Setter TargetName="AnotherThing" Property="Visibility" Value="Visible" /> 
     </DataTrigger> 
     <!-- Other triggers for HasSubItems == False, whatever --> 
    </DataTemplate.Triggers> 
</DataTemplate> 

Cela semble assez brut, mais je l'ai fait tellement dans WPF que je suis en train de désensibilisés à elle.

0

J'ai trouvé un moyen de le faire en utilisant une classe DataTemplateSelector:

using System.Windows; 
using System.Windows.Controls; 
using RibbonDynamicButtons.ViewModels; 

namespace RibbonDynamicButtons.Selectors 
{ 
    public class RibbonCommandSelector : DataTemplateSelector 
    { 
     public DataTemplate CommandTemplate { get; set; } 
     public DataTemplate SubCommandTemplate { get; set; } 

     public override DataTemplate SelectTemplate(object item, DependencyObject container) 
     { 
      if(item is RibbonCommand) 
      { 
       RibbonCommand command = (RibbonCommand)item; 
       if (command.HasSubItems) 
        return SubCommandTemplate; 
       else 
        return CommandTemplate; 
      } 

      return base.SelectTemplate(item, container); 
     } 
    } 
} 

J'ai ajouté mon sélecteur au XAML comme suit:

<UserControl 
    ... 
    xmlns:Selectors="clr-namespace:RibbonDynamicButtons.Selectors"> 
    <UserControlResources> 
     <DataTemplate x:Key="RibbonSubItemTemplate"> 
      <ContentControl> 
       <dxb:BarButtonItem RibbonStyle="SmallWithText" Content="{Binding Caption}" 
        Command="{Binding (dxr:RibbonControl.Ribbon).DataContext.MenuExecuteCommand, 
         RelativeSource={RelativeSource Self}}" CommandParameter="{Binding}" /> 
      </ContentControl> 
     </DataTemplate> 

     <Selectors:RibbonCommandSelector x:Key="RibbonCommandSelector"> 
      <Selectors:RibbonCommandSelector.CommandTemplate> 
       <DataTemplate> 
        <ContentControl> 
         <dxb:BarButtonItem RibbonStyle="All" 
          Content="{Binding Caption}" 
          Command="{Binding (dxr:RibbonControl.Ribbon).DataContext.MenuExecuteCommand, 
           RelativeSource={RelativeSource Self}}" 
          CommandParameter="{Binding}" /> 
        </ContentControl> 
       </DataTemplate>  
      </Selectors:RibbonCommandSelector.CommandTemplate> 

      <Selectors:RibbonCommandSelector.SubCommandTemplate> 
       <DataTemplate> 
        <ContentControl> 
         <dxb:BarSubItem RibbonStyle="All" Content="{Binding Caption}" 
          ItemLinksSource="{Binding SubItems}" 
          ItemTemplate="{StaticResource RibbonSubItemTemplate}" /> 
        </ContentControl> 
       </DataTemplate> 
      </Selectors:RibbonCommandSelector.SubCommandTemplate> 
     </Selectors:RibbonCommandSelector> 
    </UserControlResources> 

Je lie la ItemTemplateSelector à mon sélecteur sur la RibbonPageGroup:

<dxr:RibbonPageGroup Caption="Dynamic Commands" ItemLinksSource="{Binding DynamicCommands}" 
        ItemTemplateSelector="{StaticResource RibbonCommandSelector}" /> 

Je n'ai pas eu besoin de modifier le modèle de vue I i ncluded sur ma question originale.