Formatting Data in MVVM within Windows Phone app - c#

I have a DataModel and a ViewModel working successfully together with my xaml view.
In the view I use databindings.
In my DataModel I have some properties like Distance declared as int.
When displaying the values in view, I want a formatting like adding a trailing meter.
How get this done?

you can format string in the xaml binding...
<TextBlock Text="{Binding Distance, StringFormat={} {0} meter}"/>

Maybe by providing a property which will return a formatted value:
private int distance = 0;
public int Distance
{
get { return distance;}
set { distance = value; OnPropertyChanged("DistanceTxt"); }
}
public string DistanceTxt
{
get { return distance.ToString() + " meter"; }
}
Then when you bind to DistanceTxt you should get your distance with trailing meter. I've also added OnPropertyChanged in Distance property so that when it changes, your value on the screen updates.

Related

WPF Textbox as Double or Float

In my application i have two textboxes that are used to set the price of an entries for children and adults. Everytime the textboxes are changed, the event "textbox_ValueChanged" fires which executes "priceChanged()" and saves the content of my textboxes to a MySQL Database.
The columns that the prices are saved to are type double.
This whole thing works fine for typing integers into "adultPriceTextbox" (for example), but when trying to write a double or float into the textbox there are the following cases:
1. -> User types "5" then "," and then "5"
In this case the program crashes as soon as the second "5" is typed.
The line that crashes is cmd.ExecuteNonQuery(); which saves the value to the database (view code further below).
The error message looks like this
Data truncated for column 'adults' at row 1"
2. -> User types "5" then "." and then "5"
In this case nothing crashes, but the value being saved to the database does not contain the dot. So "5.5" would turn into "55".
This is the code that saves the values to the database. It is inside of a class called "DatabaseInterface":
public static void updatePrice(double _adults, double _children)
{
MySqlConnection cnn = OpenCnn();
MySqlCommand cmd = new MySqlCommand("UPDATE price SET adults = '" + _adults + "', children = '" + _children + "';", cnn);
cmd.ExecuteNonQuery();
}
And this is the code that executes "UpdatePrice":
private void priceChanged()
{
double adultPrice;
double childPrice;
try
{
adultPrice = Convert.ToDouble(adultPriceTextbox.Text);
}
catch
{
adultPrice = 0.0;
}
try
{
childPrice = Convert.ToDouble(childPriceTextbox.Text);
}
catch
{
childPrice = 0.0;
}
DatabaseInterface.updatePrice(adultPrice, childPrice);
}
Note that in this special case, there are two input windows. One that sets the price for children and the other one for adults.
Also my region is Germany, where decimals are written with "," instead of ".".
What would be the most elegant solution to achieve a Textbox where the user can type in integers and floats / doubles?
Addition: Ideas for blocking any alphabetical input into said textboxes are welcome as well, only numbers and "." / "," should be allowed.
Instead of binding to a text/string, just have a property on your binding object (MVVM pattern) that is the expected type of decimal, float or int for the respective type. Then, when you bind your text to that public get/set property, it will only store the value IF it qualifies for that data type, thus NOT applying the value to the property with bad values that cant be converted.
Additionally, instead of sending the data on every key stroke, you could change the binding to only submit after focus changes such as
<TextBox Text="{Binding YourIntegerField, UpdateSourceTrigger=LostFocus}"
Width="40" MaxLength="3" />
<TextBox Text="{Binding YourDecimalField, UpdateSourceTrigger=LostFocus}"
Width="70" MaxLength="6" />
The MaxLength is how many characters you actually allow. For a person's age, you probably cap at 3, but for pricing, your call.
Finally, by building out your strings with quoted values, you are open to SQL injection and should PARAMETERIZE your queries. Learn to do that early on, especially if dealing with actual text-based content and not numbers.
MVVM pattern is (M)odel, (V)iew, (VM)ViewModel. The model is the data where all stuff comes from and goes to for the database. The view is all the presentation stuff to your end-users, hence the Textbox, and all other inputs, buttons, etc. The ViewModel is the glue that ties the pieces together. You can find plenty of reading out there.
Now, the view, you got. The model where the data resides also exists. Your view model is basically the object that allows the back-and-forth exposure. Since you are not showing your actual view (more context of the .xaml and .xaml.cs, harder to add more specifics. But, lets say that your .xaml.cs is directly paired with your .xaml. In the constructor, if you set the DataContext to your .xaml.cs (or other actual object), that is what is being "bound" to. So it might look like
namespace YourApp
{
public partial class YourView
{
public YourView()
{
InitializeComponent();
// HERE, you are basically telling the view that anything with "BINDING"
// you want associated to this object.
DataContext = this;
}
// Now, any publicly prepared properties such as
// int, decimal, date, etc can be exposed as bindable in the view
private int _youngAge = 7;
public int YoungAge
{ get { return _youngAge; }
set { _youngAge = value;
DoSomethingOnceAssigned();
}
}
private int _olderAge = 83;
public int OlderAge
{ get { return _olderAge; }
set { _olderAge = value;
DoSomethingWithOlderAge();
}
}
// similar with any other properties
}
}
Now, in this scenario, since I defaulted the young and old ages, if you run the view and have the bindings to these public properties (not the private), the form SHOULD show those ages respectively. Now, if you edit the details while running the form and change focus to the next field such as by click or tab, it should hit the respective setters which you can break-point on and debug with.
See if that helps you get going some and let me know if anything else to assist.
To both cases, in the priceChanged ignores any not numeric characters, you can do as this, or using a ASCII table instead of regex, exclude the '.' or/and '.' from ignored characters.
Doing the first suggestion, i think that the crashes from the first case will not happen again.
For the second case, you the culture info as suggested Jaime and don't forget to change the ',' to '.' or the inverse before the conversion.

Is there a way I can get an Enum value by its number in the sequence?

I have this enum:
public enum PTI
{
UserInput = 0,
Five = 5,
Ten = 10,
Fifteen = 15
}
public static partial class Extensions
{
public static string Text(this PTI time)
{
switch (time)
{
case PTI.UserInput: return "User Input";
case PTI.Ten: return "10 seconds";
case PTI.Five: return "5 seconds";
case PTI.Fifteen: return "15 seconds";
}
return "";
}
}
It's a simple case but I am using it as an example. In my code I need to pass the value of the enum to a function so I came up with this:
if (selectedIndex == 1) App.DB.UpdateSetting(Settings.Pti, PTI.UserInput);
if (selectedIndex == 2) App.DB.UpdateSetting(Settings.Pti, PTI.Five);
if (selectedIndex == 3) App.DB.UpdateSetting(Settings.Pti, PTI.Ten);
if (selectedIndex == 4) App.DB.UpdateSetting(Settings.Pti, PTI.Fifteen);
It's not ideal. Maybe a Case would help here but my point is that all I get is a number from 1 to 4 and from this I need to get the ENUM value.
Is there some way that I could get the ENUM value from the value of selectedIndex without an if or case construct?
Background - Here's where the value of selectedIndex comes from. It's from a picker in a Xamarin Form XAML
<Picker x:Name="ptiPicker" IsVisible="false" SelectedIndexChanged="ptiOnPickerSelectedIndexChanged">
<Picker.Items>
<x:String>User input</x:String>
<x:String>5 seconds</x:String>
<x:String>10 seconds</x:String>
<x:String>15 seconds</x:String>
</Picker.Items>
</Picker>
Note:
If it was possible I would be happy to add some extension method to the enum if that would help get what I needed. Just not sure how to do that.
You are trying to get the index of the Enum value.
// Below code sample how to find the index of Enum.
// Sample to show how to find the index of item
PTI p = PTI.Ten;
int index = Array.IndexOf(Enum.GetValues(p.GetType()), p);
Console.WriteLine(index); // Output: 2 because of value PTI.Ten
So, finally solution for you to replace all if statements with just one statement.
PTI pti = (PTI)(Enum.GetValues(typeof(PTI))).GetValue(selectedIndex-1); // selectedIndex-1 because the index is 0 based.
App.DB.UpdateSetting(Settings.Pti, pti);
You can cast your int with PTI like in this program
public class Program
{
public static void Main(string[] args)
{
//Your code goes here
Console.WriteLine(""+(PTI)2);
Console.WriteLine(""+(PTI)5);
}
}
public enum PTI
{
UserInput = 0,
Five = 5,
Ten = 10,
Fifteen = 15
}
If the integer has a valid value existing in the enum you get the enum, if not you will get the integer unchanged as the result of the program above shows below:
2
Five
I'm not familiar with Xamarin, but may be you should try to fill items with elements of your enum directly?
In WPF It goes simply like this. And if you want to convert enum elements to string and back, you can use ValueConverter
The example below is from WPF!
<ComboBox
// properties here
SelectedItem="{Binding SelectedItem.EngineType, UpdateSourceTrigger=PropertyChanged}">
<Model:EEngineType>Diesel</Model:EEngineType>
<Model:EEngineType>Gas</Model:EEngineType>
<Model:EEngineType>Biofuel</Model:EEngineType>
<Model:EEngineType>Electrical</Model:EEngineType>
</ComboBox>
and EEngineType
public enum EEngineType
{
Diesel,
Gas,
Biofuel,
Electrical
}
May be you should look around something like this, so you won't need to convert anything and just pass selectedItem to your method.
OR
in another way you can try to use something like this
readonly TCollection _PITCollection;
// ctor here
_PITCollection = new TCollection<PIT> { PIT.UserInput, PIT.Five, PIT... };
Where instead of TCollection you write any collection type you want.
And than you can use binding and call
App.DB.UpdateSetting(Settings.Pti, myPicker.SelectedItem);
or you can use you previous style and call
App.DB.UpdateSetting(Settings.Pti, _PITCollection[selectedIndex]);
Hope this will help you
You can try to convert it as an integer to get the value.
Convert.ToInt32(PTI.Fifteen)
Picker items are in a form of string so what you can do is to get the text of the selected index of your picker and parse it to only get the number from item.
picker.Items [picker.SelectedIndex];
e.g.
var selectedValue = "15 seconds"; //this will be your selected value in picker
var splitx = selectedValue.Split(' ');
Console.WriteLine(Convert.ToInt32(PTI.Fifteen));
if (Convert.ToInt32(splitx[0]) == Convert.ToInt32(PTI.Fifteen))
{
Console.WriteLine("selected value is - 15 seconds");
}
You can also try to do a Dictionary like in the Xamarin example here
Hope this helps you...

How do I Reset value of IntegerUpDown to minimum if it exceeds maximum

I have IntegerUpDown like this
<xctk:IntegerUpDown Value ="{Binding SomeValue}", Maximum="2" Minimum="0"/>.
I was if the value is - SomeValue == 2 (Maximum).
I want to set SomeValue = 0 (Minimum) when I click on arrow up in Control.
How can I do that?
You can use the Value changed event to get the current value. At the Value changed event, check for the value, if it is equal to Maximum, set it to Minimum as follows:
private void IntegerUpDown_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var updown = (sender as IntegerUpDown);
if (updown.Value == updown.Maximum)
updown.Value = updown.Minimum;
}
If you are using MVVM, then use interaction behavior or command to do the same.
or may be, you would bind the Value to a property in your ViewModel, as like you can bind the Max, Min Value to properties in ViewModel. And you can check the value at the property changed event of Value property, and can set the Value on goes above the Maximum value property.
If you want to do it on View side, for simple dirty solution you might want to try handle ValueChanged event and check there if minimum or maximum is reached. It probably won't allow you to change value when you reach your maximum/minimum, so you probably want to set your values to
<xctk:IntegerUpDown Value ="{Binding SomeValue}", Maximum="3" Minimum="-1"/>. and change it accordingly to 0 or 2 if it's reached.
For a better and cleaner solution, I am not sure what others events are raised when you try to change value beyond maximum/minimum. But you could create a control based on IntegerUpDown and override int IncrementValue(int value, int increment) and int DecrementValue(int value, int increment) methods.
You could also remove the min/max limits in the xaml:
<xctk:IntegerUpDown Value ="{Binding SomeValue}" />
And then handle the min/max limiting and rollover in your view model:
public double SomeValue
{
get { return _SomeValue; }
set
{
if (value < 0)
_SomeValue = 0;
else if (value >= 2)
_SomeValue = 0;
else
_SomeValue = value;
OnPropertyChanged("SomeValue");
}
}
private double _SomeValue = 1;

WPF: Boldify part of binded value of TextBlock

I am looking for a way to highlight some search terms inside my custom ListView control. I have a bunch of TextBlocks (one for each property of each row). For example the artist name, title and genre of each song.
Now, if someone searches for "Emi" then I want the artist field to show up like <b>Emi</b>nem, if the value of the binding is Eminem.
I have looked around a bit but didn't get much wiser. I figure I need some combination of a converter and using Inlines (which I've never used before) and/or InlineExpressions (or are those only for ASP?).
All bindings and templates are created on-the-fly in C# and not XAML.
Thanks!
Yes, you are right about using converter(actually it will may be even multiconveter) and Inlines collection of a TextBlock.
So let's say you are passing search item(in your case word 'Emi') to the converter. You will also need to manipulate the TextBlock with resulting text somehow. For simplicity let's assume that TextBlock's Tag property(not Text) contails the whole string being searched(word 'Eminem').
class HighlightPartOfTextConverter : IValueConverter {
public object Convert(object value/*this is TextBlock*/, Type type, object parameter/*this is 'Emi'*/, CultureInfo ci){
var textBlock = value as TextBlock;
string str = textBlock.Tag as string;
string searchThis = parameter as string;
int index = str.IndexOf(searchThis);
if(index >= 0){
string before = str.Substring(0, index);
string after = str.Substring(index + searchThis.Length);
textBlock.Inlines.Clear();
textBlock.Inlines.Add(new Run(){Text=before});
textBlock.Inlines.Add(new Run(){Text=searchThis, FontWeight = FontWeights.Bold});
textBlock.Inlines.Add(new Run(){Text=after});
}
return "";
}
public object ConvertBack(...) {...}
}

how to truncate an double datatype value variable

i have an class
public class Score
{
public double marks { get; set; }
}
now in my code
List<Level1> Obj= new List<Level1>();
Score Object= new Score();
l1.marks=94.345454;
Obj.Add(Object)
// now whiling adding the object to list i need to trunacte the value to
94.34 and store in the list obj.
so that i need to get output has 94.34
how can i do it.
thanks in advance
prince
Keep the value as a double, and only format it on output.
string output = doubleValue.ToString("F2");
Source. As an example:
doubleNumber = -1898300.1987;
Console.WriteLine(doubleNumber.ToString("F1", CultureInfo.InvariantCulture));
// Displays -1898300.2
Console.WriteLine(doubleNumber.ToString("F3",
CultureInfo.CreateSpecificCulture("es-ES")));
// Displays -1898300,199
Notice the decimal comma on the last output as the culture is set to Spanish.
You could do this in the marks property setter:
value -= value % 0.01
this will subtract 0.005454 from value and so leave you with the correct number of decimal points (in this case, 2)
something like:
public class Score {
private double m_marks;
public double marks {
get { return m_marks; }
set { m_marks = value - (value % 0.01); }
}
}
You could use Math.Round(number, precision) as shown on msdn

Categories

Resources