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>
Related
I have a 'feedback' button which has this strange border:
So I searched online for some solutions and modified the control template, and I got this:
Control Template code:
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter Content="{TemplateBinding Content}" />
</ControlTemplate>
</Button.Template>
So even after modifying the control template - I am getting a strange brown border. Help would be appreciated regarding this.
Button code:
<Button Grid.Row="3"
Grid.Column="2"
Grid.RowSpan="2"
Style="{StaticResource IconStyleBase}"
Name="Feedback_Button">
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter Content="{TemplateBinding Content}" />
</ControlTemplate>
</Button.Template>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="218*" />
<RowDefinition Height="68*" />
</Grid.RowDefinitions>
<!--Icon-->
<Button Background="#3767B0"
Style="{StaticResource IconStyleContent}">
<!--Content-->
<Button.ContentTemplate>
<DataTemplate>
<Viewbox>
<TextBlock Padding="55"></TextBlock>
</Viewbox>
</DataTemplate>
</Button.ContentTemplate>
</Button>
<!--Icon Text-->
<Button Background="#FF2D5BA0"
Style="{StaticResource IconStyleSubBase}">
<!--Content-->
<Button.ContentTemplate>
<DataTemplate>
<Viewbox>
<TextBlock Padding="15">Feedback</TextBlock>
</Viewbox>
</DataTemplate>
</Button.ContentTemplate>
</Button>
</Grid>
</Button>
A DataTemplate defines the appearance of the the items that you set as Content of a button, but the button itself as a container has a default style and control template that defines how it looks like, along with its different states like mouse-over or pressed. That is where the border comes from.
You can try to create a style that sets the BorderThickness to 0 and apply it on each of your buttons. This approach works for control templates that bind the border thickness from their templated parent.
<Style x:Key="BorderlessButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="BorderThickness" Value="0"/>
</Style>
If this does not work or you want adapt the appearance of your buttons in detail, you have to extract and adapt the button style and control template.
Your custom control template does not work, because you did not apply it to the inner buttons and you should remove Content="{TemplateBinding Content}". Nevertheless, your button control template does not define any control states, so it will not be responsive at all.
You should copy the control template for Button from here, or extract it manually via Blend or Visual Studio. Then you can remove or the Border within it, change its thickness or color, so it will disappear. Moreover, you can adapt its various states to fit your desired style.
A notice on your design. It do not think that it is a good idea to nest buttons. Your control should either be a single button or a panel with two buttons in it, but that also only makes sense if they execute different actions in a related context, like split buttons do.
I have the following markup:
<StackPanel Grid.Row="0" Orientation="Horizontal">
<StackPanel Orientation="Horizontal" Visibility="{Binding OrgListVisibility}">
<Label Content="Org:" />
<ComboBox ItemsSource="{Binding OrgSelectList, NotifyOnSourceUpdated=True}" SelectedValuePath="Key" DisplayMemberPath="Value" SelectedItem="{Binding OrgId}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Visibility="{Binding BranchListVisibility}">
<TextBlock Text="Branch:" Style="{StaticResource FormLabel}" />
<ComboBox x:Name="BranchList" ItemsSource="{Binding BranchSelectList}" SelectedValuePath="Key" DisplayMemberPath="Value" SelectedItem="{Binding BranchId}" />
</StackPanel>
</StackPanel>
Yet when I run the app, only the text from the TextBlock is visible, and not that of the Label. The latter is in the Visual Tree, with a TextBlock deep down, but that is as far as I can see.
AS REQUESTED: Here is the style for FormLabel:
<Style TargetType="TextBlock" x:Key="FormLabel">
<Setter Property="Height" Value="20" />
<Setter Property="Margin" Value="10" />
<Setter Property="TextAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
A SIMILAR PROBLEM:
I found an almost similar problem with a combobox when I bound it to a collection of instances of a generic class. The items' text simply did not show, but they were present in the comboboxes. Selecting on the one by knowing the position of my sought item correctly cascaded to the 2nd combobox, which had visible items, and I could see the correct but invisible item had been selected.
As soon as I change the item source to a list of non-generic objects, the items in the dropdown were visible again.
The code looks fine and as you have mentioned in the comments section that it takes layout space then it may very well happen that the color of your label and the background color of the containing layout be same.
To troubleshoot this, try giving some different background and foreground colors e.g. red or blue to the Label. Hope this helps
Ctrl+Q -> Live Visual Tree
Then hit the "pick element" button and select your label. Check the following properties:
Visibility
Opacity
Content
Also check the child elements of the Label. Setting the Content should result in a tree like this:
If a default style has changed the control template, you might not see the TextBlock as a child here. Also drill into the TextBlock and make sure it has the right Text property, then make sure it and all its parents have the right Opacity and Visibility . Also make sure that the inner TextBlock has space allocated to it by selecting it and turning on the highlighting feature in the live visual tree window.
Can you try this code to see if it works?
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
Orientation="Horizontal" Visibility="{Binding OrgListVisibility}">
<Label Content="Org:" />
<ComboBox ItemsSource="{Binding OrgSelectList, NotifyOnSourceUpdated=True}"
SelectedValuePath="Key"
DisplayMemberPath="Value"
SelectedItem="{Binding OrgId}" />
</StackPanel>
<StackPanel Grid.Column="1"
Orientation="Horizontal" Visibility="{Binding BranchListVisibility}">
<TextBlock Text="Branch:" Style="{StaticResource FormLabel}" />
<ComboBox x:Name="BranchList"
ItemsSource="{Binding BranchSelectList}"
SelectedValuePath="Key"
DisplayMemberPath="Value"
SelectedItem="{Binding BranchId}" />
</StackPanel>
</Grid>
The Label would take up layout space while not being visible when its Visibility == Hidden. You should check and make sure that your application does not define a global style (one with no Key) for TargetType="Label" where this value could be set:
<Style TargetType="Label"> !!!note that this has no 'Key' associated
[...]
<Setter Property="Visibility" Value="Hidden" />
[...]
</Style>
This would not need to be in the same xaml file in order to be automatically applied, you should check the global dictionary or any other ResourceDictionary linked in the file.
I had the same problem. It turned out that the label Height was too small. Increased the height and its content became visible.
I can do it by define UserControl that will contain those 2 element.
But is it possible to define it by define new style ?
I want to define something like on the bitmap attached.
But i need to do it on a lot of places on my xaml.
by using a style for a HeaderedContentControl
<HeaderedContentControl Header="Title" Content="what is the best way to define label and TextBox">
<HeaderedContentControl.Template>
<ControlTemplate TargetType="HeaderedContentControl">
<StackPanel Orientation="Horizontal">
<Label Content="{TemplateBinding Header}"/>
<TextBox Text="{TemplateBinding Content}"/>
</StackPanel>
</ControlTemplate>
</HeaderedContentControl.Template>
</HeaderedContentControl>
I'm currently using this extension to set specific events which handle data in the ViewModel... Example:
<swi:Interaction.Triggers>
<swi:EventTrigger EventName="Click">
<esi:CallDataMethod Method="SaveRevision_Clicked"/>
</swi:EventTrigger>
</swi:Interaction.Triggers>
Where esi and swi are:
xmlns:esi="clr-namespace:Expression.Samples.Interactivity;assembly=Expression.Samples.Interactivity"
xmlns:swi="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
But what I want to set an event for a TreeViewItem? I don't have direct access to them, do I?
EDIT: I'm actually using ItemContainerStyle,
<Style x:Key="FolderView" TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<HierarchicalDataTemplate ItemsSource="{Binding Children}" >
<StackPanel Orientation="Horizontal">
<Image Name="img"
Width="20"
Height="20"
Stretch="UniformToFill"
Source="Images/hdicon.png"/>
<TextBlock Text="{Binding FolderName}" Margin="5,0" />
</StackPanel>
</HierarchicalDataTemplate>
</Setter.Value>
</Setter>
</Style>
But I can't place my event in there. Where should I put these lines?
<swi:Interaction.Triggers>
<swi:EventTrigger EventName="Expanded">
<esi:CallDataMethod Method="Expand"/>
</swi:EventTrigger>
</swi:Interaction.Triggers>
Thanks in advance!
You need to use TreeView.ItemContainerStyle to achive this, here are couple of implementations which may help:
Strange Behaviour WPF TreeView ItemContainerStyle and ItemTemplate
WPF Double Click TreeviewItem Child Node
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}" .../>