Allow NULL in a WPF Extended Toolkit DecimalUpDown control - c#

I have a property on my view model of type decimal?. NULL should be a valid value for this property, but when I erase the text from the DecimalUpDown control, a validation error occurs and the property is not given the value NULL (whatever it was previously remains).
The control is declared in xaml like:
<xctk:DecimalUpDown ValueChanged="UpDownBase_OnValueChanged" Text="{Binding ServiceSize}" Minimum="0" Grid.Column="4" Grid.Row="2" Margin="5" IsEnabled="{Binding IsEditable}"/>
It will bind correctly if I enter a number
But as soon as the number is erased a validation error occurs, and the value can't be set back to NULL (in this case the model still has "5" as the value for "ServiceSize").
Validation.GetHasError() returns true for this control. Can I remove the Validation Rules entirely somehow?

You can implement an IValueConverter to handle empty input.
public class DecimalUpDownValueConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
// handle input on a case-to-case basis
if(value == null)
{
// Do something
return 0;
}
else
{
return value;
}
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
// Do the conversion from model property to DecimalUpDownValue
return value;
}
}
On your view: (Assuming you added the DecimalUpDownValueConverter as a static resource)
<xctk:DecimalUpDown ValueChanged="UpDownBase_OnValueChanged" Text="{Binding ServiceSize, Converter = { StaticResource DecimalUpDownValueConverter }}" Minimum="0" Grid.Column="4" Grid.Row="2" Margin="5" IsEnabled="{Binding IsEditable}"/>

Related

IValueConverter returning as object not value that is expected

I'm trying to convert a string on a label (or anything) to another string. This is for Icon fonts.
Converter
[ValueConversion(typeof(string), typeof(string))]
public class StringToIconConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string property = ((string)value).ToLower();
switch (property)
{
case "maximize": return #"\e901";
default return property;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
...
}
Then I've added it to my pages that need it
<Helpers:StringToIconConverter x:Key="Icon" />
And this is how I'm setting it
<Button Style="{StaticResource NavButton}"
Tag="Document"
Command="{Binding GotoDataMatrixEnterCommand}">
<Button.Content>
<Label Content="{Binding Source={RelativeSource Self},
Path=Tag,
Converter={StaticResource Icon},
UpdateSourceTrigger=LostFocus}"
Tag="Document" />
</Button.Content>
</Button>
And what I'm getting is
Windows.System.Control.Label in its place. Am I not converting it properly, I'm not quite sure why it is not replacing the correct information. I've tried a few things, and reading up online though I'm stuck at the moment. Plus when I try to debug it doesn't work (it never hits the breakpoints)
The problem is with the Binding on Label.Content. You should use RelativeSource, not Source.
It should be:
RelativeSource={RelativeSource Mode=Self}
Also, you have a syntactic error in the switch statement of StringToIconConverter: default return property; should be default: return property; (you're missing a colon).

SelectedItem binding on ComboBox not showing selected value

I'm trying to build a settings page to allow the user to choice which action to execute on item swipe, like the Outlook app.
To do this I created an enum containing the available actions, and I'm binding it to a ComboBox.
Everything works, the user can choose the action and his choice is saved correctly. The problem is that the ComboBox doesn't show the selected item when I navigate to the page, it shows it only after selection.
This means that if user changes selection then the ComboBox is updated, but the selected item is shown as blank upon navigation.
Here's my code:
(XAML)
<ComboBox x:Uid="LeftActionComboBox"
Grid.Row="0"
HorizontalAlignment="Stretch"
SelectedItem="{Binding LeftSwipeActionType, Mode=TwoWay, Converter={StaticResource StringToSwipeActionTypesConverter}}"
ItemsSource="{Binding LeftSwipeActionType, Converter={StaticResource EnumToStringListConverter}}"/>
(VM Property)
public SwipeActionTypes LeftSwipeActionType
{
get { return _settings.LeftSwipeActionTypeProperty; }
set
{
_settings.LeftSwipeActionTypeProperty = value;
// RaisePropertyChanged causes a StackOverflow, but not using it is not the problem since the ComboBox is empty only before set
}
}
(Converter StringToSwipeActionTypesConverter, localization-ready)
// Returns localized string value for the Enum
public object Convert(object value, Type targetType, object parameter, string language)
{
var enumValue = (SwipeActionTypes) value;
switch (enumValue)
{
case SwipeActionTypes.Copy:
return App.ResourceLoader.GetString("CopySwipeActionName");
case SwipeActionTypes.Delete:
return App.ResourceLoader.GetString("DeleteSwipeActionName");
default:
throw new ArgumentOutOfRangeException();
}
}
// Parses the localized string into the enum value
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
var stringValue = (string) value;
if (stringValue.Equals(App.ResourceLoader.GetString("CopySwipeActionName")))
{
return SwipeActionTypes.Copy;
}
if (stringValue.Equals(App.ResourceLoader.GetString("DeleteSwipeActionName")))
{
return SwipeActionTypes.Delete;
}
return null;
}
(Converter EnumToStringListConverter)
public object Convert(object value, Type targetType, object parameter, string language)
{
var valueType = value.GetType();
return Enum.GetNames(valueType).ToList();
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
Any idea on why this is failing?
The reason you are getting a StackOverflow exception is because every time you change LeftSwipeActionType property you are changing the ItemsSource of the ComboBox which changes the SelectedItem which fires INotifyPropertyChanged which changes the ItemsSource and so on and so on.
Once you stop using the same property for ItemsSource and SelectedItem then the correct initial selection will be set.
Rather than use a converter to create your ItemsSource you should just create is in your ViewModel
public MyViewModel(type enumType)
{
SourceForItems = Enum.GetValues(enumType);
}
public IEnumerable SourceForItems { get; private set; }
First of all, here is whats wrong with your approach:
You are binding your ItemsSource to the same property as the SelectedItem, even tough you are using a converter this can cause an infinite update circle - and you don't want that.
Generating the same static list of elements over and over again seems a bit wasteful. Instead of passing an instance of a type, lets just pass the type itself to the converter:
EnumToMembersConverter.cs
public class EnumToMembersConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return Enum.GetValues((Type)value).ToList();
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return DependencyProperty.UnsetValue;
}
}
XAML
ItemsSource="{Binding Source={x:Type whateverNamespace:SwipeActionTypes}, Converter={StaticResource EnumToMembersConverter}}"
This will give you all Values of SwipeActionTypes, therefore you can bind it directly, without converting back again.
SelectedItem="{Binding LeftSwipeActionType, Mode=TwoWay}"
There is nothing wrong with using a ComboBox for types other than string, so lets make this your base for further steps:
<ComboBox x:Uid="LeftActionComboBox"
Grid.Row="0"
HorizontalAlignment="Stretch"
SelectedItem="{Binding LeftSwipeActionType, Mode=TwoWay}"
ItemsSource="{Binding Source={x:Type whateverNamespace:SwipeActionTypes}, Converter={StaticResource EnumToMembersConverter}}"/>
The reason you wrote all those converts is probably because the ComboBox showed strange values instead of readable strings. No worries, we already have your converter, you just need to invert it (Convert SwipeActionTypes to String) and apply it to a TextBox:
<ComboBox x:Uid="LeftActionComboBox"
Grid.Row="0"
HorizontalAlignment="Stretch"
SelectedItem="{Binding LeftSwipeActionType, Mode=TwoWay}"
ItemsSource="{Binding Source={x:Type whateverNamespace:SwipeActionTypes}, Converter={StaticResource EnumToMembersConverter}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=., Converter = {StaticResource SwipeActionTypesStringConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Note, I didn't run this code so you might need to adjust the used namespaces accordingly

Why binding with converter changes properties not bound to on GUI?

I bound my text box to property (only text box) and used converter which just return opposite bool value.
XAML
<TextBox Height="23" HorizontalAlignment="Left" Margin="13,41,0,0" Text="{Binding Path=CurrentProfile.profileName}" IsEnabled="{Binding Path=CurrentProfile.isPredefined, Converter={StaticResource PredefinedToControlEnabled}}" VerticalAlignment="Top" Width="247" Grid.ColumnSpan="2" TabIndex="1" />
Converter
public class PredefinedToControlEnabled: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var isPredefined = (bool)value;
return !isPredefined;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
When the property value isPredefined is true, the IsEnabled property of TextBox is set correctly to false. When the isPredefined is false, the converter returns false and all controls on GUI sets IsEnabled property to false, what means that application is not useable anymore (it works in background naturally). Why it is happening?
How does it look like:
Found,
VS automagically add line to Window properties
IsEnabled="{Binding Path=CurrentProfile.isPredefined}"
but the question still is, how?

Value Converter not Being Called XAML

I have put breakpoints inside the Value Converter and they are never triggered, but the page renders with no image being shown.
The XAML:
xmlns:datatypes="clr-namespace:DataTypes_Portable;assembly=DataTypes_WinPhone8"
...
<phone:PhoneApplicationPage.Resources>
<datatypes:WinPhone8ImageConverter x:Key="ImageConverter" />
</phone:PhoneApplicationPage.Resources>
...
<Image x:Name="LevelImage" HorizontalAlignment="Left" Height="Auto" VerticalAlignment="Top" Width="Auto" Margin="0" Grid.ColumnSpan="5" Source="{Binding Converter={StaticResource ImageConverter}, Path=App.Main.Game.CurrentLevel.CurrentPart.Image}"/>
The CS:
public class WinPhone8ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var imageProvider = value as WinPhone8ImageProvider;
return imageProvider.Image;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
From what I can understand (by process of trial and elimination and looking at what exceptions are thrown) the problem is coming with part of the XAML where I am trying to bind to the value.
At a breakpoint the value at App.Main.Game.CurrentLevel.CurrentPart.Image is being set correctly (ie is an instance of WinPhone8ImageProvider).
It turns out this was nothing to do with the converter at all. The value was binding before the image had loaded (so the source was empty). For future reference check to make sure you are implementing theINotifyPropertyChanged correctly in your view models.

WPF grid IsEnabled using ValueConverter

I have a WPF window with a Grid and a TreeView. The datacontext for the Grid is bound to the selected item on the treeview. However, because not all treeviewitems are applicable, I want to disable the grid if the treviewitem isn't applicable. So, I created a value converter to do a null check and return a bool. (Applicable items would not be null in this case)
The problem is that the value converter is never used. I set break points and they are never hit. I have other value converters I'm using and they all work just fine.
Is there something I'm missing?
<Grid Grid.Column="1" Grid.Row="0" DataContext="{Binding MyVal}" IsEnabled="{Binding MyVal, Converter={StaticResource NullCheckConverter}}" Margin="2,2,2,2">
Not that it's important for this question but here is the ValueConverter code:
internal class NullCheckValueConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return !(value == null);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
That's because you bind DataContext to the same value as you binding IsEnabled. So for IsEnabled it actually looking for MyVal.MyVal. Replace to:
IsEnabled="{Binding Converter={StaticResource NullCheckConverter}}"
Also further if you have issues with binding, check in debug mode output window for binding errors.

Categories

Resources