A very simple question:
Why I cant see _ (underscore) in WPF content?
For instance the content of
<Label Content="test_t" Name="label2" />
is shown as "testt" (with the underscore not shown).
Labels support mnemonics (i.e. you can use ctrl+(key) to give them focus). You define the mnemonic key using an underscore.
http://www.charlespetzold.com/blog/2006/01/061004.html
If you want to see underscores, replace single underscores with double underscores.
This is because Label supports defining a mnemonic based on its content, which is done by prefixing the mnemonic with an underscore (the same thing that happens in Windows Forms with &).
Use a double underscore if you want a literal one to appear:
<Label Content="test__t" Name="label2" />
I know im late to the party but I believe that if you don't have the Label associated to a TextBox than you should use a TextBlock instead.
Changing your control to a TextBlock solves this issue since only Label has the mnemonic support
This style solves your problem:
<Style x:Key="{x:Type Label}"
TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Border Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="False"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
I was binding to a data source which I didn't want to change, so I used a custom converter to create the missing underscore:
[ValueConversion(typeof(string), typeof(string))]
public class ShowUnderscoreConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
value is string text ? text.Replace("_", "__") : null;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
value is string text ? text.Replace("__", "_") : null;
}
Related
I have the following WPF Style for a custom control
<Style TargetType="{x:Type local:TransportControl}">
<Setter Property="MinorTickBrush" Value="{DynamicResource BlackBrush}"/>
<Setter Property="MajorTickBrush" Value="{DynamicResource BlackBrush}"/>
<Setter Property="IndicatorBrush" Value="{DynamicResource BlckBrush}"/>
<Setter Property="ProgressBorderBrush" Value="{DynamicResource BlackBrush}"/>
<Setter Property="ProgressBrush" Value="{DynamicResource HighlightBrush}"/>
<Setter Property="IndicatorSize" Value="16"/>
<Setter Property="IndicatorBrush" Value="{DynamicResource BlackBrush}"/>
<Setter Property="IndicatorGlow" Value="True"/>
<Setter Property="IndicatorGlowBrush" Value="GhostWhite"/>
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TransportControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{Binding Path=DataContext.IndicatorSize,
RelativeSource={RelativeSource AncestorType={x:Type local:TransportControl}},
Converter={StaticResource ValueToHorizontalPaddingConverter}}"
Margin="4,2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Canvas Name="PART_TimelineCanvas" Grid.Row="0" Height="20" ClipToBounds="False"/>
<Canvas Name="PART_ProgressCanvas" Grid.Row="1" ClipToBounds="False"/>
<Canvas Name="PART_IndicatorCanvas"
Grid.Row="0"
Grid.RowSpan="2"
ClipToBounds="False"
Panel.ZIndex="2"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
with the IValueConverter as
public class ValueToHorizontalPaddingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object format, CultureInfo culture)
{
double padding = System.Convert.ToDouble(value);
return new Thickness(padding, 0, padding, 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I am attempting to set the padding of the control so my indicator can be centered correctly. I want the padding of the control to be half the IndicatorSize set in the parent style. Currently, I am just trying to get it to be the IndicatorSize, but the binding I am attempting does not work as expected.
Padding="{Binding Path=DataContext.IndicatorSize,
RelativeSource={RelativeSource AncestorType={x:Type local:TransportControl}},
Converter={StaticResource ValueToHorizontalPaddingConverter}}"
What am I doing wrong?
Thanks for your time.
You can use TemplateBinding to do that:
Padding="{TemplateBinding IndicatorSize, Converter={StaticResource ValueToHorizontalPaddingConverter}}"
Another way of centering the indicator would be to give the border a name, get a reference to it in your custom control's OnApplyTemplate(..) method and set its Padding in C# whenever the IndicatorSize property changes. This way you would not need the binding and converter.
I hope I can explain this clearly....
We are binding our DataGrid to a collection that comes from some datasource.
Attributes for each column are described in a different collection, so we create the columns at runtime and set properties on the column (readonly, for example) based on values in the attributes collection.
A new requirement is a 'required' attribute. For columns that are required, I'd like to bind a converter that sets the DataGridCell's background color based on the value. (The simplest case of converter would be some color if the cell were empty, and white if the user entered a value. I'm sure more sophisticated validation will be expected in the future.)
I think it can be done in something like what I'm tinkering with now :
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<TextBox Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text}">
</TextBox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
(Still need to add the converter somewhere....)
Or will what I want to do have to be done in code-behind? Any pointers would be greatly appreciated...
Here is one way of doing it. IDK if it's the best way, but it works and it's been a couple hours since you asked so....
Your DataGridCell is filled with the border/textbox so I'm assuming you want to change the textbox's background color since you won't see the DataGridCell's background.
Since you mentioned there could be more complex scenarios in the future, I used a multibinding with a converter and passed in the textboxes datacontext (by using <Binding />) and it's text value.
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<TextBox Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text}">
<TextBox.Resources>
<local:ValidationBGConverter x:Key="ValidationBGConverter" />
</TextBox.Resources>
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource ValidationBGConverter}">
<Binding />
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Content.Text" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</TextBox.Style>
</TextBox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And here is the converter:
public class ValidationBGConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length != 2)
return Brushes.Black;
var datacontext = values[0] as ViewData; // Or whatever the textbox's datacontext object is
if (datacontext != null) // If null, probably the new item row
{
var txt = values[1] as string; // Textbox text
if (string.IsNullOrWhiteSpace(txt))
return Brushes.Red;
if (txt.Length < 3)
return Brushes.Pink;
if (txt.Length > 5)
return new LinearGradientBrush(Colors.White, Colors.Blue, 90.0);
}
return Brushes.White;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And, a screenshot:
I want to use Label or TextBlock that will display a lower cased and appended with ":" character string that I get from resources.
For example something like this:
<Label Content="{x:Static Localization:Captions.Login}" />
where Captions.Login is the string "Login", and the output in my view should be: "login:".
I added a template for Label, that appends ":", but I cannot get to lowercase my string within this template:
<ControlTemplate x:Key="LabelControlTemplate" TargetType="{x:Type Label}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<TextBlock>
<Run Text="{TemplateBinding Content}"/>
<Run Text=":"/>
</TextBlock>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
The same I can get by using without the Controltemplate, the line of xaml:
<Label Content="{x:Static Localization:Captions.Login}" ContentStringFormat="{}{0}:" />
So to end, my question is how to bring lowercase functionality in this scenario(note I do not want to use TextBox and restylings to achieve this)
what about using binding and a converter?
<Label Content="{Binding Source="{x:Static Localization:Captions.Login}", Path=., Converter="{StaticResource MyToLowerWithDotConverter}"/>
something like that? i have no IDE atm so i dont know if the bindings are right.
Use a Converter to transform your string to lowercase.
public class LowerCaseConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((string)value).ToLowerInvariant();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// unnecessary
throw new NotImplementedException();
}
}
How can i solve the following (simplified) problem?
M-V-VM context. I want to show text at the UI.
In case the user has the rights to change the text, i want to use a textbox to manipulate the text.
In case the user has no rights, i want to use a label to only show the text.
My main problem: how to exchange textbox and label and bind Text resp. Content to the same property in viewmodel.
Thanks for your answers
Toni
There are a few ways of achieving this, with varying degrees of ease of reuse. You can have a DataTemplateSelector that could return the appropriate DataTemplate for a given property (depending on how this is written, you may be able to use it for each of your properties).
You could create a DataTemplate for each property, and change visibility based on a DataTrigger (this gets really annoying, as it is a lot of copy and paste).
I think the easiest way of doing this is with a specialized ControlTemplate for the TextBox. Basically, when it is disabled, instead of graying it out, you can just make it look like a TextBlock:
<ControlTemplate x:Key="PermissionedTextBox" TargetType="{x:Type TextBox}">
<Border x:Name="bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="bd" Property="BorderBrush" Value="{x:Null}" />
<Setter TargetName="bd" Property="Background" Value="{x:Null}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Then you can use it like so:
<TextBox Text="{Binding PermissionedText}" IsEnabled="{Binding CanEdit}" />
I have a button control style and I want to change the padding from whatever the data-bound version is to adjust for a glyph that needs a 2 pixel offset. I'll use SimpleButton from SimpleStyles.xaml as an example (... shows where the trigger code was removed for conciseness):
<Style x:Key="SimpleButton" TargetType="{x:Type Button}" BasedOn="{x:Null}">
<Setter Property="FocusVisualStyle" Value="{DynamicResource SimpleButtonFocusVisual}"/>
<Setter Property="Background" Value="{DynamicResource NormalBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<!-- We use Grid as a root because it is easy to add more elements to customize the button -->
<Grid x:Name="Grid">
<Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}"/>
<!-- Content Presenter is where the text content etc is placed by the control. The bindings are useful so that the control can be parameterized without editing the template -->
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
</Grid>
...
</Setter.Value>
</Setter>
</Style>
What I want to do is add some extra margin where Padding="{TemplateBinding Padding}". Something like Padding="{TemplateBinding Padding} + 2,0,0,0".
Is there a XAML syntax to that? If not, is there a best approach when doing this in code (Decorator?) ?
Currently XAML does not parse expressions in Binding syntax, etc. However, you can use an IValueConverter or IMultiValueConverter to help yourself out:
XAML:
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="Grid">
<Grid.Resources>
<local:ThicknessAdditionConverter x:Key="AdditiveThickness" />
</Grid.Resources>
<Border x:Name="Border">
<Border.Padding>
<Binding Path="Padding" RelativeSource="{RelativeSource TemplatedParent}"
Converter="{StaticResource AdditiveThickness}">
<Binding.ConverterParameter>
<Thickness>2,0,0,0</Thickness>
</Binding.ConverterParameter>
</Binding>
</Border.Padding>
</Border>
...
</Setter.Value>
IValueConverter code behind:
public class ThicknessAdditionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return new Thickness(0, 0, 0, 0);
if (!(value is Thickness)) throw new ArgumentException("Value not a thickness", "value");
if (!(parameter is Thickness)) throw new ArgumentException("Parameter not a thickness", "parameter");
var thickness = new Thickness(0, 0, 0, 0);
var t1 = (Thickness)value;
var t2 = (Thickness)parameter;
thickness.Left = t1.Left + t2.Left;
thickness.Top = t1.Top + t2.Top;
thickness.Right = t1.Right + t2.Right;
thickness.Bottom = t1.Bottom + t2.Bottom;
return thickness;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
There is a product available at Blendables.com called Eval Binding and Simple Binding does this now. (The product is not free) Check out the whitepaper here
For example for the bellow XAML code you need a converter to do the operation.
<Ellipse Fill="Blue" Height="50"
Width="{Binding RelativeSource={RelativeSource Self},
Path=Height, Converter={StaticResource MyConverter}}" />
But with EvalBinding you can do like bellow
<Ellipse Fill="Blue" Height="50"
Width="{blendables:EvalBinding [{Self}.Height]/2}" />
No, not in this version of XAML - use a Value Converter to do your math.
Check out the ExpressionConverter in this library.
You can do some simple math by taking advantage of transforms.
Check out this trick that Charles Petzold came up with a long time ago:
http://www.charlespetzold.com/blog/2006/04/060223.html
Unfortunately, it doesn't seem to help your particular scenario ... since you want only to change Left property of the Thickness type for the Padding ... and that is not a dependency property that you can bind to alone.
However, I felt compelled to add this answer in the case it helps others who find their way here via Google or another search engine.
Check out the MathConverter: http://rachel53461.wordpress.com/2011/08/20/the-math-converter/
There you can send in an expression as the converter-parameter, where #VALUE is the value you are binding to:
ConverterParameter=((#VALUE-15)*.2)