Reputation: 3731
Im pretty noob in WPF but im seriously trying to master it :p
Ive been trying to create a control where one label/textblock is displayed but once the user hovers/clicks the control, a textbox is shown instead so the value can be edited.
What i have been trying is binding the Visible property to a boolean in the code-behind, which is updated using delegates for MouseOver and MouseLeave and Got/LostFocus, but it didnt work. Also i tried using a simple style which also bound the Visible property to the boolean in code-behind... didnt work either. Ultimately, i followed what WPF: Label to TextBox when selected suggested, using a ControlTemplate and a Trigger, like this:
<Style x:Key="TransformerBox" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And:
<Canvas x:Name="CnvCantidad" Grid.Row="2" Grid.Column="1">
<TextBox HorizontalAlignment="Center" VerticalAlignment="Center" Canvas.Left="16" Canvas.Top="8" Width="16"
x:Name="TxtCantidad" Style="{StaticResource TransformerBox}" Height="23" Visibility="Visible"/>
<Label HorizontalAlignment="Center" VerticalAlignment="Center" Content="0" Canvas.Left="16" Canvas.Top="6"
x:Name="LblCantidad"/>
</Canvas>
But in all the cases explained before, the TextBox was never visible no matter what :/
How should i create the ControlTemplate so the TextBox is visible when the user hovers the Label/TextBlock?
Upvotes: 2
Views: 10550
Reputation: 84674
Edited the Style for a Label a bit to make a TextBox appear when IsMouseOver is True. This is better then two Controls for re-usability.
<Style x:Key="EditableLabelStyle" TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Grid>
<TextBox Name="textBox"
Grid.ZIndex="1"
Padding="1,3,0,0"
Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Label}}, Path=Content, UpdateSourceTrigger=PropertyChanged}"
Opacity="0"/>
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="textBox" Property="Opacity" Value="1"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Use it like this
<Label Style="{StaticResource EditableLabelStyle}" HorizontalAlignment="Center" VerticalAlignment="Center" Content="0" Canvas.Left="16" Canvas.Top="6"
x:Name="LblCantidad"/>
Upvotes: 8
Reputation: 18040
You can do this by setting the ContentTemplate inside a trigger, or by setting the textbox as a resource and setting it using a trigger.Check this sample
<Label Height="30" BorderBrush="Gray" BorderThickness="1">
<Label.Resources>
<TextBox x:Key="ContenTextBoxt" HorizontalAlignment="Stretch"/>
</Label.Resources>
<Label.Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Padding"
Value="0" />
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
<Setter Property="VerticalContentAlignment"
Value="Stretch" />
<Setter Property="Content"
Value="No mouse over" />
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Content" Value="{StaticResource ContenTextBoxt}" />
</Trigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
Upvotes: 0
Reputation: 161012
If you are dealing with booleans and visibility you should consider a ValueConverter.
Here's an example on how to bind to a boolean (IsTextVisible
) in your model and have it map to visibility collapsed or visible.
XAML:
<TextBox HorizontalAlignment="Center" VerticalAlignment="Center" Canvas.Left="16"
Canvas.Top="8" Width="16"
x:Name="TxtCantidad" Style="{StaticResource TransformerBox}" Height="23"
Visibility="{Binding IsTextVisible,
Converter={StaticResource BoolToVisibilityConverter}}"/>
ValueConverter code:
public class BoolToVisibilityConverter : IValueConverter
{
object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool isVisible = Convert.ToBoolean(value);
return isVisible ? Visibility.Visible : Visibility.Collapsed;
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Also you have to import the converter namespace in your XAML
xmlns:converter="clr-namespace:Foo.Converter"
and assign it a key
<converter:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
EDIT:
If you're binding directly to the code behind for your purposes you can set the DataContext for the Window in the XAML this way
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Also make sure you are binding to a property
public bool IsTextVisible {get;set;}
In the long run you will want to look into the following topics:
Upvotes: 0
Reputation: 4960
There are a couple of ways to do it.
Here's one way, it just makes the TextBox hidden until you hover the mouse over the Label OR the TextBox (otherwise the mouse is not hovered over the Label anymore when the TextBox appears). You might have to tweak it, but you should get the idea (note that it doesn't actually hide the Label, just displays TextBox over it):
<Canvas x:Name="CnvCantidad" Grid.Row="2" Grid.Column="1">
<Label HorizontalAlignment="Center" VerticalAlignment="Center" Content="0" Canvas.Left="16" Canvas.Top="6"
x:Name="LblCantidad"/>
<TextBox HorizontalAlignment="Center" VerticalAlignment="Center" Canvas.Left="16" Canvas.Top="8" Width="16"
x:Name="TxtCantidad" Height="23">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=LblCantidad, Path=IsMouseOver}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=TxtCantidad, Path=IsMouseOver}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Canvas>
Upvotes: 1