BInding textColor in Xamarin - xamarin

In a Xamarin app I’m trying to bind a textcolor with a property in Message model.
public class Message : INotifyPropertyChanged
{
public string text { get; set; }
public Color color { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
The task is, when I click on a label in a collectionview the text should change to Gray.
I can change the color in the ObservableCollection:
this.messages = new ObservableCollection();
(that’s works, and if I delete an entry in the ObservableCollection the screen updates)
But when I change the color in the message model, the screen doesn’t update.
I use MVVMhelpers, and I would like to use that to solve the problem, if possible.
best regards..

You could change the item color to gray when you click the item to triger the SelectionChanged event of CollectionView.
Xaml:
<CollectionView ItemsSource="{Binding messages}" SelectionMode="Single" SelectionChanged="CollectionView_SelectionChanged">
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding text}" TextColor="{Binding color}"></Label>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Code behind:
public partial class Page2 : ContentPage
{
public ObservableCollection<Message> messages { get; set; }
public Page2()
{
InitializeComponent();
messages = new ObservableCollection<Message>()
{
new Message(){ text="A", color="Red"},
new Message(){ text="B", color="Red"},
new Message(){ text="C", color="Red"},
};
this.BindingContext = this;
}
private void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var previousItem = e.PreviousSelection.FirstOrDefault() as Message;
var currentItem = e.CurrentSelection.FirstOrDefault() as Message;
currentItem.color = "Gray";
if (previousItem!=null)
{
previousItem.color = "Red";
}
}
}
public class Message : INotifyPropertyChanged
{
private string _text;
public string text
{
get
{
return _text;
}
set
{
_text = value;
OnPropertyChanged("text");
}
}
private string _color;
public string color
{
get
{
return _color;
}
set
{
_color = value;
OnPropertyChanged("color");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

super, great thanks.
I should also add
<DataTemplate x:DataType="{x:Type Models:Message}">

Related

Why the RefreshView not updated my child element when I refresh?

Here's my xaml file.
<RefreshView x:Name="myRefreshView" Refreshing="myRefreshView_RefreshingAsync" RefreshColor="#b52b2b">
<ScrollView>
<StackLayout>
<Label Text="{Binding firstName }" />
</StackLayout>
</ScrollView>
</RefreshView>
Here's my .cs file which has a function
namespace Health.Views
{
public partial class LandingPage : ContentPage
{
public string firstName { set; get; }
public LandingPage()
{
firstName = "Mary";
this.BindingContext = this;
}
async void myRefreshView_RefreshingAsync(Object sender, System.EventArgs e)
{
await Task.Delay(3000);
firstName = "John";
myRefreshView.IsRefreshing = false;
}
}
}
The problem is when I refresh, the name is not change to "John". Not sure what else I have to add.
You need to implement INotifyPropertyChanged.
public class LandingPage : ContentPage, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _firstName;
public string firstName {
get{return _firstName;}
set
{
_firstName = value;
OnPropertyChanged("firstName");
} }
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}

Xamarin C# Databinding on ViewModels with multiple foreign key relations in datamodels: Picker and labels

Oke here is the context: I have a Xamarin Application that connects to ASP.NET rest service. Currently I am working on the databinding on my views
There is a certain Data model called prestatie which has a foreingn Key Reference to the Trainer model class and another that foreign key reference to the Getuigschrift Class.
public class Prestatie : INotifyPropertyChanged
{
[Key]
private Guid _PrestatieID;
public Guid PrestatieID
{
get => _PrestatieID;
set
{
_PrestatieID = value;
RaisePropertyChanged(nameof(PrestatieID));
}
}
private string _Rekeningnummer;
public string Rekeningnummer
{
get => _Rekeningnummer;
set
{
_Rekeningnummer = value;
RaisePropertyChanged(nameof(Rekeningnummer));
}
}
private string _Rijksregisternummer;
public string Rijksregisternummer
{
get => _Rijksregisternummer;
set
{
_Rijksregisternummer = value;
RaisePropertyChanged(nameof(Rijksregisternummer));
}
}
[ForeignKeyAttribute("Trainer")]
public Guid? TrainerID
{
get;
set;
}
public Trainer Trainer
{
get;
set;
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Trainer Class:
public class Trainer : Persoon
{
private Guid _TrainerID;
public Guid TrainerID
{
get => _TrainerID;
set
{
_TrainerID = value;
RaisePropertyChanged(nameof(TrainerID));
}
}
public ICollection<Prestatie> Prestaties
{
get;
set;
}
public Getuigschrift Getuigschriften
{
get;
set;
}
private Guid _GetuigschriftID;
public Guid? GetuigschriftID
{
get => _GetuigschriftID;
set
{
_GetuigschriftID = (Guid)value;
RaisePropertyChanged(nameof(GetuigschriftID));
}
}
}
Now I got two ViewModels setup fto represent this data, one for an overview and the second for the Details/Editing/adding. Databinding of items is on the viewmodels, so in Theory I should make these relations up in my view models but I am uncertain on how to do this. At one hand I just need to have some labels back in the ItemViewModel, and the other hand I need sort of comobox/list/picker for the data input to just get the Foregin Key.
Solutions I have tried it something like this, but that does not seem to work.
Xamarin ListView MVVM DataBinding
Here is a small snippet of my viewmodels, I cant post more because of the character limit.
public class PrestatieViewModel : BaseViewModel
{
private ObservableCollection<Prestatie> _prestaties;
private readonly IPrestatieDataService _prestatieDataService;
private readonly INavigationService _navigationService;
public ObservableCollection<Prestatie> Prestaties
{
get => _prestaties;
set
{
_prestaties = value;
OnPropertyChanged("Prestaties");
}
}
public class PrestatieDetailViewModel : BaseViewModel
{
private Prestatie _selectedPrestatie;
private readonly IPrestatieDataService _prestatieDataService;
private readonly INavigationService _navigationService;
public Prestatie SelectedPrestatie
{
get => _selectedPrestatie;
set
{
_selectedPrestatie = value;
OnPropertyChanged(nameof(SelectedPrestatie));
}
}
You can bind the picker's selectedItem with trainer so you could pick and set the value.
Here are the code you could refer to
xmal:
<ContentPage.BindingContext>
<local:PeopleViewModel/>
</ContentPage.BindingContext>
<CollectionView x:Name="mycol">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid ColumnDefinitions="100,* "
RowDefinitions="*,*">
<Label Text="{Binding Name}" BackgroundColor="LightBlue"/>
<Picker x:Name="mypicker" Grid.Column="1" Title="Select a Trainer"
TitleColor="Red"
ItemsSource="{Binding pgs}"
ItemDisplayBinding="{Binding Name}"
SelectedItem="{Binding Trainer}">
</Picker>
<Label Text="Trainer:" Grid.Row="1" Grid.Column="0" BackgroundColor="AliceBlue"/>
<Label
Grid.Row="1"
Grid.Column="1"
Text="{Binding Trainer.Name}"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
viewmodel:
public class PeopleViewModel:INotifyPropertyChanged
{
string name;
People trainer;
public List<People> pgs { get; private set; } = new List<People>{new People{Name="Trainer1" },
new People{ Name="Trainer2"} ,
new People{ Name="Trainer3"} };
public string Name {
get { return name; }
set { if (name != value)
{ name = value;
OnPropertyChanged();
}
} }
public People Trainer
{
get { return trainer; }
set
{
if (trainer != value)
{
trainer = value;
OnPropertyChanged();
}
}
}
#region INotifyPropertyChanged
void OnPropertyChanged(string name=null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
}}

How to Bind Xamarin Forms Checkbox isChecked to a dynamic bool variable?

I am newbie to xamarin forms. I have a Listview containing checkboxes. I bind the checkbox "isChecked" to one of the listview's itemsource bool property. the problem is, everytime i change the bool value where the checkbox is bind, checkbox appearance has'nt change. How can i achieve that kind of approach?enter image description here
[1]: https://i.stack.imgur.com/4KcT2.png
Hi #Weggie Villarante. Please try this.It's work for me
<ViewCell>
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Orientation="Horizontal">
<Label Text="{Binding Title}" HorizontalOptions="StartAndExpand"></Label>
<CheckBox IsChecked="{Binding IsCheck}" HorizontalOptions="End" HeightRequest="50"></CheckBox>
</StackLayout>
</ViewCell>
NotificationModel.cs
public class NotificationModel : INotifyPropertyChanged
{
public string Message { get; set; }
public string Title { get; set; }
public bool _IsCheck = false;
public bool IsCheck
{
get
{
return _IsCheck;
}
set
{
_IsCheck = value;
this.OnPropertyChanged("IsCheck");
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
NotificationViewModel.cs
class NotificationViewModel : INotifyPropertyChanged
{
ObservableCollection<NotificationModel> _Items;
public ObservableCollection<NotificationModel> Items
{
get
{
return _Items;
}
set
{
_Items = value;
OnPropertyChanged();
}
}
public NotificationViewModel()
{
Items = new ObservableCollection<NotificationModel>();
AddItems();
}
void AddItems()
{
_Items.Add(new NotificationModel { Title = "Info", Message = "This is only information message please ignor this one." ,IsCheck = false});
_Items.Add(new NotificationModel { Title = "Alert", Message = "This is only Alert message please ignor this one." , IsCheck = false });
_Items.Add(new NotificationModel { Title = "Suggesstion", Message = "This is only Suggesstion message please ignor this one." , IsCheck = false});
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

ReactiveList does not update in the GUI

I'm trying to make good use of ReactiveList and I think I'm close.
My expectation is that only "toyota" is shown after the user presses the filter button
XAML (yes, quick n dirty, no command for the Filter)
<Window
x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="350"
Width="525">
<StackPanel>
<ComboBox
ItemsSource="{Binding Path=CarsVM}"
DisplayMemberPath="Name" />
<Button
Click="ButtonBase_OnClick">
Filter
</Button>
</StackPanel>
</Window>
The code
using System.Windows;
using ReactiveUI;
namespace WpfApplication1
{
public partial class MainWindow
{
private readonly ViewModel _viewModel;
public MainWindow()
{
InitializeComponent();
_viewModel = new ViewModel();
DataContext = _viewModel;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
_viewModel.ChangeFilter();
}
}
}
public class CarViewModel : ReactiveObject
{
private bool _isVisible = true;
public CarViewModel(string name)
{
Name = name;
}
public bool IsVisible
{
get { return _isVisible; }
set
{
_isVisible = value;
this.RaiseAndSetIfChanged(ref _isVisible, value);
}
}
public string Name { get; set; }
}
public class ViewModel
{
private readonly ReactiveList<CarViewModel> _cars = new ReactiveList<CarViewModel>
{
new CarViewModel("bmw"),
new CarViewModel("toyota"),
new CarViewModel("opel")
};
public ViewModel()
{
_cars.ChangeTrackingEnabled = true;
CarsVM = _cars.CreateDerivedCollection(x => x, x => x.IsVisible);
}
public IReactiveDerivedList<CarViewModel> CarsVM { get; set; }
public void ChangeFilter()
{
foreach (var car in _cars)
{
car.IsVisible = car.Name.Contains("y");
}
}
}
Your bug is in the setter of IsVisible. By pre-assigning the value of _isVisible, RaiseAndSetIfChanged always thinks that the value has never changed. Remove _isVisible = value; and everything should work.

Validation fired but Red Border does not appear with User Control in Silverlight 4

I have created custom User Control which contain TextBox and PasswordBox. I bind TextBox to UserName and PassowrdBox also.
The UserName is defined in my LoginViewModel class with [Required] attribute. Now my cursor is leaving from TextBox without entering any value then UserName property fire property changeed notifcation (INotifyPropertyChanged),
but dose not mark my Textbox (which is inside the User Control) with Red border.
Following is code of my User Control.
RestrictedBox.xaml
<Grid x:Name="LayoutRoot" Background="Transparent" Margin="0" >
<TextBox x:Name="txtTextBox" HorizontalAlignment="Stretch" Height="25" />
<PasswordBox x:Name="txtPasswordBox" HorizontalAlignment="Stretch" Height="25" />
</Grid>
RestrictedBox.xaml.cs
public partial class RestrictedBox : UserControl
{
#region Properties
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(RestrictedBox), new PropertyMetadata("", ValueChanged));
private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public bool Updateable
{
get { return (bool)GetValue(UpdateableProperty); }
set { SetValue(UpdateableProperty, value); }
}
public static readonly DependencyProperty UpdateableProperty = DependencyProperty.Register("Updateable", typeof(bool), typeof(RestrictedBox), new PropertyMetadata(UpdateableChanged));
private static void UpdateableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public bool Redactable
{
get { return (bool)GetValue(RedactableProperty); }
set { SetValue(RedactableProperty, value); }
}
public static readonly DependencyProperty RedactableProperty = DependencyProperty.Register("Redactable", typeof(bool), typeof(RestrictedBox), new PropertyMetadata(RedactableChanged));
private static void RedactableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
#endregion
#region Constructors
public RestrictedBox()
{
InitializeComponent();
txtTextBox.SetBinding(TextBox.TextProperty, new Binding { Source = this, Path = new PropertyPath("Value"), Mode = BindingMode.TwoWay});
txtTextBox.SetBinding(TextBox.VisibilityProperty, new Binding("Redactable") { Source = this, Converter = new BoolToVisibilityConverterReverse() });
txtPasswordBox.SetBinding(PasswordBox.PasswordProperty, new Binding { Source = this, Path = new PropertyPath("Value"), Mode = BindingMode.TwoWay });
txtPasswordBox.SetBinding(TextBox.VisibilityProperty, new Binding("Redactable") { Source = this, Converter = new BoolToVisibilityConverter() });
}
#endregion
}
Following is the code where i used my Custom User Control
LoginView.xaml
<Control:RestrictedBox x:Name="UserName" VerticalAlignment="Top" TabIndex="2" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" Height="40" Value="{Binding Path=LoginModelValue.UserName, Mode=TwoWay, ValidatesOnNotifyDataErrors=True, ValidatesOnExceptions=True,
ValidatesOnDataErrors=True, NotifyOnValidationError=True}" Validatevalue:UpdateSourceTriggerHelper.UpdateSourceTrigger="True" Redactable="True" Updateable="True" />
LoginView.xaml.cs
[Export(typeof(LoginView))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class LoginView : UserControl, IPageTitle
{
#region Constuctors
public LoginView()
{
InitializeComponent();
}
[Import]
public LoginViewModel ViewModel
{
get {return this.DataContext as LoginViewModel;}
set { DataContext = value; }
}
#endregion
}
LoginViewModel.cs
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class LoginViewModel : INotifyPropertyChanged, IRegionMemberLifetime
{
private LoginModel _LoginModelValue;
public LoginModel LoginModelValue
{
get { return _LoginModelValue; }
set
{
_LoginModelValue = value;
OnPropertyChanged("LoginModelValue");
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private void OnPropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
void LoginModelValue_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (LoginModelValue.IsValidObject())
{
LoginCommand.RaiseCanExecuteChanged();
IsEnabled = LoginModelValue.IsValidObject();
SetIncorrectLogin(!IsEnabled);
}
}
#endregion
}
Can anybody has idea why i am not getting Red Border surrounded with my TextBox which is inside my Custom User Control?
Any help, suggestions and comments would be highly appreciated!
Thanks,
Imdadhusen
As I've already said, the validation works only for one binding and is not inherited by consequent bindigns as in your case.
The easiest way would be to add the Required annotation directly to the Value property of your control and validate it once again:
[Required]
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(RestrictedBox), new PropertyMetadata("", ValueChanged));
private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var rb = d as RestrictedBox;
Validator.ValidateProperty(rb.Value, new ValidationContext(rb, null, null) { MemberName = "Value" });
}
And add the ValidatesOnExceptions attribute to your bindings so that validation works:
txtTextBox.SetBinding(TextBox.TextProperty, new Binding { Source = this, Path = new PropertyPath("Value"), Mode = BindingMode.TwoWay,
ValidatesOnExceptions = true });
//...
txtPasswordBox.SetBinding(PasswordBox.PasswordProperty, new Binding { Source = this, Path = new PropertyPath("Value"), Mode = BindingMode.TwoWay,
ValidatesOnExceptions = true });
//...
Another way: to remove all the properties and bind the RestrictedBox control directly to your view model.
<TextBox x:Name="txtTextBox" HorizontalAlignment="Stretch" Height="25"
Text="{Binding LoginModelValue.UserName, Mode=TwoWay, ValidatesOnExceptions=True}" />
<PasswordBox x:Name="txtPasswordBox" HorizontalAlignment="Stretch" Height="25"
Password="{Binding LoginModelValue.UserName, Mode=TwoWay, ValidatesOnExceptions=True}" />
These solutions seem far from ideal, but actually the validation by data annotations is not good by design. I would recommend to use the INotifyDataErrorInfo interface.
Now i resolved issue using following code. I have replaced following line
txtTextBox.SetBinding(TextBox.VisibilityProperty, new Binding("Redactable") { Source = this, Converter = new BoolToVisibilityConverterReverse() });
with
this.MapBinding(RestrictedControl.ValueProperty, txtTextBox, TextBox.TextProperty);
and added following code. that's it.
namespace QSys.Library.Helpers
{
public static class FrameworkElementExtension
{
public static void MapBinding(this FrameworkElement element, DependencyProperty firstProperty, FrameworkElement targetElement, DependencyProperty secondProperty)
{
BindingExpression firstExpression = element.GetBindingExpression(firstProperty);
if (firstExpression != null && firstExpression.ParentBinding != null)
{
targetElement.SetBinding(secondProperty, firstExpression.ParentBinding);
}
}
}
}
I specially thanks to everybody how was looking for this. and i am also very thanksful Rakesh Gunijan (http://www.codeproject.com/Articles/293302/Silverlight-user-control-validation) how expain in very much clear.
Thanks,
Imdadhusen

Resources