Adding Unselectable controls to RibbonMenuButton - wpf

I am working on a WPF project and I started developing the Ribbon area. I just put a RibbonMenuButton and added three RibbonTextBox inside of it. I want these TextBoxes to retrieve some data from the user. Everything is fine so far.
<rb:RibbonMenuButton LargeImageSource="/image.png" Label="Settings" >
<rb:RibbonTextBox Label="Field 01:" Text="{Binding Field01 }" />
<rb:RibbonTextBox Label="Field 02:" Text="{Binding Field02 }" />
<rb:RibbonTextBox Label="Field 03:" Text="{Binding Field03 }" />
</rb:RibbonMenuButton>
My problem is that the RibbonTextBox becomes a menu item, i.e. I can click it and select it.
But I want to avoid this behavior, I just want to have an "unselectable" RibbonTextBox.
Is there a way to achieve that?
Thank you in advance.

I found the solution here:
<Style TargetType="{x:Type rb:RibbonMenuItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type rb:RibbonMenuItem}">
<ContentPresenter ContentTemplate="{TemplateBinding HeaderTemplate}"
Content="{TemplateBinding Header}" Grid.Column="1"
ContentStringFormat="{TemplateBinding HeaderStringFormat}"
ContentSource="Header"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
VerticalAlignment="Center"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This works pretty well for me.

Those are typically called Labels. But in lieu of using the appropriate control, the RibbonTextBox has both a IsReadOnly propery, which will leave it selectable (ie. for copy/paste) but not editable. Or IsEnabled which will make it completely non-interactive.
I think the IsEnabled will also prevent you from being able to click on it at all, but I'm not 100% sure on that.

Related

ContentPresenter loosing it data binding after triggers invoked more than twice

I have created an extended button with 2 different border styles invoked by triggers in XAML. Both share the same contentpesenter but after changing the border style more than twice the content in the contentpresenter fails to display.
Below is a link to the entire project with a test bed application that demonstrates the issue, I think the issue is somewhere in the XAML below but I cannot see why it breaks:
Sample Button App
<Style.Resources>
<ContentPresenter x:Key="ButtonContent" Margin="5" HorizontalAlignment="Center"
Content="{Binding Content}"/>
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Margin="{Binding KeyMargin}">
<Grid Visibility="{Binding RectangleVisibility}">
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=rectBorder}" />
</Grid.OpacityMask>
<Border x:Name="rectBorder"
CornerRadius="{Binding BorderCorners}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="{Binding BorderThickness}"/>
<Viewbox Stretch="Fill"
StretchDirection="Both">
<ContentControl Content="{StaticResource ButtonContent}"/>
</Viewbox>
</Grid>
<Grid Visibility="{Binding EllipseVisibility}">
<Ellipse Stroke="{TemplateBinding BorderBrush}"
StrokeThickness="{Binding BorderThickness}"
Fill="{TemplateBinding Background}">
</Ellipse>
<Viewbox Stretch="Fill"
StretchDirection="Both">
<ContentControl Content="{StaticResource ButtonContent}"/>
</Viewbox>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
The problem is most likely that you cannot have the same element (the ContentPresenter in this case) in more than one place in the visual tree, and in which one of the two grids it ends up is undefined, i.e., an implementation archetype of WPF.
To get the element duplicated this might work:
<ContentControl Content="{TemplateBinding Content}"/>
or in your case
<ContentControl Content="{TemplateBinding Content}" Margin="5" HorizontalAlignment="Center"/>
instead of a static resource. The <ContentPresenter/> syntax is pretty much an optimized shortcut for that (or you could set x:Shared="False" on the resource, but having a ContentPresenter as a static resource is as far as I know not how it is intended to be used)
If the Button content is a UIElement itself though, it will be used directly itself in the visual tree, i.e., twice and this wont work either. A better solution would be to just have the content once in the control template and change the visual appearance around it, e.g., using a trigger to set the Grid's OpacityMask.
Another remark is that your control template is very tightly bound to where the Button is used, with direct bindings to the current data context, which reduces its reusability. Some easy fixes is to use TemplateBinding instead of Binding for BorderThickness respectively Margin (instead of KeyMargin), since those are existing properties of the Button.
For better reusability and cleaner code you should consider looking into creating a custom control deriving from Button with dependency properties for BorderCorners, the desired visual state (ellipse vs rectangle) etc. You might also want to use triggers to get the mouse-over effects of the button etc. Have fun control templating!

Embedding content within a UserControl instance

I have a WPF UserControl, which is simply a Label for whatever else it goes with. E.g, a Label for a TextBox. I want to place this TextBox inside the LabeledControl markup, like this:
<LabeledControl Label="First name">
<TextBox Binding="{FirstName}" />
</LabeledControl>
The reason I want to do this is to style the way controls and their labels look.
I can't find an obvious way to do this. Am I even approaching this the right way? Should I be looking at templates instead?
I'd say that a better option would be to use the built-in HeaderedContentControl, which allows you to specify a Header (your label) and a Content (your text box) property.
You can then specify a ControlTemplate for the HeaderedContentControl to alter the appearance:
<Style x:Key="MyLabelledItemStyle" TargetType="HeaderedContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="HeaderedContentControl">
<StackPanel Orientation="Horizontal">
<ContentControl Content="{TemplateBinding Header}" Margin="2" />
<ContentControl Content="{TemplateBinding Content}" Margin="2" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This example just concatenates the two components horizontally in a StackPanel, but you could do something more complicated if required.
You can then use this in XAML as below:
<HeaderedContentControl Style="{StaticResource MyLabelledItemStyle}" Header="First Name">
<TextBox Text="{Binding FirstName}" />
</HeaderedContentControl>

WPF Changing text in a controltemplate at run time

I am making a template control so that I can have a button with an image that changes when you click it. I also am trying to get text on top of the button that can change at run time. I have the button images and everything working but I can't seem to get that label at runtime so I can change the text. Here is the code in the xaml. I am missing the code behind
<UserControl.Resources>
<ControlTemplate TargetType="{x:Type Button}" x:Key="ActionButton">
<Grid>
<Label Panel.ZIndex="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Arial" Name="lblText" Foreground="#5E4421" FontWeight="Bold" FontSize="14">Test</Label>
<Image Name="Normal" Source="/AssaultWare.Controls;component/Replayer/Images/button_off.png"/>
<Image Name="Pressed" Source="/AssaultWare.Controls;component/Replayer/Images/button_on.png"/>
<Image Name="Disabled" Source="/AssaultWare.Controls;component/Replayer/Images/button_off.png" Visibility="Hidden"/>
</Grid>
<ControlTemplate.Triggers>
...
</ControlTemplate.Triggers>
</ControlTemplate>
</UserControl.Resources>
<Button Canvas.Left="471" Canvas.Top="465" Template="{StaticResource ActionButton}" Name="btnRight"/>
Difficult to decipher your question, but I think you just need to change the Label to a ContentControl and bind its Content property to the Button's Content property:
<ContentControl Content="{TemplateBinding Content}" .../>

How to make a plain text-only Silverlight button?

I simply want a button with no background or anything other than plain text. I have done the following and the button does not show up at all:
<UserControl.Resources>
<ControlTemplate x:Key="linkButtons" TargetType="Button">
<TextBlock Foreground="White" FontSize="28" FontFamily="Verdana" Padding="10"></TextBlock>
</ControlTemplate>
</UserControl.Resources>
<Button Template="{StaticResource linkButtons}" Content="Hello World!"/>
This is because the TextBlock inside the Control template does not have a template binding. Make an attribute like this:
<TextBlock Foreground="White" FontSize="28" FontFamily="Verdana" Padding="10" Text="{TemplateBinding Content}" />
Not sure if thats the correct syntax, but thats the concept.
The problem is that a button is designed to have content, not text - it's a kind of ContentControl. So, to display the content, your template should have this in it:
<ContentPresenter x:Name="contentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"/>
OR, you could make a custom control based on button, add a Text property to it, use your current TextBlock control in the template (but with Text="{Binding Text}") and leave the ContentPresenter out of your template. Making a custom control is a little trickier than just making a template for an existing one, but it's really the best way to get exactly what you're going for.

WPF tab control spacing between headers

The default behavior of the WPF Tabcontrol is to place the Tab Headers adjacent to each other, without any empty space in between. What if I wanted to specify a gap between the headers? Do I have to define a control template for this? I'm relatively new to WFP and any help is appreciated.
Thanks
I believe you will need to define a custom control template for the TabItem, maybe even one for the TabControl. Here is an example of a TabItem that uses a spacer for some separation.
<Style
x:Key="SpacedTab"
TargetType="{x:Type TabItem}">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type TabItem}">
<Border
x:Name="Spacer"
Width="Auto"
Height="Auto"
Padding="0 0 5 0"
Margin="0 0 0 0"
BorderBrush="Transparent"
BorderThickness="0">
<Border
x:Name="Border"
MinWidth="150"
Width="Auto"
Height="30"
Background="Gray"
BorderBrush="DarkGray"
BorderThickness="0,0,0,0"
CornerRadius="6,6,0,0"
Cursor="Hand"
VerticalAlignment="Bottom">
<ContentPresenter
x:Name="ContentSite"
TextElement.FontSize="10pt"
TextElement.FontFamily="Arial"
TextElement.Foreground="Black"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="8,3,8,3"
Width="Auto"
Height="Auto" />
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Hopefully that is a nudge in the right direction; you will still need to add that as a style resource and reference it from your TabControl -> TabItem.
It is easy to add space by doing it in the designer. Select the Tab you want to move, by starting with the rightmost tab. Then hold ctrl and use the right arrow key to move the tab to the right. Do the same with the rest of the tabs. Then you can manually adjust the margin in the xaml code.

Resources