Windows Phone 7: Making ListBox items change dynamically - c#

I am working on creating a Windows Phone app that will play a series of sound clips selected from a list. I am using the MVVM (Model View View-Model) Design pattern and have designed a model for my data, along with a view model for my page. Here is what the XAML for the ListBox looks like:
<ListBox x:Name="MediaListBox" Margin="0,0,-12,0" ItemsSource="{Binding Media}" SelectionChanged="MediaListBox_SelectionChanged" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<ListBox.ItemTemplate >
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Orientation="Horizontal">
<Image Source="../Media/Images/play.png" />
<StackPanel >
<TextBlock Text="{Binding Title}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding ShortDescription}" TextWrapping="Wrap" Margin="12,-6,12,0" Visibility="{Binding ShortDescriptionVisibility}" Style="{StaticResource PhoneTextSubtleStyle}"/>
<TextBlock Text="{Binding LongDescription}" TextWrapping="Wrap" Visibility="{Binding LongDescriptionVisibility}" />
<StackPanel>
<Slider HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Visibility="{Binding LongDescriptionVisibility}" ValueChanged="Slider_ValueChanged" LargeChange="0.25" SmallChange="0.05" />
</StackPanel>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My question is this: I want to be able to expand and collapse part of the items in the ListBox. As you can see, I have a binding for the visibility. That binding is coming from the MediaModel. However, when I change this property in the ObservableCollection, the page is not updated to reflect this.
The ViewModel for this page looks like this:
public class ListenPageViewModel : INotifyPropertyChanged
{
public ListenPageViewModel()
{
this.Media = new ObservableCollection<MediaModel>;
}
/// <summary>
/// A collection for MediaModel objects.
/// </summary>
public ObservableCollection<MediaModel> Media { get; private set; }
public bool IsDataLoaded { get; private set; }
/// <summary>
/// Creates and adds the media to their respective collections.
/// </summary>
public void LoadData()
{
this.Media.Clear();
this.Media.Add(new MediaModel()
{
Title = "Media 1",
ShortDescription = "Short here.",
LongDescription = "Long here.",
MediaSource = "/Media/test.mp3",
LongDescriptionVisibility = Visibility.Collapsed,
ShortDescriptionVisibility = Visibility.Visible
});
this.Media.Add(new MediaModel()
{
Title = "Media 2",
ShortDescription = "Short here.",
LongDescription = "Long here.",
MediaSource = "/Media/test2.mp3",
LongDescriptionVisibility = Visibility.Collapsed,
ShortDescriptionVisibility = Visibility.Visible
});
this.IsDataLoaded = true;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The bindings work correctly and I am seeing the data displayed; however, when I change the properties, the list does not update. I believe that this may be because when I change things inside the observable collection, the property changed event is not firing.
What can I do to remedy this? I have poked around for some info on this, but many of the tutorials don't cover this kind of behavior. Any help would be greatly appreciated!
Thanks
Edit: As requested, I have added the MediaModel code:
public class MediaModel : INotifyPropertyChanged
{
public string Title { get; set; }
public string ShortDescription { get; set; }
public string LongDescription { get; set; }
public string MediaSource { get; set; }
public Visibility LongDescriptionVisibility { get; set; }
public Visibility ShortDescriptionVisibility { get; set; }
public MediaModel()
{
}
public MediaModel(string Title, string ShortDescription, string LongDescription, string MediaSource, Visibility LongDescriptionVisibility, Visibility ShortDescriptionVisibility)
{
this.Title = Title;
this.ShortDescription = ShortDescription;
this.LongDescription = LongDescription;
this.MediaSource = MediaSource;
this.LongDescriptionVisibility = LongDescriptionVisibility;
this.ShortDescriptionVisibility = ShortDescriptionVisibility;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Originally, I did not have this class implement the INotifyPropertyChanged. I did this to see if it would solve the problem. I was hoping this could just be a data object.

Try changing your long description visibility property to this to see if that fixes it
private Visibility _longDescriptionVisibility;
public Visibility LongDescriptionVisibility
{
get { return _longDescriptionVisibility; }
set
{
_longDescriptionVisibility = value;
NotifyPropertyChanged("LongDescriptionVisibility");
}
}
If it does make the same change to the short description property.

Related

Can the Visibility of a StackPanel (inside an ItemsControl) be controlled by a button?

I have a property List<Filter> Filters which is the ItemSource of an ItemsControl. What I am trying to accomplish is to show at the beginning only the filters which have the property IsShown = true. Then, when I push the button, to show the rest of the filters. Is it possible to be done using XAML? If no, which approach should I use?
The content of the Filter class is:
public List<string> Options { get; set; } = new List<string>();
public bool IsShown { get; set; }
public string Title { get; set; }
public string ValueSelected { get; set; }
public Filter(List<string> Options, string Title, string ValueSelected, bool IsShown)
{
this.Options = Options;
this.Title = Title;
this.ValueSelected = ValueSelected;
this.IsShown = IsShown;
}
In MainContext I have defined the List and a button:
public ObservableCollection<Filter> Filters { get; set; } = new ObservableCollection<Filter>();
public ICommand DoShowHide
In MainWindow.XAML at this point I have the following:
<ItemsControl ItemsSource="{Binding Filters}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Visibility="{Binding Path=IsShown, Converter={StaticResource BoolToVisConverter} }" Name="MyStackPanel">
<TextBlock Text="{Binding Title}"/>
<ComboBox ItemsSource="{Binding Path=Options}"
SelectedValue="{Binding Path=ValueSelected}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Show/Hide" Command="{Binding DoShowHide}"/>
with the mentioning that I have defined the converter
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</Window.Resources>
****I have tried to set all the filters' IsShown property to true at the push of the button. No need to mention that it did not work...
private void ShowHide(object obj)
{
MessageBox.Show("message");
foreach(Filter filter in Filters)
{
if(filter.IsShown == false)
{
filter.IsShown = true;
NotifyPropertyChanged("Filters");
}
}
}
Thank you for taking the time to read my question :)
Your Filter class must implement INotifyPropertyChanged. Otherwise property changes inside this class are not propagated to the binding system.
Raising the ProperyChanged event on the Filters property, as you did, is useless.
Note: you can use XOR operation to toggle boolean values (show/hide).
Shortened Filter class:
class Filter : INotifyPropertyChanged
{
private bool isDisplayed
public bool IsDisplayed
{
get => this.isDisplayed;
set
{
if (value != this.isDisplayed)
{
this.isDisplayed = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
The shortened DataTemplate for the Filter item:
<DataTemplate DataType="{x:Type Filter}">
<StackPanel Visibility="{Binding IsDisplayed, Converter={StaticResource BoolToVisibilityConverter}}">
</StackPanel>
</DataTemplate>
The modified ICommand execution handler:
private void ShowHide(object obj)
{
// Toggle all Filter.IsDisplayed
foreach (Filter filter in Filters)
{
filter.IsDisplayed ^= true;
}
}
you can make it using converter where you return the a visibility object

ItemsControl not updating after data change to an ObservableCollection<T> property

I have the following test code…
XAML:
<Page
x:Class="Test.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Test"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="using:Test"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Name="StartButton" Content="Start" Click="StartButton_Click" Height="30" Width="200"/>
<ItemsControl Grid.Row="1" Background="Gray" ItemsSource="{x:Bind RowItems}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="data:MyData">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind FirstName}" Margin="10,0,5,0"/>
<TextBlock Text="{x:Bind Surname}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Page>
Code behind:
namespace Test
{
public class MyData
{
public string FirstName { get; set; }
public string Surname { get; set; }
}
public class LoadData
{
public static void Get_RowItems(ObservableCollection<MyData> Items)
{
Items.Add(new MyData() { FirstName = "John", Surname = "Doe" });
}
}
public sealed partial class MainPage : Page
{
private ObservableCollection<MyData> RowItems;
public MainPage()
{
this.InitializeComponent();
RowItems = new ObservableCollection<MyData>();
LoadData.Get_RowItems(RowItems);
}
private void StartButton_Click(object sender, RoutedEventArgs e)
{
RowItems[0].FirstName = "Bill";
}
}
}
On running it, the ItemsControl displays the first line of data (John Doe) fine.
When the Start button is clicked, the underlying data changes to Bill Doe (as expected)
But, the ItemsControl stubbornly continues to display: John Doe
I’ve read so many articles relating to this kind of issue and none of the solutions seem to work (if I’ve implemented them correctly) so now I can’t see the wood for the trees.
Any help would be appreciated.
Like #Clemens said, you should just implement INotifyPropertyChanged event at the MyData class to notify UI when properties of the class are changed.
public class MyData:INotifyPropertyChanged
{
//public string FirstName { get; set; }
private string firstName;
public string FirstName
{
get { return firstName; }
set { firstName = value;
OnPropertyChanged("FirstName");
}
}
private string surName;
public string Surname
{
get { return surName; }
set { surName = value;
OnPropertyChanged("Surname");
}
}
//public string Surname { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You're not modifying the ObservableCollection itself (such as adding/removing items) but the items INSIDE that collection. The ObservableCollection is responsible for notifying its own changes, not changes pertaining to its items. You Should NotifyPropertyChange("EachYourProperty") in the setter of your MyData class and your UI will be updated.
And change your binding of yourTextBlock and "Surname" properties to "OneWay" cause by default it is set to "OneTime":
<TextBlock Text="{x:Bind FirstName, Mode=OneWay}" Margin="10,0,5,0"/>
<TextBlock Text="{x:Bind Surname, Mode=OneWay}"/>
As MSDN says:
One-way - Updates the binding target (target) property when the binding source (source) changes. This type of binding is appropriate if the control being bound is implicitly read-only.
One-time - Updates the binding target when the application starts or when the data context changes. This type of binding is appropriate if you are using data where either a snapshot of the current state is appropriate to use or the data is truly static.
Update 1:
If you have time-consuming operation after changing an item of ObservableCollection<T>, it is better to perform time-consuming operation at non-UI thread:
private void Button_Click(object sender, RoutedEventArgs e)
{
coll[0].FirstName = "Bill";
Task.Run(()=> {
Thread.Sleep(5000);
MessageBox.Show("");
});
}
Clemens is correct. In addition, the default for x:Bind is a OneTime binding, so it won't ever get updated. Instead you need something like:
<TextBlock Text="{x:Bind FirstName, Mode=OneWay}" Margin="10,0,5,0"/>
and the same thing for everywhere else you're using x:Bind.
Based on provided answers you can go a little further and define a common class for your entities and also notify in a strongly type way the view that the property value has changed:
public abstract class BaseEntity : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises the PropertyChanged event
/// </summary>
/// <param name="propertyName">Name of the property</param>
public void OnPropertyChanged(string propertyName)
{
var ev = PropertyChanged;
if (ev != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// Raises the PropertyChanged event
/// </summary>
/// <param name="expr">Lambda expression that identifies the updated property</param>
public void OnPropertyChanged<TProp>(Expression<Func<BaseEntity, TProp>> expr)
{
var prop = (MemberExpression)expr.Body;
OnPropertyChanged(prop.Member.Name);
}
}
public class MyData : BaseEntity
{
private string firstName;
public string FirstName
{
get { return firstName; }
set { firstName = value; OnPropertyChanged(e => FirstName); }
}
private string surName;
public string Surname
{
get { return surName; }
set { surName = value; OnPropertyChanged(e => Surname); }
}
}

C# ListBox Update Binding Text

I have a ListBox on WP8.1 and want to Bind some items in there. That works all fine, but changing a value on the ItemSource doesn't change anything in the ListBox
<ListBox x:Name="myListBox" Width="Auto" HorizontalAlignment="Stretch" Background="{x:Null}" Foreground="{x:Null}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="PanelTap" Tapped="PanelTap_Tapped">
<Border x:Name="BorderCollapsed">
<StackPanel Margin="105,0,0,0">
<TextBlock Text="{Binding myItem.location, Mode=TwoWay}" />
</StackPanel>
</Border>
</ListBox.ItemTemplate>
</ListBox>
I bind the items via
ObservableCollection<LBItemStruct> AllMyItems = new ObservableCollection<LBItemStruct>();
with
public sealed class LBItemStruct
{
public bool ext { get; set; }
public Container myItem { get; set; }
}
public sealed class Container
{
public string location{ get; set; }
...
}
and when I now want to change the TextBlock Text, nothing happens
private void PanelTap_Tapped(object sender, TappedRoutedEventArgs e)
{
int sel = myListBox.SelectedIndex;
if (sel >= 0)
{
myListBox[sel].myItem.location = "sonst wo";
}
}
The PanelTap_Tapped gets triggered, when I tap the Panel (checked via Debug), but the TextBlock Text does not change
If you want the view to update when a property changes, then you need to have the source object implement INotifyPropertyChaned, and raise the PropertyChanged event:
public sealed class Container : INotifyPropertyChanged
{
public string location
{
get { return _location; }
set { _location = value; RaisePropertyChanged("location"); }
}
private string _location;
...
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propName)
{
var handler = PropertyChanged;
if (handler != null)
handler(new PropertyChangedEventArgs(this, propName));
}
}

Trouble Binding class to grid, second place

So I'm trying to create my own music player.
I have a Listview updating properly with current playlist.
My problem begins when I want a grid to show the song which is currently playing.
When binding to those strings they all return Null.
From Class:
public class Song : INotifyPropertyChanged
{
public string Title { get; set; }
public string Path { get; set; }
public string Artist { get; set; }
public int Time { get; set; }
public string Album { get; set; }
//public ImageBrush Portrait { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public Song(string title, string path, string artist, int time, string album)//, ImageBrush portrait)
{
this.Path = path;
this.Title = title;
this.Artist = artist;
this.Time = time;
this.Album = album;
//this.Portrait = portrait;
}
public string SongCurrentPlaying
{
get { return Title; }
set
{
Title = value;
OnPropertyChanged("SongCurrentPlaying");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(Title));
}
}
From XAML:
<Grid HorizontalAlignment="Left" Height="143" VerticalAlignment="Top" Width="276">
<Image HorizontalAlignment="Left" Height="124" Margin="10,10,0,0" VerticalAlignment="Top" Width="134" Stretch="Fill"/>
<TextBlock HorizontalAlignment="Left" Margin="144,100,0,0" TextWrapping="Wrap" Text="{Binding Songs.Title}" VerticalAlignment="Top" Height="25" Width="122"/>
<TextBlock HorizontalAlignment="Left" Margin="144,40,0,0" TextWrapping="Wrap" Text="{Binding SongCurrentPlaying.Title, PresentationTraceSources.TraceLevel=High}" VerticalAlignment="Top" Height="25" Width="122"/>
<TextBlock HorizontalAlignment="Left" Margin="144,70,0,0" TextWrapping="Wrap" Text="{Binding Song.Title}" VerticalAlignment="Top" Height="25" Width="122"/>
<TextBlock HorizontalAlignment="Left" Margin="144,10,0,0" TextWrapping="Wrap" Text="{Binding Songs.Title}" VerticalAlignment="Top" Height="25" Width="122"/>
</Grid>
As you can see I've been experimenting on different bindings to get values from Title as example, none has been successful.
Your class structure does not make much sense. You have a Song class that holds a Song's information. However, that class also holds SongCurrentPlaying. Now, if you mean to have SongCurentPlaying on the same class as Song then I would narrow down your issue to how you have performed the XAML bindings. I would assume that the DataContext of your control has not been set to an instance of Song. e.g.
public partial class MainWindow : Window
{
public MainWindow()
{
var someSong = new Song(...);
this.DataContext = someSong;
InitializeComponent();
}
}
Once set as the DataContext you may then bind to the class' properties directly (e.g. {Binding Title}).
Your song class does not need to implement INotifyPropertyChanged. You should think of your songs as models. Instead you should be making a viewmodel for your music player that will hold all your information for your view such as in this case CurrentSongPlaying.
I would make a viewmodel that looks like this
internal class SongPlayerViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Song _songPlaying;
public Song SongPlaying
{
get { return _songPlaying; }
set {
_songPlaying = value;
OnPropertyChanged("SongPlaying");
}
}
protected void OnPropertyChanged(string name)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
Then make sure to set the datacontext to an instance of this in the view and inside of the xaml just bind the the title with code like this.
datacontext setup
private readonly SongPlayerViewModel _viewModel = new SongPlayerViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _viewModel;
}
example xaml binding for current song playing
<TextBlock text="{Binding SongPlaying.Title}"/>
If you want something when no song is playing look into Fallbackvalue

Add additional control to ObervableCollection

I'm really new to WPF so apologies in adavnced if this is an obvious question. I have a simple Checkbox in XAML as
<ListBox ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Selections}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid >
<CheckBox IsChecked="{Binding IsChecked}"
Content="{Binding Path=Item.SelectionName}" />
</Grid >
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Simplified code behind to allow bindings and INotifyPropertyChanged is:
public ObservableCollection<CheckedListItem<Selection>> Selections { get; set; }
public class Selection
{
public String SelectionName { get; set; }
}
Selections = new ObservableCollection<CheckedListItem<Selection>>();
Selections.Add(new CheckedListItem<Selection>(new Selection()
{ SelectionName = "SomeName" }, isChecked: true));
public class CheckedListItem<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool isChecked;
private T item;
public CheckedListItem()
{ }
public CheckedListItem(T item, bool isChecked = false)
{
this.item = item;
this.isChecked = isChecked;
}
public T Item
{
get { return item; }
set
{
item = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Item"));
}
}
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
}
}
}
I now need to add an additional TextBox associated with each Checkbox, so in XAML I have
<ListBox ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Selections}" Margin="12,22,12,94">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid >
<CheckBox IsChecked="{Binding IsChecked}"
Content="{Binding Path=Item.SelectionName}" />
<<TextBox />
</Grid >
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'm a bit stumped how to include this as part of the ObservableCollection and set it up the binding on both the CheckBox and associated TextBox? Both are being added together using Selections.Add(new CheckedListItem<Selection>(new Selection()
{ SelectionName = "SomeName" }, isChecked: true)); which is causing me some confusion.
EDIT: Added full code
public partial class SelectionSettingWindow : Window
{
public ObservableCollection<CheckedListItem<Selection>> Selections { get; set; }
public class Selection
{
public String SelectionName { get; set; }
public string SelectionTextField { get; set; }
}
public SelectionSettingWindow()
{
InitializeComponent();
Selections = new ObservableCollection<CheckedListItem<Selection>>();
string fg = #"Item1,true,TExtbox1text:Item2,true,TExtbox2text:Item3,false,TExtbox3text"; //Test String
string[] splitSelections = fg.Split(':');
foreach (string item in splitSelections)
{
string[] spSelectionSetting = item.Split(',');
bool bchecked = bool.Parse(spSelectionSetting[1].ToString());
string tbText = spSelectionSetting[2].ToString();
Selections.Add(new CheckedListItem<Selection>(new Selection()
{ SelectionName = spSelectionSetting[0].ToString(),
SelectionTextField = bText }, isChecked: bchecked));
}
DataContext = this;
}
public class CheckedListItem<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool isChecked;
private T item;
private string textField;
public CheckedListItem()
{ }
public CheckedListItem(T item, bool isChecked = false)
{
this.item = item;
this.isChecked = isChecked;
}
public T Item
{
get { return item; }
set
{
item = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Item"));
}
}
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
}
}
public string TextField
{
get { return textField; }
set
{
textField = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("TextField"));
}
}
}
}
<ListBox ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Selections}" Margin="12,22,12,94">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}"
Content="{Binding Path=Item.SelectionName}" />
<TextBox Text="{Binding Item.SelectionTextField, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
replace SelectionTextField above with whatever the field is that needs to be edited using the textbox on your Selection class.
Note that I changed the <Grid> to a <StackPanel> So they wouldn't appear on top of eachother and changed the bindings to TwoWay so the changes are reflected in the model.
Make sure your Selection class implements INotifyPropertyChanged (ObservableCollection updates the UI when things get added to/removed from the collection, it doesn't know anything about notifying when it's content's properties change so they need to do that on their own)
Implementing INotifyPropertyChanged on many classes can be cumbersome. I find implementing a base class useful for this. I've got this along with an extra reflection helper for raise property changed available here and a snippet I've made available. It's silverlight but it should work fine for WPF. Using the code I've provided via download you can simply type proprpc and hit tab and visual studio will stub in a property that notifies on change. Some explanation is in one of my old blog posts here and gives credit for where I based the code and snippet from.

Categories

Resources