So far, i have an ObservableCollection<T> for objects.
I always want to display the last inserted element into a TextBlock. I implemented two solutions in XAML, but both not working:
<TextBlock Text="{Binding Path=entries.Last().message, FallbackValue=...}" />
<TextBlock Text="{Binding Path=entries[entries.Length-1].message, FallbackValue=...}" />
This one works, but references the first entry:
<TextBlock Text="{Binding Path=entries[0].message, FallbackValue=...}" />
Am i missing something? Is it possible to do with pure XAML?
Solution 1 :
You can use a custom converter to achieve this :
Converter class :
class LastItemConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
IEnumerable<object> items = value as IEnumerable<object>;
if (items != null)
{
return items.LastOrDefault();
}
else return Binding.DoNothing;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
Xaml :
<Application.Resources>
<local:LastItemConverter x:Key="LastItemConverter" />
</Application.Resources>
<TextBlock Text="{Binding Path=entries, Converter={StaticResource LastItemConverter}}" />
Solution 2 :
The other way is to create a new property in your model that returns the entry :
public Object LastEntry => entries.LastOrDefault();
Xaml :
<TextBlock Text="{Binding Path=LastEntry, ... " />
Related
I need access to the entry component that the converter is attached to, so I can change the cursor position with Entry.CursorPosition.
I have a BindableObject that is also an IValueConverter, how can I get to the Entry
public class MaskConverter : BindableObject, IValueConverter
{
...
}
In XAML name the Entry and use x:Reference:
Converter with MyEntry property (ConvertBack for Mode=TwoWay not shown):
public class MyConverter : BindableObject, IValueConverter
{
public Entry MyEntry { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var entry = MyEntry;
Debug.WriteLine($"convert:pos:{entry?.CursorPosition}:");
return (string)value;
}
...
}
XAML using MyEntry property (MyText is a property on the viewmodel, not shown):
<ContentPage.Resources>
<local:MyConverter x:Key="myConverter" MyEntry="{x:Reference myEntry}" />
...
</ContentPage.Resources>
...
<Entry x:Name="myEntry" Text="{Binding MyText,
Converter={StaticResource myConverter}}">
Without the MyEntry property the named Entry might be passed to the converter using ConverterParameter:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var param = parameter as Entry;
Debug.WriteLine($"convert:pos:{param?.CursorPosition}:");
return (string)value;
}
XAML when passing the named Entry in ConverterParameter:
<ContentPage.Resources>
<local:MyConverter x:Key="myConverter" />
...
</ContentPage.Resources>
...
<Entry x:Name="myEntry" Text="{Binding MyText,
Converter={StaticResource myConverter},
ConverterParameter={x:Reference myEntry}}">
As the title suggest I want to hide my grid when its itemsource has 0 rows.
<sdk:DataGrid Name="RegionDataGrid" Visibility="{Binding <!-- WHAT_SHOULD_COME_HERE -->}" AutoGenerateColumns="False" VerticalAlignment="Top" IsReadOnly="False" Height="Auto" Width="Auto" >
First you need a converter which will return Collapsed when List is empty.
public class EmptyCollectionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ICollection list = (ICollection)value;
if (list == null)
return Visibility.Collapsed;
return list.Count != 0 ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then you can use RelativeSource binding with value Self to bind the ItemsSource,
<sdk:DataGrid Visibility="{Binding ItemsSource, RelativeSource={RelativeSource Self}, Converter={StaticResource EmptyCollectionConverter}}" />
I would like to use static texts fetched from a web service in my WP7 app. Each text has a Name (the indetifier) and a Content property.
For example a text could look like this:
Name = "M43";
Content = "This is the text to be shown";
I would then like to pass the Name (i.e. the identifier) of the text to an IValueConverter, which would then look up the the Name and return the text.
I figured the converter to look something like this:
public class StaticTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
return App.StaticTexts.Items.SingleOrDefault(t => t.Name.Equals(value)).Content;
}
return null;
}
}
Then in the XAML:
<phone:PhoneApplicationPage.Resources>
<Helpers:StaticTextConverter x:Name="StaticTextConverter" />
</phone:PhoneApplicationPage.Resources>
...
<TextBlock Text="{Binding 'M43', Converter={StaticResource StaticTextConverter}}"/>
However, this does not seem to work and I am not sure that I pass in the value to the converter correctly.
Does anyone have some suggestions?
I finally found the answer. The answer was a mix between that of #Shawn Kendrot and another question I asked here: IValueConverter not getting invoked in some scenarios
To summarize the solution for using the IValueConverter I have to bind my control in the following manor:
<phone:PhoneApplicationPage.Resources>
<Helpers:StaticTextConverter x:Name="TextConverter" />
</phone:PhoneApplicationPage.Resources>
<TextBlock Text="{Binding Converter={StaticResource TextConverter}, ConverterParameter=M62}" />
Since the ID of the text is passed in with the converter parameter, the converter looks almost the same:
public class StaticTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (parameter != null && parameter is string)
{
return App.StaticTexts.Items.SingleOrDefault(t => t.Name.Equals(parameter)).Content;
}
return null;
}
}
However, as it turns out, the binding and thus the converter is not invoked if it does not have a DataContext. To solve this, the DataContext property of the control just has to be set to something arbitrary:
<TextBlock DataContext="arbitrary"
Text="{Binding Converter={StaticResource TextConverter}, ConverterParameter=M62}" />
And then everything works as intended!
The problem lies in your binding. It will check the DataContext, and on this object, it will try to evaluate the properties M62 and ValueboxConsent on that object.
You might want to add static keys somewhere in your application where you can bind to:
<TextBlock Text="{Binding Source="{x:Static M62.ValueboxConsent}", Converter={StaticResource StaticTextConverter}}" />
Where M62 is a static class where your keys are located.. like so:
public static class M62
{
public static string ValueboxConsent
{
get { return "myValueBoxConsentKey"; }
}
}
If you want to use a value converter, you'll need to pass the string to the parameter of value converter
Xaml:
<TextBlock Text="{Binding Converter={StaticResource StaticTextConverter}, ConverterParameter=M43}"/>
Converter:
public class StaticTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (parameter != null)
{
return App.StaticTexts.Items.SingleOrDefault(t => t.Name.Equals(parameter)).Content;
}
return null;
}
}
xmlns:prop="clr-namespace:MyProj.Properties;assembly=namespace:MyProj"
<TextBlock Text="{Binding Source={x:Static prop:Resources.MyString}, Converter={StaticResource StringToUpperCaseConverter}}" />
I am trying to learn how to use IValueConverter. I have the following converter:
[ValueConversion(typeof(string), typeof(string))]
public class RequiredFieldConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return "";
return value.ToString() + "*";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return "";
var str = value.ToString();
return str+"Convert Back testing";
}
}
I have added the RequiredFieldConverter resource in my app.xaml file and I want to try it as:
<TextBox Name="textBox2" Width="120" />
<TextBox Text="{Binding ElementName=textBox2, Path=Text, Converter=RequiredFieldConverter}" Name="textBox3" Width="120" />
I was hoping that when I type "hello" in textbox2 it shows "hello*" in textbox3 but it does not work. In fact I get the following exception at runtime:
{"Unable to cast object of type 'System.String' to type 'System.Windows.Data.IValueConverter'."}
also I know that the value converter function is working because it works when I do:
Content="{Binding Source={StaticResource Cliente}, Converter={StaticResource RequiredFieldConverter}}"
... You are getting the error as it trying to interpret RequiredFieldConverter as an reference to an IValueConverter. You need to use a StaticResource or DynamicResource to reference the converter as you have done in your second example.
<TextBox Text="{Binding ElementName=textBox2, Path=Text, Converter={StaticResouce RequiredFieldConverter}}" Name="textBox3" Width="120" />
I am trying to bind a TextBlock's Text property by converting the Total Seconds i.e
1004 to Minutes:Seconds and I can successfully pull my Seconds from the XML but I dont know how to work with Getters and Setters so I can convert my Seconds to Minutes:Seconds
I had a look at TimeSpan and I know it can do what I ask but I dont know how to write the getter and setter so it will convert the integer values (seconds) to a Minute:Seconds format.
This is what I have in my Class so far
public class Stats
{
public TimeSpan Time {get;set;}
}
any help would be greatly appreciated,
thanks
John
To do it as a property you can do:
public class Stats {
public TimeSpan Time { get; set; }
public string TimeFormated { get { return Time.TotalMinutes + ":" + Time.Seconds; } }
}
Although you really should do that in your XAML since the what are doing is layout:
<StackPanel Orientation="Horizontal">
<TextBlock Text={Binding Time.TotalMinutes}" />
<TextBlock Text=":" />
<TextBlock Text=={Binding Time.Seconds}" />
</StackPanel>
Would recommend this converter instead (since the two previous answers will give you 2:1 when you really want 2:01 -
public class FriendlyTimeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
TimeSpan ts = TimeSpan.FromSeconds((int)value);
return String.Format("{0}:{1:D2}", ts.Minutes, ts.Seconds);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Note the :D2 specifier for format strings.
And to use it, you specify it at the same time as your binding:
<phone:PhoneApplicationPage.Resources>
<util:FriendlyTimeConverter x:Key="FriendlyTimeConverter"/>
</phone:PhoneApplicationPage.Resources>
...
<TextBlock Text="{Binding timeRemaining, Converter={StaticResource FriendlyTimeConverter}}" Name="TimerDisplay" Grid.Column="4" HorizontalAlignment="Right" Margin="12,0" Style="{StaticResource PhoneTextTitle2Style}"></TextBlock>
Use a converter.
XAML:
<phone:PhoneApplicationPage.Resources>
<classes:TimeSpanConverter x:Key="c" />
</phone:PhoneApplicationPage.Resources>
...
<TextBlock Text="{Binding Time, Converter={StaticResource c}}" />
C#:
public class TimeSpanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var time = (TimeSpan) value;
return time.TotalMinutes + ":" + time.Seconds;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}