what wrong with my binding convert? - wpf

I have some interface and class that contain List
public interface IListContain
{
Int32 ItemCount
{
get;
}
}
public class myStackPanel : StackPanel, IListContain
{
... // implimentation ...
}
I want to do binding between some TextBlock and the variable that 'point' on the object instance myStackPanel - so i wrote is in this way
XAML:
<TextBlock x:Name="ItemCount" FontSize="12" Text="{Binding ElementName=ListContainObject, Path=ItemCount,Converter={StaticResource IntConverter}}" />
The convert code ( int to string )
public class IntToStringConverter : IValueConverter
{
public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
{
return ( ( int )value ).ToString();
}
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
{
int result;
var succes = int.TryParse( ( string )value, out result );
return succes ? result : 0;
}
}
And on the cs file of the xaml i define in the constructor the
DataContext = this;
But still - nothing work !!!
I dont have fire convert event !!!
And i dont know what i did wrong.
Please help ...
Thanks.
( this code is in silverlight and the ListContainObject is not null ... its point on real object )

Can't say for sure without you showing us your implementation, but it's likely you've not used a dependency property for ItemCount / implemented INotifyPropertyChanged. Thus, WPF has no idea when the property is changing and the UI won't update accordingly (nor will your redundant converter).

Your using ElementName in your binding - this must resolve to the "name" field of an object listed in the xaml file - Im not sure from your code if thats the case. For example if you had in your xaml a ListBox control with name="my_listbox" then it would be fine for your binding to icnlude ElementName="my_listbox", but the way you describe it here Ive got a feeling your ListContainObject is declared somewhere in code behind?

You don't need a string converter when you bind an int sincer is done automatically. Probably your issue is that you don't have any element having x:Name="ListContainObject"

Related

How to bind int to Visibility in WPF?

I have BudgetControlType Properties that has 1 .. 7 value
if(BudgetControlType ==1)
dataComboBox1.Visibility=Visibility.Visiblile;
dataComboBox2 to dataComboBox7 =Visibility.Hidden;
if(BudgetControlType ==2)
dataComboBox1.Visibility=Visibility.Visiblile;
dataComboBox2.Visibility=Visibility.Visiblile;
dataComboBox3 to dataComboBox7 =Visibility.Hidden;
and so on...
How to do this in xaml?
Here is another approach I have used in the past using WPFConverters.
<TabItem.Visibility>
<Binding Path="SomeObservableCollection.Count">
<Binding.Converter>
<converters:ConverterGroup>
<converters:ExpressionConverter Expression="{}{0} > 0" />
<BooleanToVisibilityConverter />
</converters:ConverterGroup>
</Binding.Converter>
</Binding>
</TabItem.Visibility>
The ConvertGroup allows for multiple converters to be run sequentially.
The ExpressionConverter lets you define an arbitrary expression. In my case I want the TabItem to be visible if the collection count is greater than zero. Being defined in xaml means escaping characters and a somewhat awkward syntax but it works well enough!
The BooleanToVisibilityConverter converts the boolean result from the expression to our desired visibility.
For Elham, BudgetControlType could be bound to as long as it implemented INotifyPropertyChanged. An equals expression is done like this (I'm returning true if the bound value equals 7):
<converters:ExpressionConverter Expression="{}{0} == 7" />
You can use 1,2,4,8,... and convert it to Visibility
for example if your int number is 6 (2+4) then Control with paramerter 2 and Control with parameter 4 is Visible!
public class IntToVisibilityConverter:IValueConverter
{
private int val;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int intParam = (int)parameter;
val = (int)value;
return ((intParam & val) != 0) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
And in xaml :
<ComboBox Visibility="{Binding Path=MyEnum,UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IntToVisibilityConverter}, ConverterParameter=1}"/>
<ComboBox Visibility="{Binding Path=MyEnum,UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IntToVisibilityConverter}, ConverterParameter=2}"/>
<ComboBox Visibility="{Binding Path=MyEnum,UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IntToVisibilityConverter}, ConverterParameter=4}"/>
The best way I'd say would be to go with properties on your ViewModel, and bind to them.
example (you'll have to massage it a bit, but it's fairly simple from here) :
public Visibility dtcb1 { get; set; }
// all the rest till 7
// Somewhere in your logit / constructor :
dtcb1 = BudgetControlType == 1 ? Visible : Hidden;
// and so on
And on your xaml you'll bind your visibility to dtcb1
You can make the property boolean, and use a boolean to visibility converter as well (as per this answer for example, or just google yourself)

WPF user control to display years and months from one total months value

I have a value in a database that is the totals number of months. In my WPF UI I need to display and update this value as the number of years and the number of months. I am struggling to get the bindings to work in this control so that I can view and update this one value of total months using the two separate textboxes (years and months)
Can anyone help with this?
In the class that is the source of your bindings (e.g. a ViewModel) you can add two properties that calculate the two values whenever needed. For example:
private const int MonthsInAYear = 12; // pedagogic purposes only :)
// This field contains the updated database value
private int _timeInMonths;
public int TimeYears
{
get { return _timeInMonths / MonthsInAYear; }
}
public int TimeMonths
{
get { return _timeInMonths % MonthsInAYear; }
}
If you want these values to be automatically updated, make this class implement the INotifyPropertyChanged interface and raise the PropertyChanged event for both properties whenever the value of _timeInMonths changes.
I guess you should use a converter to convert your month value to the corresponding Year and month values.Or you can do it in your viewmodel itself
Sample
public class MonthConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if(((string)parameter)=="Year")
{
return (int)value / 12;
}
if (((string)parameter) == "Month")
{
return (int)value % 12;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
and in your xaml
<StackPanel Orientation="Horizontal">
<TextBlock Height="23" Text="{Binding TotalMonths,Converter={StaticResource MonthConverter},ConverterParameter='Year',StringFormat={}{0}Years}"/>
<TextBlock Height="23" Text="{Binding TotalMonths,Converter={StaticResource MonthConverter},ConverterParameter='Month',StringFormat={}{0}Months}"/>
</StackPanel>

How to set the default value of DateTime to empty string?

I have a property called Raised_Time, this property shows the time at which alarm is raised in datagrid Cell. I don't want to show anything in the datagrid cell when user creates any alarm, it just display the empty cell.
I googled in the internet and found that the default value of DateTime can be set using DateTime.MinValue and this will display MinValue of datetime i:e "1/1/0001 12:00:00 AM".
Instead I want that the datagrid cell remain blank until alarm is raised, it don't show any time.
I think datatrigger can be written in this case. I am not able to write the datatrigger for this scenario. Do I need a converter also that checks if DateTime is set to DateTime.MinValue the leave the datagrid cell blank??
Please help!!
I would use a Converter for this because it's something I can easily see reusing in the future. Here's one I used to use that took a string value of the DateFormat as the ConverterParameter.
public class DateTimeFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((DateTime)value == DateTime.MinValue)
return string.Empty;
else
return ((DateTime)value).ToString((string)parameter);
}
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
I see two easy options to solve this:
You use the Nullable data type DateTime?, so that you can store null instead of DateTime.MinValue if the alarm time is not set.
You can use a converter, here is an example.
How about just changing your property to link to a private field of DateTime e.g.:
public string Raised_Time
{
get
{
if(fieldRaisedTime == DateTime.MinValue)
{
return string.Empty();
}
return DateTime.ToString();
}
set
{
fieldRaisedTime = DateTime.Parse(value, System.Globalization.CultureInfo.InvariantCulture);
}
}
I use a nullable datetime for this, with an extension method like:
public static string ToStringOrEmpty(this DateTime? dt, string format)
{
if (dt == null)
return string.Empty;
return dt.Value.ToString(format);
}

WPF Binding with invalid value for source

I have a TextBox that binds to an integer property.
What can I do so that when there is nothing no valid text in the TextBox that the property gets set to 0.
Really I think this can be extended so that if the binding fails then we set the source to default(T).
I need a nudge in the right direction.
TargetNullValue is the opposite of what I'm looking for(I think), that sets the TextBox text when the source is null. I want when the TextBox text is an invalid binding value to set the source as its default.
Applying a Converter such as the following to your binding should do the trick:
public class TextConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
int actual = (int)value;
return actual.ToString();
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
string actual = (string)value;
int theValue = 0;
int.TryParse(actual, out theValue);
return theValue;
}
}
Your TextBox binding would look something like this:
<TextBox Text="{Binding ... Converter={StaticResource convert}}"></TextBox>
With the convertor defined as a resource of your Window/Control/...

Problem with binding Nullable value to WPF ComboBox

I am binding a WPF ComboBox to a nullable property of type MyEnum? (where MyEnum is an enumerated type)
I am programmatically populating the ComboBox items like this:
// The enum type being bound to
enum MyEnum { Yes, No }
// Helper class for representing combobox listitems
// (a combination of display string and value)
class ComboItem {
public string Display {get;set}
public MyEnum? Value {get;set}
}
private void LoadComboBoxItems()
{
// Make a list of items to load into the combo
var items = new List<ComboItem> {
new ComboItem {Value = null, Display = "Maybe"},
new ComboItem {Value = MyEnum.Yes, Display = "Yes"},
new ComboItem {Value = MyEnum.No, Display = "No"},};
// Bind the combo's items to this list.
theCombo.ItemsSource = items;
theCombo.DisplayMemberPath = "Display";
theCombo.SelectedValuePath = "Value";
}
Also in the code-behind, I am setting the DataContext to an instance of a class with a property called TheNullableProperty (for this example anyway) of type MyEnum?.
The binding of theCombo's SelectedValue is done in my XAML file.
<ComboBox
Name="theCombo"
SelectedValue="{Binding Path=TheNullableProperty,
UpdateSourceTrigger=PropertyChanged}"/>
Problem:
When the value of the bound property is initially non-null, the combo box displays the value properly.
But when the value of the bound property is initially null, the combo box is blank.
It looks like every aspect of data binding is working apart from the representation of the null value when the combobox is first shown.
For example: you can select Maybe from the dropdown, and the bound property is correctly set to null. It's just that initial loading that's failing. Maybe I need to just manually set the SelectedValue initially...
What I Ended Up Doing
Add a hidden textblock databound to the underlying nullable enum value via a Converter that converts from the nullable enum to a string (enum.ToString, or "null").
Load up the combo box with 'ComboItems' each having a string Label (displayed in the combo) and a string Value equal to the enum values as strings (and "null" for the null value).
Data-bind the combo box to the textblock.
/// <summary>
/// Convert from EnumeratedType? to string (null->"null", enum values->ToString)
/// </summary>
public class EnumConverter<T> : IValueConverter where T:struct
{
public static string To(T? c)
{
if (c == null)
return "null";
return c.ToString();
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return To((T?)value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var s = (string) value;
if (s == "null")
return null;
return (T?)Enum.Parse(typeof(T), s);
}
}
public class MyEnumConverter : EnumConverter<MyEnum>
{
}
public class ComboItem
{
public string Value { get; set; }
public string Label { get; set; }
public ComboItem(MyEnum? e, string label)
{
Value = MyEnumConverter.To(e);
Label = label;
}
}
static IEnumerable<ComboItem> GetItems()
{
yield return new ComboItem(null, "maybe");
yield return new ComboItem(MyEnum.Yes, "yup");
yield return new ComboItem(MyEnum.No, "nope");
}
private void SetupComboBox()
{
thecombo.ItemsSource = GetItems().ToList();
}
You cannot bind to a null value by design in WPF (at least 3.5 SP1). This means that at the moment Source gets a Null as a value your Binding will be automatically broken and won't work even if you specify a valid value for the Source. You need to provide some "heart beating" mechanism for your binding via Value Converter. So that Converter transforms null value to some "Undefined" (non-null) for the Targets and than is able to convert your "Undefined" back to null...
There seem to be many issues with having null be a valid value for a ComboBox or ListBox, as similar questions have been asked here, here and here.
There hasn't been a superb, ogre-slaying answer to any of those.
My own suggestion is to add Maybe as a member of MyEnum. I know it's just an example but if everything with a MyEnum has it as nullable, then maybe MyEnum should have an Undefined member (or something similar), this is pretty common with enums anyway.
I found this solution online, which I think is pretty deck. I don't fully understand the implementation -- it's some pretty serious .NET kung fu -- but it's great from my perspective as a user. Give it a try:
http://philondotnet.wordpress.com/2009/09/18/how-to-select-null-none-in-a-combobox-listbox-listview/
DependencyProperty.UnsetValue Field
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace MyConverters
{
[ValueConversion(typeof(DateTime), typeof(String))]
public class StringToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int number;
return int.TryParse(value.ToString(), out number) ? number : DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.ToString();
}
}
}
Here's a veryy simple solution to this problem:
Instead of having an item with a value of null in your ItemsSource, use DbNull.Value as item or as the item's value property.
I described this approach in detail here: https://stackoverflow.com/a/44170898/6713814

Resources