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

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); }
}
}

Related

My UserControl's TextBlock binding doesn't update even once

I know this has been asked for many times. I read a lot of them and tried different ways but still could not get it to work.
The xaml code is a UserControl:
<Grid Name="middle">
<d:TextBlock Text="{x:Bind LayerNodeData.CleanName, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Foreground="WhiteSmoke" FontSize="12" FontFamily="Arial" VerticalAlignment="Center" RelativePanel.RightOf="visibleUI" DoubleTapped="OnEditNameBegin" />
</Grid>
I set both this.DataContext and the Grid's DataContext to the data instance.
c#
public ucLayerRow(ImageLayerNode data)
{
LayerNodeData = data;
DataContext = LayerNodeData;
this.InitializeComponent();
middle.DataContext = LayerNodeData;
LayerNodeData.NotifyPropertyChanged("CleanName"); // test if it work
RefreshUI();
}
Model class
public partial class ImageLayerNode : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
// PropertyChanged is always null.
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public string mCleanName = string.Empty;
public string CleanName {
get => mCleanName;
set { mCleanName = value; NotifyPropertyChanged();}
}
....
}
I tried add a breakpoint to the PropertyChanged and found that it is always null and thus never get called. I also tried changing the mode to OneWay, TwoWays but still nothing.
The textblock is away empty not even getting a value once.
The user control is added like this to the main page. Not sure if it is related.
var rowUI = new ucLayerRow(layerNode);
layerContainer.Children.Add(rowUI);
My UserControl's TextBlock binding doesn't update even once
During the testing, the problem looks that you use design time for usercontrol. <d:TextBlock/> please remove d: and make your usercontrol like the following.
Xaml
<Grid>
<TextBlock
VerticalAlignment="Center"
FontFamily="Arial"
FontSize="12"
Foreground="Red"
Text="{x:Bind LayerNodeData.CleanName, Mode=OneWay}" />
</Grid>
Code behind
public sealed partial class ucLayerRow : UserControl
{
public ucLayerRow(ImageLayerNode data)
{
this.InitializeComponent();
LayerNodeData = data;
}
public ImageLayerNode LayerNodeData { get; set; }
}
public partial class ImageLayerNode : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
// PropertyChanged is always null.
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
private string mCleanName = string.Empty;
public string CleanName
{
get => mCleanName;
set { mCleanName = value; NotifyPropertyChanged(); }
}
}

Recognizing checkbox created by a template in a fired event

I've created an unfoldable list of checkboxes like so.
<Expander x:Name=...>
<ListBox ItemsSource="{x:Static local:MainWindow.AllTypes}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}"
Checked="ToggleButton_OnToggled"
Unchecked="ToggleButton_OnToggled"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
I also have a method with the signature below.
private void FilterStuffOut(String condition)
{
CollectionViewSource source
= new CollectionViewSource { Source = dataGrid.ItemsSource };
ICollectionView view = source.View;
view.Filter = element => BringItOut(element, condition);
dataGrid.ItemsSource = view;
}
I'm unsure (and poking around with intellisense both in sender and eventArgs gave me nothing) how to get to know which checkbox is the firey one. Where should I look for it in the method below?
private void ToggleButton_OnToggled(
Object sender, RoutedEventArgs eventArgs) { ... }
You would typically write it like shown below, explicitly not using the as operator, but casting to the desired types. This is because you expect those types, and any other type should result in a runtime error, i.e. an InvalidCastException.
private void ToggleButton_OnToggled(object sender, RoutedEventArgs eventArgs)
{
var element = (FrameworkElement)sender;
var myType = (MyType)element.DataContext;
// do something with myType.MyValue
}
If you would need properties of more derived types, e.g. ToggleButton.IsChecked, you would use that type instead of FrameworkElement.
As promised.
I tend to use Movies for my examples, so please excuse my habit. I wasn't certain exactly what your UI looked like, or what you were trying to achieve here, but I think I understood the general idea.
If you're not familiar with the MVVM design pattern, I'd advise working through this tutorial.
Here we go.
These are my models:
//This is a base class which handles our notify property changed stuff which will update the UI
//when properties change.
public class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
The class above is the base class for all models and sometimes view models if the view model requires it. It's pretty useful and I'd advise that you implement something like this in all of your MVVM applications.
public class Filter : NotifyPropertyChangedBase
{
public event EventHandler OnEnabledChanged;
public string Genre { get; set; }
private bool _IsEnabled;
public bool IsEnabled
{
get { return _IsEnabled; }
set
{
_IsEnabled = value;
OnPropertyChanged();
if (OnEnabledChanged != null)
OnEnabledChanged(this, new EventArgs());
}
}
public Filter(string genre)
{
this.Genre = genre;
}
}
public class Movie
{
//We don't need to implement INotifyPropertyChanged here
//because these values will never change.
public string Name { get; set; }
public string Genre { get; set; }
}
The models above represent movies, and a filter for the genre of a movie. All models do not "do" anything, they simply represent data.
And here is the ViewModel:
public class MovieViewModel : NotifyPropertyChangedBase
{
private ObservableCollection<Movie> _FilteredMovies;
public ObservableCollection<Movie> FilteredMovies
{
get { return _FilteredMovies; }
set
{
_FilteredMovies = value;
//Need to implement INotifyPropertyChanged here because
//I am instantiating a new observable collection in the enabled changed
//method. This will refresh the binding on the DataGrid.
OnPropertyChanged();
}
}
public ObservableCollection<Movie> Movies { get; set; }
public ObservableCollection<Filter> Filters { get; set; }
public MovieViewModel()
{
this.Movies = new ObservableCollection<Movie>();
this.Filters = new ObservableCollection<Filter>();
#region Sample Data
this.Movies.Add(new Movie()
{
Name = "Movie Action",
Genre = "Action"
});
this.Movies.Add(new Movie()
{
Name = "Movie Romance",
Genre = "Romance"
});
this.Movies.Add(new Movie()
{
Name = "Movie Comedy",
Genre = "Comedy"
});
this.Filters.Add(new Filter("Action"));
this.Filters.Add(new Filter("Romance"));
this.Filters.Add(new Filter("Comedy"));
foreach (Filter filter in this.Filters)
filter.OnEnabledChanged += filter_OnEnabledChanged;
#endregion
}
void filter_OnEnabledChanged(object sender, EventArgs e)
{
var filteredMovies = (from m in this.Movies
join f in this.Filters on m.Genre equals f.Genre
where f.IsEnabled
select m).ToList();
this.FilteredMovies = new ObservableCollection<Movie>(filteredMovies);
}
}
It has a collection of movies, and a collection of filters. When a checkbox is selected, the OnEnabledChanged method will be called and set the FilteredMovies property to that of the selected filters. This in turn will call the notify property changed code and update the UI.
Here is the UI:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<ViewModels:MovieViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Expander>
<ItemsControl ItemsSource="{Binding Filters}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsEnabled}"
Content="{Binding Genre}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander>
<DataGrid Grid.Row="1"
ItemsSource="{Binding FilteredMovies}"/>
</Grid>
Similar to your implementation, there is a DataGrid which is bound to the FilteredMovies property in the ViewModel, and the list of Filters is represented as a list of CheckBox objects.
Like I mentioned earlier, I wasn't exactly sure what you were trying to implement, but I think this was something of what you were trying to do.

Bind collection to combobox

I have this combobox
<ComboBox Height="30" SelectedIndex="0" Margin="5 3 5 3" Width="170" ItemsSource="{Binding WonderList}" SelectedValuePath="selectedWonder">
<ComboBox.ItemTemplate>
<DataTemplate>
<WrapPanel>
<Image Source="{Binding Path}" Height="20"></Image>
<Label Content="{Binding Name}" Style="{StaticResource LabelComboItem}"></Label>
</WrapPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
where I want to show items as an image plus a text.
This is the business class for the objects in the item list
public class Wonder: INotifyPropertyChanged
{
private string name;
private string path;
public event PropertyChangedEventHandler PropertyChanged;
#region properties, getters and setters
public String Name { get; set; }
public String Path { get; set; }
#endregion
public Wonder(string name, string path)
{
this.name = name;
this.path = path;
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
and the code behind of the window
public class Window1 {
public List<Wonder> WonderList;
public Window1()
{
InitializeComponent();
WonderList = new List<Wonder>();
WonderList.Add(new Wonder("Alexandria", "Resources/Images/Scans/Wonders/Alexandria.jpg"));
WonderList.Add(new Wonder("Babylon", "Resources/Images/Scans/Wonders/Babylon.jpg"));
}
}
I´m pretty new to this xaml "magic" and guess I dont understand correctly how the data binding works, I think that with ItemsSource="{Binding WonderList}" it should take the collection with that name (from the code behind) and show their Name and Path, but it shows an empty list.
If I do Combo1.ItemsSource = WonderList; in the code behind (I prefer to use the xaml and avoid the code behind), it shows two blank slots but still don´t know how to show the items.
Can you point me in the right direction?
Thanks
If you want to bind like this ItemsSource="{Binding WonderList}" you have to set the DataContext first.
public Window1()
{
...
this.DataContext = this;
}
Then Binding will find the WonderList in Window1 but only if it is a property too.
public List<Wonder> WonderList { get; private set; }
Next: It is useless to bind to property Name if you assign your value to private field name. Replace your constructor with
public Wonder(string name, string path)
{
this.Name = name;
this.Path = path;
}
Next: Your auto properties ({ get; set; }) will not notify for changes. For this you have to call OnPropertyChanged in setter. e.g.
public String Name
{
get { return name; }
set
{
if (name == value) return;
name = value;
OnPropertyChanged("Name");
}
}
Same thing for WonderList. If you create the List to late in constructor it could be all bindings are already resolved and you see nothing.
And finally use ObservableCollection if you want to notify not for a new list but a new added item in your list.
You are not doing the correct way. Simply saying, you should have a Wonders class holding an ObservableCollection property, which is bound to ComboBox's ItemsSource. You should read MSDN:
http://msdn.microsoft.com/en-us/library/ms752347.aspx

Populate ListBox

I have a window with a textbox and a submit button. When pressing the submit button, the data in the textbox should populate into the listbox and be saved.
What's the best way of doing this? I tried a recommendation (using ObservableCollection) from an earlier question I had, but I can't seem to get it work. I have tried implementing it like this:
I created a class:
public class AccountCollection
{
private string accountName;
public string AccountName
{
get { return accountName; }
set { accountName = value; }
}
public AccountCollection(string accountName)
{
AccountName = accountName;
}
}
Assigned the binding in my XAML:
<ListBox ItemsSource="{Binding AccountName, Mode=TwoWay}" IsSynchronizedWithCurrentItem="True" Height="164" HorizontalAlignment="Left" Margin="12" Name="accountListBox" VerticalAlignment="Top" Width="161" SelectionChanged="accountListBox_SelectionChanged" />
...and finally, when a user clicks the submit button from another window that contains the Submit button and textbox:
private void okBtn_Click(object sender, RoutedEventArgs e)
{
BindingExpression expression = okBtn.GetBindingExpression(accountaddTextBox.Text);
expression.UpdateSource();
}
But alas, I'm getting nowhere. I get an error message at the GetBindingExpression section:
Argument 1: cannot convert from 'string' to 'System.Windows.DependencyProperty'
What's obvious to me here is that when I created the class I didn't specify anything about the account name from the textbox, so I don't even know if the class is correct.
I'm basically confused and don't know what to do. Any help would be appreciated...
MODEL
// the model is the basic design of an object containing properties
// and methods of that object. This is an account object.
public class Account : INotifyPropertyChanged
{
private string m_AccountName;
public event PropertyChangedEventHandler PropertyChanged;
public string AccountName
{
get { return m_AccountName;}
set
{
m_AccountName = value;
OnPropertyChanged("AccountName");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
ListBox XAML
<ListBox Name="MyAccounts" DisplayMemberPath="AccountName" />
CODE BEHIND
// create a collection of accounts, then whenever the button is clicked,
//create a new account object and add to the collection.
public partial class Window1 : Window
{
private ObservableCollection<Account> AccountList = new ObservableCollection<Account>();
public Window1()
{
InitializeComponent();
AccountList.Add(new Account{ AccountName = "My Account" });
this.MyAccounts.ItemsSource = AccountList;
}
private void okBtn_Click(object sender, RoutedEventArgs e)
{
AccountList.Add(new Account{ AccountName = accountaddTextBox.Text});
}
}
edit: added displaymemberpath on listbox xaml
Here is a Demo using MVVM approach
ViewModel
public class AccountListViewModel : INotifyPropertyChanged
{
ICommand AddAccountCommand {get; set;}
public AccountListViewModel()
{
AccountList = new ObservableCollection<string>();
AddAccountCommand= new RelayCommand(AddAccount);
//Fill account List saved data
FillAccountList();
}
public AddAccount(object obj)
{
AccountList.Add(AccountName);
//Call you Model function To Save you lIst to DB or XML or Where you Like
SaveAccountList()
}
public ObservableCollection<string> AccountList
{
get {return accountList} ;
set
{
accountList= value
OnPropertyChanged("AccountList");
}
}
public string AccountName
{
get {return accountName } ;
set
{
accountName = value
OnPropertyChanged("AccountName");
}
}
}
Xaml Binding
<ListBox ItemsSource="{Binding Path=AccountList}" Height="164" HorizontalAlignment="Left" Margin="12" Name="accountListBox" VerticalAlignment="Top" Width="161" />
<TextBox Text={Binding Path=AccountName}></TextBox>
<Button Command={Binding Path=AddAccountCommand}><Button>
Xaml.cs Code
# region Constructor
/// <summary>
/// Default Constructor
/// </summary>
public MainView()
{
InitializeComponent();
this.DataContext = new AccountListViewModel();
}
# endregion
The Implementation of INotifyPropertyChanged and forming porpeties is left upto you
Your ItemsSource for your ListBox is AccountName, which is only a string but not a collection.
You need to create a viewmodel (your datacontext for the view) like this:
public class ViewModel
{
public ViewModel()
{
Accounts = new ObservableCollection<string>();
}
public ObservableCollection<string> Accounts { get; set; }
}
Bind ItemsSource to Accounts property:
<ListBox ItemsSource="{Binding Accounts}" Height="164" HorizontalAlignment="Left" Margin="12" Name="accountListBox" VerticalAlignment="Top" Width="161" />
And then, in your click event handler of the button you can simple add the current value of the textbox to your collection:
private void okBtn_Click(object sender, RoutedEventArgs e)
{
Accounts.Add(accountaddTextBox.Text);
}
But don't forget to set the DataContext of your window to the class ViewModel.

Windows Phone 7: Making ListBox items change dynamically

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.

Categories

Resources