I a have typical label that I want to control its visibility by a property that is null/empty or not.
I've put breakpoints and also log and it seems that return value is true but still it does not show the element. When I scroll my listview then they are visible but sometimes still not.. There are several items, sometimes some of them are visible sometimes not.. it is changable..
here my converter
public class TestBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var result= value != null && !value.ToString().Equals("");
Console.WriteLine("Result: " +result);
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and the property
public string LocalizedReadoutDescription
{
get
{
Console.WriteLine("Description: " + dataItem.Description);
string localizedDescription = null;
if (!string.IsNullOrEmpty(this.dataItem.Description))
{
string[] descriptionKeyParts = this.dataItem.Description.Split(';');
localizedDescription = descriptionKeyParts[0];
if (!string.IsNullOrEmpty(localizedDescription))
{
localizedDescription =
this.getLocalizedString(Constants.Localization.LogicalItemDescriptionFmt,
localizedDescription);
}
}
return localizedDescription;
}
}
and Xaml Code
<ContentView.Resources>
<converters:TestBooleanConverter x:Key="nullToBoolConverter"/>
.....
</ContentView.Resources>
.....
<StackLayout Orientation="Horizontal" Margin="4,2" Grid.Column="1" VerticalOptions="StartAndExpand"
HorizontalOptions="FillAndExpand" Spacing="0" BackgroundColor="White">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="Help_Tapped" CommandParameter="{Binding}"/>
</StackLayout.GestureRecognizers>
<Label x:Name="HelpLabel" Style="{StaticResource InfoIconLabel}" Text="{x:Static resx:UI.Icon_Info}" Margin="0"
HorizontalOptions="EndAndExpand" VerticalOptions="Start" IsVisible="{Binding LocalizedReadoutDescription,
Converter={StaticResource nullToBoolConverter}}" FontSize="Micro" LineBreakMode="NoWrap"/>
</StackLayout>
I feel that, even it returns true, but it uses the previous rows value. but only this part does not update. label names, values are updated, but only some items' visibility is not updating..
where is my mistake?
Update:
I've created an event for property change of the label that I want to control its visibility. I can see that, the IsVisible is always true but on the GUI, only one item is visible.. but when I scroll, several are visible, and when I scroll more then all items are visible as it must be
private void HelpLabel_OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals("IsVisible"))
{
// I check => ((Xamarin.Forms.Label)sender).IsVisible
//always true
}
}
I have found the problem. It was not regarding cache or informing UI element. Somehow it was regarding the item's height. I've gave a height and heightrequest value, and then it works always.. weird..
Related
I want to show a label when i click on my item in my listview.
The real problem i don't know how to link between my viewmodel and my views
I want modify my label in viewmodel but I don't know if its possible currently.
My xaml :
<StackLayout>
<Label x:Name="labelperso"
Text="{Binding newProduct}"
IsVisible="{Binding Addproduct}"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
BackgroundColor="#000000"
FontSize="20"
Opacity="0"/>
<ListView ItemsSource="{Binding Products}" CachingStrategy="RecycleElement" RowHeight="50" >
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding CodeReferenceLibelle}" TextColor="Black"/>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Behaviors>
<b:EventToCommandBehavior EventName="ItemSelected" Command="{Binding
SelectCommand}" Converter="{StaticResource SelectedItemConverter}"/>
</ListView.Behaviors>
my viewmodel :
#region labelperso property
private string _newProduct;
public string newProduct
{
get { return _newProduct; }
set { SetProperty(ref _newProduct, value); }
}
#endregion
#region Addproduct property
private bool _Addproduct;
public bool Addproduct
{
get { return _Addproduct; }
set { SetProperty(ref _Addproduct, value); }
}
#endregion
when I click on my item :
async Task Select()
{
newProduct = "Produit ajouté !";
basketManager.AddProductSkuAsync(sku);
newProduct = "";
await Task.Run(() => ShowText());
}
//I have tried this but I can't use my label in my view
async Task ShowText()
{
await labelperso.FadeTo(1);
await Task.Delay(1000);
await labelperso.FadeTo(0);
}
Why are you want to take the label "labelperso" in VM ? you can use it in xaml.cs instead.
You just need to add the event ItemSelected like this:
<ListView ItemsSource="{Binding Products}" ItemSelected="OnSelection">
In xaml.cs
void OnSelection(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
{
return;
}
//suppose the binding Object is Product
Product product = (Product)e.SelectedItem;
//labelperso.Text = "name = " + product.Name;
labelperso.FadeTo(1);
Task.Delay(1000);
labelperso.FadeTo(0);
}
Normally, VM are unrelated to Xaml, and we should not get labels from VM.
And we don't recommend it.But if you must, you can pass the Label in from the xaml.cs file like this:
You can define a variable in yourpage.xaml.cs:
public Label pageLabel;
and initial like this:
pageLabel = labelperso;
BindingContext = new YourViewmodel(this);
And in YourViewmodel.cs:
public Label ss;
public YourViewmodel(ContentPage parentPage)
{// here HomePage is your contentPage name of the page`
ss = ((HomePage)parentPage).pageLabel;//after this you can use it
}
You need to add a SelectedProduct property to your VM.
private string _SelectedProduct;
public string SelectedProduct
{
get { return _SelectedProduct; }
set { SetProperty(ref _SelectedProduct, value); }
}
You can then bind your ListView's SelectedItem to it
<ListView ItemsSource="{Binding Products}"
SelectedItem="{Binding SelectedProduct}"
CachingStrategy="RecycleElement"
RowHeight="50" >
You can then control the visibility of your label by binding to SelectedProduct via a "nullToVisibility" converter, or by using triggers etc.
You should try to use MVVM pattern rather than hacking with code behind.
Using MVVM you can add a Visible property to your viewmodel and bind the IsVisible property of the label to it.
Code will be much easy to read and maintain.
In the ListView, I need to show some images and text, only display the text when the Image.Source is empty. How to do?
<ListView ItemsSource="{x:Bind ViewModel.News}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="home:NormalNews">
<StackPanel>
<TextBlock Text="{x:Bind Title}"/>
<Image Source="{x:Bind Thumbnail}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ViewModel Data Source like:
News.Add(new NormalNews{ Title = "title1", Thumbnail = "http://a.com/test.jpg" });
News.Add(new NormalNews{ Title = "title2", Thumbnail = "" });
When I tried to run this page, it stopped running.
You can handle this using xaml converters.
Add a converter and define a key for it in your page.
In XAML page
<converter:ImageUriConverter x:Key="ImageUriConvert"/>
In your list
<Image Source="{Binding Thumbnail,Converter={StaticResource ImageUriConvert}}"/>
Converter class code
class ImageUriConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value.ToString() == string.Empty)
{
return new BitmapImage();
}
return new BitmapImage(new Uri(value.ToString()));
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
While you are populating the ViewModel object, do this:
ViewModel.News.Add(new NormalNews{
Thumbnail=(the Thumbnail source which you will be using),
Title=(the Thumbnail source which you will be using)==""?"Your Title":""});
This will set your Title to the specified string when your Thumbnail source is empty.
Hope this helps.
I have a list of items - when one is selected, I'd like to slide the appbar up. This is what I have so far:
<AppBar IsOpen="{Binding BookIsSelected}">
<Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<AppBarButton Icon="Remove" Label="Remove Book" Command="{Binding RemoveBook}" Visibility="{Binding BookIsSelected, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityConverter}}" />
</StackPanel>
</Grid>
</AppBar>
In the gridview of books, I have this:
SelectedItem ="{Binding SelectedBook, Mode = TwoWay}" />
BookIsSelected:
private bool _bookSelected;
public bool BookIsSelected {
get {
return _bookSelected;
}
set {
SetProperty(ref _bookSelected, value);
}
}
I can see the get/set hit when I select a book, but the appbar never flies out. What am I doing wrong?
I can't see any obvious problems with the code that you've shown so far. However, you haven't shown the code for the SelectedBook property or SetProperty method, so perhaps your problem lies there? Your SelectedBook property should look something like this, setting BookIsSelected to true:
private YourDataType _selectedBook;
public YourDataType SelectedBook{
get {
return _selectedBook;
}
set {
SetProperty(ref _selectedBook, value);
BookIsSelected = true;
}
}
However, unless you set the BookIsSelected property back to false at some stage, this will only work once. Your SetProperty method should notify the INotifyPropertyChanged interface of property changes, as #Amer mentioned in the comments. It should look something like this example from the linked page:
private void SetProperty([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I would like to set the bottom Corner Radius of a ListView Item for just the "last" item in the list. I've attempted to do so with a Converter (which in fact finds the last row), but to no avail.
The desirable effect is when the Converter returns true after finding the last item in the ListView, the border CornerRadius on the last ListViewItem is set to CornerRadius="0,0,10,10". For all other items in the ListView, CornerRadius="0,0,0,0"
What I've done so far.
The Converter...
public class IsLastItemConverter : IValueConverter
{
#region IValueConverter Members
public object TrueValue { get; set; }
public object FalseValue { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ListViewItem item = value as ListViewItem;
ListView listView = ItemsControl.ItemsControlFromItemContainer(item) as ListView;
if (listView != null)
{
int index = listView.ItemContainerGenerator.IndexFromContainer(item);
if (index == listView.Items.Count - 1)
{
TrueValue = true;
return (bool)TrueValue;
}
else
{
FalseValue = false;
return (bool)FalseValue;
}
}
FalseValue = false;
return (bool)FalseValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Just Convert Back
return true;
}
#endregion
}
The XAML...
<local:IsLastItemConverter x:Key="lastItemConverter"
TrueValue="0,0,10,10" FalseValue="0,0,0,0"/>
<DataTemplate x:Key="CellContentTemplate">
<Border
x:Name="CellContentBorder"
Background="{StaticResource GrayCharcoal}"
BorderThickness="4,4,4,4"
BorderBrush="{StaticResource Gray}"
CornerRadius="{Binding Converter={StaticResource lastItemConverter},
RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}}}"
HorizontalAlignment="Left"
Width="210"
Height="50"
ContextMenu="{StaticResource MarginalUnitsContextMenu}"
ScrollViewer.VerticalScrollBarVisibility="Hidden">...
Thoughts and ideas much appreciated - Glenn
I would try returning a real CornerRadius instead of a string (which, you are essentially returning).
My assumption is following:
When passing as string "0,0,0,0" in xaml as CornerRadius, the appropriate Converter is used to convert this string in to a CornerRadius struct.
As you are now using a custom converter, possibly the string to CornerRadius Converter is not anymore used...
EDIT (in light of Clemens answer): The Converter for the property does seem to kick in when a string was returned from the custom converter associated with the binding!
This is because CornerRadius has an associated TypeConverter:
[TypeConverterAttribute(typeof(CornerRadiusConverter))]
public struct CornerRadius : IEquatable<CornerRadius>
which handles this conversion. This converter handles the Conversion from string to CornerRadius.
(Taken from http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverterattribute.aspx )
I am pulling data from a previous page which was a selected item in a listbox from a wcf service.
Ther error I am having is that the textblock is not reading the formatting in my in my data.
this is the code that brings the data in from the previous page
private void LoadPlayer()
{
FrameworkElement root1 = Application.Current.RootVisual as FrameworkElement;
var currentPlayer = root1.DataContext as PlayerProfile;
_SelectedPlayer = currentPlayer;
}
this is the xaml
<TextBlock Height="Auto" TextWrapping="Wrap" Name="Blurb" Text="{Binding Bio}" xml:space="preserve" />
specifically I am trying to get the \r\n to work in my display as a linebreak.
See the answer here:
Newline in string attribute
In your case what you need to do write a Converter (something that implements IValueConverter) that turns the string data that contains the \r\n into encoded entities i.e.
and
. Then just use that converter on your Binding.
public class EncodeCRLFConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string stringtoconvert = value as string;
if (input != null))
{
// Note there are different ways to do the replacement, this is
// just a very simplistic method.
stringtoconvert = stringtoconvert.Replace( "\r", "
" );
stringtoconvert = stringtoconvert.Replace( "\n", "
" );
return stringtoconvert;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new Exception("The method or operation is not implemented.");
}
}
Create an instance of your converter somewhere...e.g. typically in .Resources....(in this example I've just used Window because I don't know what your TextBlock is inside).
<Window.Resources>
<EncodeCRLFConverter x:Key="strconv"/>
<Window.Resources>
<TextBlock Height="Auto" TextWrapping="Wrap" Name="Blurb" Text="{Binding Bio, Converter={StaticResource strconv}}" />