My Senario: I have two ListBoxes bound to two different ObervableCollections--a collection of shapes and a collection of colors user may select from to find part numbers with matching attribute criteria. (More attribute collections exist in my app but I am omitting them for clarity.)
Upon a selection from either of the two attribute value-containing listboxes, I gather the resulting part numbers possessing the selected attribute property in a collection called ResultingPNsIntersect. (The collection of resulting part numbers is displayed in the third ListBox.)
What should happen: after making a selection in either of the two listboxes, the intersection of resulting part numbers possesing that Selected'Attribute' should update so that only relevant part numbers remain. If a shape has been selected, the listbox holding the ColorsCollection must update so that only color attributes (in ColorsCollection) relevant to PartNumbers that have the SelectedShape are displayed in the second listbox.
My Problem: After selecting a shape, the ResultingPNsIntersect ObservableCollection updates, but the PropertyChanged notification for ColorsCollection is never fired, so the second listbox never updates to give the user the updated color attributes to choose from.
I've done this before in other apps without any problems. I see no need to subscribe to CollectionChanged since I am not editing property values in ResultingPNsIntersect--I am replacing the collection with new values. Please help me see where my code is failing and why so that I can better understand the conditions INPCs require for firing.
The xaml binding:
<ListBox x:Name="SelectFromAvailableShapesLB" DockPanel.Dock="Top"
ItemsSource="{Binding AvailableShapesCollection}"
DisplayMemberPath="AttVal"
SelectedItem="{Binding SelectedShape, Mode=TwoWay}"/>
<ListBox x:Name="SelectFromAvailableColorsLB" DockPanel.Dock="Top"
ItemsSource="{Binding AvailableColorsCollection}"
DisplayMemberPath="AttVal"
SelectedItem="{Binding SelectedColor, Mode=TwoWay}"/>
<ListBox x:Name="PnsResultingFromAttributeSelectionsLB" DockPanel.Dock="Top"
ItemsSource="{Binding ResultingPNsIntersect}"
DisplayMemberPath="PartNum"
SelectedItem="{Binding SelectedPartNum, Mode=TwoWay}"/>
My ViewModel:
public ObservableCollection<AttributeValuesLibrary> AvailableShapesCollection
{
get
{
if (_resultingPNsIntersect != null)
{
foreach (PartNumber shape in _resultingPNsIntersect.Where(x => x.ShapeID != null))
{
if (!_availableShapesCollection.Contains(shape.AttributeValuesLibrary_Shape))
{
this._availableShapesCollection.Add(shape.AttributeValuesLibrary_Shape);
}
}
}
return _availableShapesCollection;
}
set
{
if (_availableShapesCollection != value)
{
this._availableShapesCollection = value;
RaisePropertyChanged("AvailableShapesCollection");
}
}
}
public ObservableCollection<AttributeValuesLibrary> AvailableColorsCollection
{
get
{
if (_resultingPNsIntersect != null)
{
foreach (PartNumber color in _resultingPNsIntersect.Where(x => x.ColorID != null))
{
if (!_availableColorsCollection.Contains(color.AttributeValuesLibrary_Color))
{
_availableColorsCollection.Add(color.AttributeValuesLibrary_Color);
}
}
}
return _availableColorsCollection;
}
set
{
if (_availableColorsCollection != value)
{
_availableColorsCollection = value;
RaisePropertyChanged("AvailableColorsCollection");
}
}
}
public AttributeValuesLibrary SelectedShape
{
get
{
return _selectedShape;
}
set
{
if (_selectedShape != value)
{
_selectedShape = value;
RaisePropertyChanged("SelectedShape");
RaisePropertyChanged("ResultingPNsIntersect");
}
}
}
public ObservableCollection<ConnectorPartNumber> ConnAttPNResults
{
get
{
// If a shape has been selected, we need to navigate to it's related PartNumbers and add those to the intersection
// contained by ResultingPNsIntersection.
if (_selectedShape != null)
{
var shapeResults = _context.PartNumbers.Where(x => x.AttributeValuesLibrary_Shape.AttValID == _selectedShape.AttValID);
if (_resultingPNsIntersect != null)
{
var resultsFromPreviousSelection = _resultingPNsIntersect;
_resultingPNsIntersect = new ObservableCollection<PartNumber>(resultsFromPreviousSelection.Intersect(shapeResults));
}
else if (_resultingPNsIntersect == null)
{
_resultingPNsIntersect = new ObservableCollection<PartNumber>(shapeResults);
}
}
return _resultingPNsIntersect;
}
set
{
if (_resultingPNsIntersect != value)
{
this._resultingPNsIntersect = value;
RaisePropertyChanged("ResultingPNsIntersect");
RaisePropertyChanged("AvailableColorsCollection"); <--Not firing!!!!!
}
}
}
Thanks in advance!
::UPDATE:: I can force this to work if I put the RaisePropertyChanged("AvailableColorsCollection") in the setter of my SelectedShape. But it makes less sense there, of course, because AvailableColorsCollection is dependent upon the ResultingPNsIntersect Collection which changes based on a selection in the attribute listboxes.
I think in general your approach is going to give you issues. Instead of implementing the logic in the getters of your properties, you should consider making your properties much "dumber". I would move this logic out of the properties into a helper method that modifies your available options:
private readonly ObservableCollection<AttributeValuesLibrary> _availableShapesCollection =
new ObservableCollection<AttributeValuesLibrary>();
private readonly ObservableCollection<AttributeValuesLibrary> _availableColorsCollection =
new ObservableCollection<AttributeValuesLibrary>();
public ObservableCollection<AttributeValuesLibrary> AvailableShapesCollection
{
get { return _availableShapesCollection; }
}
public ObservableCollection<AttributeValuesLibrary> AvailableColorsCollection
{
get { return _availableColorsCollection; }
}
public AttributeValuesLibrary SelectedShape
{
get { return _selectedShape; }
set
{
if (_selectedShape != value)
{
_selectedShape = value;
RaisePropertyChanged("SelectedShape");
SelectedShapeChanged();
}
}
}
public ObservableCollection<ConnectorPartNumber> ConnAttPNResults
{
get { return _resultingPNsIntersect; }
set
{
if (_resultingPNsIntersect != value)
{
this._resultingPNsIntersect = value;
RaisePropertyChanged("ResultingPNsIntersect");
UpdateAvailableOptions();
}
}
}
private void SelectedShapeChanged()
{
// If a shape has been selected, we need to navigate to it's related
// PartNumbers and add those to the intersection contained by ResultingPNsIntersection.
if (_selectedShape != null)
{
var shapeResults = _context.PartNumbers.Where(x => x.AttributeValuesLibrary_Shape.AttValID == _selectedShape.AttValID);
if (_resultingPNsIntersect != null)
{
var resultsFromPreviousSelection = _resultingPNsIntersect;
ConnAttPNResults = new ObservableCollection<PartNumber>(resultsFromPreviousSelection.Intersect(shapeResults));
}
else
{
ConnAttPNResults = new ObservableCollection<PartNumber>(shapeResults);
}
}
}
private void UpdateAvailableOptions()
{
if (_resultingPNsIntersect != null)
{
_availableColorsCollection.Clear();
_availableShapesCollection.Clear();
foreach (PartNumber color in _resultingPNsIntersect.Where(x => x.ColorID != null).Distinct())
{
_availableShapesCollection.Add(color.AttributeValuesLibrary_Color);
}
foreach (PartNumber shape in _resultingPNsIntersect.Where(x => x.ShapeID != null).Distinct())
{
shapes.Add(shape.AttributeValuesLibrary_Shape);
}
}
}
If you would rather have settable properties, the UpdateAvailableOptions could create new collections and set the AvailableColorsCollection & AvailableShapesCollection properties to the new instances (but then there is no need for ObservableCollections).
I would even take this a bit further actually. Since you don't want anybody to alter your Available collections, I would make them return ReadonlyObersvableCollection instances, and make their return types IEnumerable<T>.
Related
I am working with a xamarin Forms.
I am using Picker for DropDownList.
How can I set selectedItem to Picker?
My code
<Picker x:Name="VendorName" Title="Select" ItemDisplayBinding="{Binding VendorName}" SelectedItem="{Binding VendorName}" Style="{StaticResource PickerStyle}"></Picker>
and server side code is
Device.BeginInvokeOnMainThread(() =>
{
VendorName.ItemsSource = VendorList;
});
var currentVendor = new List<Vendor>();
currentVendor.Add(new Vendor { VendorID = "111", VendorName = "aaaa" });
VendorName.SelectedItem = currentVendor;
This may not be the most efficient but you could loop to find the index and set that way.
for (int x = 0; x < VendorList.Count; x++)
{
if (VendorList[x].VendorName == currentVendor .VendorName )
{
VendorName.SelectedIndex = x;
}
}
After adding all values as list in Picker
just treat with it as an array
so if you want to set selected item just set selected item index
currentVendor.SelectedIndex = 0;
zero means you make selected item is the first one you added to Picker
If you are using MVVM, and want to set SelectedItem from the view model, things get tricky. There seems to be a bug in Xamarin that prevents us from using SelectedItem with a two way binding. More info: Xamarin Forms ListView SelectedItem Binding Issue and https://xamarin.github.io/bugzilla-archives/58/58451/bug.html.
Luckily, we can easily write our own Picker.
public class TwoWayPicker : Picker
{
public TwoWayPicker()
{
SelectedIndexChanged += (sender, e) => SelectedItem = ItemsSource[SelectedIndex];
}
public static new readonly BindableProperty SelectedItemProperty = BindableProperty.Create(
nameof(SelectedItem), typeof(object), typeof(TwoWayPicker), null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged);
public new object SelectedItem
{
get => GetValue(SelectedItemProperty);
set => SetValue(SelectedItemProperty, value);
}
private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (TwoWayPicker)bindable;
control.SetNewValue(newValue);
}
private void SetNewValue(object newValue)
{
if (newValue == null)
{
return;
}
for(int i = 0; i < ItemsSource.Count; i++)
{
if (ItemsSource[i].Equals(newValue))
{
SelectedIndex = i;
return;
}
}
}
}
Because is uses the same SelectedItem property, it is a drop-in replacement for Picker.
Note that if you want value equality rather than reference equality for the item class, you'll also need to override Equals like this:
public override bool Equals(object obj)
{
var other = obj as YourClass;
if (other == null)
{
return false;
}
else
{
return other.SomeValue == SomeValue; // implement your own
}
}
If you define the item class as a record instead of a class then it can select the item programmatically using the SelectedItem property.
In your case change
public class Vendor { // your class properties }
to
public record Vendor { // your class properties }
This will now work
VendorName.SelectedItem = currentVendor;
we are developing a cross platform app on Xamarin.Forms.
On one of the pages we need to display a set of 3 pickers with the same list of items. The idea is that when you select an item on one of the pickers it gets removed from the item-source of the other two.
To do this we developed the following code:
We started with a list of Items called BaseList which we get from a web service. We also create 3 separate lists (ListA, ListB and ListC) and 3 Items to store the selected Items of each picker (SelectedA, SelectedB and SelectedC).
private List<Item> BaseList;
private List<Item> _ListA;
private Item _SelectedA;
private List<Item> _ListB;
private Item _SelectedB;
private List<Item> _ListC;
private Item _SelectedC;
…
//Api Calls
private void LoadData()
{
…
BaseList = new List<Item> (ListFromWebServices);
_ListA = new List<Item>(BaseList);
OnPropertyChanged(nameof(ListA));
_ListB = new List<Item>(BaseList);
OnPropertyChanged(nameof(ListB));
_ListC = new List<Item>(BaseList);
OnPropertyChanged(nameof(ListC));
}
…
//Public Fields
public List<Item> ListA
{
get
{
return _ListA;
}
}
public Item SelectedA
{
get
{
return _SelectedA;
}
set
{
SetProperty(ref _SelectedA, value, nameof(SelectedA));
}
}
public List<Item> ListB
{
get
{
return _ListB;
}
}
public Item SelectedB
{
get
{
return _SelectedB;
}
set
{
SetProperty(ref _SelectedB, value, nameof(SelectedB));
}
}
public List<Item> ListC
{
get
{
return _ListC;
}
}
public Item SelectedC
{
get
{
return _SelectedC;
}
set
{
SetProperty(ref _SelectedC, value, nameof(SelectedC));
}
}
This code is on our ViewModel, so we use SetProperty to set the referenced property to the value and invoke PropertyChangedEventArgs from INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value,
[CallerMemberName] string propertyName = null)
{
if (Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
In order to update the ItemSource's, whenever a selected item is changed we call OnSelectedItemChanged from the setters of SelectedA, SelectedB and SelectedC. This method receives an index which indicates which Picker triggered it:
private void OnSelectedItemChanged(int index)
{
Item CurrentA = SelectedA;
Item CurrentB = SelectedB;
Item CurrentC = SelectedC;
int i;
switch (index)
{
case 0:
_ListB = new List<Item> (BaseList);
_ListB.Remove(CurrentA);
_ListB.Remove(CurrentC);
OnPropertyChanged(nameof(ListB));
_ListC = new List<Item>(BaseList);
_ListC.Remove(CurrentA);
_ListC.Remove(CurrentB);
OnPropertyChanged(nameof(ListC));
i = ListB.IndexOf(CurrentB);
if (i > -1)
{
_SelectedB = ListB[i];
}
OnPropertyChanged(nameof(SelectedB));
i = ListC.IndexOf(CurrentC);
if (i > -1)
{
_SelectedC = ListC[i];
}
OnPropertyChanged(nameof(SelectedC));
break;
case 1:
_ListA = new List<Item>(BaseList);
_ListA.Remove(CurrentB);
_ListA.Remove(CurrentC);
OnPropertyChanged(nameof(ListA));
_ListC = new List<Item>(BaseList);
_ListC.Remove(CurrentA);
_ListC.Remove(CurrentB);
OnPropertyChanged(nameof(ListC));
i = ListA.IndexOf(CurrentA);
if (i > -1)
{
_SelectedA = ListA[i];
}
OnPropertyChanged(nameof(SelectedA));
i = ListC.IndexOf(CurrentC);
if (i > -1)
{
_SelectedC = ListC[i];
}
OnPropertyChanged(nameof(SelectedC));
break;
case 2:
_ListA = new List<Item>(BaseList);
_ListA.Remove(CurrentB);
_ListA.Remove(CurrentC);
OnPropertyChanged(nameof(ListA));
_ListB = new List<Item>(BaseList);
_ListB.Remove(CurrentA);
_ListB.Remove(CurrentC);
OnPropertyChanged(nameof(ListB));
i = ListA.IndexOf(CurrentA);
if (i > -1)
{
_SelectedA = ListA[i];
}
OnPropertyChanged(nameof(SelectedA));
i = ListB.IndexOf(CurrentB);
if (i > -1)
{
_SelectedB = ListB[i];
}
OnPropertyChanged(nameof(SelectedB));
break;
}
}
What we do here is basically save the current selected item for each picker on a separate variable, copy the BaseList into the two pickers that didn't call the event, then on the each new list remove all the options in use by the other pickers, set again the selected Item on each new list to the one that was selected originally and finally call OnPropertyChanged() to inform the views of the change.
The issue here is that when we change the ItemSource on a Picker it sets the SelectedItem to null. calling OnPropertyChanged() on the setter after OnSelectedItemChanged()was called leads to an infinite loop of one Picker updating the other, and adding a filter that checks if the value isn't null before setting it makes the Picker display no selected item, while the value is already set.
just in case anyone has the same issue, we found a solution for this. Turns out if you make CurrentA, CurrentB and CurrentC global variables and add on each case an if ((CurrentA != SelectedA) && (!(SelectedA is null))) { ... (do all the stuff) } break; and at the end you set
_SelectedA = CurrentA;
OnPropertyChanged(nameof(SelectedA));
_SelectedB = CurrentB;
OnPropertyChanged(nameof(SelectedB));
_SelectedC = CurrentC;
OnPropertyChanged(nameof(SelectedC));
it works. We don't know why tho :)
My application have some working modes which can be changed from model, and from UI by user.
When I start the application it show default mode correct (data updated from Model). But as I change selected item from UI, it shows selected item for a while, then unselect it (update from UI, and after that update from model).
I have devided update logic in two cases
first, update from UI shall call model update.
second, update UI from model shall not call model update.
What is my mistake?
See code below
View
<ComboBox ItemsSource="{Binding AlgorithmCollection}"
SelectedItem="{Binding SelectedAlgorithm, Mode=TwoWay}"
Style="{StaticResource AutoOpenComboBoxStyle}" />
ViewModel
private NamedInt _selectedAlgorithm;
private ObservableCollection<NamedInt> _algorithmCollection;
public NamedInt SelectedAlgorithm
{
get { return this._selectedAlgorithm; }
set { Set(() => SelectedAlgorithm, ref this._selectedAlgorithm, value);
if (this._needUpdate && Core.Kernel.Instance.PluginController.ActiveConverter != null &&
this._selectedAlgorithm != null)
{
Core.Kernel.Instance.PluginController.ActiveConverter.SetActiveAlgorithm(this._selectedAlgorithm.Id);
}
}
}
public ObservableCollection<NamedInt> AlgorithmCollection
{
get { return this._algorithmCollection; }
set { Set(() => AlgorithmCollection, ref this._algorithmCollection, value);
}
}
and i listen to model event to update ViewModel when it's nessesary. In constructor of ViewModel
Messenger.Default.Register<SoftwareSettingsUpdateMessage>(this, ReceiveUpdateMessage);
private void ReceiveUpdateMessage(SoftwareSettingsUpdateMessage action)
{
if (action.SettingType.HasFlag(SoftwareSettingsType.Algorithm))
{
RefreshAlgorithms();
}
this._needUpdate = true;
}
private void RefreshAlgorithms()
{
var converter = Core.Kernel.Instance.PluginController.ActiveConverter;
var algorithms = converter?.Algorithms;
if (algorithms != null)
{
AlgorithmCollection = new ObservableCollection<NamedInt>(
algorithms.Select((x, index) => new NamedInt(x, index))
);
var activeId = converter.ActiveAlgorithmId;
if (activeId >= 0 && activeId < AlgorithmCollection.Count)
{
this._needUpdate = false;
SelectedAlgorithm = AlgorithmCollection[activeId];
this._needUpdate = true;
}
else
{
SelectedAlgorithm = null;
}
}
else
{
AlgorithmCollection = new ObservableCollection<NamedInt>();
SelectedAlgorithm = null;
}
IsActive = true;
}
I have two drop down lists. Niether of them have a relation ship with each other. But I need to filter one drop down list based on the chosen value of another drop down list.
I can filter it in code. When I debug I can see the filtered results on the property. However when I run the app, it does not work. Here is my code so far:
private BindingList<Commodity> _AllocationCommodities;
[Browsable(false)]
public BindingList<Commodity> AllocationCommodities
{
get
{
if (_AllocationCommodities == null)
{
_AllocationCommodities = new BindingList<Commodity>();
ChangeCommodities();
}
return _AllocationCommodities;
}
}
private SourceEntity _SourceEntity;
[ImmediatePostData]
[Association("SourceEntity-LimitAllocations")]
[RuleRequiredField("RuleRequiredField_LimitAllocation_SourceEntity", DefaultContexts.Save)]
public SourceEntity SourceEntity
{
get
{
return _SourceEntity;
}
set
{
//New Code
if (SetPropertyValue<SourceEntity>("SourceEntity", value))
{
if (IsSaving || IsLoading) return;
ChangeCommodities();
}
}
}
private Commodity _Commodity;// This is the drop down to be filtered
[ImmediatePostData]
[DataSourceProperty("AllocationCommodities")] //// This Attribute Should filter Commodities
[RuleRequiredField("RuleRequiredField_LimitAllocation_Commodity", DefaultContexts.Save)]
public Commodity Commodity
{
get
{
return _Commodity;
}
set
{
SetPropertyValue("Commodity", ref _Commodity, value);
if (Commodity.Oid != Guid.Empty)
AllocationVolumeUnits.Reload();
}
}
private void ChangeCommodities()
{
if (!this.IsLoading && _SourceEntity != null)
{
_AllocationCommodities.RaiseListChangedEvents = false;
_AllocationCommodities.Clear();
OperandValue[] _params;
System.Collections.Generic.List<CMSBOD.SourceCommodity> _sc = new System.Collections.Generic.List<SourceCommodity>();
BindingList<Commodity> _Commodities = new BindingList<Commodity>();
foreach (SourceCommodityEntity _tempSCE in _SourceEntity.SourceCommodityEntities)
{
if (_tempSCE.SourceCommodity != null)
_sc.Add(_tempSCE.SourceCommodity);
}
foreach (SourceCommodity _tempSC in _sc)
{
if (_tempSC.Commodity != null && !_Commodities.Contains<Commodity>(_tempSC.Commodity) && _tempSC.Commodity.IsActive)
_Commodities.Add(_tempSC.Commodity);
}
_AllocationCommodities.RaiseListChangedEvents = true;
_AllocationCommodities = _Commodities;///This is where I can see the filtered list when debugging.
}
}
You can find a DataSourceCriteria useful in this scenario, instead of DataSourceProperty.
Assuming you have collection properties that associates Commodity back to SourceCommodityEntity, you can use this criteria:
[DataSourceCriteria("IsActive And SourceCommodities[SourceCommodityEntities[SourceEntity = '#SourceEntity'] ]")]
Even if its designed to be a 1x1 assocation, you can find that associations can be useful for filtering purposes.
I'm having trouble getting my UI to update Two Listboxes' to update properly when my ViewModel changes.
First, the basic logic behind the page:
Movie is an object with a title, and a variety of MovieDetails. Some MovieDetail are different than others, as they are detailed which is a glorified way of saying they're more Important.
I use two ListBoxes to separate these MovieDetails into stacked ListBoxes, one for 'Detailed' and one for 'NotDetailed'
If a movie has no 'Detailed' attributes, the corresponding list is Hidden via a BooleanToVisibilityConverter (and vice-versa)
When I navigate to the page, I set the Movie the page corresponds to, and it should RaisePropertyChanged to alert the AllMoviesDetail ObservableCollection that it should re-get Movies.MovieDetailFetchedList.
From there, AllMoviesDetail would alert the two ObservableCollections (Detailed, NotDetailed) they should be re-get.
In fact, RaisePropertyChanged on NotDetailedMovieDetails or DetailedMovieDetails does not seem to do anything either. (And the corresponding HasNotDetailedMovieDetails, Has...)
What does work, however, is if I add more items into the list, the CollectionChanged event seems to fire and reactivate the list. I have also been able to do this by instantiating the ObservableCollections in code first var temp = DetailedMoviesDetail;
public class MoviesDetailViewModel : ViewModelBase
{
#region Property Names
public const string MoviePropertyString = "Movie";
public const string AllMoviesDetailPropertyString = "AllMoviesDetail";
public const string DetailedMoviesDetailPropertyString = "DetailedMoviesDetail";
public const string NotDetailedMoviesDetailPropertyString = "NotDetailedMoviesDetail";
public const string HasNotDetailedMoviesDetailPropertyString = "HasNotDetailedMoviesDetail";
public const string HasDetailedMoviesDetailPropertyString = "HasDetailedMoviesDetail";
public const string NotDetailedHeaderPropertyString = "NotDetailedHeader";
#endregion
public MoviesDetailViewModel()
{
if (IsInDesignMode)
{
Movie = DesignDataStore.MovieList[0];
Movie.Category = Category.DDA;
}
}
private Movie _Movie;
/// <summary>
/// The Movie for which to browse MoviesDetail. It is expected when setting this property, that MoviesDetail for it have been downloaded previously.
/// </summary>
/// <remarks>The 'Master' property for this ViewModel. All properties are Dependent on this and the underlying property MoviesDetailList</remarks>
/// <seealso cref="MovieDetailFetchedList"/>
public Movie Movie
{
get { return _Movie; }
set
{
if (_Movie != value)
{
if (_Movie != null)
_Movie.MovieDetailFetchedList.CollectionChanged -= MoviesDetailListChanged;
_Movie = value;
RaisePropertyChanged(MoviePropertyString);
RaisePropertyChanged(StatementPeriodAvailablePropertyString);
RaisePropertyChanged(NotDetailedMoviesDetailPropertyString);
Movie.MovieDetailFetchedList.CollectionChanged += MoviesDetailListChanged;
RaisePropertyChanged(AllMoviesDetailPropertyString);
RaisePropertyChanged(DetailedMoviesDetailPropertyString);
RaisePropertyChanged(NotDetailedHeaderPropertyString);
}
}
}
private void MoviesDetailListChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (var item in e.NewItems)
{
if (((MovieDetail) item).IsDetailed())
DetailedMoviesDetail.Add(item as MovieDetail);
else
NotDetailedMoviesDetail.Add(item as MovieDetail);
}
}
else
{
RaisePropertyChanged(AllMoviesDetailPropertyString);
RaisePropertyChanged(DetailedMoviesDetailPropertyString);
RaisePropertyChanged(NotDetailedMoviesDetailPropertyString);
}
}
#endregion
private MovieDetailFetchedList _allMoviesDetail;
public MovieDetailFetchedList AllMoviesDetail
{
get
{
if (Movie == null)
return new MovieDetailFetchedList();
return _allMoviesDetail ?? (AllMoviesDetail = Movie.MovieDetailFetchedList);
}
set
{
if (_allMoviesDetail != value)
{
if (_allMoviesDetail != null)
_allMoviesDetail.CollectionChanged -= MoviesDetailListChanged;
_allMoviesDetail = value;
_allMoviesDetail.CollectionChanged += MoviesDetailListChanged;
RaisePropertyChanged(AllMoviesDetailPropertyString);
//force update
DetailedMoviesDetail = NotDetailedMoviesDetail = null;
RaisePropertyChanged(DetailedMoviesDetailPropertyString);
RaisePropertyChanged(HasDetailedMoviesDetailPropertyString);
RaisePropertyChanged(NotDetailedMoviesDetailPropertyString);
RaisePropertyChanged(HasNotDetailedMoviesDetailPropertyString);
}
}
}
public bool HasNotDetailedMoviesDetail { get { return NotDetailedMoviesDetail != null && NotDetailedMoviesDetail.Count > 0; } }
private ObservableCollection<MovieDetail> _notDetailedMoviesDetail;
public ObservableCollection<MovieDetail> NotDetailedMoviesDetail
{
get
{
if (Movie == null) return new ObservableCollection<MovieDetail>();
return AllMoviesDetail;
return _notDetailedMoviesDetail ?? //make sure RaisePropertyChanged happens by using property setter
(NotDetailedMoviesDetail = AllMoviesDetail.Where(mem => !mem.IsDetailed()).ToObservableCollection());
}
set
{
_notDetailedMoviesDetail = value;
RaisePropertyChanged(NotDetailedMoviesDetailPropertyString);
RaisePropertyChanged(HasNotDetailedMoviesDetailPropertyString);
}
}
public bool HasDetailedMoviesDetail
{ get { return DetailedMoviesDetail != null && DetailedMoviesDetail.Count > 0; } }
private ObservableCollection<MovieDetail> _DetailedMoviesDetail;
public ObservableCollection<MovieDetail> DetailedMoviesDetail
{
get
{
if (Movie == null) return new ObservableCollection<MovieDetail>();
return AllMoviesDetail;
return _DetailedMoviesDetail ?? //make sure RaisePropertyChanged happens by using property setter
(DetailedMoviesDetail = AllMoviesDetail.Where(mem => mem.IsDetailed()).ToObservableCollection());
}
set
{
_DetailedMoviesDetail = value;
RaisePropertyChanged(DetailedMoviesDetailPropertyString);
RaisePropertyChanged(HasDetailedMoviesDetailPropertyString);
}
}
private string _DetailedHeader;
public string DetailedHeader
{
get { return _DetailedHeader ?? (_DetailedHeader = AppResources.in_available); }
set { _DetailedHeader = value; }
}
public string NotDetailedHeader
{
get { return (Movie != null && Movie.Category == Category.DRAMA) ? AppResources.Movie_MoviesDetail : AppResources.not_in_available; }
}
}
All of your property getters (except AllMoviesDetail) have two return statements. Since only the first will be executed, the values are not being assigned and the PropertyChanged events are not being twiggered.