If I bind Text in a TextBox to a float Property then the displayed text doesn't honor the system decimal (dot or comma). Instead it always displays a dot ('.'). But if I display the value in a MessageBox (using ToString()) then the correct System Decimal is used.
Xaml
<StackPanel>
<TextBox Name="floatTextBox"
Text="{Binding FloatValue}"
Width="75"
Height="23"
HorizontalAlignment="Left"/>
<Button Name="displayValueButton"
Content="Display value"
Width="75"
Height="23"
HorizontalAlignment="Left"
Click="displayValueButton_Click"/>
</StackPanel>
Code behind
public MainWindow()
{
InitializeComponent();
FloatValue = 1.234f;
this.DataContext = this;
}
public float FloatValue
{
get;
set;
}
private void displayValueButton_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(FloatValue.ToString());
}
As of now, I've solved this with a Converter that replaces dot with the System Decimal (which works) but what's the reason that this is neccessary? Is this by design and is there an easier way to solve this?
SystemDecimalConverter (in case someone else has the same problem)
public class SystemDecimalConverter : IValueConverter
{
private char m_systemDecimal = '#';
public SystemDecimalConverter()
{
m_systemDecimal = GetSystemDecimal();
}
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.ToString().Replace('.', m_systemDecimal);
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.ToString().Replace(m_systemDecimal, '.');
}
public static char GetSystemDecimal()
{
return string.Format("{0}", 1.1f)[1];
}
}
Looks like there's a solution for this:
http://www.nbdtech.com/Blog/archive/2009/03/18/getting-a-wpf-application-to-pick-up-the-correct-regional.aspx
Here is another discussion that can possibly help:
http://connect.microsoft.com/VisualStudio/feedback/details/442569/wpf-binding-uses-the-wrong-currentculture-by-default
Related
Can i simply add characters without binding this characters to my ViewModel?
I need these to show physical units like cm, mm, m, cm^3, ...
XAML:
<TextBox
Text="{Binding value_top}" //sth. like + "cm"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="50"/>
VW:
value_top = 22.9
Output aim:
22.9 cm
I know, I can overlay a Label, but i would like to know if there is another possibility.
Create a converter which will take the double and return a string. Here is an untested example to get you started:
public class DoubleToString: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var dbl = (double) value;
return $"{dbl} cm";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Double.Parse(Regex.Match(value.ToString(), "[\d.]+").Value);
}
}
I have a ListBox with some items bound to it. Those items are read from files like so:
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
bindList();
}
private void bindList()
{
var appStorage = IsolatedStorageFile.GetUserStoreForApplication();
string[] fileList = appStorage.GetFileNames();
List<Activity> activities = new List<Activity>();
foreach (string file in fileList)
{
string fileName = file;
string cYear = file.Substring(0, 4);
string cMonth = file.Substring(5, 2);
string cDay = file.Substring(8, 2);
string cHour = file.Substring(11, 2);
string cMinute = file.Substring(14, 2);
string cSeconds = file.Substring(17, 2);
DateTime dateCreated = new DateTime(int.Parse(cYear), int.Parse(cMonth), int.Parse(cDay), int.Parse(cHour), int.Parse(cMinute), int.Parse(cSeconds));
string dYear = file.Substring(20, 4);
string dMonth = file.Substring(25, 2);
string dDay = file.Substring(28, 2);
DateTime dateDeadline = new DateTime(int.Parse(dYear), int.Parse(dMonth), int.Parse(dDay));
string aTitle = file.Substring(31);
aTitle = aTitle.Substring(0, aTitle.Length - 4);
activities.Add(new Activity() { Title = aTitle, DateCreated = dateCreated.ToLongDateString(), Deadline = dateDeadline.ToLongDateString(), FileName = fileName });
}
activityListBox.ItemsSource = activities;
}
As you can see I'm reading dates and a title from the file name. Afterwards I bind them to the ListBox. What I want to do is change ListBox item (2 textbox and a hyperlink) color each time the dateDeadline is past the current date.
Here is how my ListBox looks like:
<ListBox HorizontalAlignment="Stretch"
Name="activityListBox"
VerticalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<HyperlinkButton Name="activityTitle"
FontSize="40"
Content="{Binding Title}"
HorizontalContentAlignment="Left"
Tag="{Binding FileName}"
Click="activityTitle_Click"
/>
<TextBlock Name="activityDateCreated"
Text="{Binding DateCreated, StringFormat='Stworzono: {0}'}"
Margin="10" />
<TextBlock Name="activityDeadline"
Text="{Binding Deadline, StringFormat='Deadline: {0}'}"
Margin="10" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Every guide I found was dealing with particular ListBox item (like changing 3rd item, 4th item etc.) and it does not solve my problem. I want to be able to check if the Deadline is past the current date each time files are loaded to the app and change it accordingly.
I'll greatly appreciate your help.
You can use a converter for just such a thing.
<UserControl.Resources>
<ResourceDictionary>
<local:DateToColorConverter x:Key="DateToColorConverter"/>
</ResourceDictionary>
</UserControl.Resources>
...
<TextBlock Name="activityDateCreated"
Text="{Binding DateCreated, StringFormat='Stworzono: {0}'}"
Margin="10"
Foreground="{Binding Deadline, Converter={StaticResource DateToColorConverter}" />
...
Your Converter (put this in your code behind)...
public class DateToColorConverter : IValueConverter
{
static SolidColorBrush _normalColor = new SolidColorBrush(Colors.Black);
static SolidColorBrush _pastDeadlineColor = new SolidColorBrush(Colors.Red);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is DateTime)
{
var deadline = value as DateTime;
return deadline < DateTime.Now ? _pastDeadlineColor : _normalColor;
}
return _normalColor;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
BTW - you should use an ObservableCollection instead of a List to hold your activity objects. Also, make sure your activity object supports INotifyPropertyChanged and that all your property methods call PropertyChanged.
In order to achieve this, you would first want to add a property Forecolor to your Activity class. This property will be a getter property that returns a color based on your condition (In this case, if the current date is greater than the deadline, return Red else Green). Note that I have changed your Deadline data type to Date to allow comparison of dates.
public DateTime Deadline { get; set; }
public Color Forecolor
{
get
{
if (DateTime.Now > Deadline)
return Colors.Red;
else
return Colors.Green;
}
}
Now bind you controls Foreground property to this property Forecolor
Foreground="{Binding Forecolor, Converter={StaticResource ColorToSolidColorBrush_ValueConverter}}"
Since the Foreground property expects a Brush, it will not work with just a color binding, you will need to use a converter that converts a Color to a Brush.
Define a Converter class in your project.
public class ColorToSolidColorBrushValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (null == value)
{
return null;
}
// For a more sophisticated converter, check also the targetType and react accordingly..
if (value is Color)
{
Color color = (Color)value;
return new SolidColorBrush(color);
}
// You can support here more source types if you wish
// For the example I throw an exception
Type type = value.GetType();
throw new InvalidOperationException("Unsupported type [" + type.Name + "]");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// If necessary, here you can convert back. Check if which brush it is (if its one),
// get its Color-value and return it.
throw new NotImplementedException();
}
}
Finally define the converter in your window resources.
<Window.Resources>
<local:ColorToSolidColorBrushValueConverter x:Key="ColorToSolidColorBrush_ValueConverter"/>
</Window.Resources>
Note: I have put in code from a WPF project. There may be a few syntax issues if your project is in WP7 (Though I think, it should work). However the principle is the same.
I have a propery PhoneNumber and in the UI, I have 2 textboxes, one is the prefix, and the other one is the postfix, how can I bind it to the property? (The property inside the DataContext).
<TextBox Grid.Column="0" MaxLength="3" /> //Prefix
<TextBlock Grid.Column="1" Text="-" />
<TextBox Grid.Column="2" /> //Postfix
The only way I see it work is with code behind using textbox1.Text + textbox2.Text... Is there a better way?
Thanks in advance :)
Just use two more properties in the data context
code is not complied or tested
public string PhoneNumber { get; set; }
public string Prefix
{
get
{
return PhoneNumber.Substring(0, 3);
}
set
{
// replace the first three chars of PhoneNumber
PhoneNumber = value + PhoneNumber.Substring(3);
}
}
public string Postfix
{
get
{
return PhoneNumber.Substring(3);
}
set
{
// replace the chars of starting from index 3 of PhoneNumber
PhoneNumber = PhoneNumber.Substring(0, 3) + value;
}
}
I think uou can use Converter for this purpose, the example going one way can look like this:
In this my Number is a string 000-000000, but you can surely change it.
In XAML:
<Window.Resources>
<conv:PostixConverter x:Key="PostfixConv" xmlns:conv="clr-namespace:Example.Converters"/>
<conv:PrefixConverter x:Key="PrefixConv" xmlns:conv="clr-namespace:Example.Converters"/>
</Window.Resources>
<StackPanel>
<TextBox MaxLength="3" Text="{Binding Number, Converter={StaticResource PrefixConv}}"/>
<TextBlock Text="-" />
<TextBox Text="{Binding Number, Converter={StaticResource PostfixConv}}"/>
</StackPanel>
And in code behind:
namespace Example.Converters
{
public class PrefixConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null) return null;
else return ((string)value).Substring(0, 3);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class PostixConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null) return null;
else return ((string)value).Substring(4);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
So I have a button. I want to set the visibility of the button according to the value of an integer property of a class. This requires a data binding and a converter.
The XAML code for the button is as follows:
<Window.Resources>
<local:Button1VisibilityConverter x:Key="Button1VisibilityConverter"/>
<local:ModeValues x:Key="ModeHolder"/>
</Window.Resources>
<Grid>
<StackPanel HorizontalAlignment="Left" Height="150" Margin="92,90,0,0" VerticalAlignment="Top" Width="301">
<Button Content="1" Height="58" Background="#FFA20000" Foreground="White" Visibility="{Binding Source={StaticResource ModeHolder}, Path=State, Converter=Button1VisibilityConverter}"/>
<Button Content="2" Height="58" Background="#FF16A200" Foreground="White"/>
<Button Content="3" Height="58" Background="#FF4200A2" Foreground="White"/>
</StackPanel>
</Grid>
My converter is as follows:
class Button1VisibilityConverter : IValueConverter
{
public object Convert(object value, Type targettype, object parameter, System.Globalization.CultureInfo culture)
{
int mode = (int)value;
if (mode == ModeValues.Red)
return System.Windows.Visibility.Visible;
else
return System.Windows.Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
The class that has the property I want to control the visibility is as follows:
public class ModeValues : IObservable<int>
{
private int _state = -1;
public static int Red
{
get
{
return 0;
}
}
public static int Green
{
get
{
return 1;
}
}
public static int Purple
{
get
{
return 2;
}
}
public int State
{
get
{
return this._state;
}
set
{
this.State = value;
}
}
}
I have no idea why it isn't working. I thought I had to bind the visibility to the property of the instance of the ModeHolder, make the ModeHolder observable, and convert the int to a visibility. What am I missing?
Converter=Button1VisibilityConverter
should be:
Converter={StaticResource Button1VisibilityConverter}
May someone tell me whats wrong with this sourcecode?
when i click the button its not updating ist value?
At first binding the converter makes his job.
the sourcecode is pretty big so i will post only some snippets.
XAML:
Instances is type of ObservableCollection
<ListBox Name="Instances">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Tag="{Binding Path=Instance.Name}" Content="{Binding Path=Instance.Active, Converter={StaticResource BTSC}}" Click="ChangeAccess"/>
<TextBlock Text="{Binding Path=Instance.Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Converter:
public class BoolToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (((Boolean)value) == true)
return "No";
else
return "Yes";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Event:
private void ChangeAccess(object sender, RoutedEventArgs e)
{
for...
if ((sender as Button).Tag.ToString() == (DP.Instances[i].Instance as CInstance).Name)
{
SkipIfAndElse...
DP.Instances[i].Instance.Active = true;
}
}
CInstance:
class CInstance : INotifyPropertyChanged
{
private Boolean active;
public Boolean Active
{
get { return active; }
set
{
active = value;
NotifyPropertyChanged("Access");
}
}
}
All other values of the CInstance class are updating as expected.
In your CInstance class
NotifyPropertyChanged("Access");
should be
NotifyPropertyChanged("Active");
I would suggest you start using some kind of INPC framework. I personally like Simon Cropp's Fody.
Fody adds the appropriate OnNotifyPropertyChanged as a post compilation step, which means you don't get the Runtime hit that you get with Expression based solutions.
At the end of the day, string based OnNotifyPropertyChanged are all pretty fragile.