I dislike WPF's inability to interpret text in a case-insensitive way.
Are there any tools (i.e. VS plugins) out there that will take my VB .NET code and handle the case-sensitivity issues for me?
Edit: Now with examples.
Input:
<Dockpanel DockPanel.Dock="Bottom">
<Label Content="(c) blahblah" HorizontalAlignment="Left" Name="Label2" VerticalAlignment="Bottom" Opacity=".75" Background="White" DockPanel.Dock="bottom"/>
</DockPanel>
Output:
<DockPanel DockPanel.Dock="Bottom">
<Label Content="(c) blahblah" HorizontalAlignment="Left" Name="Label2" VerticalAlignment="Bottom" Opacity=".75" Background="White" DockPanel.Dock="Bottom"/>
</DockPanel>
This is kind of like trying to use C# without ; or XAML without angle brackets. Case sensitivity is an intrinsic part of the XAML language and the WPF Binding system. If your VB code is causing problems when you're using it with WPF turn Option Strict on and fix the inconsistent casing in your code.
I don't think that WPF is the problem here.
If you need to validate data and remove case from the problem, then convert all your strings to Upper or Lower before comparing.
If you need to change the way that a TextBox functions in WPF, either create your own inherited TextBox and override the Text property or modify the setters in your bound properties to modify any value it receives such as
public string Name
{
get { return this._name; }
set
{
this._name = value.ToUpper();
OnPropertyChanged("Name");
}
}
Without more information about the problem, I am not sure what else to suggest.
I'm not exactly sure what you're trying to achieve, but I ran into case sensitivity issues when checking usernames. Our standard is SimpsonHJ, but some users would log into their machines as simpsonhj or SIMPSONHJ. So I made a variable that changes the username found to all uppercase
private string un = Environment.UserName.ToUpper();
easy and simple
If you have to compare two strings.
One can be stored in list, string or is some variable, other string is inputted by user on text box.
Then simply use To Upper or To Lower
These will convert the string first into upper or lower case just for compair_values.
Ex.
string s = "ram" ;
string p = "Ram" ;
if(s.ToUpper()==p.ToUpper())
{
Console.WriteLine("String matched");
MessageBox.Show("String matched");
}
else
{
Console.WriteLine("Not matched");
MessageBox.Show("Not matched");
}
Try it, you will get your answer
Related
I am writing a WPF program and I am trying to figure out a way to format data in a TextBox through some repeatable method like a style or template. I have a lot of TextBoxes (95 to be exact) and each one is bound to its own numeric data which can each have their own resolution defined. For example if the data is 99.123 with a resolution of 2 then it should display 99.12. Similarly a data value of 99 and resolution 3 should be displayed as 99.000 (not 99). Is there a way to do this?
Edit:
I should clarify, there are 95 TextBoxes on the current screen I'm working on, but I want every TextBox throughout the various screens in my program to display the correct number of decimal places. Now that I think about it, some of these are TextBoxes (like the screen I'm working on now) and some are DataGrids or ListViews, but if I can figure out how to get it working for TextBoxes I'm sure I can figure it out for the other controls as well.
There's not much code to share in this case but I'll attempt to make it clearer:
I have a View Model which contains the following properties (vb.net):
Public ReadOnly Property Resolution As Integer
Get
Return _signal.DisplayResolution
End Get
End Property
Public ReadOnly Property Value As Single
Get
Return Math.Round(_signal.DisplayValue, Resolution)
End Get
End Property
and in the XAML I have:
<UserControl.Resources>
<vm:SignalViewModel x:Key="Signal" SignalPath="SomeSignal"/>
</UserControl.Resources>
<TextBox Grid.Column="3" IsEnabled="False" Text="{Binding Path=Value, Source={StaticResource Signal}, Mode=OneWay}" />
EDIT2 (my solution):
It turns out that after walking away from the computer for a while, I came back to find a simple answer that was staring me in the face. Format the data in the view model!
Public ReadOnly Property Value As String
Get
Return (Strings.FormatNumber(Math.Round(_signal.DisplayValue, _signal.DisplayResolution), _signal.DisplayResolution))
End Get
End Property
You should use the StringFormat on the Binding. You can use either standard string formats, or custom string formats:
<TextBox Text="{Binding Value, StringFormat=N2}" />
<TextBox Text="{Binding Value, StringFormat={}{0:#,#.00}}" />
Note that the StringFormat only works when the target property is of type string. If you are trying to set something like a Content property (typeof(object)), you will need to use a custom StringFormatConverter (like here), and pass your format string as the ConverterParameter.
Edit for updated question
So, if your ViewModel defines the precision, I'd recommend doing this as a MultiBinding, and creating your own IMultiValueConverter. This is pretty annoying in practice, to go from a simple binding to one that needs to be expanded out to a MultiBinding, but if the precision isn't known at compile time, this is pretty much all you can do. Your IMultiValueConverter would need to take the value, and the precision, and output the formatted string. You'd be able to do this using String.Format.
However, for things like a ContentControl, you can much more easily do this with a Style:
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentStringFormat"
Value="{Binding Resolution, StringFormat=N{0}}" />
</Style>
Any control that exposes a ContentStringFormat can be used like this. Unfortunately, TextBox doesn't have anything like that.
The accepted answer does not show 0 in integer place on giving input like 0.299. It shows .3 in WPF UI. So my suggestion to use following string format
<TextBox Text="{Binding Value, StringFormat={}{0:#,0.0}}"
void NumericTextBoxInput(object sender, TextCompositionEventArgs e)
{
TextBox txt = (TextBox)sender;
var regex = new Regex(#"^[0-9]*(?:\.[0-9]{0,1})?$");
string str = txt.Text + e.Text.ToString();
int cntPrc = 0;
if (str.Contains('.'))
{
string[] tokens = str.Split('.');
if (tokens.Count() > 0)
{
string result = tokens[1];
char[] prc = result.ToCharArray();
cntPrc = prc.Count();
}
}
if (regex.IsMatch(e.Text) && !(e.Text == "." && ((TextBox)sender).Text.Contains(e.Text)) && (cntPrc < 3))
{
e.Handled = false;
}
else
{
e.Handled = true;
}
}
I use the default WPF ribbon shipped with VS2012 Express.
When RibbonTextBox databound to double property in viewmodel initialised by value 1.75, it displays it and allows modifying numbers around the decimal separator without framing it in red colour as it does when entered non-numeric character such as 'x' etc.
But once decimal separator deleted, there's no way to type it back into the RibbonTextBox. It accepts nonsense characters, but not the decimal separator. In other words, after deleting the decimal separator, it behaves rather as databound to int.
XAML
xmlns:rib="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
...
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" >
<Label Content="Source Gamma " />
<rib:RibbonTextBox Text="{Binding SrcGamma, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="50"/>
</StackPanel>
C# code behind
public double SrcGamma { get; set; } // initialised to 1.75d
Note 1: First, I suspected it to be a culture problem. My Windows culture (cs-CZ) uses ',' decimal separator but my application displayed '.' separator.
a) Setting Windows culture separator to '.' didn't help.
b) After overrriding application locale according to this SO question, the correct Windows culture separator is displayed, but cannot be entered either.
Note 2:
During my investigation I added a standard TextBox (outside the ribbon). After adding a custom double validation rule to it, it started behaving just the same way as the RibbonTextBox mentioned.
Thanks in advance for any suggestion.
The answer was hidden in this SO Article.
The strange behaviour was caused by UpdateSourceTrigger=PropertyChanged I used to use in .NET 3.5 where it behaved in an expected way. After removing it, the decimal separator can be added without any problems now.
Well, MS had reasons to do this change, so let's bear it in mind.
I'd like to modify the spacing between characters in a WPF TextBox.
Something like the letter-spacing: 5px thing that is available in CSS.
I think it is possible in XAML; what's the simplest way?
I found the "Introduction to the GlyphRun Object and Glyphs Element" document, and found it to be exceedingly unhelpful.
This is a code example from that page:
<!-- "Hello World!" with explicit character widths for proportional font -->
<Glyphs
FontUri = "C:\WINDOWS\Fonts\ARIAL.TTF"
FontRenderingEmSize = "36"
UnicodeString = "Hello World!"
Indices = ",80;,80;,80;,80;,80;,80;,80;,80;,80;,80;,80"
Fill = "Maroon"
OriginX = "50"
OriginY = "225"
/>
The same documentation page gives this "explanation" for what the Indices property does:
I have no idea what any of that means. I'm also not sure that Indices is the right thing - the comment in the code speaks of "character widths" which I don't care about. I want to adjust the width between characters.
Also, there is no example for how to apply a Glyphs element to a TextBox. When I tried it, my WPF test app just crashed.
What I want to do is slightly increase the empty space that appears between drawn characters within a WPF TextBox. The text will vary in length and content. Do I have to modify the Indicies property every time there is a new character? Is there a way to say "make it 20% more space than usual, for every character".
Can anybody help me?
I tried Glyphs and FontStretch and couldn't easily get the result I was looking for. I was able to come up with an approach that works for my purposes. Maybe it will work for others, as well.
<ItemsControl ItemsSource="{Binding SomeString}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"
Margin="0,0,5,0"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I can bind to any string and don't need to do any character width detection to set the spacing properly. The right margin is the space between the letters.
Example:
I found a way to have letter spacing with TextBlock class as it supports TranslateTransforms. By replacing a default PropertyChangedCallback on the TextBlock.TextProperty with a custom one, we can apply TranslateTransform to each letter in the TextBlock.
Here is a complete step-by-step coding I did:
First, we create a custom class and inherit from TextBlock like so:
using System.Windows.Controls;
namespace MyApp
{
class SpacedLetterTextBlock : TextBlock
{
public SpacedLetterTextBlock() : base()
{
}
}
}
Then, in XAML, we change the TextBlock to our custom class (more information can be found here):
<Window x:Class="MyApp.MainWindow"
...
xmlns:app="clr-namespace:MyApp">
<Grid>
<app:SpacedLetterTextBlock>
Some Text
</app:SpacedLetterTextBlock>
</Grid>
</Window>
Finally, before the InitializeComponent() method in the .cs code-behind file, add the OverrideMetadata method like so:
// This line of code adds our own callback method to handle any changes in the Text
// property of the TextBlock
SpacedLetterTextBlock.TextProperty.OverrideMetadata(
typeof(SpacedLetterTextBlock),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnTextChanged)
)
);
... and apply TranslateTransform to each letter each time TextProperty changes:
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SpaceLettersOut(d);
}
// This method takes our custom text block and 'moves' each letter left or right by
// applying a TranslateTransform
private static void SpaceLettersOut(DependencyObject d)
{
SpacedLetterTextBlock thisBlock = (SpacedLetterTextBlock)d;
for (int i = 1; i <= thisBlock.Text.Length; i++)
{
// TranslateTransform supports doubles and negative numbers, so you can have
// whatever spacing you need - do see 'Notes' section in the answer for
// some limitations.
TranslateTransform transform = new TranslateTransform(2, 0);
TextEffect effect = new TextEffect();
effect.Transform = transform;
effect.PositionStart = i;
effect.PositionCount = thisBlock.Text.Length;
thisBlock.TextEffects.Add(effect);
if (effect.CanFreeze)
{
effect.Freeze();
}
}
}
NOTES:
First, I am a complete novice in WPF and C#, so my answer might not be the cleanest solution available. If you have any comments on how to improve this answer, it will be greatly appreciated!
Second, I haven't tested this solution with a large number of TextBlock elements, and there (probably) is a huge performance penalty as TranslateTransform is applied to each individual letter in a TextBlock.Text.
Finally, the text of the TextBlock goes out of bounds with any positive X value for TranslateTransform. I think that you can re-calculate the width of the TextBlock and only then place it programmatically (?)
is FontStretch an option for you?
Otherwise you might want to look into this there is an image, showing what advance width means. Though I have not done this before and don't know if this works increasing right and left side bearings might be what you want!
For what its worth . . .
If you have the option to switch your implementation to RichTextBox, this might be easier than the work-around you found Sept 2013. I just tried it for my own needs and it works for what I need. I do not see a way with RichTextBox to control kerning of individual spaces like typesetters do. But TextBox was eating additional spaces (consolidating multiple adjacent spaces to a single space) like HTML. I needed for the spaces to display the same amount of spacing as is in my text String, and RichTextBox does this.
<RichTextBox x:Name="MyRichTextBox"></RichTextBox>
I'm no expert, but it seems you can't specify the text content in XAML. I had to specify it in a code-behind event:
this.MyRichTextBox.AppendText("V A R I E D S P A C E S");
I want to stream a bunch of text to display the status/progress of a long running task (such as the output window in Visual Studio).
Currently I have something like this XAML:
<ScrollViewer Canvas.Left="12" Canvas.Top="12" Height="129" Name="scrollViewer1" Width="678">
<TextBlock Name="text" TextWrapping="Wrap"></TextBlock>
</ScrollViewer>
and this code behind:
private void Update(string content)
{
text.Text += content + "\n";
scrollViewer1.ScrollToBottom();
}
After a while, it gets really slow.
Is there a recommended way of doing this type of thing? Am I using the right kinds of controls?
Thanks!
At a minimum, you'll want to use a readonly TextBox and use the AppendText() method to append text.
Of course, you're still not immune from performance problems if you have sufficient volumes of text. That being the case, you might need to look into virtualization (both data and UI) solution.
I'm running into a problem that seems to have no sensible / tractable solution that I am happy with. Silverlight and Internationalisation - a quagmire in the making.
I have a set of resource files that contain translated strings.
In the simple case, I can declare the language resource etc and bind the content / text of a value within the strongly typed resource. Thats fine - plenty of examples of that posted around.
A less simple case is that the strings can have a parameter, so I need to inject a value into the string for the display of it, which in itself can be a data binding.
The more complex scenario is a string with multiple parameters.
You can argue that the VM should provide this ability, but I am unhappy at that since it breaks the divide between the UX Designer and the Developer, requiring the developer to implement a property / method on the VM to support every string the UI requires.
For example : The designer decides after user feedback to add a custom tooltip with more information on it. The tooltip is done declaratively and combines a better explanation with values from the datacontext. The explanation is stored in the resources and the values used come from either an existing data context or an element to element binding.
If I have to run every string through the VM then the addition of something like this requires VM changes. Equally if the source of the parameters will be from other elements, then the VM is not necessarily in the position to provide the formatted string.
How have people got round / approached this issue?
A.
This question is more complex than I can answer fully, but if you want bindings to consider a specific localization you should set the Language property of your UI Container (maybe your top level UserControl class). After that all bindings should use your requested localization. Check out this article, which concerns WPF but uses techniques that appear to be applicable to Silverlight: http://www.west-wind.com/weblog/posts/796725.aspx
I don't know exactly what you want to do but you've got several solutions.
Create a new string in your VM and make it INotifyPropertyChanged-able
public string MyTranslatedString
{
get
{
return string.Format("{0} Someone", LocalizedResource.Hello;
}
};
And then listen for localization change events (from your application)
Create several text blocks and bind the localized items:
<TextBlock HorizontalAlignment="Stretch" Foreground="Black" Text="{Binding Path=Resource.CurrentlyLoggedInAs, Source={StaticResource LocalizedStrings }}" VerticalAlignment="Center" Margin="0,0,5,0" />
<TextBlock HorizontalAlignment="Stretch" Foreground="Black" Text="{Binding Path=Username}" VerticalAlignment="Center" Margin="0,0,5,0" />
<Button Commands:Click.Command="{Binding Path=LogOutCommand}" Commands:Click.CommandParameter="" Content="{Binding Path=Resource.LogOut, Source={StaticResource LocalizedStrings }}" />
You need to add, in your main app:
<Application.Resources>
<local:LocalizedStrings
xmlns:local="clr-namespace:Localization.Silverlight;assembly=Localization.Silverlight"
x:Key="LocalizedStrings" />
</Application.Resources>
These are the easiest approaches I came up with but I'm quite happy to have something providing me with something simpler.