I've found the example at telerik forum of binding enum to radgridview, but it doesn't work hwo I need, and I need it on today, so i need a help.
Below are classes of this example, and only difference which I need is possibility to change value of positionof players. Now I can only change position by typing new value, but I need to select it from comboboxcolumn.
How can I do it?
<UserControl x:Class="BindingGridViewToEnumCollection.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:my="clr-namespace:BindingGridViewToEnumCollection"
mc:Ignorable="d" d:DesignHeight="700" d:DesignWidth="700">
<UserControl.Resources>
<my:MyViewModel x:Key="MyViewModel"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot"
Background="White"
DataContext="{StaticResource MyViewModel}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<telerik:RadGridView Name="playersGrid" Grid.Row="0"
ItemsSource="{Binding Players}"
AutoGenerateColumns="False">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn DataMemberBinding="{Binding Name}"/>
<telerik:GridViewDataColumn DataMemberBinding="{Binding Number}"/>
<telerik:GridViewDataColumn DataMemberBinding="{Binding Position}"/>
<telerik:GridViewDataColumn DataMemberBinding="{Binding Country}"/>
</telerik:RadGridView.Columns>
</telerik:RadGridView>
</Grid>
</UserControl>
My ViewModel
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Generic;
namespace BindingGridViewToEnumCollection
{
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<Club> clubs;
private ObservableCollection<Player> players;
private object selectedItem;
//public IEnumerable<string> AssignedPositions
public IEnumerable<Position> AssignedPositions
{
get
{
return new[] { Position.DF, Position.FW };
}
}
public ObservableCollection<Club> Clubs
{
get
{
if (this.clubs == null)
{
this.clubs = Club.GetClubs();
}
return this.clubs;
}
}
public ObservableCollection<Player> Players
{
get
{
if (this.players == null)
{
this.players = Player.GetPlayers();
}
return this.players;
}
}
public object SelectedItem
{
get
{
return this.selectedItem;
}
set
{
if (value != this.selectedItem)
{
this.selectedItem = value;
this.OnPropertyChanged("SelectedItem");
}
}
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, args);
}
}
private void OnPropertyChanged(string propertyName)
{
this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
}
}
Class Club:
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Linq;
namespace BindingGridViewToEnumCollection
{
/// <summary>
/// A football club.
/// </summary>
public class Club : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string name;
private DateTime established;
private int stadiumCapacity;
private ObservableCollection<Player> players;
public string Name
{
get { return this.name; }
set
{
if (value != this.name)
{
this.name = value;
this.OnPropertyChanged("Name");
}
}
}
public DateTime Established
{
get { return this.established; }
set
{
if (value != this.established)
{
this.established = value;
this.OnPropertyChanged("Established");
}
}
}
public int StadiumCapacity
{
get { return this.stadiumCapacity; }
set
{
if (value != this.stadiumCapacity)
{
this.stadiumCapacity = value;
this.OnPropertyChanged("StadiumCapacity");
}
}
}
public ObservableCollection<Player> Players
{
get
{
if (null == this.players)
{
this.players = new ObservableCollection<Player>();
}
return this.players;
}
}
public Club()
{
}
public Club(string name, DateTime established, int stadiumCapacity)
{
this.name = name;
this.established = established;
this.stadiumCapacity = stadiumCapacity;
}
public Club(string name, DateTime established, int stadiumCapacity, ObservableCollection<Player> players)
: this(name, established, stadiumCapacity)
{
this.players = players;
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, args);
}
}
private void OnPropertyChanged(string propertyName)
{
this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
public override string ToString()
{
return this.Name;
}
public static ObservableCollection<Club> GetClubs()
{
ObservableCollection<Club> clubs = new ObservableCollection<Club>();
Club club;
// Liverpool
club = new Club("Liverpool", new DateTime(1892, 1, 1), 45362);
club.Players.Add(new Player("Pepe Reina", 25, Position.GK, "Spain"));
club.Players.Add(new Player("Jamie Carragher", 23, Position.DF, "England"));
club.Players.Add(new Player("Steven Gerrard", 8, Position.MF, "England"));
club.Players.Add(new Player("Fernando Torres", 9, Position.FW, "Spain"));
clubs.Add(club);
// Manchester Utd.
club = new Club("Manchester Utd.", new DateTime(1878, 1, 1), 76212);
club.Players.Add(new Player("Edwin van der Sar", 1, Position.GK, "Netherlands"));
club.Players.Add(new Player("Rio Ferdinand", 5, Position.DF, "England"));
club.Players.Add(new Player("Ryan Giggs", 11, Position.MF, "Wales"));
club.Players.Add(new Player("Wayne Rooney", 10, Position.FW, "England"));
clubs.Add(club);
// Chelsea
club = new Club("Chelsea", new DateTime(1905, 1, 1), 42055);
club.Players.Add(new Player("Petr Čech", 1, Position.GK, "Czech Republic"));
club.Players.Add(new Player("John Terry", 26, Position.DF, "England"));
club.Players.Add(new Player("Frank Lampard", 8, Position.MF, "England"));
club.Players.Add(new Player("Nicolas Anelka", 39, Position.FW, "France"));
clubs.Add(club);
// Arsenal
club = new Club("Arsenal", new DateTime(1886, 1, 1), 60355);
club.Players.Add(new Player("Manuel Almunia", 1, Position.GK, "Spain"));
club.Players.Add(new Player("Gaël Clichy", 22, Position.DF, "France"));
club.Players.Add(new Player("Cesc Fàbregas", 4, Position.MF, "Spain"));
club.Players.Add(new Player("Robin van Persie", 11, Position.FW, "Netherlands"));
clubs.Add(club);
return clubs;
}
}
}
class Player
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Linq;
namespace BindingGridViewToEnumCollection
{
/// <summary>
/// A football player.
/// </summary>
public class Player : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string name;
private int number;
private Position position;
private string country;
public string Name
{
get { return this.name; }
set
{
if (value != this.name)
{
this.name = value;
this.OnPropertyChanged("Name");
}
}
}
public int Number
{
get { return this.number; }
set
{
if (value != this.number)
{
this.number = value;
this.OnPropertyChanged("Number");
}
}
}
public Position Position
{
get { return this.position; }
set
{
if (value != this.position)
{
this.position = value;
this.OnPropertyChanged("Position");
}
}
}
public string Country
{
get { return this.country; }
set
{
if (value != this.country)
{
this.country = value;
this.OnPropertyChanged("Country");
}
}
}
public Player()
{
}
public Player(string name, int number, Position position, string country)
{
this.name = name;
this.number = number;
this.position = position;
this.country = country;
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, args);
}
}
private void OnPropertyChanged(string propertyName)
{
this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
public override string ToString()
{
return this.Name;
}
public static ObservableCollection<Player> GetPlayers()
{
return new ObservableCollection<Player>(Club.GetClubs().SelectMany(c => c.Players));
}
}
}
namespace BindingGridViewToEnumCollection
{
/// <summary>
/// A football position.
/// </summary>
public enum Position
{
GK,
DF,
MF,
FW
}
}
EDIT
I'm using 2010.1.603.1040 version telerik, so I can't do i tlike there
http://demos.telerik.com/silverlight/#GridView/EnumDataSource
Your DataMemberBinding is wrong. You should add the mode:
DataMemberBinding="{Binding Position,Mode=TwoWay}"
<telerik:GridViewComboBoxColumn DataMemberBinding="{Binding Position,Mode=TwoWay}"
ItemsSource="{Binding Positions}">
<telerik:GridViewComboBoxColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Position}" />
</DataTemplate>
</telerik:GridViewComboBoxColumn.CellTemplate>
</telerik:GridViewComboBoxColumn>
One thing you can do is to add the following field and property to your MyViewModel class:
private static readonly Position[] positions = new Position[]
{
Position.GK, Position.DF, Position.MF, Position.FW
};
public IEnumerable<Position> Positions
{
get { return positions; }
}
(There's no Enum.GetValues() in Silverlight, so we have to make our own collection of the enum's values.)
Then you can change the Position column of your RadGridView to the following:
<telerik:GridViewComboBoxColumn DataMemberBinding="{Binding Position}"
ItemsSource="{Binding Positions}">
<telerik:GridViewComboBoxColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Position}" />
</DataTemplate>
</telerik:GridViewComboBoxColumn.CellTemplate>
</telerik:GridViewComboBoxColumn>
All we really should need to get the combobox column working is to change the type of the column to GridViewComboBoxColumn and add an ItemsSource that specifies the items to show in the combobox. However, I found that the Position column had a habit of going blank when other columns were focused. Once I added the CellTemplate. I found that the Position column behaved itself a bit better.
Note that you will need to set the Mode of your bindings to TwoWay if you want the changes you make in the grid to be sent back to your view-model.
Related
I have a Entry control inside DataTemplate of Bindable StackLayout. I have implemented TextChanged event of Entry control with Behavior but event is not getting fired.
This is xaml code
<Frame Padding="20,14,10,10"
Grid.Column="1"
BorderColor="LightGray">
<Entry MaxLength="5"
Keyboard="Numeric"
HeightRequest="42">
<Entry.Behaviors>
<helpers:EventToCommandBehavior Command="{Binding RefreshCommand}"
EventName="TextChanged"></helpers:EventToCommandBehavior>
</Entry.Behaviors>
</Entry>
</Frame>
Behavior classes in a single file
namespace Product.Helpers
{
public class EventToCommandBehavior : BehaviorBase<VisualElement>
{
Delegate eventHandler;
public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
public string EventName
{
get { return (string)GetValue(EventNameProperty); }
set { SetValue(EventNameProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
protected override void OnAttachedTo(VisualElement bindable)
{
base.OnAttachedTo(bindable);
RegisterEvent(EventName);
}
protected override void OnDetachingFrom(VisualElement bindable)
{
DeregisterEvent(EventName);
base.OnDetachingFrom(bindable);
}
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = (EventToCommandBehavior)bindable;
if (behavior.AssociatedObject == null) return;
string oldEventName = (string)oldValue;
string newEventName = (string)newValue;
behavior.DeregisterEvent(oldEventName);
behavior.RegisterEvent(newEventName);
}
void RegisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name)) return;
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName));
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent");
eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler(AssociatedObject, eventHandler);
}
void DeregisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name) || eventHandler == null)
return;
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName));
eventInfo.RemoveEventHandler(AssociatedObject, eventHandler);
eventHandler = null;
}
void OnEvent(object sender, object eventArgs)
{
if (Command == null) return;
object resolvedParameter;
resolvedParameter = eventArgs;
if (Command.CanExecute(resolvedParameter))
Command.Execute(resolvedParameter);
}
}
public class BehaviorBase<T> : Behavior<T> where T : BindableObject
{
public T AssociatedObject { get; private set; }
protected override void OnAttachedTo(T bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
if (bindable.BindingContext != null)
BindingContext = bindable.BindingContext;
bindable.BindingContextChanged += OnBindingContextChanged;
}
protected override void OnDetachingFrom(T bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= OnBindingContextChanged;
AssociatedObject = null;
}
void OnBindingContextChanged(object sender, EventArgs e)
{
OnBindingContextChanged();
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
BindingContext = AssociatedObject.BindingContext;
}
}
}
ViewModel Code for Command
public ICommand RefreshCommand
{
get
{
return new Command(async (args) =>
{
Refresh();
});
}
}
public void Refresh()
{
var textbox = Subtotal;
}
From here I have take the code csharpcorer - behavior. How can I make it work ?
The reason you are not able to find it is because of the context.
Give your current ContentPage a name :
<ContentPage
...
x:Name="currentPage"/>
Then your Entry would look something like:
<Entry MaxLength="5"
Keyboard="Numeric"
HeightRequest="42">
<Entry.Behaviors>
<helpers:EventToCommandBehavior Command="{Binding BindingContext.RefreshCommand, Source={x:Reference currentPage}}"
EventName="TextChanged"></helpers:EventToCommandBehavior>
</Entry.Behaviors>
</Entry>
I have multiple Entry views in my page connecting to a View Model using Data Binding. Everything works as intended except I need to calculate a values as the user enters it.
public decimal DownPayment
{
get => this.loanValues.DownPayment;
set
{
this.loanValues.DownPayment = value;
this.CalculateValues();
}
}
public decimal TradeInPrice
{
get => this.loanValues.TradeInPrice;
set
{
this.loanValues.TradeInPrice = value;
this.CalculateValues();
}
}
// Other properties
Now the problem is the property is set whenever user is entering the value. Is there anyway to change the event on which the Data Binding happens (i.e on Completed instead of TextChanged)?
I see there is UpdateSourceEventName property in XAML binding but I don't know why it doesn't work:
<Entry Placeholder="Down Payment ($)" Text="{Binding DownPayment, UpdateSourceEventName=Completed}" />
UPDATE: The documentation of UpdateSourceEventName says it's For internal use by the Xamarin.Forms platform
You could use EventToCommandBehavior to convert the Event Completed of Entry to Command and handle the logic in ViewModel .
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace App18
{
public class BehaviorBase<T> : Behavior<T> where T : BindableObject
{
public T AssociatedObject { get; private set; }
protected override void OnAttachedTo(T bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
if (bindable.BindingContext != null)
{
BindingContext = bindable.BindingContext;
}
bindable.BindingContextChanged += OnBindingContextChanged;
}
protected override void OnDetachingFrom(T bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= OnBindingContextChanged;
AssociatedObject = null;
}
void OnBindingContextChanged(object sender, EventArgs e)
{
OnBindingContextChanged();
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
BindingContext = AssociatedObject.BindingContext;
}
}
}
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Windows.Input;
using Xamarin.Forms;
namespace App18
{
public class EventToCommandBehavior : BehaviorBase<View>
{
Delegate eventHandler;
public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty InputConverterProperty = BindableProperty.Create("Converter", typeof(IValueConverter), typeof(EventToCommandBehavior), null);
public string EventName
{
get { return (string)GetValue(EventNameProperty); }
set { SetValue(EventNameProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public IValueConverter Converter
{
get { return (IValueConverter)GetValue(InputConverterProperty); }
set { SetValue(InputConverterProperty, value); }
}
protected override void OnAttachedTo(View bindable)
{
base.OnAttachedTo(bindable);
RegisterEvent(EventName);
}
protected override void OnDetachingFrom(View bindable)
{
DeregisterEvent(EventName);
base.OnDetachingFrom(bindable);
}
void RegisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return;
}
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
{
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName));
}
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent");
eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler(AssociatedObject, eventHandler);
}
void DeregisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return;
}
if (eventHandler == null)
{
return;
}
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
{
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName));
}
eventInfo.RemoveEventHandler(AssociatedObject, eventHandler);
eventHandler = null;
}
void OnEvent(object sender, object eventArgs)
{
if (Command == null)
{
return;
}
object resolvedParameter;
if (CommandParameter != null)
{
resolvedParameter = CommandParameter;
}
else if (Converter != null)
{
resolvedParameter = Converter.Convert(eventArgs, typeof(object), null, null);
}
else
{
resolvedParameter = eventArgs;
}
if (Command.CanExecute(resolvedParameter))
{
Command.Execute(resolvedParameter);
}
}
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = (EventToCommandBehavior)bindable;
if (behavior.AssociatedObject == null)
{
return;
}
string oldEventName = (string)oldValue;
string newEventName = (string)newValue;
behavior.DeregisterEvent(oldEventName);
behavior.RegisterEvent(newEventName);
}
}
}
in xaml
</StackLayout>
<Entry WidthRequest="100" Text="{Binding Value1,Mode=OneWayToSource}" Keyboard="Numeric" >
<Entry.Behaviors>
<local:EventToCommandBehavior EventName="Unfocused" Command="{Binding CompletedCommand}" />
</Entry.Behaviors>
</Entry>
<Entry WidthRequest="100" Text="{Binding Value2,Mode=OneWayToSource}" Keyboard="Numeric">
<Entry.Behaviors>
<local:EventToCommandBehavior EventName="Unfocused" Command="{Binding CompletedCommand}" />
</Entry.Behaviors>
</Entry>
<Label WidthRequest="100" Text="{Binding Sum}" TextColor="Black" />
</StackLayout>
in ViewModel
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
double value1;
public double Value1
{
get
{
return value1;
}
set
{
if (value1 != value)
{
value1 = value;
NotifyPropertyChanged("Value1");
}
}
}
double value2;
public double Value2
{
get
{
return value2;
}
set
{
if (value2 != value)
{
value2 = value;
NotifyPropertyChanged("Value2");
}
}
}
private string sum;
public string Sum
{
get { return sum; }
set
{
if (sum != value)
{
sum = value;
NotifyPropertyChanged("Sum");
}
}
}
public ICommand CompletedCommand { get; set; }
public MyViewModel()
{
CompletedCommand = new Command(()=> {
Sum = (Value1 + Value2).ToString();
});
}
}
im working with custon entry rendered, i need to hear from xaml in my custom render when i clicked my button
i have this code in my xaml
<local:MyEntry eventRefresh="true">
when i clicked my button this function is actived
private async void Execute(object sender)
{
var entry = ((MyEntry)view);
entry.eventRefresh = "false";
but my EntryRendered donot hear the change
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var element = Element as MyEntry;
You should define the property eventRefresh as Bindable Property .
in your custom Entry
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Xamarin.Forms;
namespace xxx
{
public class MyEntry:Entry,INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public static readonly BindableProperty eventRefreshProperty = BindableProperty.Create("eventRefresh", typeof(bool), typeof(MyEntry), true,propertyChanged:(obj,oldValue,newValue)=> {
//var entry = obj as MyEntry;
// entry.Text = newValue.ToString();
});
bool refresh;
public bool eventRefresh
{
get { return refresh; }
set {
if(refresh !=value)
{
refresh = value;
NotifyPropertyChanged("eventRefresh");
}
}
}
public MyEntry()
{
}
}
}
in xaml
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<local:MyEntry eventRefresh="{Binding Refresh}" BackgroundColor="{Binding BGcolor}" WidthRequest="200" HeightRequest="50" />
<Button Command="{Binding ClickCommand}" />
</StackLayout>
in View Model
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Color color;
public Color BGcolor
{
get { return color; }
set
{
if (color != value)
{
color = value;
NotifyPropertyChanged("BGcolor");
}
}
}
bool refresh;
public bool Refresh
{
get { return refresh; }
set
{
if (refresh != value)
{
refresh = value;
NotifyPropertyChanged("Refresh");
}
}
}
public ICommand ClickCommand { get; set; }
public MyViewModel()
{
BGcolor = Color.LightPink;
ClickCommand = new Command(()=> {
BGcolor = Color.Red;
});
}
}
in Custom Renderer
using System.ComponentModel;
using Android.Content;
using xxx;
using xxx.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly:ExportRenderer(typeof(MyEntry),typeof(NyEntryRenderer))]
namespace xxx.Droid
{
public class NyEntryRenderer : EntryRenderer
{
public NyEntryRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Element.TextChanged += Element_TextChanged;
}
}
private void Element_TextChanged(object sender, TextChangedEventArgs e)
{
// var content = Element.Text;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == MyEntry.BackgroundColorProperty.PropertyName)
{
// will been invoked when click button
}
}
}
}
Make your view model like this.
public class YourViewModel
{
public Command command
{
get
{
return new Command(() => {
//Change here button background colors
BackgroundColor = Color.Green;
});
}
}
private _backgroundColor = Color.White;
public Color BackgroundColor
{
get { return _backgroundColor;}
set
{
if (value == _backgroundColor)
return;
_backgroundColor = value;
NotifyOnPropertyChanged(nameof(BackgroundColor));
}
}
}
Your XAML
<local:MyEntry Text="{Binding Password}" Placeholder="Enter" />
<Button Text="send" Command="{Binding command}" BackgroundColor="{Binding BackgroundColor}"></Button>
I have tried everything but I cannot get to update my observable collection and be reflected in the UI. I have a method that adds a new entry to the collection that is bound to a CollectionViewSource which is bound to my collection. When I run the application Universal App I get the list correctly but if I add a value on click nothing gets reflected. Any suggestions?
The XAML looks like this:
<SemanticZoom>
<SemanticZoom.ZoomedInView>
<ListView IsHoldingEnabled="True"
ItemsSource="{Binding Mode=OneWay, Source={StaticResource MenuGroups}}"
ItemTemplate="{StaticResource MenuItemTemplate}"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.GroupStyle>
<GroupStyle HidesIfEmpty="True" HeaderTemplate="{StaticResource MenuGroupHeaderTemplate}"/>
</ListView.GroupStyle>
</ListView>
</SemanticZoom.ZoomedInView>
<SemanticZoom.ZoomedOutView>
<GridView Background="Black"
ItemsSource="{Binding Source={StaticResource MenuGroups}, Path=CollectionGroups}"
ItemTemplate="{StaticResource MenuJumpTemplate}">
</GridView>
</SemanticZoom.ZoomedOutView>
</SemanticZoom>
Here is my code for the code behind:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using TestWin.TestWinService;
using System.Globalization;
using System.Collections.ObjectModel;
using System.ComponentModel;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace TestWin
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MenuPage : Page
{
#region Members
TestWinConnectionClient TestWinService;
ObservableCollection<Menu> ocMenuItems = null;
ObservableCollection<AlphaKeyGroup<Menu>> ocItemSource = null;
#endregion Members
#region Properties
public ObservableCollection<Menu> MenuItems
{
get
{
if (ocMenuItems == null)
{
ocMenuItems = new ObservableCollection<Menu>();
}
return ocMenuItems;
}
set
{
ocMenuItems = value;
OnPropertyChanged("MenuItems");
}
}
public ObservableCollection<AlphaKeyGroup<Menu>> ItemSource
{
get
{
if (ocItemSource == null)
{
ocItemSource = new ObservableCollection<AlphaKeyGroup<Menu>>((AlphaKeyGroup<Menu>.CreateGroups(MenuItems, CultureInfo.CurrentUICulture, s => s.MenuName, true)));
}
return ocItemSource;
}
set
{
ocItemSource = value;
OnPropertyChanged("ItemSource");
}
}
#endregion Properties
public MenuPage()
{
TestWinService = new TestWinConnectionClient();
this.InitializeComponent();
#region Events
this.Loaded += MenuPage_Loaded;
#endregion
}
private void MenuPage_Loaded(object sender, RoutedEventArgs e)
{
SetItemSource();
}
private async void SetItemSource()
{
MenuItems = await TestWinService.GetMenuEntriesAsync();
((CollectionViewSource)Resources["MenuGroups"]).Source = ItemSource;
}
private void TextBlock_Tapped(object sender, TappedRoutedEventArgs e)
{
Menu m = new Menu();
m.MenuName = "Test Entry";
m.SysRowID = Guid.NewGuid();
MenuItems.Add(m);
//this.Frame.Navigate(typeof(MenuPage));
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
If you add the new item to the MenuItems you also need to refresh the Source of CollectionViewSource.
Might be you have an ObservableCollection (ItemSource) that is not neccesary, you can take a look how I did it in Codeproject
and add for instance:
private async void Test()
{
await Task.Delay(5000);
for (int i = 0; i < 5; i++)
{
Favorites.Add(new Favorite()
{
Name = $"AAFriends {i}",
Category = new Category() { Name = "Friends" },
Uri = "http://www.expediteapps.com/blog/"
});
}
InitializeGrouping();
}
That refreshes only when I call the grouping again.
I have ObservableCollection and value that need to find the item in the collection. any ideas? (p.s converter not good idea, because i have many collections)
This functionality (applying a filter) belongs into the ViewModel. Here is an easy example for illustration.
You might also want to look at the CollectionViewSource for a more refined version of the same concept.
Xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" >
<ListBox ItemsSource="{Binding MyClasses}" DisplayMemberPath="Name" Margin="5" />
<ListBox ItemsSource="{Binding MyFilteredClasses}" DisplayMemberPath="Name" Margin="5" />
<TextBox Text="{Binding MySelectedClass.Name}" Margin="5" />
</StackPanel>
</Window>
ViewModel:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
namespace WpfApplication1
{
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private ObservableCollection<Class1> _myClasses;
public ObservableCollection<Class1> MyClasses { get { return _myClasses; } set { _myClasses = value; OnPropertyChanged("MyClasses"); } }
private List<Class1> _myFilteredClasses;
public List<Class1> MyFilteredClasses { get { return _myFilteredClasses; } set { _myFilteredClasses = value; OnPropertyChanged("MyFilteredClasses"); } }
private Class1 _mySelectedClass;
public Class1 MySelectedClass { get { return _mySelectedClass; } set { _mySelectedClass = value; OnPropertyChanged("MySelectedClass"); } }
public ViewModel()
{
MyClasses = new ObservableCollection<Class1>()
{
new Class1() { Name = "Connelly" },
new Class1() { Name = "Donnelly" },
new Class1() { Name = "Fonnelly" },
new Class1() { Name = "McGregor" },
new Class1() { Name = "Griffiths" }
};
// filter your ObservableCollection by some criteria, and bind to the result (either another list, or just one item)
MyFilteredClasses = MyClasses.Where(c => c.Name.EndsWith("onnelly")).ToList();
MySelectedClass = MyClasses.FirstOrDefault(c => c.Name.StartsWith("Mc"));
}
}
public class Class1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private string _name;
public string Name { get { return _name; } set { _name = value; OnPropertyChanged("Name"); } }
}
}