Hi All,
I'm not quite sure where I'm going wrong here, I'm sure its data binding related, but basically I'm trying to build an autocomplete entry. I have an entry which when the user starts to type a list view below would be displayed of suggestions. This part works great, however I want to hide the listview when the suggestion is clicked or the entry isn't being typed into. This part I'm struggling with. I've tried using a grid (I was using a stack layout before) and setting the rows height to zero, I've tried directly setting the ListViews visibility in the code behind and I've tried binding the controls visibility to a property.
Do you have to implement INotifyProperty changed here?
XAML
<ContentView
xmlns:behaviors="clr-FB.Behaviors;assembly=FB"
x:Class="FB.Controls.MyControl2"
x:Name="This">
<ContentView.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="70"/>
</Grid.RowDefinitions>
<Entry x:Name="innerEntry"
Grid.Row="0" FontFamily="{StaticResource Key='AbrilFatface'}">
<Entry.Behaviors>
<behaviors:EventToCommandBehavior EventName="TextChanged"
Command="{Binding EntryTextChanged, Source={Reference This}}" />
</Entry.Behaviors>
</Entry>
<ListView x:Name="innerSuggestionBox" RowHeight="25"
Grid.Row="1"
IsVisible="{Binding IsEntryVisible, Source={Reference This}}"
behaviors:ItemTappedCommandListView.ItemTappedCommand="{Binding SuggestionItemTapped, Source={Reference This}}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding .}" HorizontalOptions="Start" />
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</ContentView.Content>
</ContentView>
Code Behind
namespace FB.Controls
{
public partial class MyControl2 : ContentView
{
public MyControl2()
{
InitializeComponent();
privateSuggestionList = new ObservableRangeCollection<string>();
this.IsEntryVisible = false;
ListHeight = 0;
innerEntry.SetBinding(Entry.PlaceholderProperty, new Binding("Placeholder", source: this));
innerEntry.SetBinding(Entry.TextProperty, new Binding("Text", source: this));
innerSuggestionBox.SetBinding(ListView.ItemsSourceProperty, new Binding("privateSuggestionList", source: this));
innerEntry.Keyboard = Keyboard.Create(KeyboardFlags.CapitalizeSentence | KeyboardFlags.Spellcheck);
//innerSuggestionBox.IsVisible = false;
//innerSuggestionBox.SetBinding(ListView.IsVisibleProperty, new Binding("IsEntryVisible", source: this));
}
public static BindableProperty PlaceholderProperty =
BindableProperty.Create("Placeholder", typeof(string), typeof(MyControl2), default(string));
public string Placeholder
{
// ----- The display text for the composite control.
get { return (string)base.GetValue(PlaceholderProperty); }
set
{
if (value != this.Placeholder)
base.SetValue(PlaceholderProperty, value);
}
}
public static BindableProperty TextProperty = BindableProperty.Create(
propertyName: "Text",
returnType: typeof(string),
declaringType: typeof(MyControl2),
defaultValue: string.Empty,
defaultBindingMode: BindingMode.OneWay,
propertyChanged: HandleTextPropertyChanged);
public string Text
{
// ----- The display text for the composite control.
get { return (string)base.GetValue(TextProperty); }
set
{
if (value != this.Text)
base.SetValue(TextProperty, value);
}
}
private static void HandleTextPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
MyControl2 targetView;
targetView = (MyControl2)bindable;
if (targetView != null)
targetView.Text = (string)newValue;
targetView.IsEntryVisible = true;
}
private bool _isEntryVisible;
public bool IsEntryVisible
{
get { return _isEntryVisible; }
set
{
_isEntryVisible = value;
//RaisePropertyChanged(() => IsEntryVisible);
}
}
private int _listHeight;
public int ListHeight
{
get { return _listHeight; }
set
{
_listHeight = value;
//RaisePropertyChanged(() => IsEntryVisible);
}
}
public ObservableRangeCollection<string> privateSuggestionList { get; set; }
public ICommand SuggestionItemTapped => new Command<string>(onSuggestionTapped);
private void onSuggestionTapped(string item)
{
this.Text = item;
Debug.WriteLine("List disabled");
//innerSuggestionBox.IsVisible = false;
IsEntryVisible = false;
ListHeight = 0;
Debug.WriteLine("IsEntryVisible value: {0}", IsEntryVisible);
}
public ICommand EntryTextChanged => new Command(onEntryTextChanged);
private void onEntryTextChanged()
{
if (this.ItemsSource2 != null)
{
this.privateSuggestionList.Clear();
this.privateSuggestionList.AddRange(ItemsSource2.Cast<string>()
.Where(x => x.ToLower().StartsWith(this.Text.ToLower(), StringComparison.Ordinal))
.OrderBy(x => x)
.ToList());
Debug.WriteLine("List Enabled");
//innerSuggestionBox.IsVisible = true;
IsEntryVisible = true;
ListHeight = 70;
Debug.WriteLine("IsEntryVisible value: {0}", IsEntryVisible);
}
}
public ICommand EntryTextLeft => new Command(onEntryTextLeft);
private void onEntryTextLeft()
{
Debug.WriteLine("List disabled");
IsEntryVisible = false;
ListHeight = 0;
//innerSuggestionBox.IsVisible = false;
}
public static readonly BindableProperty ItemsSource2Property =
BindableProperty.Create(nameof(ItemsSource2), typeof(IEnumerable), typeof(MyControl2), null,
BindingMode.Default, null, OnItemsSource2Changed);
public IEnumerable ItemsSource2
{
get { return (IEnumerable)GetValue(ItemsSource2Property); }
set { SetValue(ItemsSource2Property, value); }
}
static void OnItemsSource2Changed(BindableObject bindable, object oldvalue, object newvalue)
{
System.Diagnostics.Debug.WriteLine("source changed");
}
}
}