How can I get shell.searchandler to push its own text? - xamarin

I am trying to push the text from my Shell.SearchHandler to a command.
I have built this with SearchBar , but i need this to work in the Shell.SearchHandler
<Shell.SearchHandler >
<SearchHandler x:Name="searchBar"
Placeholder="Search..."
Command="{Binding PerformSearch}"
CommandParameter="{Binding Text, Source={x:Reference searchBar}}" TextColor="Black" BackgroundColor="LightGray" />
</Shell.SearchHandler>
And in my View model
public ICommand PerformSearch => new Command<string>((string query) =>
{
//do work
});
The command does execute but the query param is always null.
How can I get the text that was entered into the searchandler to be posted to the binding command?

CommandParameter="{Binding Text, Source={x:Reference searchBar}}"
After having a look at SearchHandler reference document as follow :
Query, of type string, the user entered text in the search box.
The reason is that SearchHandler not contains Text property .You should replace it with Query , then it can work .
<Shell.SearchHandler >
<SearchHandler x:Name="searchBar"
Placeholder="Search..."
Command="{Binding PerformSearch}"
CommandParameter="{Binding Query, Source={x:Reference searchBar}}"
TextColor="Black"
BackgroundColor="LightGray" />
</Shell.SearchHandler>
Note : Also can Custom a SearchHandler to monitor Query changed if needed .
Creare a MySearchHandler :
public class MySearchHandler : SearchHandler
{
protected override void OnQueryChanged(string oldValue, string newValue)
{
base.OnQueryChanged(oldValue, newValue);
if (string.IsNullOrWhiteSpace(newValue))
{
ItemsSource = null;
}
else
{
Console.WriteLine("search string " + newValue);
// here you can add code to deal with the viewmodel
//ItemsSource = MonkeyData.Monkeys
.Where(monkey => monkey.Name.ToLower().Contains(newValue.ToLower()))
.ToList<Animal>();
}
}
}
In Xaml :
<ContentPage ...
xmlns:controls="clr-namespace:Xaminals.Controls">
<Shell.SearchHandler>
<controls:MonkeySearchHandler Placeholder="Enter search term"
ShowsResults="true"
DisplayMemberName="Name" />
</Shell.SearchHandler>
...
</ContentPage>
Here is the official sample for reference , this need some time to research it.

Related

Does anyone know how to converter I can use in Xamarin forms that will do an OR between two bool parameters?

Here is the situation that I have:
<Stack IsVisible="{Binding IsGood}" >
<Label Text="Is Good or Okay" />
</Stack>
<Stack IsVisible="{Binding IsOkay}" >
<Label Text="Is Good or Okay" />
</Stack>
What I would like to do is to somehow code it like this:
<Stack IsVisible="{Binding IsGood, IsOkay, Converter={StaticResource ORConverter} }" >
<Label Text="Is Good or Okay" />
</Stack>
You can't make a converter do that. A converter only takes one value. Instead, why not just use a property in the ViewModel which reflects this instead?
public bool AorB => A || B;
private bool _a;
public bool A
{
get => _a;
set
{
_a = value;
RaisePropertyChanged();
RaisePropertyChanged(nameof(AorB));
}
}
private bool _b;
public bool B
{
get => _b;
set
{
_b = value;
RaisePropertyChanged();
RaisePropertyChanged(nameof(AorB));
}
}
Now, if you are using MvvmCross, you could use the Value Combiners it provides. However, it will only work for MvvmCross's binding descriptions, which would look like:
If(Or(A, B), 'true', 'false')
That would need you to depend on MvvmCross though and switch to its bindings for these kind of operations.

Cannot convert from 'Xamarin.Forms.Entry' to 'Tweetinvi.Models.IUserIdentifier'

I have been trying to use the x:name of the entry field to store the username of a twitter user and then using it for accessing the feeds. But I'm facing this error: cannot convert from 'Xamarin.Forms.Entry' to 'Tweetinvi.Models.IUserIdentifier'. What to do?
XAML File
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App7.Views.AnalysisPage">
<ContentPage.Content>
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<Entry x:Name="twitteruser_entry" Placeholder="#Username"></Entry>
</StackLayout>
</ContentPage.Content> </ContentPage>
XAML.CS File
using System.Threading.Tasks;
using Xamarin.Forms;
using Tweetinvi;
using Xamarin.Forms.Xaml;
using Tweetinvi.Models.Webhooks;
namespace App7.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AnalysisPage : ContentPage
{
public AnalysisPage ()
{
var user_identifier = twitteruser_entry; //this is where i'm getting the error.
var User = (dynamic)null;
var authenticatedUser = User.GetAuthenticatedUser();
var tweets = Timeline.GetUserTimeline(user_identifier, 10);
}
}
}
This is failing because it is trying all of the overloads and only returns the error on the last one.
Given the name of the field I am going to assume that the user is going to enter their username into the field. In this case you are probably wanting this overload
public static IEnumerable<ITweet> GetUserTimeline(string userScreenName, IUserTimelineParameters userTimelineParameters)
If this is the case, you need to get the text from the entry and pass it to that method.
var tweets = Timeline.GetUserTimeline(user_identifier.Text, 10);

I dont understand how to call Validation logic with Template 10 Validation

I've been trying to reproduce the simplest validation logic ever possible with template 10 validation, but I Just dont get it.
I have created my Model like the wiki at the example at github:
public class User : ValidatableModelBase
{
//public User()
//{
// FirstName = string.Empty;
// LastName = string.Empty;
// Validator = i =>
// {
// var u = i as User;
// if (string.IsNullOrEmpty(u.FirstName))
// u.Properties[nameof(u.FirstName)].Errors.Add("The first name is required");
// else if (u.FirstName.Length <= 3)
// u.Properties[nameof(u.FirstName)].Errors.Add("First Name must be greater than 3 chars.");
// if (string.IsNullOrEmpty(u.LastName))
// u.Properties[nameof(u.LastName)].Errors.Add("The last name is required");
// else if (u.LastName.Length <= 3)
// u.Properties[nameof(u.LastName)].Errors.Add("Last Name must be greater than 3 chars.");
// };
//}
public int Id { get; set; }
public string FirstName
{
get
{
return Read<string>();
}
set
{
Write(value);
}
}
public string LastName
{
get
{
return Read<string>();
}
set
{
Write(value);
}
}
public override string ToString() => $"{FirstName} {LastName}";
}
as you can see I've even created a constructor to initialize my Object, I commented out because I wanted to initialize the values at my ViewModel Constructor.
Then my view model is this:
public class MainPageViewModel : ViewModelBase
{
public MainPageViewModel()
{
User = new User
{
FirstName = string.Empty,
LastName = string.Empty,
Validator = i =>
{
var u = i as User;
if (string.IsNullOrEmpty(u.FirstName))
u.Properties[nameof(u.FirstName)].Errors.Add("The first name is required");
else if (u.FirstName.Length <= 3)
u.Properties[nameof(u.FirstName)].Errors.Add("First Name must be greater than 3 chars.");
if (string.IsNullOrEmpty(u.LastName))
u.Properties[nameof(u.LastName)].Errors.Add("The last name is required");
else if (u.LastName.Length <= 3)
u.Properties[nameof(u.LastName)].Errors.Add("Last Name must be greater than 3 chars.");
},
};
}
private User _User;
public User User
{
get { return _User; }
set { _User = value; }
}
public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> suspensionState)
{
User.Validate();
await Task.CompletedTask;
}
public override async Task OnNavigatingFromAsync(NavigatingEventArgs args)
{
args.Cancel = false;
await Task.CompletedTask;
}
public void GotoSettings() =>
NavigationService.Navigate(typeof(Views.SettingsPage), 0);
public void GotoPrivacy() =>
NavigationService.Navigate(typeof(Views.SettingsPage), 1);
public void GotoAbout() =>
NavigationService.Navigate(typeof(Views.SettingsPage), 2);
}
Now at my view all I have is this:
<Page x:Class="ValidationSample.Views.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Behaviors="using:Template10.Behaviors"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:controls="using:Template10.Controls"
xmlns:validate="using:Template10.Controls.Validation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:ValidationSample.Views"
xmlns:m="using:ValidationSample.Models"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:ValidationSample.ViewModels" mc:Ignorable="d">
<Page.DataContext>
<vm:MainPageViewModel x:Name="ViewModel" />
</Page.DataContext>
<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="AdaptiveVisualStateGroup">
<VisualState x:Name="VisualStateNarrow">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource NarrowMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO: change properties for narrow view -->
<!--<Setter Target="stateTextBox.Text" Value="Narrow Visual State" />-->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateNormal">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource NormalMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO: change properties for normal view -->
<!--<Setter Target="stateTextBox.Text" Value="Normal Visual State" />-->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="VisualStateWide">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="{StaticResource WideMinWidth}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<!-- TODO: change properties for wide view -->
<!--<Setter Target="stateTextBox.Text" Value="Wide Visual State" />-->
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<controls:PageHeader x:Name="pageHeader" RelativePanel.AlignLeftWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
RelativePanel.AlignTopWithPanel="True" Text="Main Page">
<!-- secondary commands -->
<controls:PageHeader.SecondaryCommands>
<AppBarButton Click="{x:Bind ViewModel.GotoSettings}" Label="Settings" />
<AppBarButton Click="{x:Bind ViewModel.GotoPrivacy}" Label="Privacy" />
<AppBarButton Click="{x:Bind ViewModel.GotoAbout}" Label="About" />
</controls:PageHeader.SecondaryCommands>
</controls:PageHeader>
<validate:ControlWrapper PropertyName="FirstName"
RelativePanel.AlignLeftWithPanel="True"
RelativePanel.Below="pageHeader">
<TextBox Width="300"
Margin="12,0,0,0"
Header="First Name"
Text="{Binding FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</validate:ControlWrapper>
</RelativePanel>
As fas as I know I have the model with the ValidatableModelBase logic Applied, I do have the Validate:wrapper applied to the view, I've set the validator at the VM ctor or I could set it at model ctor.
My problem is where do i make the Calling logic???
Because I havent been able to trigger the UpdateSourceTrigger of my FirstName field.
What am i doing wrong??
To be more honest I dont know where to place the Validate method, because at the sample at github the validate method is call everytime you open the modal dialog window, but that is when you are navigating to that window and its field everytime they changed they are being validated, but in my case nothing happens, why?? Hopefully someone can help me out, since I'm new at template 10 and also at UWP.
Damn, I was so damn tired but my mistake was so god damn simple I forgot to set the DataContext at the Parent Panel, In this case I should had add DataContext ={Binding Model}
this at XAML within the relative panel or any other Panel.
I felt so noob to have made this question.

Nativescript how to make a if condition in View XML

Is there anyway to do a if condition in the XML file of nativescript? (without angular)
if
<Card:CardView class="cardStyle" margin="10" elevation="40" radius="5">
<Slider value="18" minValue="5" maxValue="30" />
</Card:CardView>
else
<Card:CardView class="cardStyle" margin="10" elevation="40" radius="5">
<Label text="Example" class="h3" margin="10" />
</Card:CardView>
What you could do is use a boolean property (which in its get function has the condition you want) and bind it to the visibility of the CardView.
Looks like you can show/hide from the template file using visibility:
In XML file: ie. 'sample-page.xml'
<Button text="{{ isShowing ? 'Hide Me' : 'Show Me' }}" tap="toggleShowing"/> <!-- Notice missing interpolation in Button tag -->
<Label text="Showing Hidden Element" visibility="{{ isShowing ? 'visible' : 'collapsed' }}"/>
In Page file: ie. 'sample-page.ts'
let model = new ViewModel();
// Event handler for Page 'loaded' event attached in main-page.xml
export function pageLoaded(args: observable.EventData) {
const page = <Page>args.object;
page.bindingContext = model;
}
export function toggleShowing() {
model.set('isShowing', !model.get('isShowing'));
}
In View Model: ie. 'sample-view-model.ts'
isShowing:boolean = false;
The only way I found to do to do this was to use the navigatingTo event of the page:
export function navigatingTo(args: EventData) {
let page = <Page>args.object;
var myLayout = <StackLayout>page.getViewById("myLayout");
if (condition) {
let segmentedBar = new SegmentedBar;
...
myLayout.addChild(segmentedBar);
}
else {
let button: Button = new Button;
...
myLayout.addChild(button);
}
No possibility in the template file :-/
It can be done using ng-container.For example
<ng-container *ngIf="true">Your logic here....</ng-container>

How to bind with dynamic resource and specifying a path

I want to bind to a resource (DynamicResource) and access properties on that resource, but is there a way to do that?
(I want to visualize the default values from constructor in the xaml editor in visual studio. Those cannot be seen when referencing an object through DataContext nor through a property added on my Window class...)
Not working xaml: (works in composer but not at runtime...)
<Window ... >
<Window.Resources>
<local:MyClass x:Key="myResource" />
</Window.Resources>
<StackPanel>
<Button Content="{Binding Source={DynamicResource myResource} Path=Property1}" />
<Button Content="{Binding Source={DynamicResource myResource} Path=Property2}" />
</StackPanel>
</Window>
with the class (which probably need to implement INotifyPropertyChanged):
public class MyClass
{
public MyClass()
{
this.Property1 = "Ok";
this.Property2 = "Cancel";
}
public string Property1 { get; set; }
public string Property2 { get; set; }
}
That's because the DynamicResource markup extension can only be used on a dependency property, because it will need to update it if the resource changes. And Binding.Source is not a dependency property...
As a workaround, you could set the DataContext of the button with the DynamicResource :
<Button DataContext="{DynamicResource myResource}" Content="{Binding Path=Property1}" />
<Button DataContext="{DynamicResource myResource}" Content="{Binding Path=Property2}" />
Abusing the DataContext of an unrelated object seems to be the easiest workaround.
In case you still need the DataContext of your control (MVVM anyone?), you can also create an invisible helper FrameworkElement elsewhere:
<FrameworkElement Visibility="Collapsed" x:Name="ControlBrushGetter" DataContext="
{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
and later refer to it by using the name in the binding:
<SolidColorBrush Opacity="0.8"
Color="{Binding ElementName=ControlBrushGetter, Path=DataContext.Color}" />
Your designer will quite likely complain about not being able to resolve "Color" in the context of "object", but it will work fine at runtime.

Resources