MVVM DataBinding - c#

I've started an MVVM project and now I'm stucking with correct DataBinding.
My project has:
A UserControl whit a ViewModel as DataContext like:
public partial class TestUserControl: UserControl
{
public TestUserControl()
{
this.DataContext = new TestUserControlViewModel();
}
}
ViewModel code is (BaseViewModel class contains PropertyChangedEventHandler):
public class TestUserControlViewModel : BaseViewModel
{
public KrankenkasseControlViewModel()
{}
public IEnumerable<DataItem> GetAllData
{
get
{
IGetTheData src= new DataRepository();
return src.GetData();
}
}
}
IGetTheData is the interface to DataContext:
public interface IGetTheData
{
IEnumerable<DataItem> GetData();
}
}
and finally the DataRepository code:
public class DataRepository : IGetTheData
{
private TestProjectDataContext dax = new TestProjectDataContext();
public IEnumerable<DataItem> GetData()
{
return (from d in this.dax.TestData
select new DataItem
{
ID = d.ID,
SomeOtherData = d.SomeOtherData
});
}
}
My UserControl has a few TextBoxes, but what's the best way to bind correctly?
Thanks for your help, regards.

EDIT: Binding the data against multiple textboxes
After reading your comment, I will elaborate my example for textboxes.
First important thing is that the ViewModel will model the things in the View, so that the View gets all information it needs in the structure it needs. That means, if you have multiple textboses in the View, you will need multiple string Properties in your ViewModel, one for each textbox.
In your XAML you could have something like
<TextBox Text="{Binding ID, Mode=TwoWay}" />
<TextBox Text="{Binding SomeOtherData, Mode=TwoWay}" />
and in your ViewModel
public class TestUserControlViewModel : BaseViewModel {
private string id;
private string someOtherData;
public TestUserControlViewModel() {
DataItem firstItem = new DataRepository().GetData().First();
this.ID = firstItem.ID;
this.SomeOtherData = firstItem.SomeOtherData;
}
public string ID {
get {
return this.id;
}
set {
if (this.id == value) return;
this.id = value;
this.OnPropertyChangedEvent("ID");
}
}
public string SomeOtherData {
get {
return this.someOtherData;
}
set {
if (this.someOtherData == value) return;
this.someOtherData = value;
this.OnPropertyChangedEvent("SomeOtherData");
}
}
}
Here I assume that in your BaseViewModel there is an OnPropertyChangedEvent method to fire the corresponding event. This tells the View that the property has changed and it must update itself.
Note the Mode=TwoWay in the XAML. This means, that it doesn't matter on which side the value changes, the other side will reflect the change immediately. So if the user changes a value in a TwoWay bound TextBox, then the corresponding ViewModel property will automatically change! And also vice versa: if you change the ViewModel property programmatically, the View will refresh.
If you want to show multiple textboxes for more than one data item, then you must introduce more Properties in the ViewModel and bind them accordingly. Maybe a ListBox with a flexible number of TextBoxes inside is a solution then, like #Haspemulator already answered.
Binding the data against a collection control
In the TestUserControl I guess you have a control (like a ListView) to show the list of loaded things. So bind that control against the list in the ViewModel with
<ListView ... ItemsSource="{Binding GetAllData}" ... />
First you must understand that Binding means not "read the data and then forget the ViewModel". Instead you bind the View to the ViewModel (and its Properties) as long as the View lasts. From this point of view, AllData is a much better name than GetAllData (thanks #Malcolm O'Hare).
Now in your code, every time the View reads the AllData property, a new DataRepository is created. Because of the Binding, that is not what you want, instead you want to have one instance of DataRepository for the whole lifetime of the View, which is used to read the initial data and can later be used to update the View, if the underlying database changes (maybe with an event).
To enable such a behavior you should change the type of the AllData property to an ObservableCollection, so that the View can automatically update the list if changes occur.
public class TestUserControlViewModel : BaseViewModel
private ObservableCollection<DataItem> allData;
public TestUserControlViewModel() {
IGetTheData src = new DataRepository();
this.allData = new ObservableCollection<DataItem>(src.GetData());
}
public ObservableCollection<DataItem> AllData {
get {
return this.allData;
}
}
public void AddDataItem(DataItem item) {
this.allData.Add(item);
}
}
Now if you call AddDataItem later, the ListView will update itself automatically.

Your Property Name is bad. You should call it AllData, not GetAllData.
Since you are returning a collection, you probably should be using some sort of list control (ListBox, ListView).
In that case you'd be doing
<ListBox ItemsSource="{Binding GetAllData}" />

Guten Abend. :) As it already mentioned, since you're returning the collection, it's better to use a ListBox. The comment about having ObservableCollection as a cache is also absolutely valid. I would add that if you need to have your data editable, you should use TextBox inside the ItemTemplate:
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text={Binding SomeOtherData,Mode=TwoWay} />
</DataTemplate>
</ListBox.ItemTemplate>
In this case if user edits the text in the box, data will be updated in your data object, so that it could be saved in the database later.

Related

c# WPF MVVM TabControl with Multiple ViewModels and changing tabs

So I currently have a Window with a TabControl. The MainWindow has its own ViewModel and all the TabItems have their own ViewModels also.
I can easily change tabs from the MainWindow ViewModel through a bound SelectedIndex property. What I would like to do is change to another tab from code that runs within ANOTHER tab viewmodel. Since the Tabs are not part of the MainWindowViewModel, I am looking for a clean way to change the Tab without resorting to code behind to do it.
There are also cases, where I might need to change the tab from something such as a message prompt. I thinking my only way is to create and event and subscribe to that from MainWindowViewModel.
So I solved this with an EventAggregator.
public static class IntAggregator
{
public static void Transmit(int data)
{
if (OnDataTransmitted != null)
{
OnDataTransmitted(data);
}
}
public static Action<int> OnDataTransmitted;
}
First ViewModel sends data.
public class ModifyUsersViewModel : INotifyPropertyChanged
{
private void change_tab(int data)
{
IntAggregator.Transmit(data);
}
}
Second ViewModel receives data and then does something with it.
public class MainWindowViewModel : INotifyPropertyChanged
{
private int _Tab_SelectedIndex = 0;
public int Tab_SelectedIndex
{
get
{
return _Tab_SelectedIndex;
}
set
{
_Tab_SelectedIndex = value;
OnPropertyChanged(new PropertyChangedEventArgs("Tab_SelectedIndex"));
}
}
public MainWindowViewModel()
{
IntAggregator.OnDataTransmitted += OnDataReceived;
}
private void OnDataReceived(int data)
{
Tab_SelectedIndex = data;
}
}
Rather than trying to bind to SelectedIndex, if the TabItems have their own view models, then you can create a property for each of those view models: IsSelected and then bind the TabItem.IsSelected property to that:
<TabItem IsSelected="{Binding IsSelected}">
This prevents the view models from needing to know the index of their corresponding TabItem, something I would argue is a detail that should be specific to the view and something the view model should not concern itself with. What if you add another TabItem or want to change the order? Now you've got changes to make in the view models for something that could be just simple change to the view.

Calling multiple OnPropertyChanged within the same Setter (or is there a other easy way)

I am trying to keep my question simple and to the point.
At the moment, if I have a property that updates the underlying Model data, and it therefore needs to inform a few other properties that the source has changed, I do it like this:
public Data.MeetingInfo.Meeting Meeting
{
get { return _Meeting; }
set
{
if(value != null)
{
_Meeting = value;
if (_Meeting.IsDirty)
{
_Model.Serialize();
_Meeting.MarkClean();
OnPropertyChanged("Meeting");
OnPropertyChanged("BibleReadingMain");
OnPropertyChanged("BibleReadingClass1");
OnPropertyChanged("BibleReadingClass2");
}
}
}
}
private Data.MeetingInfo.Meeting _Meeting;
As you can see, I added several different OnPropertyChanged method calls. Is this an acceptable way to do it? Or, can the specific properties in the Model inform the View that some of it's source has changed?
I have read about implementing the same OnPropertyChanged features in the Model classes. Thus the XAML will pick it up. But I thought those two parts of the MWWV we not supposed ot know about each other.
The thing is, the other 3 are in disabled controls, but they can be updated from two places on the window. So I don't think I can have two update source triggers can I?
Thank you.
Second attempt at explainign things:
ObservableCollection of Meeting objects. Bound to a ComboBox:
<ComboBox x:Name="comboMeetingWeek" ItemsSource="{Binding Meetings}"
SelectedItem="{Binding Meeting, UpdateSourceTrigger=PropertyChanged}" />
The Meeting object contains several properties. We bind controls on the window with these properties. Example:
<ComboBox x:Name="comboNotes" IsEditable="True"
DataContext="{Binding Meeting}"
Text="{Binding Note, UpdateSourceTrigger=LostFocus}"
ItemsSource="{StaticResource Notes}"/>
I do this for the majority of the controls. So the Meeting property in the view model is kept up to date and then when you select a different meeting it commits it to the model data and displays the new meeting (as previously described).
But, in some places on the window, I have some disabled text boxes. These are associated with properties nested inside the Meeting object. For example:
<TextBox x:Name="textBibleReadingMain" Grid.Column="0" Margin="2" IsEnabled="False"
DataContext="{Binding TFGW.BibleReadingItem.Main}"
Text="{Binding DataContext.BibleReadingMain, ElementName=oclmEditor, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"/>
The parent TabItem already has it's DataContext set to {Binding Meeting}. What we need to display in the text box is:
Meeting (current context).TFGW.BibleReadingItem.Main.Name
This is why I had to do it has I did. For the above text box, this is what I want to allow to happen:
It should display the content of Meeting.TFGW.BibleReadingItem.Main.Name (Meeting already being a bound property).
As you select a different meeting from the dates combo, this text box should update.
If the user selects a name from the DataGrid and the ActiveAstudentAssignmentType combo is set to StudentAssignmentType::BibleReadingMain then I also want to update the text box.
I think what I am getting confused about is when I am supposed to derive my classes from INotifyPropertyChanged. My Model data is the Meeting objects with it's own data. Should all of these be inheriting from INotifyPropertyChanged and raising OnPropertyChanged? At the moment I do not have that implemented anywhere. I tell a lie, the only place I implemented it was for the view model itself:
public class OCLMEditorViewModel : INotifyPropertyChanged
So that is why I had to do it the way I did.
Any clearer?
Based on all the comments and further reasearch ....
One of the answers stated:
Viewmodel is created and wraps model
Viewmodel subscribes to model's PropertyChanged event
Viewmodel is set as view's DataContext, properties are bound etc
View triggers action on viewmodel
Viewmodel calls method on model
Model updates itself
Viewmodel handles model's PropertyChanged and raises its own PropertyChanged in response
View reflects the changes in its bindings, closing the feedback loop
I also read a bit of this (which confused me somewhat) where it stated:
The Model notifies the ViewModel if the data in the underlying data store has changed.
So, the first thing I did was change my Meeting object to derive from INotifyPropertyChanged. In addition, I added new properties for gaining access to deeper data in the Meeting model. Example (stripped down):
public class Meeting : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
#region Bible Reading Name Properties
[XmlIgnore]
public string BibleReadingMainName
{
get { return _TFGW.BibleReadingItem.Main.Name; }
set
{
_TFGW.BibleReadingItem.Main.Name = value;
OnPropertyChanged("BibleReadingMainName");
}
}
[XmlIgnore]
public string BibleReadingClass1Name
{
get { return _TFGW.BibleReadingItem.Class1.Name; }
set
{
_TFGW.BibleReadingItem.Class1.Name = value;
OnPropertyChanged("BibleReadingClass1Name");
}
}
[XmlIgnore]
public string BibleReadingClass2Name
{
get { return _TFGW.BibleReadingItem.Class2.Name; }
set
{
_TFGW.BibleReadingItem.Class2.Name = value;
OnPropertyChanged("BibleReadingClass2Name");
}
}
#endregion
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
In my ViewModel I set it as a listener for PropertyChanged:
_Meeting.PropertyChanged += Meeting_PropertyChanged;
At this point in time, the handler just relays the property that was changed:
private void Meeting_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(e.PropertyName);
}
In my XAML, I adjust my TextBox to work with the new property, and I remove the DataContext reference. So I now have:
<TextBox x:Name="textBibleReadingMain" Grid.Column="0" Margin="2" IsEnabled="False"
Text="{Binding BibleReadingMainName, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
ON the right, where I have the DataGrid, when we click a row and the SelectedStudentItem is updated, we can now do:
private Student _SelectedStudentItem;
public Student SelectedStudentItem
{
get
{
return _SelectedStudentItem;
}
set
{
// We need to remove this item from the previous student history
if (_SelectedStudentItem != null)
_SelectedStudentItem.History.Remove(Meeting.DateMeeting);
_SelectedStudentItem = value;
if (_SelectedStudentItem == null)
return;
_EditStudentButtonClickCommand.RaiseCanExecuteChanged();
_DeleteStudentButtonClickCommand.RaiseCanExecuteChanged();
OnPropertyChanged("SelectedStudentItem");
if (ActiveStudentAssignmentType == StudentAssignmentType.BibleReadingMain)
_Meeting.BibleReadingMainName = _SelectedStudentItem.Name;
else if (ActiveStudentAssignmentType == StudentAssignmentType.BibleReadingClass1)
_Meeting.BibleReadingClass1Name = _SelectedStudentItem.Name;
else if (ActiveStudentAssignmentType == StudentAssignmentType.BibleReadingClass2)
_Meeting.BibleReadingClass2Name = _SelectedStudentItem.Name;
}
Based on the current ActiveStudentAssignmentType value we can directly update the source property. Thus the TextBox will automatically know about it due to the PropertyChange listener.
Thus, the original Meeting property code now looks like this:
public Data.MeetingInfo.Meeting Meeting
{
get { return _Meeting; }
set
{
// Has the existing meeting object changed at all?
if(_Meeting != null && _Meeting.IsDirty)
{
// Yes, so save it
_Model.Serialize();
_Meeting.MarkClean();
}
// Now we can update to new value
if (value != null)
{
_Meeting = value;
OnPropertyChanged("Meeting");
}
}
}
private Data.MeetingInfo.Meeting _Meeting;
All of those extra OnPropertyChanged calls are now obsolete!
The thing I was missing was implementing Notification from the Model to the ViewModel. And then the ViewModel informing the View.

Store grid rowcount in ViewModel in MVVM

I'm implementing MVVM for a WPF application.
The ViewModels are created as follows:
ViewModel: base class from which all ViewModels override
MainTemplateViewModel: the 'Masterpage' ViewModel which contains a ViewModel property Current that contains the ViewModel to show
CustomerOverviewViewModel: an example of a view that can be placed in the MainTemplateViewModel.Current
The CustomerGridViewModel contains a Telerik GridView. I would like to show the number of items in the title of the MainTemplateViewModel. The GridView.Items.Count property implements the INotifyPropertyChanged so I would like to bind this property to ViewModel.RowCount (because the CustomerGridViewModel doesn't know it is part of the MainTemplateViewModel it cannot be bound directly to the TextBlock). I can in turn use ViewModel.NumberOfRecords to show the amount in the title.
How can I bind the Count property to a property in my ViewModel?
Edit
I'll describe the issue in more detail:
The list of objects shown in the grid is a binding from the ViewModel:
<telerik:RadGridView x:Name="CustomerGrid" ItemsSource="{Binding CustomerViewModels}">
</telerik:RadGridView>
When filtering the Grid in memory, the Telerik Grid automatically changes the GridView.Items.Count property (this does not mean the original list count is changed!). So if I can bind this property to a property in the ViewModel class, this would solve the problem.
ViewModel.cs
public class ViewModel : INotifyPropertyChanged
{
private int numberOfRecords;
public int NumberOfRecords
{
get { return numberOfRecords; }
set { numberOfRecords = value; OnPropertyChanged(); }
}
}
MainTemplateViewModel.cs
public class MainTemplateViewModel : ViewModel
{
private ViewModel current = new MainOverviewViewModel();
public ViewModel Current
{
get { return current; }
set
{
if (current != value)
{
current = value; OnPropertyChanged();
}
}
}
}
CustomerOverview.xaml.cs
public partial class CustomerOverview : UserControl
{
public CustomerOverview()
{
InitializeComponent();
this.CustomerGrid.Items.CollectionChanged += ItemsCollectionChanged;
this.CustomerGrid.Loaded += CustomerGrid_Loaded;
}
void CustomerGrid_Loaded(object sender, RoutedEventArgs e)
{
/* METHOD 1 PROBLEM: the field to bind to in the MainTemplate is out of scope and accessing a view is not MVVM */
var binding = new Binding();
binding.Path = new PropertyPath("Items.Count");
binding.Source = CustomerGrid;
((MainWindow)this.ParentOfType<MainWindow>()).NumberOfRecords.SetBinding(TextBlock.TextProperty, binding);
}
void ItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
/* METHOD 2 PROBLEM: codebehind code should be in viewmodel */
((CustomerOverviewViewModel)this.DataContext).NumberOfRecords = CustomerGrid.Items.Count;
}
}
Instead of loading the data in your UserControl, just declare a DependencyProperty of the relevant type in it. You can then load the data in the main view model and simply data bind to it from the UserControl. You could do something like this simple example:
In CustomerOverview.xaml.cs:
public static DependencyProperty ItemsProperty = DependencyProperty.Register("Items",
typeof(ObservableCollection<YourDataType>), typeof(CustomerOverview),
new PropertyMetadata(null));
...
In CustomerOverview.xaml:
<ListView ItemsSource="{Binding Items, RelativeSource={RelativeSource AncestorType={
x:Type YourPrefix:CustomerOverview}}}" ... />
...
In MainWindow.xaml (or whichever relevant view):
<YourPrefix:CustomerOverview
Items="{Binding SomeCollectionPropertyInMainTemplateViewModel}" ... />
...
In MainTemplateViewModel.cs (or whichever relevant view model):
public ObservableCollection<YourDataType> SomeCollectionPropertyInMainTemplateViewModel
{
get { return someCollectionPropertyInMainTemplateViewModel; }
set
{
someCollectionPropertyInMainTemplateViewModel = value;
NotifyPropertyChanged("SomeCollectionPropertyInMainTemplateViewModel");
NotifyPropertyChanged("NumberOfRecords");
}
}
public int NumberOfRecords
{
get { return someCollectionPropertyInMainTemplateViewModel.Count; }
}
Telerik Grid has two properties
Visible Count
TelerikGrid.Items.Count
Total Count
TelerikGrid.Items.TotalItemCount
In case this helps!
If i get you right, you want your master to show details of the child.
Your master should be able to know your child by your Current property.
If you are using MVVM correctly, the data bound to your grid comes from the child-ViewModel.
In that case, you have already have the itemscount in your child-ViewModel.
After this you can say in your Master something like
<Label Content="{Binding Current.NumberOfRows}"></Label>
According to this page you could wrap your source in a QueryableCollectionView

Implementing TreeView using MVVM

I'm new to the MVVM pattern and I have an assignment to implement a TreeView which acts like a work space viewer (sort of like eclipse's/vs's solution explorer).
The tree view can contain multiple types of items (like a file, a folder of other items etc).
I have created the Models (the Folder's model have Children (which can be any kind of item), Name etc).
Example model:
public class SystemFolder: IWorkspaceItem
{
string mTitle;
public ObservableCollection<IWorkspaceItem> Children { get; set; }
public string Path
{
get { return mTitle; }
set
{
mTitle = value;
OnPropertyChanged("Title");
}
}
//Constructor
public SystemFolder(string name, ItemType type, string path)
: base(name, type)
{
Path = path;
Children = new ObservableCollection<IWorkspaceItem>();
//add children here...
}
//Some more code here..
}
I've created a ViewModel for each model (Which all store the model's instance).
The ViewModels have the necessary properties that the view needs (like Title, Children etc).
Example ViewModel:
public class SystemFolderViewModel : TreeViewModelItem
{
SystemFolder mFolder;
ObservableCollection<TreeViewModelItem> mChildren;
public ObservableCollection<TreeViewModelItem> Children
{
get { return mChildren; }
}
//====================
// Constructor
//====================
public SystemFolderViewModel(SystemFolder folder, TreeViewModelItem parentWorkspaceItem)
: base(parentWorkspaceItem)
{
mFolder = folder;
mFolder.Attach(OnItemPropertyChanged);
}
public string Name
{
get { return mFolder.Name; }
set { Name = value; }
}
public string IconPath
{
get { return mFolder.ItemType.IconPath; }
set { IconPath = value; }
}
//Some more code here..
}
I've also implemented the View which defined the HierarchicalDataTemplate of each ViewModel.
It all works fine and I actually made a mockup.
Example of HierarchicalDataTemplate in View:
<HierarchicalDataTemplate
DataType="{x:Type local:SystemFolderViewModel}"
ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16" Margin="3,0" Source="{Binding Path=IconPath}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
The whole initialization:
Workspace data_model = new Workspace("Main Workspace", PredefinedTypes.GetWorkspaceType(), Database.GetItems());
TreeViewModel vm = new TreeViewModel(data_model);
WorkspaceView viewer = new WorkspaceView(vm);
//add to grid etc..
Now my problem is that my program is dynamic. Meaning, items can be added to the TreeView in run-time.
Now let me explain how I understand MVVM should work and please correct me.
The Data model provides the view with items.
So my program should only add items to the data model.
The main ViewModel of the tree holds a DataModel instance which hold the workspace's main children.
Each item that is added to the model should automatically update the ViewModel which in turn should update the view.
Since I only update the DataModel, when I add a child to one of its items, the ViewModel should find the corresponding item in the ViewModel and add a new child to it.
Why do I have to have two seperate collections? The DataModel's Children and the ViewModel Children.
I need every data model to inherit from INotifyPropertyChanged so it will update its ViewModel.
Also as I said, there are data models which have their own children. If that collection changes I need the collection in the item's ViewModel to change.
This all seems kind of dumb to me. Why should I get through all this trouble? Why can't I just add items to the ViewModel which will update the view?
What am I missing?
How do I need to go about with this?
If you need more info, please ask me and I will provide/explain.
Thank you!
Dolev.

WPF DateGrid: How to bind a column of ComboBox plus need to enable/disable entries dynamically

This part is ready and operational:
"How to bind a column of ComboBox"
<DataGridTemplateColumn Header="Bot Plate Thickness">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding SteelThickness, RelativeSource={RelativeSource AncestorType=Window}}" SelectedItem="{Binding BottomPlateThickness, UpdateSourceTrigger=PropertyChanged}" SelectionChanged="ComboBox_SelectionChanged" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
And this is the relevant part of my model:
public class GridModel : PropertyChangedBase
{
private string _BottomPlateThickness;
public string BottomPlateThickness
{
get
{
return _BottomPlateThickness;
}
set
{
if (_BottomPlateThickness != value)
{
_BottomPlateThickness = value;
RaisePropertyChanged("BottomPlateThickness");
}
}
}
}
This is another part:
public List<string> SteelThickness { get; set; }
SteelThickness = new List<string> { "0.3750", "0.4375", "0.5000", "0.6250", "0.7500", "0.8650", "1.0000" };
As you can see, the ComboBox contents are based on a static list. I read that in order to be able to be turned on/off, I have to base that column on an ObservableList<object>.
TIA.
The answer is simple... you don't access a ComboBox in a specific row of a DataGridTemplateColumn. Why do so many people want to use WPF like WinForms?... it's not WinForms. I say this line so much that I'm starting to feel like a preacher... WPF is a data-centric language... that means that we manipulate data objects, not UI objects. Why not make your life easier and hold the metaphoric hammer by the handle instead of the head?
Thinking of this problem in terms of data, we have a collection of data objects. One object is represented by one row in the DataGrid, so one property of these objects will relate to the selected item from the ComboBoxes in question. Now if you were to make your life really easy, you'd add a new collection property into that class that you could bind to the ComboBox.ItemsSource property.
Now, to change the possible options in each ComboBox, all you need to do is to change the items in that collection property in your data bound object. You could define your 'unfiltered' collection in your data type as a static variable that each instance could share:
private static ObservableCollection<string> steelThickness = new
ObservableCollection<string> { "0.3750", "0.4375", "0.5000", "0.6250", "0.7500",
"0.8650", "1.0000" };
public ObservableCollection<string> ComboBoxItemsSource
{
get { return new ObservableCollection<string>(
steelThickness.Where(item => item.MeetsCertainCriteria(item))); }
}
private bool MeetsCertainCriteria(string item)
{
// return true or false for each item to adjust the members in the collection
// based on whatever your condition is
if ( ... ) return true;
return false;
}
The only points to note with this set up is that you'll have to manually call NotifyPropertyChange("ComboBoxItemsSource") when the collection is updated and that you'll need to use a OneWay Binding because it has no setter. Now, wasn't that easier?

Categories

Resources