Use GroupSizeReductionOrder in RibbonControlsLibrary with MVVM - wpf

I am using the RibbonControlsLibrary (.Net 4.0) for my ribbons. My implementation is completely realized using MVVM.
Now I like to use the benefit of the resizing feature. But I can't set the reduction order of the group boxes. This is because I have to define the names of the group boxes in a special order. I can't set the names of the group boxes, because I am using data templates.
I tried to bind the name of the ribbon group box user controls to a property on the datacontext, but as I supposed this doesn't work.
So, do I have any chance to set the ribbon group box user control names to a property of the data context?

Setting the RibbonGroups' names
There may be others solutions, mine is to implement a Behavior that sets the RibbonGroup's name in the OnAttached method.
public class RibbonGroupNameBehavior : Behavior<RibbonGroup>
{
protected override void OnAttached()
{
base.OnAttached();
GroupeCommandesViewModel groupeCommandesViewModel = this.AssociatedObject.DataContext as GroupeCommandesViewModel;
if (groupeCommandesViewModel != null)
{
this.AssociatedObject.Name = groupeCommandesViewModel.Nom;
}
}
}
You may want to add a try-catch block around the assignment...
Using the behavior
As you are using DataTemplates, I think you'll have to assign the behavior to the RibbonGroups with a Style.
I have been using this solution with success.
As you'll see, my behavior's code does not provide the required dependency property, you'll have to add it.
Here is my shortened Ribbon's style :
<r:Ribbon.Style>
<Style TargetType="{x:Type r:Ribbon}">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type r:RibbonTab}">
<Setter Property="ItemsSource" Value="{Binding ListeCommandes, Converter={StaticResource CommandesToGroupesConverter}}" />
<Setter Property="GroupSizeReductionOrder" Value="{Binding ListeCommandesOrdreRedimensionnement}" />
<Setter Property="ItemContainerStyleSelector">
<Setter.Value>
<ribbonVM:RibbonGroupStyleSelector>
<ribbonVM:RibbonGroupStyleSelector.GenericStyle>
<Style TargetType="{x:Type r:RibbonGroup}" BasedOn="{StaticResource RibbonGroupStyle}" />
</ribbonVM:RibbonGroupStyleSelector.GenericStyle>
</ribbonVM:RibbonGroupStyleSelector>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</r:Ribbon.Style>
And my RibbonGroup's style :
<Style x:Key="RibbonGroupStyle" TargetType="{x:Type r:RibbonGroup}" BasedOn="{StaticResource RibbonControlStyle}">
<Setter Property="Header" Value="{Binding Libellé}" />
<Setter Property="ItemsSource" Value="{Binding Commandes}" />
<Setter Property="CanAddToQuickAccessToolBarDirectly" Value="False" />
<Setter Property="ihm_behaviors:RibbonGroupNameBehavior.IsEnabled" Value="True" />
</Style>
Databinding the GroupSizeReductionOrder property
If you look at the definition of the GroupSizeReductionOrder property, you'll see it's a StringCollection with a TypeConverter StringCollectionConverter.
From what I have seen, this converter only converts from string to StringCollection.
So your property shoud be either a string or a StringCollection.

Related

MenuItem.Icon appears only on the last item

I have a Menu with the following style on the items:
<Style TargetType="MenuItem">
<Setter Property="Template" Value="{StaticResource MenuItem}"/>
<Setter Property="Icon">
<Setter.Value>
<TextBlock FontWeight="Bold">Ic</TextBlock>
</Setter.Value>
</Setter>
<Setter Property="Header" Value="{Binding Name}"/>
<Setter Property="ItemsSource" Value="{Binding SubItems}"/>
</Style>
(Name, and SubItems are properties of the class MenuItem.
the ItemsSource property of the menu is bound to an object of type List<MenuItem> )
problem is the "Icon" part appears only on the last item of the menu:
Furthermore, if I click to expand the "Playlist" Item here's what happens:
I ultimately want to bind each Item to its own Icon, but that doesn't seem to work either.
Any ideas what causes this misbehavior and how to fix it?
update I've seen this: MenuItem style with icon creates only one icon
but it didn't work for me because a. x:Shared=false made a XamlParseException and b. if I moved it out of the Style.Resources it didn't make an exception but simply didn't work. Note that I do need this INSIDE the Style because ultimately I want it to be bound to a property of the class I'm binding the MenuItem to.
Don't Share the TextBlock
<TextBlock x:Key="tb" x:Shared="false" FontWeight="Bold">Ic</TextBlock>
<Style TargetType="{x:Type MenuItem}">
...
<Setter Property="Icon" Value="{StaticResource tb}"/>
</Style>

Problems with WPF ToolTipService properties (BetweenShowDelay, etc.) in Microsoft.Windows.Controls.Ribbon control

I have an very, very huge application in WPF with a Ribbon in it. The ribbon contain a bunch of RibbonControls, each binded to a different command. On every control, we put a ToolTip. We overrided these ToolTip templates to use a control of our own, which gives more information. We could call il a superToolTip.
The override of the tooltip templates is working just fine. Now we want to unify the way the tooltips are showing. What I mean is we want the same initialShowDelay, ShowDuration, etc., for every single tooltips in the application (there are tooltips elsewhere than in the ribbon, which use the same home made control that the ones of the ribbon). So, I binded the ToolTipService.InitialShowDelay, ToolTipService.BetweenShowDelay, ToolTipService.ShowDuration properties to global constants in the application.
InitialShowDelay :
The property InitialShowDelay is working just fine for almost every control in the application... The only one not working is RibbonSplitButton, which keep the default value of 400...
BetweenShowDelay :
The property BetweenShowDelay is working just fine when the tooltip is on a ListBoxItem... but not working in the Ribbon nor in a complex control of our own (a Property Grid).
These properties are set in the control on which the tooltip is set, and not on the tooltip themselves.
I honestly have absolutely no idead why it is behaving this way... Anyone has any idea on what could cause this or how to solve it?
If you need more information, do not hesitate to ask, i really am desperate about this.
Thank you very much!
The problem was that the condition for BetweenShowDelay wasn't respected, you need to have a value set for the property "ToolTip", in this case you were using a template, so the value was at null. You can resolve it this way :
<Style x:Key="{x:Type ToolTip}" TargetType="ToolTip">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Utils:ToolTipControl DataContext="{Binding ToolTipInfo}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and then place the dummy in the specified button :
<!-- RibbonButton -->
<Style TargetType="{x:Type ribbon:RibbonButton}" BasedOn="{StaticResource RibbonControlStyle}" >
<Style.Triggers>
<DataTrigger Value="true" >
<DataTrigger.Binding>
<Binding Converter="{StaticResource IsBoundConverter}" />
</DataTrigger.Binding>
<Setter Property="Command" Value="{Binding}" />
<Setter Property="ribbon:RibbonControlService.Label" Value="{Binding Name}" />
<Setter Property="ribbon:RibbonControlService.SmallImageSource" Value="{Binding Icon}" />
<Setter Property="ribbon:RibbonControlService.LargeImageSource" Value="{Binding LargeIcon}" />
<Setter Property="Visibility" Value="{Binding Visibility}" />
<Setter Property="ToolTip" Value="dummy"/> <!-- Use dummy value to force tooltip to show and to Bind the tooltip-->
</DataTrigger>
<DataTrigger Value="false" >
<DataTrigger.Binding>
<Binding Converter="{StaticResource IsBoundConverter}" />
</DataTrigger.Binding>
<Setter Property="Background" Value="#FF900000" />
</DataTrigger>
</Style.Triggers>
</Style>
That way the dummy value will be override.
:D
Here is some code showing how I implemented my ToolTips
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ribbon="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
...>
...
<!-- Ribbon Tooltips Style -->
<Style TargetType="ribbon:RibbonToolTip">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Utils:ToolTipControl DataContext="{Binding ToolTipInfo}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
...
<!-- RibbonControl -->
<Style x:Key="RibbonControlStyle">
<Setter Property="ribbon:RibbonControlService.ToolTipTitle" Value="dummy" /><!-- Use dummy value to force tooltip to show -->
<Setter Property="ToolTipService.InitialShowDelay" Value="{x:Static Utils:ToolTipViewModel.ToolTipInitialDelay}"/>
<Setter Property="ToolTipService.ShowDuration" Value="{x:Static Utils:ToolTipViewModel.ToolTipShowDuration}"/>
<Setter Property="ToolTipService.BetweenShowDelay" Value="{x:Static Utils:ToolTipViewModel.ToolTipBetweenShowDelay}"/>
<!-- This style is used to select the "Editors" tab when opening Editor without a world, and to select the "Home" tab otherwise -->
<Style.Triggers>
<DataTrigger Binding="{Binding IsWorldLoaded, Source={x:Static ViewModels:ViewportSettingsViewModel.Instance}}" Value="false">
<Setter Property="ribbon:Ribbon.SelectedIndex" Value="2"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsWorldLoaded, Source={x:Static ViewModels:ViewportSettingsViewModel.Instance}}" Value="true">
<Setter Property="ribbon:Ribbon.SelectedIndex" Value="0"/>
</DataTrigger>
</Style.Triggers>
</Style>
Also, for the splitbutton problem it was that the tooltipservice werent set for the child of the splitbutton ( the two parts) wich are named PART_HeaderButton and PART_ToggleButton. So even if you create your own style it will be override by the style of the ribbonsplit button ( see this link for the splitbutton.xaml file :
https://wpfcontrolextension.svn.codeplex.com/svn/trunk/Common/RibbonControlsLibrary/v3.5/Themes/Generic.xaml
So to bypass this overriding problem ( because we don't have access to the part directly we have to go via code. Im my case, I overrided the RibbonSplitButton class and the OnLoadTemplate method. That way with getchild we can access the property of the part and change them.
public partial class DuniaRibbonSplitButton : RibbonSplitButton
{
public DuniaRibbonSplitButton()
{
InitializeComponent();
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var HeaderButton = base.GetTemplateChild("PART_HeaderButton");
var ToggleButton = base.GetTemplateChild("PART_ToggleButton");
OverrideAttributes(HeaderButton as Control);
OverrideAttributes(ToggleButton as Control);
}
private void OverrideAttributes(Control control)
{
control.ToolTip = "Dummy";
ToolTipService.SetInitialShowDelay(control, ToolTipViewModel.ToolTipInitialDelay);
ToolTipService.SetShowDuration(control, ToolTipViewModel.ToolTipShowDuration);
ToolTipService.SetBetweenShowDelay(control, ToolTipViewModel.ToolTipBetweenShowDelay);
}
}

XAML - Automation ID for ComboBox elements in DataGridComboBoxColumn

To start off, the method that I'm using for automating individual elements of ComboBox is as follows:
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="AutomationProperties.AutomationId"
Value="{Binding ProviderName}" />
</Style>
</ComboBox.ItemContainerStyle>
ProviderName is bound to the ComboBox's DisplayMemberPath property.
My problem is that ItemContainerStyle does not seem to be available when trying to modify DataGridComboBoxColumn so that the elements of the combo box contained within also have automation IDs.
Has anyone come across a method for doing so?
I'm still toying around with different ideas, so if I come across any meaningful results I'll post them. Thanks in advance.
After some experimenting, I managed to get it to work by setting the EditingElementStyle.
Here's the XAML:
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ComboBoxItem">
<Setter Property="AutomationProperties.AutomationId"
Value="{Binding ProviderName}" />
</Style>
</Setter.Value>
</Setter>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>

Resource Dictionary WPF

I have a resource dictionary in my WPF application which contains the style information for the various controls.
Can it be used like the way we use in CSS in HTML? For example
p
{
margin:20px;
font:Tahoma;
}
this applies to all "p" tags in HTML. We dont have to specifically mention that in the HTML for "p" tag.
Is the same approach applicable in WPF, or do we have to specifically
mention the style
<TextBlock Text="Test" Style="{DynamicResource SomeTextblockStyle}" />
in the XAML
You can certainly set a default style for each type. You can do this within your Generic.xaml, note that I am not providing a key.
<Style TargetType="{x:Type Button}">
<Setter Property="Height" Value="25"/>
<Setter Property="Foreground" Value="White"/>
</Style>
This will style every instance of a Button within your application as such.
If you were go to a XAML file and define an instance of a Button, overriding the Foreground value, that local instance will take precedence over the global style.
<Button Foreground="Black"/>
You can set style like using key
<Style TargetType="{x:Type TextBlock}" x:Key="myStyle">
<Setter Property="Margin" Value="20"/>
<Setter Property="FontFamily" Value="Tahoma"/>
</Style>
And in the Window.Xaml
<TextBlock Text="Hello" Style="{DynamicResource myStyle}"/>

Can you define multiple TargetTypes for one XAML style?

In HTML/CSS you can define a style which can be applied to many types of elements, e.g.:
.highlight {
color:red;
}
can be applied to both P and DIV, e.g.:
<p class="highlight">this will be highlighted</p>
<div class="highlight">this will also be highlighted</div>
but in XAML you seem to have to define the TargetType for styles, otherwise you get an error:
<Style x:Key="formRowLabel" TargetType="TextBlock">
is there a way to allow a XAML style to be applied to multiple elements or even to leave it open as in CSS?
The setters in WPF styles are checked during compile time; CSS styles are applied dynamically.
You have to specify a type so that WPF can resolve the properties in the setters to the dependency properties of that type.
You can set the target type to base classes that contain the properties you want and then apply that style to derived classes. For example, you could create a style for Control objects and then apply it to multiple types of controls (Button, TextBox, CheckBox, etc)
<Style x:Key="Highlight" TargetType="{x:Type Control}">
<Setter Property="Foreground" Value="Red"/>
</Style>
...
<Button Style="{StaticResource Highlight}" Content="Test"/>
<TextBox Style="{StaticResource Highlight}" Text="Test"/>
<CheckBox Style="{StaticResource Highlight}" Content="Test"/>
<!-- Header text style -->
<Style x:Key="headerTextStyle">
<Setter Property="Label.VerticalAlignment" Value="Center"></Setter>
<Setter Property="Label.FontFamily" Value="Trebuchet MS"></Setter>
<Setter Property="Label.FontWeight" Value="Bold"></Setter>
<Setter Property="Label.FontSize" Value="18"></Setter>
<Setter Property="Label.Foreground" Value="#0066cc"></Setter>
</Style>
<!-- Label style -->
<Style x:Key="labelStyle" TargetType="{x:Type Label}">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Margin" Value="0,0,0,5" />
</Style>
I think both of these methods of declaring a style might answer your question.
In the first one, there is no TargetType specified, but the property names are prefixed with 'Label'. In the second one, the style is created for Label objects.
Another method to do it is:
<UserControl.Resources>
<Style x:Key="commonStyle" TargetType="Control">
<Setter Property="FontSize" Value="24"/>
</Style>
<Style BasedOn="{StaticResource commonStyle}" TargetType="ListBox"/>
<Style BasedOn="{StaticResource commonStyle}" TargetType="ComboBox"/>
</UserControl.Resources>
I wanted to apply a style to a Textblock and a TextBox but the selected answer didn't work for me because Textblock doesn't inherit from Control, in my case I wanted to affect the Visibility property, so I used FrameworkElement
<Style x:Key="ShowIfRequiredStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ShowIfRequiredStyle, UpdateSourceTrigger=PropertyChanged}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
<TextBlock Style="{StaticResource ResourceKey=ShowIfRequiredStyle}"/>
<TextBox Style="{StaticResource ResourceKey=ShowIfRequiredStyle}"/>
This works for the Visibility property because both items inherit from Frameworkelement and the property is defined there. Of course this will not work for properties defined only in Control, you can search the hierarchy tree and try to find a base class, anyway I thought this could help someone since this is a top search result and the selected answer is a little incomplete.
There is an alternative answer to the question. You CAN leave the TargetType parameter off the style altogether which will allow it to apply to various different controls, but only if you prefix the property name with "Control."
<Style x:Key="Highlight">
<Setter Property="Control.Foreground" Value="Red"/>
</Style>
Obviously, this only works for properties of the base control class. If you tried to set ItemsSource say, it would fail because there is no Control.ItemsSource
I got this working
<Style x:Key="HeaderStyleThin" TargetType="{x:Type Border}">
<Setter Property="Background" Value="Black" />
<Style.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background=" Value="Red" />
</Style>
</Style.Resources>
</Style>

Resources