I have created in my viewmodel Dictionary<string, string>.
public ObservableCollection<Dictionary<string, string>> ObjectDetailsRows { get; set; } = new ObservableCollection<Dictionary<string, string>>();
public void SomeMethod()
{
...
//add some items to a dictionary..
...
OnPropertyChanged(nameof(ObjectDetailsRows));
}
On my XAML part Im trying to do this:
<ListView
ItemsSource="{Binding Path=ObjectDetailsRows}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell TextColor="Black" Text="{Binding Key}" Detail="{Binding Value}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I can clearly see that I binded correctly my dictionary, I can see lines on my page (in emulator).
If I remove binding for example Key and put just Text="some text" it works and populates all 26 rows, based on provided dictionary (which has 26 objects).
But when I set just like this Text="{Bindings Key}" or Text="{Bindings Value}" it gives me nothing.
UPDATE:
public class CustomPin : Pin
{
//string base64
public string PinIcon { get; set; }
public Color Color { get; set; }
public InfoBoxMapModel InfoBox { get; set; } = new InfoBoxMapModel();
public int Id { get; set; }
}
public class InfoBoxMapModel
{
//base64
public string ImageString { get; set; }
public List<string> Items { get; set; } = new List<string>();
public Dictionary<string, string> ItemsTest { get; set; } = new Dictionary<string, string>();
}
private async Task GetObjectInstancesList()
{
var objectsResponse = await ApiServiceProvider.GetObjectInstances();
Device.BeginInvokeOnMainThread(() =>
{
ListOfObjects = new ObservableCollection<CustomPin>();
if (objectsResponse.Succeeded)
{
foreach (var item in objectsResponse.ObjectInstances)
{
CustomPin pinData = new CustomPin();
pinData.Id = item.IdObjectInstance;
pinData.Label = item.ObjectClassName;
if (item.Points != null)
{
pinData.Position = new Position(item.Points.FirstOrDefault().Latitude, item.Points.FirstOrDefault().Longitude);
}
else
{
//add polygon
}
Guid id = Guid.NewGuid();
foreach (var s in item.Strings)
{
pinData.InfoBox.ItemsTest.Add(s.ClassParameterName+id + ": ", s.StringValue);
}
foreach (var i in item.Integers)
{
if (i.IntValue.HasValue)
{
pinData.InfoBox.ItemsTest.Add(i.ClassParameterName+id +": ", i.IntValue.Value.ToString());
}
}
foreach (var date in item.Dates.Take(1))
{
pinData.InfoBox.ItemsTest.Add(date.ClassParameterName + id + ": ", date.DateValue.ToString());
}
ListOfObjects.Add(pinData);
}
}
TemporalData.ObjectsData = ListOfObjects;
OnPropertyChanged(nameof(ListOfObjects));
OnPropertyChanged(nameof(TemporalData.ObjectsData));
});
}
Ive tried this xaml:
<ListView
ItemsSource="{Binding ListOfObjects}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell TextColor="Black" Text="{Binding InfoBox.ItemsTest}" Detail="{Binding Value}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Related
I have a CollectionView with groups. Each group has a string with a Date.
I subsequently created a CarouselView with all the dates of the CollectionView groups.
I am trying to create a way to scroll the elements of the CarouselView and consequently scroll the CollectionView to the corresponding group, but it doesn't work.
The CollectionView remains stationary.
<CollectionView x:Name="CollectionDiary"....../>
c#
public class HumorGroup : ObservableCollection<HumorDiary>
{
public string Name { get; private set; }
public HumorGroup(string name, ObservableCollection<HumorDiary> icon) : base(icon)
{
Name = name;
}
}
public ObservableCollection<HumorGroup> TotHumor { get; private set; } = new ObservableCollection<HumorGroup>();
HumorGroup group = new HumorGroup("Month" + " " + Year, new ObservableCollection<HumorDiary>());
TotHumor.Add(group);
group.Add(item HumorDiary);
private void ScrollCollectionView_Clicked(object sender, EventArgs e)
{
var current = CarouselView.CurrentItem as HumorGroup;
CollectionDiary.ScrollTo(current, position: ScrollToPosition.Start);
}
I am trying to create a way to scroll the elements of the CarouselView and consequently scroll the CollectionView to the corresponding group, but it doesn't work.
I agree with Jason's opinion, you can let CollectionView to scroll to the first item for current group in the CarouselView_Scrolled event.
private void CarouselView_Scrolled(object sender, ItemsViewScrolledEventArgs e)
{
var current = CarouselView1.CurrentItem as HumorGroup;
if(current!=null)
{
CollectionDiary.ScrollTo(current.FirstOrDefault(),ScrollToPosition.Center);
}
}
I do one sample that you can take a look:
<StackLayout>
<CarouselView
x:Name="CarouselView1"
ItemsSource="{Binding humors}"
Scrolled="CarouselView_Scrolled">
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding Name}" />
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
<CollectionView
x:Name="CollectionDiary"
HeightRequest="100"
IsGrouped="True"
ItemsSource="{Binding humors}"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding name}" />
<Label Text="{Binding count}" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.GroupHeaderTemplate>
<DataTemplate>
<Label
BackgroundColor="LightGray"
FontAttributes="Bold"
FontSize="Large"
Text="{Binding Name}" />
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
</CollectionView>
</StackLayout>
public partial class Page8 : ContentPage
{
public GroupHumorViewmodel groups { get; set; }
public Page8()
{
InitializeComponent();
groups = new GroupHumorViewmodel();
this.BindingContext =groups;
}
private void CarouselView_Scrolled(object sender, ItemsViewScrolledEventArgs e)
{
var current = CarouselView1.CurrentItem as HumorGroup;
if(current!=null)
{
CollectionDiary.ScrollTo(current.FirstOrDefault(),ScrollToPosition.Center);
}
}
}
public class HumorDiary
{
public string name { get; set; }
public int count { get; set; }
}
public class HumorGroup:ObservableCollection<HumorDiary>
{
public string Name { get; set; }
public HumorGroup(string name, ObservableCollection<HumorDiary> humor) : base(humor)
{
Name = name;
}
}
public class GroupHumorViewmodel
{
public ObservableCollection<HumorGroup> humors { get; set; }
public GroupHumorViewmodel()
{
humors = new ObservableCollection<HumorGroup>();
humors.Add(new HumorGroup("2021",new ObservableCollection<HumorDiary>() {
new HumorDiary(){name="2021-day1",count=3},
new HumorDiary(){name="2021-day2",count=3},
new HumorDiary(){name="2021-day3",count=4},
new HumorDiary(){name="2021-day4",count=2},
new HumorDiary(){name="2021-day5",count=5},
new HumorDiary(){name="2021-day6",count=4},
new HumorDiary(){name="2021-day7",count=2},
new HumorDiary(){name="2021-day8",count=5}
}));
humors.Add(new HumorGroup("2020", new ObservableCollection<HumorDiary>() {
new HumorDiary(){name="2020-day1",count=3},
new HumorDiary(){name="2020-day2",count=3},
new HumorDiary(){name="2020-day3",count=4},
new HumorDiary(){name="2020-day4",count=2},
new HumorDiary(){name="2020-day5",count=5},
new HumorDiary(){name="2020-day6",count=4},
new HumorDiary(){name="2020-day7",count=2},
new HumorDiary(){name="2020-day8",count=5}
}));
humors.Add(new HumorGroup("2019", new ObservableCollection<HumorDiary>() {
new HumorDiary(){name="2019-day1",count=3},
new HumorDiary(){name="2019-day2",count=3},
new HumorDiary(){name="2019-day3",count=4},
new HumorDiary(){name="2019-day4",count=2},
new HumorDiary(){name="2019-day5",count=5},
new HumorDiary(){name="2019-day6",count=4},
new HumorDiary(){name="2019-day7",count=2},
new HumorDiary(){name="2019-day8",count=5}
}));
}
}
I am trying to bind a ObservableCollection on a ListView ItemsSource but it doesn't show anything to me, tried binding inside code, on the xaml..
public partial class ReadPage : ContentPage
{
private CarregarClientes _CClientes = new CarregarClientes();
private MySQLCon _db = new MySQLCon();
private MySQLConOverloads _over = new MySQLConOverloads();
private MySQLiteCon _dbSqLiteCon = new MySQLiteCon();
private MySQLiteConOverloads _oversqlite = new MySQLiteConOverloads();
//MY OBSERVABLECOLLECTION DEFINITION -----------------------------
public ObservableCollection<Clientes> _ClientesList { get; set; }
private string _tabela = "Clientes";
public ReadPage()
{
InitializeComponent();
backBtn.Clicked += async (s, o) => await Navigation.PopModalAsync();
//Method used to populate the ObservableCollection (_ClientesList);
PopularObservableCollection();
}
I am defining the ObservableCollection inside my ReadPage class, then populating it with a method called PopularObservableCollection.
public void PopularObservableCollection()
{
_ClientesList = new ObservableCollection<Clientes>();
int quantidadeDados = _CClientes.CNumeroItems() -1;
List<string> id = _CClientes.Cid();
List<string> debito = _CClientes.CDebito();
List<string> endereco = _CClientes.CEndereco();
List<string> nome = _CClientes.CNome();
List<string> observacao = _CClientes.CObservacao();
List<string> saldo = _CClientes.CSaldo();
List<string> telefone = _CClientes.CTelefone();
for (int i = 0; i <= quantidadeDados; i++)
{
_ClientesList.Add(new Clientes
{
id = id[i],
Debito = debito[i],
Endereco = endereco[i],
Nome = nome[i],
Observacao = observacao[i],
Saldo = saldo[i],
Telefone = telefone[i]
});
}
}
Clientes.cs:
public class Clientes : BindableObject
{
public string id { get; set; }
public string Nome { get; set; }
public string Endereco { get; set; }
public string Telefone { get; set; }
public string Debito { get; set; }
public string Saldo { get; set; }
public string Observacao { get; set; }
}
XAML:
<ListView
BindingContext="{Binding Source={x:Reference MyPage}, Path=.}"
x:Name="readListView"
BackgroundColor="PaleVioletRed"
HasUnevenRows="True"
CachingStrategy="RecycleElement"
HorizontalOptions="FillAndExpand"
ItemsSource="{Binding _ClientesList}"
VerticalOptions="FillAndExpand"
ItemTapped="ReadListView_OnItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Label Text="Id:" Grid.Row="0"/>
<Label Text="{Binding id}" Grid.Row="0" Margin="10,0,0,0"/>
<Label Text="{Binding Nome}" Grid.Row="1" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I want to bind my Treeview control to a collection that holds objects of type MeasurementResult. The MeasurementResult object itself has two collections, one for MeasurementInfo and one for DeviceInfo types.
After googling and searching on SO I found out that the best solution might be a CompositeCollection. The problem I have with that is that I just can't figure out how to define the (Hierarchical?!)DataTemplate's in a way that my data get shown in the Treeview in the way I want it.
Ultimately I would like to have a TreeView structure like that:
-MeasurementResult1
---MeasurementInformation
------MeasurementInformation1
------MeasurementInformation2
------MeasurementInformation3
---DeviceInformation
------DeviceInformation1
------DeviceInformation2
------DeviceInformation3
-MeasurementResult2
---MeasurementInformation
------MeasurementInformation1
------MeasurementInformation2
------MeasurementInformation3
---DeviceInformation
------DeviceInformation1
------DeviceInformation2
------DeviceInformation3
-MeasurementResultN
But the problem is that my current Treeview looks like that:
The nested properties for MeasurementData and DeviceData are not shown in my TreeView.
The code that I have so far, XAML:
<local:TreeViewSampleData x:Key="TreeViewSampleData"/>
<DataTemplate x:Key="MeasurementDataTemplate">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Finished: " Margin="0,0,10,0"/>
<TextBlock Text="{Binding Finished}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Median: " Margin="0,0,10,0"/>
<TextBlock Text="{Binding Median}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Maximum: " Margin="0,0,10,0"/>
<TextBlock Text="{Binding Maximum}" />
</StackPanel>
</StackPanel>
</DataTemplate>
<HierarchicalDataTemplate x:Key="DeviceDataTemplate" DataType="{x:Type local:DeviceData}" ItemTemplate="{StaticResource MeasurementDataTemplate}"
ItemsSource="{Binding MeasurementData}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="MeasurementResultTemplate" DataType="{x:Type local:MeasurementResult}" ItemTemplate="{StaticResource DeviceDataTemplate}"
ItemsSource="{Binding Measurements}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<telerik:RadTreeView x:Name="tvMeasResults"
ItemsSource="{Binding Source={StaticResource TreeViewSampleData}, Path = MeasurementResults}"
ItemTemplate="{StaticResource MeasurementResultTemplate}"
>
</telerik:RadTreeView>
My related classes:
public class MeasurementResult
{
public string Name { get; set; } = "Measurement Result";
internal ObservableCollection<MeasurementInfo> MeasurementInfo { get; set; }
internal ObservableCollection<DeviceInfo> DeviceInfo { get; set; }
public CompositeCollection Measurements
{
get
{
var items = new CompositeCollection();
items.Add(new CollectionContainer { Collection = MeasurementInfo });
items.Add(new CollectionContainer { Collection = DeviceInfo });
return items;
}
}
public MeasurementResult()
{
MeasurementInfo = new ObservableCollection<MeasurementInfo>();
DeviceInfo = new ObservableCollection<DeviceInfo>();
}
}
public class MeasurementInfo
{
public string Name { get; set; } = "Measurement Information";
public ObservableCollection<MeasurementData> ThicknessData { get; set; }
public MeasurementInfo()
{
ThicknessData = new ObservableCollection<MeasurementData>();
}
}
public class MeasurementData
{
public DateTime Finished { internal set; get; }
public double Median { internal set; get; }
public double Maximum { internal set; get; }
public MeasurementData()
{
Finished = DateTime.Now;
Median = 150;
Maximum = 200;
}
}
public class DeviceInfo
{
public string Name { get; set; } = "Device Information";
public ObservableCollection<DeviceData> DeviceData { get; set; }
public DeviceInfo()
{
DeviceData = new ObservableCollection<DeviceData>();
}
}
public class DeviceData
{
public DateTime Finished { internal set; get; }
public int Port { internal set; get; }
public int Slot { internal set; get; }
public DeviceData()
{
Finished = DateTime.Now;
Port = 1;
Slot = 1;
}
}
What is wrong with my bindings? I guess the DataTemplates are wrong but I couldn't figure out how to define them to get my expected result.
This will allow you to add specific items to specific leaves and they will be concatenated by GetEnumerator so the TreeView presents things in the way you expected.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace WpfApp1
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
var item = new InformationTreeItem("ROOT")
{
Children =
{
new InformationTreeItem("Level 1")
{
DeviceInformation =
{
new DeviceInformation("Device 1/1"),
new DeviceInformation("Device 1/2")
},
MeasurementInformation =
{
new MeasurementInformation("Measure 1/1"),
new MeasurementInformation("Measure 1/2")
},
Children =
{
new InformationTreeItem("Level 2")
{
DeviceInformation =
{
new DeviceInformation("Device 2/1"),
new DeviceInformation("Device 2/2")
},
MeasurementInformation =
{
new MeasurementInformation("Measure 2/1"),
new MeasurementInformation("Measure 2/2")
},
Children =
{
new InformationTreeItem("Level 3")
}
}
}
}
}
};
DataContext = item;
}
}
public interface IInformation
{
string Description { get; }
}
public class InformationTreeItem : IEnumerable<IInformation>, IInformation
{
public InformationTreeItem(string description)
{
Description = description;
}
private InformationTreeItem(string description, IList<IInformation> children)
{
Description = description;
Children = children;
}
public IList<IInformation> Children { get; } = new List<IInformation>();
public IList<DeviceInformation> DeviceInformation { get; } = new List<DeviceInformation>();
public IList<MeasurementInformation> MeasurementInformation { get; } = new List<MeasurementInformation>();
public string Description { get; }
public IEnumerator<IInformation> GetEnumerator()
{
var list = new List<IInformation>();
if (DeviceInformation.Any())
{
list.Add(new InformationTreeItem(nameof(DeviceInformation), new List<IInformation>(DeviceInformation)));
}
if (MeasurementInformation.Any())
{
list.Add(new InformationTreeItem(nameof(MeasurementInformation), new List<IInformation>(MeasurementInformation)));
}
foreach (var child in Children)
{
list.Add(child);
}
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override string ToString()
{
return Description;
}
}
public class DeviceInformation : IInformation
{
public DeviceInformation(string description)
{
Description = description;
}
public string Description { get; }
public override string ToString()
{
return Description;
}
}
public class MeasurementInformation : IInformation
{
public MeasurementInformation(string description)
{
Description = description;
}
public string Description { get; }
public override string ToString()
{
return Description;
}
}
}
I update ObservableCollection List but UI is not updating from Tab Page
I also clear List then Assign new list, Value of list is change but UI is not updated
public ObservableCollection<Dashboard> DetailsList { get; set; } = new ObservableCollection<Dashboard>();
//API Call
details = await _clientAPI.getDashboardDetails(id);
if (details != null)
{
DetailsList.Clear();
foreach (var item in details)
{
DetailsList.Add(item);
}
}
I think you miss to binding the context. Add the code below.
this.BindingContext = this;
I make a code sample for your reference. I am not sure what your Model, I use a simple model to test.
Page1.xaml.cs
public partial class Page1 : ContentPage
{
public ObservableCollection<Dashboard> DetailsList { get; set; }
public Page1()
{
InitializeComponent();
DetailsList = new ObservableCollection<Dashboard>()
{
new Dashboard(){ Name="AA", Country="CountryA"},
new Dashboard(){ Name="BB", Country="CountryB"},
};
this.BindingContext = this;
}
private void btnUpdate_Clicked(object sender, EventArgs e)
{
List<Dashboard> details = new List<Dashboard>();
details.Add(new Dashboard() { Name = "CC", Country = "CountryC" });
details.Add(new Dashboard() { Name = "DD", Country = "CountryD" });
if (details != null)
{
DetailsList.Clear();
foreach (var item in details)
{
DetailsList.Add(item);
}
}
}
}
public class Dashboard
{
public string Name { get; set; }
public string Country { get; set; }
}
Xaml:
<ContentPage.Content>
<StackLayout>
<Button
x:Name="btnUpdate"
Clicked="btnUpdate_Clicked"
Text="Update" />
<ListView ItemsSource="{Binding DetailsList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Name}" />
<Label Text="{Binding Country}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
Updated:
public ObservableCollection<Dashboard> DetailsList { get; set; } = new ObservableCollection<Dashboard>();
//API Call
details = await _clientAPI.getDashboardDetails(id);
if (details != null)
{
DetailsList.Clear();
foreach (var item in details)
{
DetailsList.Add(item);
}
}
YourGridView.ItemSource =DetailsList;
YourGridView.ItemSource =DetailsList
You are missing this line. This code - it just assigns ObservableCollection to gridview (which you want to display the data)
Thanks!!!
I've created a ListView in Xamarin form and bind to Observable collection in view model, adding item dynamically to ListView is working fine by calling OnPropertyChanged event.
But after getting status update from service I'm updating corresponding ListView item status and calling OnPropertyChanged event as well as re-assigining the ListView items to it but didn't get updated GUI properly sometimes working and some times not.
Below is the sample code that I've done.
<ListView Grid.Row="3" HasUnevenRows="True" ItemsSource="{Binding ServiceList}" IsPullToRefreshEnabled="True" SeparatorColor="Black">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Spacing="4" Padding="5" BackgroundColor="LightGray">
<Label Text="{Binding OperationStatus, Converter={x:Static local:StatusMessageConverter.Default}}" FontSize="13" FontAttributes="Bold" TextColor="White" BackgroundColor="DarkCyan" />
<Label Text="{Binding Operation}" FontSize="10" Margin="10,0,0,0" />
<Label Text="{Binding OperationType}" FontSize="10" Margin="10,0,0,0" />
<Label Text="{Binding OperationStatus}" LineBreakMode="WordWrap" IsVisible="{Binding CanStatusVisible}" FontSize="10" Margin="10,0,0,0" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public class ServiceViewModel : INotifyPropertyChanged
{
public ObservableCollection<ServiceItem> ServiceList
{
get
{
return _serviceList;
}
set
{
_serviceList = value;
OnPropertyChanged("ServiceList");
}
}
var tempList = new ObservableCollection<ServiceItem>();
tempList = ServiceList;
var targetItem = from item in tempList
where item.UniqueId == uniqueId
select item;
if (targetItem.Any())
{
var resultItem = targetItem.FirstOrDefault();
resultItem.CanStatusVisible = true;
resultItem.OperationStatus = string.Format("{0}: {1}", "Status Message", resultMessage);
}
ServiceList = null;
ServiceList = tempList;
OnPropertyChanged("ServiceList");
}
public class ServiceItem
{
public string UniqueId { get; set; }
public string Operation { get; set; }
public string OperationType { get; set; }
public string OperationStatus { get; set; }
public string StatusMessage { get; set; }
public bool CanStatusVisible { get; set; }
}
See to it that your model class inherits from INotifyPropertyChangedinterface(as mentioned in the above comments).
public class ServiceItem :INotifyPropertyChanged
{
private string uniqueId,operation,operationType,operationStatus,statusMessage;
private bool statusVisible;
public string UniqueId { get { return uniqueId; } set { uniqueId= value; RaisePropertyChanged(nameof(UniqueId)); } }
public string Operation { get { return operation; } set { operation= value; RaisePropertyChanged(nameof(Operation)); } }
public string OperationType { get { return operationType; } set { operationType= value; RaisePropertyChanged(nameof(OperationType)); } }
public string OperationStatus { get { return operationStatus; } set { operationStatus= value; RaisePropertyChanged(nameof(OperationStatus)); } }
public string StatusMessage { get { return statusMessage; } set { statusMessage= value; RaisePropertyChanged(nameof(StatusMessage)); } }
public bool CanStatusVisible { get { return statusVisible; } set { statusVisible= value; RaisePropertyChanged(nameof(CanStatusVisible )); } }
}
Then your ViewModel code should look something like this:
var tempList = new ObservableCollection<ServiceItem>();
tempList = ServiceList;
var targetItem = from item in tempList
where item.UniqueId == uniqueId
select item;
if (targetItem.Any())
{
var resultItem = targetItem.FirstOrDefault();
resultItem.CanStatusVisible = true;
resultItem.OperationStatus = string.Format("{0}: {1}", "Status Message", resultMessage);
}
ServiceList = null;
ServiceList = tempList;
Once you do these changes your code should work
--- To clarify my comment on FreakyAli's good answer ---
The essential part of FreakyAli's answer is the first code snippet:
public class ServiceItem :INotifyPropertyChanged
...
Once that is done, the other code in question can be greatly simplified. I think (though I have not tested) that you can replace all the code Ali shows under "Then your ViewModel code should look something like this:" with:
ServiceItem resultItem = ServiceList.Where(item => item.UniqueId == uniqueId).FirstOrDefault();
if (resultItem != null)
{
resultItem.CanStatusVisible = true;
resultItem.OperationStatus = string.Format("{0}: {1}", "Status Message", resultMessage);
}
That is, it is not necessary to create a temp list, nor to manipulate ServiceList. When you change the property of a ServiceItem, that property's RaisePropertyChanged will trigger the needed display refresh.