I am using Label in Xamarin forms.
I got to display a text which is basically a sentence but part of that string contains a number which I get from an api call and rest of the string is fixed.
I want to use data binding to set that part.
Example :
Text could be like : "You can win {0} dollars for sure"
{0} value comes from api and want to use data binding to bind it.
Need the syntax to be used to bind this kind of string.
You can use modle bind to data in your label.Just like this:
in xaml :
<Label Text="{Binding Name,StringFormat='You can win {0} dollars for sure'}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
in ContentPage, should bind context:
nativeDataTemple = new NativeDataTemple();
BindingContext = nativeDataTemple;
and Molde(NativeDataTemple you custom) should contain the binding property,like this:
private string name = "520";
public string Name
{
set
{
if (name != value)
{
name = value;
OnPropertyChanged("Name");
}
}
get
{
return name;
}
}
and in your modle ,when Name value change in the background,add INotifyPropertyChanged to the modle,and method
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
then where you want change the data ,jusst do that:
nativeDataTemple.Name = "550";
if have problem ,you can refer to thisOfficial document
use spans within a Label
<Label>
<Label.FormattedText>
<FormattedString>
<Span Text="You can win " />
<Span Text="{Binding DollarAmount}" />
<Span Text=" dollars for sure." />
</FormattedString>
</Label.FormattedText>
</Label>
Related
When I use -
string result = await DisplayPromptAsync("Question 1", "What's your name?");
It shows only one textbox in the pop-up. But how to display two or more textboxes in the pop-up?
Any help would be greatly appreciated.
As IvanIčin said that you can use Rg.Plugins.Popup to create custom popup.
Firstly, install Rg.Plugins.Popup bu nuget package..., then creating popup page
<pages:PopupPage
x:Class="FormsSample.popup.popup2"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup">
<pages:PopupPage.Content>
<StackLayout
Padding="20,0"
BackgroundColor="CadetBlue"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center">
<Label Text="Question 1" />
<Label Text="this is one question!" />
<Entry />
<Entry />
<Button
x:Name="btnsub"
Clicked="btnsub_Clicked"
Text="subit" />
</StackLayout>
</pages:PopupPage.Content>
</pages:PopupPage>
public partial class popup2 : PopupPage
{
public popup2()
{
InitializeComponent();
}
private void btnsub_Clicked(object sender, EventArgs e)
{
}
}
To call this Popup Page from contentpage button.click event.
private async void btnPopupButton_Clicked(object sender, EventArgs e)
{
await PopupNavigation.Instance.PushAsync(new popup2());
}
You can see the screenshot:
You can't as it is not intended to. You can create a custom pop-up either by using some pop-up plug-in or by creating your custom code based on the native prompts (similar to what Xamarin.Forms do).
Just for the record having one input field is very generous from Xamarin as the native Android or iOS developers don't have such a prompt with the input field out of the box (though it isn't too hard to create it but still it goes much beyond one line of code).
I'm building a chatbot app with chat bubbles for incoming and outgoing messages. For the incoming messages, I've given it a Task.Delay() and now I'd like to give it an ActivityIndicator every time before the message pops up (i.e. I want to show the activity indicator whiles the message is being delayed). I've added the activity indicator to the XAML of the incoming messages control;
IncomingMessageItemControl
<ViewCell
x:Class="BluePillApp.Controls.IncomingMessageItemControl"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:pancake="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView"
mc:Ignorable="d">
<Grid x:Name="Gridoo">
<pancake:PancakeView
Margin="10,10,80,10"
Padding="15"
BackgroundColor="#53ffc6"
CornerRadius="20,20,0,20"
HasShadow="False"
HorizontalOptions="StartAndExpand">
<Label
FontSize="Medium"
Text="{Binding Text}"
TextColor="#1a1a1a" />
</pancake:PancakeView>
<ActivityIndicator IsRunning="True" IsVisible="True" />
</Grid>
</ViewCell>
The problem is, in the ChatbotMessagingPage, the send button is pressed then an outgoing message is sent before getting a reply/incoming message and I've done this in MVVM like so;
ChatbotMessagingPageViewModel
//This gets the chatbots response for each message
chatbot.MainUser.ResponseReceived += async (sender, args) =>
{
await Task.Delay(1500);
Messages.Add(new ChatMessageModel() { Text = args.Response.Text, User = App.ChatBot });
};
}
#region CLASS METHODS
/// <summary>
/// This function sends a message
/// </summary>
public void Send()
{
if (!string.IsNullOrEmpty(TextToSend))
{
var msgModel = new ChatMessageModel() { Text = TextToSend, User = App.User };
//This adds a new message to the messages collection
Messages.Add(msgModel);
var result = chatbot.Evaluate(TextToSend);
result.Invoke();
//Removes the text in the Entry after message is sent
TextToSend = string.Empty;
}
}
Everytime I press the send button the ActivityIndicator comes along with the IncomingMessage, I'd like the ActivityIndicator to come first, whiles the IncomingMessage is being delayed.
I'm guessing that that view cell is the message bubble.
When you do:
Messages.Add(new ChatMessageModel() { Text = args.Response.Text, User = App.ChatBot });
Your collection is updated and your ListView or whatever hold those ViewCelss is also updated. The ActivityIndicator is part of the ViewCell so it comes at the same time as the message.
[OPTION 1] Using an additional flag
What you can do is create a flag IsBusy or IsDelay or something and bind the visibility of the ActivityIndicator and Label to it:
<Grid x:Name="Gridoo">
<pancake:PancakeView
Margin="10,10,80,10"
Padding="15"
BackgroundColor="#53ffc6"
CornerRadius="20,20,0,20"
HasShadow="False"
HorizontalOptions="StartAndExpand">
<Label
FontSize="Medium"
Text="{Binding Text}"
TextColor="#1a1a1a"
IsVisible="{Binding IsBusy, Converter={Helpers:InverseBoolConverter}}""> />
</pancake:PancakeView>
<ActivityIndicator x:Name="activityIndicator" IsRunning="True" IsVisible="{Binding IsBusy}" />
</Grid>
Note that I've used a IValueConverter to negate the value for the label. In case you're not familiar with it, check this
What's left is to add the flag in your ViewModel:
IsBusy = true; // this will make the activity indicator visible, but not the Label
// Also note that you first need to add the message
Messages.Add(new ChatMessageModel() { Text = args.Response.Text, User = App.ChatBot });
await Task.Delay(1500);
IsBusy = false; // this will hige the activity indicator visible, and make Label visible
So basically the logic is the following:
You add the message to your chat BUT the actual text is hidden when on the other hand, the activity indicator is visible.
You apply the delay
Delay ends, you change the visibility of both views.
Note that in my example I've not declared where that flag is since I'm not sure how the rest of your code looks like. It could be added to ChatMessageModel or ChatMessageViewModel since you would need a flag for each message.
[OPTION 2] in IncomingMessageItemControl.xaml.cs
A better solution could be to handle it in the code behind of your control. The issue is the same, the activity indicator and the label comes at the same time.
To fix this you can move the delay in IncomingMessageItemControl.xaml.cs.
First, you need to add x:Name to both the activity indicator and the label.
Then you could do:
private async Task ChangeVisibilityAsync()
{
Label.IsVisibe= false;
ActivityIndicator.IsVisible = true;
await Task.Delay(1500);
Label.IsVisibe = true;
ActivityIndicator.IsVisible = false;
}
I have an custom control with following DP:
public FrameworkElement NoResultContent
{
get { return (FrameworkElement)GetValue(NoResultContentProperty); }
set { SetValue(NoResultContentProperty, value); }
}
public static readonly DependencyProperty NoResultContentProperty =
DependencyProperty.Register("NoResultContent", typeof(FrameworkElement), typeof(AdvancedAutoCompleteBox), new PropertyMetadata(null));
The ControlTemplate of my custom control shows this DP in a ContentControl:
<ContentControl Content="{TemplateBinding NoResultContent}" />
It's used in a view to provide arbitrary functions:
<Controls:AdvancedAutoCompleteBox
x:Name="Box"
ItemsSource="{Binding Persons}"
SelectedItem="{Binding SelectedPerson}"
Watermark="Search here">
<Controls:AdvancedAutoCompleteBox.NoResultContent>
<StackPanel>
<Button
Content="Add by ICommand"
Command="{Binding AddPerson}" />
<Button
x:Name="AddPerson"
Content="Add by Caliburn" />
</StackPanel>
</Controls:AdvancedAutoCompleteBox.NoResultContent>
</Controls:AdvancedAutoCompleteBox>
The Command-Binding to a ICommand works just fine. Buy why does it not work with Caliburn.Micro?
I also tried to attach the context to the second Button manually by cal:Bind.Model
I'm trying to bind my ListBox to a selection of my ViewModel, because I have multiple ListBoxes in a Pivot and I don't want to type out the entire Page for each property. To illustrate my issue, here's a small sample:
XAML:
<DataTemplate x:Key="PropertyTemplate">
<StackPanel>
<TextBlock Text="{Binding Label}" />
<TextBlock Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
<controls:Pivot>
<controls:PivotItem>
<ListBox ItemsSource="{Binding PropertySelectionOne}" ItemTemplate="{StaticResource PropertyTemplate}" />
</controls:PivotItem>
<controls:PivotItem>
<ListBox ItemsSource="{Binding PropertySelectionTwo}" ItemTemplate="{StaticResource PropertyTemplate}" />
</controls:PivotItem>
</controls:Pivot>
ViewModel:
public class SomeViewModel
{
private Property _propOne;
public Property PropOne
{
get { return _propOne; }
set { _propOne = value; NotifyPropertyChanged("PropOne"); }
}
private Property _propTwo;
public Property PropTwo
{
get { return _propTwo; }
set { _propTwo = value; NotifyPropertyChanged("PropTwo"); }
}
private Property _propThree;
public Property PropThree
{
get { return _propThree; }
set { _propThree = value; NotifyPropertyChanged("PropThree"); }
}
}
So basically I want to bind my ListBoxes to PropertySelectionOne and PropertySelectionTwo, which would contain references to a selection of the properties in my ViewModel. For instance, PropertySelectionOne could include PropOne and PropTwo and PropertySelectionTwo could include PropTwo and PropThree.
Is there a simple way to "group" these properties to a new property to bind against without changing the architecture of my application?
Thanks
If you've got different properties to be displayed from the same date type in different list boxes, then arguably you need to split your view model, but you say you don't want to change the architecture of your application, which is your choice.
So, what you need to do is to provide a different ItemTemplate for each ListBox that defines which properties and how you want to display in each ListBox. Then you can bind the ItemsSource for all of the list boxes to the same data source but they will present different properties according to the ItemTemplate.
Not sure how familiar you are with these concepts, but you know that ItemsSource needs to be a collection of your data instances (SomeViewModel?), right?
I have a hierarchy of view models representing formatted content:
public abstract class ContentPartViewModel : ViewModel
{
}
public class TextContentPartViewModel : ContentPartViewModel
{
public string Text { ... }
}
public class TitleContentPartViewModel : TextContentPartViewModel
{
}
public class HyperlinkContentPartViewModel : TextContentPartViewModel
{
public string Uri { ... }
}
I have an encompassing view model that contains a collection of ContentPartViewModels to be rendered:
public class ContentViewModel
{
public ICollection<ContentPartViewModel> ContentParts { ... }
}
I then have a ContentView that renders all parts of the content:
<UserControl ...>
<ItemsControl ItemsSource="{Binding ContentParts}"/>
</UserControl>
In an ideal world, I would just define a DataTemplate for each of the content part types and they would be rendered accordingly. However, Silverlight does not support the DataType property on the DataTemplate class, so that is not an option.
Another option would be to provide a DataTemplateSelector and do the mapping from view model type to DataTemplate myself. Alas, ItemsControl in SL2 does not have an ItemTemplateSelector property - only an ItemTemplate property.
That left me with no option but to provide an ItemTemplate that then uses a converter to turn off all the UI apart from the piece relevant to that content part:
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Text}" FontWeight="Bold" Visibility="{Binding Converter={StaticResource TitleContentPartConverter}}"/>
<TextBlock Text="{Binding Text}" Visibility="{Binding Converter={StaticResource TextContentPartConverter}}"/>
<HyperlinkButton Content="{Binding Text}" NavigateUri="{Binding Uri}" Visibility="{Binding Converter={StaticResource HyperlinkContentPartConverter}}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
This is obviously rather awful, both for performance and for readability/correctness of code. It also makes it much harder for me to format the output correctly. So, questions:
Can anyone recommend a better way to do this in SL2?
Can anyone confirm whether the situation has improved in SL3?
Thanks,
Kent
Yes. DataType in DataTemplate is not supported in Silverlight 2 or Silverlight 3.
You can work around ItemTemplateSelector in Silverlight. Please take a look at this sample.
http://silverlight.net/forums/t/12598.aspx
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
DataTemplateSelector selector = this.ItemTemplateSelector;
if (null != selector)
{
((ContentPresenter)element).ContentTemplate = selector.SelectTemplate(item, element);
}
}