i have three usercontrol in a C# win application ; the main User is called UcReferenteTecnico that only contains UcContatto that has a nested usercontrol UcIndirizzo.
UcContatto has a modelView named ContattoMV and UcIndirizzo has a modelview named IndirizzoMV
UcContatto modelview has a properies and a nested IndirizzoMV properties; they are done in this way:
public class ContattoMV:INotifyPropertyChanged
{
string _NOME_CONTATTO;
[HeaderAttribute("Nome contatto", true, 2)]
public string NOME_CONTATTO
{
get { return _NOME_CONTATTO; }
set
{
_NOME_CONTATTO = value;
NotifyPropertyChanged("NOME_CONTATTO");
}
}
public IndirizzoMV Indirizzo
{
get { return _Indirizzo; }
set
{
_Indirizzo = value;
NotifyPropertyChanged("Indirizzo");
}
}
public void NotifyPropertyChanged(string aiPropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(aiPropertyName));
}
}
}
public class IndirizzoMV:INotifyPropertyChanged
{
public string TOPONIMO
{
get { return _TOPONIMO; }
set
{
_TOPONIMO = value;
NotifyPropertyChanged("TOPONIMO");
}
}
public void NotifyPropertyChanged(string aiPropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(aiPropertyName));
}
}
}
All properties are binding in UcContatto and in UcIndirizzo to Control in this way:
In UcContatto:
this.txtNome.DataBindings.Add(new System.Windows.Forms.Binding("EditValue", this._bsContatto, "NOME_CONTATTO", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
and to bind nested usercontrol UcIndirizzo do this:
this.ucIndirizzo1.DataBindings.Add(new System.Windows.Forms.Binding("BsIndirizzo", this._bsContatto, "Indirizzo", true));
where _bsContatto is typeof ContattoMV and BsIndirizzo is bindable properties done in this way:
[Bindable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IndirizzoMV BsIndirizzo
{
get
{
return (IndirizzoMV)_bsIndirizzo.DataSource;
}
set
{
if (value == null)
{
return;
}
_bsIndirizzo.DataSource = value;
}
}
In UcIndirizzo properites is binding in this way:
this.txtToponimo.DataBindings.Add(new System.Windows.Forms.Binding("EditValue", this._bsIndirizzo, "TOPONIMO", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
where _bsIndirizzo is typeof IndirizzoMV.
In UcContatto to spread properties to main UserControl i use another bindable properties in this way:
[Bindable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ContattoMV BsContatto
{
get
{
return (ContattoMV)_bsContatto.DataSource;
}
set
{
if (value == null)
{
return;
}
_bsContatto.DataSource = value;
}
}
to initialize usercontrol in main Control UcReferenteTecnico i do this:
this.ucContatto1.BsContatto = new ContattoMV();
when i change value in my usercontrol if i set value in txtNome , NOME_CONTATTO properties is valued (enter in breakpoint put in set properties)
if i change value in ucIndirizzo in txtToponimo no properties is valued
where is my error?
thanks a lot
I'd say that your error is not using XAML to define your Bindings, but I guess that you might have some valid reason for that. I found it really difficult to follow your question because of all of the foreign type and property names, so while I don't think that I can help directly with your problem, I can provide this simple advice:
When you want to data bind to a property that is in a parent view model, you can simply use a RelativeSource Binding:
Imagine that this was in the parent view model:
public string NOME_CONTATTO
{
get { return _NOME_CONTATTO; }
set
{
_NOME_CONTATTO = value;
NotifyPropertyChanged("NOME_CONTATTO");
}
}
You could data bind to it directly from any child view like this:
<TextBox Text="{Binding DataContext.NOME_CONTATTO,
RelativeSource={RelativeSource AncestorType={x:Type Local:ParentView}}}" ... />
Alternatively, if you just want to pass some value between view models, you can use delegates... see my answer to the How to call functions in a main view model from other view models? question to find out how to do that.
Related
I have 2 windows Parent window - Window_Products and Child window - Window_NewProduct
1)In my Window_Products
I have a list ObservableCollection ProductsList in this window which displays a list of products
AddNewProduct() is used to add new product to the list from child window
public AddNewProduct()
{
Window_NewProduct newProduct = new Window_NewProduct();
if(newProduct.ShowDialog() = true)
{
ProductsList.Add(//what code should I write here);
}
}
2)In my Window_NewProduct
This window uses a user control ProductUserControl since I use the user control as a Page as well as Window
<Window>
<local:ProductUserControl x:Name="ProductUserControl">
</Window>
3)In my product user control
public ProductUserControl()
{
this.DataContext = new ProductViewModel();
}
4)In my ProductViewModel
I have this object Product that stores the values like Prod_Name,Prod_Code in it.
What I want is this object Product to be returned to the parent window(Window_Products) after I save the product into database so that I can add new product to the observable collection above.
How can my object return back from the view model through the usercontrol,child window and then reach parent window.
Help me around this. Thanks in advance.
Make a new constructor for the indow_NewProduct:
public ProductUserControl(ProductViewModel model):base()
{
this.DataContext = model;
}
In your example :
1)In my Window_Products becomes:
var myPVM = new ProductViewModel();
Window_NewProduct newProduct = new Window_NewProduct(myPVM);
if(newProduct.ShowDialog() = true)
{
ProductsList.Add(myPVM.<THE NEW PRODUCT PROPERTY YOU WILL WRITE>);
}
A couple of things:
1. This is not good, but it may fit your needs:
2. Take a look at MVVM and MVC, combine them to also have controlers.
3. In WPF you should try as much as possible to use the DataContext to move your data arround, this NewProduct could be part of the prant's window data context.
Add a dependency property for your user control and bind to that in the xaml as below.
public static readonly DependencyProperty ProductProperty = DependencyProperty.Register(
"Product", typeof(ProductDto), typeof(ProductUserControl), new FrameworkPropertyMetadata(null));
public ProductDto Product
{
get { return (ProductDto)this.GetValue(ProductProperty); }
set { this.SetValue(ProductProperty, value); }
}
<TextBox Margin="2" Text="{Binding Path=Product.Code, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Margin="2" Text="{Binding Path=Product.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
You should have a Product property for your Window_NewProduct's view model
public class Window_NewProductViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private ProductDto product;
public ProductDto Product
{
get
{
return this.product;
}
set
{
if (value != this.product)
{
this.product = value;
NotifyPropertyChanged();
}
}
}
}
Then in the Window_NewProduct xaml you should bind this property to the usercontrols dependency property
<local:ProductUserControl x:Name="ProductUserControl" Product="{Binding Product}"/>
Add parameter to the Window_NewProduct constructor that takes in the ProductDto and passes that to the ViewModel.
public Window_NewProduct(ProductDto product)
{
InitializeComponent();
this.DataContext = new Window_NewProductViewModel() { Product = product };
}
Then in your MainWindow you can just create a new productDto to pass on to the DetailsWindow.
var newProduct = new ProductDto();
var window_NewProduct = new Window_NewProduct(newProduct);
if (window_NewProduct.ShowDialog() == true)
{
Debug.WriteLine(newProduct.Code);
Debug.WriteLine(newProduct.Name);
}
I am trying to use the following code example from the Infragistics site and I'd like edits in the XamDataCards to be reflected in the XamDataGrid. However, my DataSource for the XamDataGrid is an ObservableCollection<Companies> in my ViewModel. How can I also bind to the card and relay updates back to my Companies object in the ViewModel?
<igDP:XamDataGrid x:Name="dgCompanies" Theme="IGTheme" DataSource="{Binding Companies}" SelectedDataItemsScope="RecordsOnly">
<igDP:XamDataGrid.FieldSettings>
<igDP:FieldSettings CellClickAction="SelectCell" AllowEdit="True"/>
</igDP:XamDataGrid.FieldSettings>
</igDP:XamDataGrid>
<igDP:XamDataCards x:Name="XamDataCards1"
Grid.Row="1"
DataSource="{Binding Path=SelectedDataItems, ElementName=dgCompanies}"
Theme="IGTheme">
Edit: Added ViewModel
public class CompanyMgmtViewModel : ViewModelBase
{
private ObservableCollection<Object> _Companies = null;
public ObservableCollection<Object> Companies
{
get { return _Companies; }
set
{
if (_Companies != value)
{
_Companies = value;
RaisePropertyChanged(GetPropertyName(() => Companies));
}
}
}
public CompanyMgmtViewModel()
{
this.LoadData();
}
public void LoadData()
{
ObservableCollection<Object> records = new ObservableCollection<Object>();
var results = from res in AODB.Context.TCompanies
select res;
foreach (var item in results)
if (item != null) records.Add(item);
Companies = records;
}
}
The Model/Context code is just EF Database First generated.
You would need to bind your XamDataGrid's SelectedDataItems property to a property of type object[] ie. SelectedCompanies in your ViewModel and bind to that for your XamDataCards' datasource.
The accepted answer in this thread has a sample that shows how to do this, albeit with a ListBox instead of XamDataCards:
http://www.infragistics.com/community/forums/t/89122.aspx
Just replace that ListBox with your XamDataCards control, it works and updates the XamDataGrid. The ViewModel in the example is contained in the MainWindow code-behind, so it is MVVM like you want.
more info:
http://help.infragistics.com/Help/Doc/WPF/2014.1/CLR4.0/html/xamDataGrid_Selected_Data_Items.html
IG's SelectedDataItems is an object[] :
http://help.infragistics.com/Help/Doc/WPF/2014.1/CLR4.0/html/InfragisticsWPF4.DataPresenter.v14.1~Infragistics.Windows.DataPresenter.DataPresenterBase~SelectedDataItems.html
I couldn't have gotten to this answer without Theodosius' and Ganesh's input - so thanks to them, they both had partial answers.
I first tried to bind the SelectedDataItems of the XamDataGrid to the XamDataCards by way of a property on the ViewModel as Theodosius suggested, but that wasn't enough. Thanks to Ganesh, I implemented INotifyPropertyChanged on my model objects, by inheriting from ObservableObject in MVVMLight (how did I not know the Model needed this?).
Below are the relevant pieces of code to make it work.
I also implemented PropertyChanged.Fody as documented here; that's where the TypedViewModelBase<T> and removal of RaisePropertyChanged() comes from.
I'm also creating my Model objects by using a LINQ/Automapper .Project().To<T>() call which can be found here.
Model
public class Company : ObservableObject
{
public Company() { }
public int id { get; set; }
public string strName { get; set; }
public string strDomicileCode { get; set; }
}
ViewModel
public class CompanyMgmtViewModel : TypedViewModelBase<Company>
{
private ObservableCollection<Object> _Companies = null;
private Object[] _selectedCompany = null;
public Object[] Company
{
get { return _selectedCompany; }
set
{
if (_Company != value)
{
_selectedCompany = value;
}
}
}
public ObservableCollection<Object> Companies
{
get { return _Companies; }
set
{
if (_Companies != value)
{
_Companies = value;
}
}
}
public CompanyMgmtViewModel()
{
this.LoadData();
}
public void LoadData()
{
ObservableCollection<Object> records = new ObservableCollection<Object>();
var results = AODB.Context.TCompanies.Project().To<Company>();
foreach (var item in results)
if (item != null) records.Add(item);
Companies = records;
}
}
View
<igDP:XamDataGrid x:Name="dgCompanies"
Theme="IGTheme"
DataSource="{Binding Companies, Mode=OneWay}"
SelectedDataItemsScope="RecordsOnly"
SelectedDataItems="{Binding Company}">
...
<igDP:XamDataCards x:Name="XamDataCards1"
Grid.Row="1"
DataSource="{Binding ElementName=dgCompanies, Path=SelectedDataItems}"
Theme="IGTheme">
Using MvvmCross, I have a ViewModel with a property that I want to bind in both iOS and Android. The property represents the item a user has selected from a list of items.
In iOS I have implemented the list using an MT.Dialog RootElement with RadioElements, binding to the RadioSelected property of the RootElement (similar to the example in https://github.com/MvvmCross/MvvmCross-Tutorials/blob/master/DialogExamples/DialogExamples.Touch/Views/FirstView.cs):
new Section("Radio") {
new RootElement("Dessert", new RadioGroup("Dessert", 0)) {
new Section {
radioChoices
}
}.Bind(bindings, e => e.RadioSelected, vm => vm.CurrentDessertIndex) as Element
}
where CurrentDessertIndex represents the index (which is an int) of the item selected.
In Android I am using an MvxSpinner for the list:
<MvxSpinner
android:spinnerMode="dropdown"
local:MvxItemTemplate="#layout/itemspinner"
local:MvxDropDownItemTemplate="#layout/itemspinnerdropdown"
local:MvxBind="ItemsSource radioChoices; SelectedItem CurrentDessert" />
Note that the MvxSpinner needs to bind to an object (and not an int).
This means I have to have two properties in my ViewModel representing the same thing, depending on the platform:
public class FirstViewModel : MvxViewModel
{
private int _currentDessertIndex;
public int CurrentDessertIndex
{
get { return _currentDessertIndex; }
set {
_currentDessertIndex = value;
RaisePropertyChanged(() => CurrentDessertIndex);
}
}
private int _currentDessert;
public int CurrentDessert
{
get { return _currentDessert; }
set {
_currentDessert = value;
RaisePropertyChanged(() => CurrentDessert);
}
}
}
How can I consolidate this to use only one property?
One simple solution would be to link the two properties using RaisePropertyChanged - e.g.
public class FirstViewModel : MvxViewModel
{
private int _currentDessertIndex;
public int CurrentDessertIndex
{
get { return _currentDessertIndex; }
set {
_currentDessertIndex = value;
_currentDessert = _desserts[value];
RaisePropertyChanged(() => CurrentDessertIndex);
RaisePropertyChanged(() => CurrentDessert);
}
}
private Dessert _currentDessert;
public Dessert CurrentDessert
{
get { return _currentDessert; }
set {
_currentDessert = value;
_currentDessertIndex = _desserts.IndexOf(_currentDessert);
RaisePropertyChanged(() => CurrentDessertIndex);
RaisePropertyChanged(() => CurrentDessert);
}
}
}
Alternatively, it would be fairly straight-forward to add a custom binding to Android to support the index position in your project. You'd need to base this code on https://github.com/MvvmCross/MvvmCross/blob/3.2/Cirrious/Cirrious.MvvmCross.Binding.Droid/Target/MvxSpinnerSelectedItemBinding.cs - but use the integer selection position rather than the selected object itself. See the N+1 on custom bindings in http://mvvmcross.blogger.com
I Have a model SupplierInvoice as follows:
public class SupplierInvoice
{
public bool Use { get; set; }
public ApInvoice Invoice { get; set; }
}
And a ViewModel with a list of this model:
private List<SupplierInvoice> _SupplierInvoices;
public List<SupplierInvoice> SupplierInvoices
{
get
{
return this._SupplierInvoices;
}
set
{
if (this._SupplierInvoices != value)
{
this._SupplierInvoices = value;
this.RaisePropertyChanged("SupplierInvoices");
}
}
}
within this ViewModel I have a calculated property too:
public decimal ApTotal
{
get
{
decimal total = 0;
if (this.SupplierInvoices != null)
{
foreach (SupplierInvoice invoice in this.SupplierInvoices)
{
if (invoice.Use)
{
total += invoice.Invoice.MthInvBal1;
}
}
}
return total;
}
}
this calculated property returns the sum of the balance of all the invoices (if the invoice's Use property is true). The Use property is selected to be true on the view with a checkbox in a grid.
Now... the question is: How do I NotifyPropertyChanged of this calculated property (ApTotal) when the Use property of the SupplierInvoice model has been changed?
I think replacing your List<TObject> by an ObservableCollection<TObject> will do the trick.
From what I remember the List isn't propagating the PropertyChangedEvent to the UI thread.
This may be a bit naughty, but you could always do this:
private List<SupplierInvoice> _SupplierInvoices;
public List<SupplierInvoice> SupplierInvoices
{
get
{
return this._SupplierInvoices;
}
set
{
if (this._SupplierInvoices != value)
{
this._SupplierInvoices = value;
this.RaisePropertyChanged("SupplierInvoices");
this.RaisePropertyChanged("ApTotal");
}
}
}
Whenever you have a calculated property, you just need to raise the INotifyPropertyChanged.PropertyChanged event from the other properties that are involved in the calculation. So as your ApTotal property is calculated from just the SupplierInvoices property, then you can just notify the interface from that property setter:
public List<SupplierInvoice> SupplierInvoices
{
get
{
return this._SupplierInvoices;
}
set
{
if (this._SupplierInvoices != value)
{
this._SupplierInvoices = value;
this.RaisePropertyChanged("SupplierInvoices");
this.RaisePropertyChanged("ApTotal");
}
}
}
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>.