Caliburn.Micro + MaterialToolkitDialog not Open .. : ( - caliburn.micro

with Calibrun.Micro(WPF) + MaterialToolkit,
I tried to open Dialog. but not work..
Could you check my code ? (in GitHub)
Here is small test project.
Click the "Open" button.
this button fired dialog like this.
public async void NewConnection(){
var result = await DialogHost.Show(
new UserControl { DataContext = new TestDialogViewModel() },
"MainDialogHost");
}
Change to gray background( good ), but No dialog.. Why ?

I found a solution.
// MainViewModel.cs
TestDialogViewModel vm;
...
public async void NewConnection()
{
vm = IoC.Get<TestDialogViewModel>();
var dialog = new TestDialogView()
{
DataContext = vm
};
var result = await DialogHost.Show(dialog, "MainDialogHost",
(object sender, DialogOpenedEventArgs eventArgs) =>
{
// pass DialogSession to ViewModel.
// View Model can close own dialog !
vm.dialogSession = eventArgs.Session;
},
(object sender, DialogClosingEventArgs eventArgs) =>
{
Debug.WriteLine($"IPaddress = "+vm.IpAddress);
});
}
and
<!-- in MainView.xaml -->
<materialDesign:DialogHost Identifier="MainDialogHost"
CloseOnClickAway="True"
cal:Message.Attach="[Event DialogClosing]=[Action DialogHost_OnDialogClosing()]"
>
and..
// in TestDialogViewModel
public DialogSession dialogSession;
public void BtnConnect()
{
dialogSession.Close();
}
and..
<!-- in TestDialogView.xaml -->
<StackPanel Margin="20" Orientation="Vertical">
<TextBlock>Input IP Address</TextBlock>
<TextBox Margin="0 20 0 10"
FontSize="28"
HorizontalAlignment="Stretch"
Text="{Binding Path=IpAddress, Mode=TwoWay}"
TextAlignment="Center"/>
<TextBlock Foreground="Red" TextAlignment="Center" HorizontalAlignment="Center"></TextBlock>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Style="{StaticResource MaterialDesignFlatButton}"
cal:Message.Attach="[Event Click]=[Action BtnConnect()]"
IsDefault="True"
Margin="0 8 8 0">
<Button.CommandParameter>
<system:Boolean xmlns:system="clr-namespace:System;assembly=mscorlib">True</system:Boolean>
</Button.CommandParameter>
Connect
</Button>
</StackPanel>
</StackPanel>
Screenshots.
It will help someone Caliburn.Micro user !
: )

Related

set custom font for alert messages for both android and ios using xamarin.forms

I am using xamarin forms for my project. I need to set custom font family(Montserrat-Medium.ttf) for the following alert messages for both android and iOS.
var ans = await App.Current.MainPage.DisplayAlert("", "Are you want to leave the application?", "Yes", "No");
Anyone help me to resolve this issue.
This is not possible in shared Xamarin project, but you can simply create a custom alert, and do what ever you want with it, like this:
Add your font to the solution
Add the font somewhere in shared project and then right click on it and choose Properties.
In Properties, choose Embedded resource as a Build Action.
Add this line
[assembly: ExportFont("Montserrat-Medium.ttf", Alias = "MyMontserrat")]
to the AssemblyInfo.cs
Create custom popup view like this
<?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="MyApp.MainPage">
<AbsoluteLayout Padding="0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Button Text="Display Alert!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
Clicked="OnButtonClicked" />
</StackLayout>
<!--Here's the custom popupView-->
<ContentView x:Name="popupView" BackgroundColor="#C0808080" Padding="10, 0" IsVisible="false" AbsoluteLayout.LayoutBounds="0, 0, 1, 1" AbsoluteLayout.LayoutFlags="All">
<StackLayout VerticalOptions="Center" HorizontalOptions="Center">
<StackLayout Orientation="Vertical" HeightRequest="150" WidthRequest="200" BackgroundColor="White">
<Label x:Name="myLabel" FontSize="16" FontFamily="MyMontserrat" Text="Are you want to leave the application?" />
<Button Text="Yes" FontSize="16" FontFamily="MyMontserrat" BackgroundColor="White" TextTransform="None" Clicked="Yes_Clicked" />
<Button Text="No" FontSize="16" FontFamily="MyMontserrat" BackgroundColor="White" TextTransform="None" Clicked="No_Clicked" />
</StackLayout>
</StackLayout>
</ContentView>
</AbsoluteLayout>
</ContentPage>
Use your popup in .cs
void OnButtonClicked(object sender, EventArgs args)
{
//This will show the pop up
popupView.IsVisible = true;
}
private void Yes_Clicked(object sender, EventArgs e)
{
popupView.IsVisible = false;
//Your stuff here
}
private void No_Clicked(object sender, EventArgs e)
{
popupView.IsVisible = false;
//Your stuff here
}
You could use DependencyService to call the native dialog,and define the font in the native dialog.
Here is a simple sample for Android (ios is similar to this,you could refer to this):
define a interface in your forms project:
public interface ICustomAlert
{
void Show(string message);
}
then in your Android project:
public class CustomAlert : ICustomAlert
{
public void Show(string message)
{
AndroidX.AppCompat.App.AlertDialog.Builder alertdialogbuilder = new AndroidX.AppCompat.App.AlertDialog.Builder(MainActivity.Instance);
alertdialogbuilder.SetMessage(message);
alertdialogbuilder.SetPositiveButton("Yes",OkEvent);
alertdialogbuilder.SetNeutralButton("No", NoEvent);
AndroidX.AppCompat.App.AlertDialog alertdialog = alertdialogbuilder.Create();
alertdialog.Show();
TextView textView = alertdialog.FindViewById<TextView>(Android.Resource.Id.Message);
textView.SetTextColor(Android.Graphics.Color.Red);
Typeface face = Typeface.CreateFromAsset(MainActivity.Instance.Assets, "fonts/Montserrat-Medium.tff");
textView.SetTypeface(face, TypefaceStyle.Normal);
}
private void NoEvent(object sender, DialogClickEventArgs e)
{
}
private void OkEvent(object sender, DialogClickEventArgs e)
{
}
}
then you could call like
DependencyService.Get<ICustomAlert>().Show("your message");

Make Keyboard popup automatically on entry

I am using a grid in Xamain forms and I want on the selection event to call the keyboard I thought doing this word wok.
I am using the plugin dialogue kit to display a numeric entry but my quesiton is the keyboard is only displaying on the text box when it has focus how Do I force the keyboard to come up so the user does not have to click into the field.
new Entry()
{
Keyboard = Keyboard.Numeric
};
var resultQty = await Plugin.DialogKit.CrossDiaglogKit.Current.GetInputTextAsync("Test", $"Please goto Bin {item.BinName} , and enter the visible stock of the item." + item.Name, null, Keyboard.Numeric);
The code from Dialog kit shows that it attempts to place a focus on the entry field.
<ContentView.Content>
<StackLayout Padding="10" BackgroundColor="White" VerticalOptions="CenterAndExpand" Margin="25">
<Label FontAttributes="Bold" FontSize="Large" Text="{Binding Title}"/>
<Label FontSize="Large" Text="{Binding Message}"/>
<Entry x:Name="txtInput" Keyboard="{Binding Keyboard}"/>
<StackLayout Margin="10" Orientation="Horizontal">
<Button Text="{Binding OK}" Clicked="Confirm_Clicked" HorizontalOptions="FillAndExpand"/>
<Button Text="{Binding Cancel}" Clicked="Cancel_Clicked" HorizontalOptions="FillAndExpand"/>
</StackLayout>
</StackLayout>
</ContentView.Content>
You will see here that the dialog kit calls the above few as such
public Task<string> GetInputTextAsync(string title, string message,string currentText = null, Keyboard keyboard = null)
{
if (keyboard == null) keyboard = Keyboard.Default;
var cts = new TaskCompletionSource<string>();
var _dialogView = new Plugin.DialogKit.Views.InputView(title, message,currentText,keyboard);
_dialogView.FocusEntry();
_dialogView.Picked += (s, o) => { cts.SetResult(o); PopupNavigation.PopAsync(); };
PopupNavigation.PushAsync(new PopupPage { Content = _dialogView });
return cts.Task;
}
Which as you can see is calling the but i think the placement of this is wrong as its before its pops onto the view.
public void FocusEntry()
{
txtInput.Focus();
}
​
I did some test and found you should Call the FocusEntry after PopUp to force the keyboard to come up automatically.
private async void Button_Clicked(object sender, EventArgs e)
{
var resultQty = await GetInputTextAsync("Test", $"Please goto Bin, the visible stock of the item.", null, Keyboard.Numeric);
}
public async Task<string> GetInputTextAsync(string title, string message, string currentText = null, Keyboard keyboard = null)
{
if (keyboard == null) keyboard = Keyboard.Default;
var cts = new TaskCompletionSource<string>();
var _dialogView = new Plugin.DialogKit.Views.InputView(title, message, currentText, keyboard);
_dialogView.Picked += (s, o) => { cts.SetResult(o); PopupNavigation.PopAsync(); };
await PopupNavigation.PushAsync(new PopupPage { Content = _dialogView });
//Call the FocusEntry after PopUp
_dialogView.FocusEntry();
return await cts.Task;
}

Custom content view with Label-Entry duplicates Xamarin forms

I have custom content view with a Label as title and another Label as detail and an edit Icon ; when the icon is clicked detail label is converted to Entry to make changes and the changes are carried over to binding.
I have bound multiple of these custom views to different properties of same object and trying to edit each one and move to next one, the problem is it seems to duplicate the individual views
I have also put x:Name but still it duplicates same value to the views above it ..
Just the edit of Lastname
Now if I move to 3rd view and edit it , it replicates new value to all previously edited values. - for lastname in this case which is weird considering its not same view used in the page and on debug it hits the method only once.
Custom content view:
<StackLayout Orientation="Horizontal"
VerticalOptions="Start"
Padding="25,10,25,10">
<StackLayout x:Name="stackLayoutDetail"
HorizontalOptions="FillAndExpand">
<Label x:Name="title"
Text="{Binding Title}" />
<Label x:Name="detail"
Text="{Binding Detail}"
FontSize="Large"
FontAttributes="Bold" />
</StackLayout>
<Image x:Name="editIcon"
Source="edit_icon.png"
WidthRequest="25"
HeightRequest="25"
IsVisible="{Binding EditIconVisible}">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="EditIcon_Clicked" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
Code behind:
private static Entry newEntry = new Entry();
public static readonly BindableProperty DetailProperty = BindableProperty.Create(propertyName: nameof(Detail),
returnType: typeof(string),
declaringType: typeof(LabelledEntrywithIcon),
defaultValue: default(string));
public string Detail
{
get
{
return (string)GetValue(DetailProperty);
}
set => SetValue(DetailProperty, value);
}
private void EditIcon_Clicked(object sender, System.EventArgs e)
{
detailLabel = (Label)stackLayoutDetail.Children[1];
stackLayoutDetail.Children.RemoveAt(1);
newEntry.Text = Detail;
stackLayoutDetail.Children.Add(newEntry);
editIcon.IsVisible = false;
newEntry.Completed += NewEntry_Completed;
}
private void NewEntry_Completed(object sender, System.EventArgs e)
{
try
{
var _newText = newEntry.Text;
detailLabel.Text = _newText;
stackLayoutDetail.Children.RemoveAt(1);
stackLayoutDetail.Children.Add(detailLabel);
Detail = _newText;
editIcon.IsVisible = true;
}
catch (System.Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
Page
<local:LabelledEntrywithIcon x:Name="firstName"
Title="First Name"
Detail="{Binding Fella.FirstName}" />
<local:LabelledEntrywithIcon x:Name="lastname"
Title="Last Name"
Detail="{Binding Fella.LastName}" />
<local:LabelledEntrywithIcon x:Name="gender"
Title="Gender"
Detail="{Binding Fella.Gender}" />
Code behind:
ViewModel=new MainViewModel();
BindingContext = ViewModel;
Complete code to test is at Github repo : https://github.com/pmahend1/CustomViewDuplicationIssue
Strange but I changed a line of code and it works as expected now.
On the class variables changed private static Entry newEntry= new Entry(); to
private static Entry newEntry;
in EditIcon_Clicked method instead of newEntry.Text = Detail; used
newEntry = new Entry { Text = Detail };
I am not sure why it was taking same reference even though its new Entry for each LabelledEntrywithIcon
Instead of creating a new entry and finding and removing the label and adding the new entry after, you could simplify your problem by:
<StackLayout Orientation="Horizontal"
VerticalOptions="Start"
Padding="25,10,25,10">
<StackLayout x:Name="stackLayoutDetail"
HorizontalOptions="FillAndExpand">
<Label x:Name="title"
Text="{Binding Title}" />
<Label x:Name="detail"
Text="{Binding Detail}"
IsVisible="{Binding ShowLabel}"
FontSize="Large"
FontAttributes="Bold" />
<Entry ... IsVisible="{Binding ShowEntry}" ... />
</StackLayout>
<Image x:Name="editIcon"
Source="edit_icon.png"
WidthRequest="25"
HeightRequest="25"
IsVisible="{Binding ShowLabel}">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="EditIcon_Clicked" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
Note that I intentionally wrote ... inside the entry element as Placeholder for all customizations you might want do there (font size, etc...).
Now you add two BindablyProperties (type bool) ShowEntry and ShowLabel, where ShowLabel defaults to true and ShowEntry defaults to false.
Now all you have to do is to adapt your EditIcon_Clicked Event:
private void EditIcon_Clicked(object sender, System.EventArgs e)
{
ShowLabel = false;
ShowEntry = true;
newEntry.Text = Detail;
newEntry.Completed += NewEntry_Completed;
}
And adapt NewEntry_Completed to
private void NewEntry_Completed(object sender, System.EventArgs e)
{
try
{
var _newText = newEntry.Text;
detailLabel.Text = _newText;
ShowLabel = true;
ShowEntry = false;
Detail = _newText;
}
catch (System.Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
Basically this does the same as your solution, however you save yourself from having to push UI Items around in your codebehind and especially the bugs and errors coming with it.

RelayCommand.CanExecute not updating IsEnabled in UI

I have a Windows Phone 8 app and I have a RelayCommand Instance called DiscoverExpansionModulesCommand. I have a button with the Command property bound to DiscoverExpansionModulesCommand. When the app first loads, the button is enabled or disabled properly. However, when on the page and I want to change whether the command can execute, the method CanExecuteDiscoverExpansionModulesCommand() properly fires and it returns the proper true or false value, but the button does not reflect it. Why isn't button updating it's UI? I found another article on this issue here http://social.msdn.microsoft.com/Forums/en-US/silverlightarchieve/thread/48a341e4-f512-4c33-befd-b614404b4920/
My ViewModel:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using MAL.Portable.Commands;
using MAL.Portable.Message;
using MAL.Portable.Model;
using System;
using System.Collections.Generic;
using System.Windows.Input;
namespace MAL.Portable.ViewModel
{
public class SettingsViewModel : ViewModelBase
{
// Define an observable collection property that controls can bind to.
private List<Setting> settings;
private String controllerUrl;
private String controllerPort;
private String temperature;
private Wifi wifi;
private Boolean connected;
private Boolean checkingConnection;
public SettingsViewModel()
{
DiscoverExpansionModulesCommand = new RelayCommand(OnDiscoverExpansionModules, CanExecuteDiscoverExpansionModulesCommand);
Messenger.Default.Register<RetrieveSettingsMessage>
(
this, (action) => RetrievedListsMessage(action)
);
Messenger.Default.Send<GetSettingsMessage>(new GetSettingsMessage());
}
public ICommand DiscoverExpansionModulesCommand
{
get;
private set;
}
public String ConnectionStatus
{
get
{
if (checkingConnection)
return "checking";
else
return connected ? "connected" : "not connnected";
}
}
private Boolean CanExecuteDiscoverExpansionModulesCommand()
{
return connected;
}
private void OnDiscoverExpansionModules()
{
}
private void CheckConnection()
{
wifi = null;
if (!String.IsNullOrWhiteSpace(ControllerUrl) && !String.IsNullOrWhiteSpace(ControllerPort) && !checkingConnection)
{
checkingConnection = true;
wifi = new ReefAngelWifi(controllerUrl, controllerPort);
wifi.TestConnectionComplete += wifi_TestConnectionComplete;
wifi.RequestFail += wifi_RequestFail;
wifi.BeginTestConnection();
}
}
private void wifi_RequestFail(object sender, RequestExceptionEventArgs e)
{
connected = false;
checkingConnection = false;
RaisePropertyChanged("ConnectionStatus");
}
private void wifi_TestConnectionComplete(object sender, TestConnectionEventArgs e)
{
connected = e.TestSuccessful;
checkingConnection = false;
DiscoverExpansionModulesCommand.CanExecute(null);
RaisePropertyChanged("ConnectionStatus");
RaisePropertyChanged("DiscoverExpansionModulesCommand");
}
private object RetrievedListsMessage(RetrieveSettingsMessage action)
{
settings = action.Settings;
CheckConnection();
return null;
}
private String GetStringValue(String key)
{
if (settings == null) return String.Empty;
var item = settings.Find(x => x.Key == key);
if (item == null) return String.Empty;
else return item.Value;
}
private Boolean GetBooleanValue(String key)
{
if (settings == null) return false;
var item = settings.Find(x => x.Key == key);
if (item == null) return false;
else return Boolean.Parse(item.Value);
}
}
}
And the XAML
<phone:PhoneApplicationPage
xmlns:ReefAngel="clr-namespace:MAL.WindowsPhone8"
xmlns:Controls="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Input"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform.WP8"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:telerikPrimitives="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Primitives"
x:Class="MAL.WindowsPhone8.ReefAngel.SettingsPage"
xmlns:converter="clr-namespace:MAL.WindowsPhone8.Converters"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
DataContext="{Binding Settings, Source={StaticResource Locator}}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources>
<converter:BooleanToStringConverter x:Key="temperatureConverter" TrueString="Celsius" FalseString="Fahrenheit" />
<converter:BooleanToStringConverter x:Key="timeFormatConverter" TrueString="24 hour" FalseString="12 hour" />
<converter:BooleanToStringConverter x:Key="dateFormatConverter" TrueString="dd/mm/yyyy" FalseString="mm/dd/yyyy" />
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" >
<phone:Pivot Title="{Binding LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}, StringFormat='\{0\} Settings'}">
<phone:PivotItem Header="connection">
<Grid>
<StackPanel Margin="12,0,0,0">
<TextBlock Margin="0,20,0,0" TextWrapping="Wrap" Text="Reef Angel Wifi Address"/>
<TextBox Height="72" TextWrapping="Wrap" Text="{Binding ControllerUrl, Mode=TwoWay}"/>
<TextBlock Margin="0,20,0,0" TextWrapping="Wrap" Text="Reef Angel Wifi Port"/>
<TextBox Height="72" TextWrapping="Wrap" Text="{Binding ControllerPort, Mode=TwoWay}"/>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0,20,0,0" TextWrapping="Wrap" Text="Reef Angel Wifi Status : "/>
<TextBlock Margin="0,20,0,0" TextWrapping="Wrap" Text="{Binding ConnectionStatus, Mode=OneWay}"/>
</StackPanel>
</StackPanel>
</Grid>
</phone:PivotItem>
<phone:PivotItem Header="expansion">
<Grid>
<Button Content="Discover Expansion Modules" x:Name="DiscoverButton" Command="{Binding DiscoverExpansionModulesCommand, Mode=OneWay}" />
</Grid>
</phone:PivotItem>
</phone:Pivot>
</Grid>
</phone:PhoneApplicationPage>
I am using the MVVM Light Portable Class Libraries.
You need to call RelayCommand.RaiseCanExecuteChanged() when the conditions you evaluate inside your CanExecute method change.
Edit
private void wifi_RequestFail(object sender, RequestExceptionEventArgs e)
{
connected = false;
checkingConnection = false;
RaisePropertyChanged("ConnectionStatus");
DiscoverExpansionModulesCommand.RaiseCanExecuteChanged();
}
private void wifi_TestConnectionComplete(object sender, TestConnectionEventArgs e)
{
connected = e.TestSuccessful;
checkingConnection = false;
DiscoverExpansionModulesCommand.CanExecute(null);
RaisePropertyChanged("ConnectionStatus");
RaisePropertyChanged("DiscoverExpansionModulesCommand");
DiscoverExpansionModulesCommand.RaiseCanExecuteChanged();
}
This will not cause a loop as it only tells the RelayCommand to re-execute the specified CanExecute method. In your case this only means that the property CanExecuteDiscoverExpansionModulesCommand is read.
It appears to be a cross threading issue. And figuring out how to call a Dispatcher in the PCL was tricky, but I found it here: Update UI thread from portable class library

What's wrong with my Windows Phone 7 Databinding(no viewmodels used)?

I am having difficulty in databinding. I can successfully get the results but it just won't display. here is my code:
private List<FacebookFriend> friendList;
public List<FacebookFriend> FriendList
{
get { return friendList; }
set
{
friendList = value;
NotifyPropertyChanged("FriendList");
}
}
private void GetFbFriends()
{
var fb = new FacebookClient(_accessToken);
friendList = new List<FacebookFriend>();
fb.GetCompleted += (o, e) =>
{
if (e.Error != null)
{
return;
}
var result = (JsonObject)e.GetResultData();
foreach (var friend in (JsonArray)result["data"])
friendList.Add(new FacebookFriend()
{
Id = (string)(((JsonObject)friend)["id"]),
Name = (string)(((JsonObject)friend)["name"])
});
FriendList = friendList;
};
fb.GetAsync("me/friends");
}
then in the page's xaml:
<ListBox ScrollViewer.VerticalScrollBarVisibility="Auto" Grid.Row="2" Grid.ColumnSpan="3" ItemsSource="{Binding FriendList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Background="Red" Height="100" Width="300" Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}"/>
<TextBlock Text="{Binding Path=Id}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
It seems correct but still, it does not display anything. Any help is appreciated. Thanks so much!
Try using ObservableCollection<> instead of list<>. For more info please see this
Note: ObservableCollection is a generic dynamic data collection that provides notifications (using an interface "INotifyCollectionChanged") when items get added, removed, or when the whole collection is refreshed.

Resources