As the title suggests; I have a combobox using a composite collection to bind to an observable collection using the MVVM pattern.
If I load my model with existing data then the combobox shows the values so I know the binding works. I can add items to the observable collection and they are shown in a data grid so I know the notify property changed events on the observable collection are working. I suspect it is not working because the composite collection is using a "Static Resource" as its source but if I change it to Dynamic Resource then I get the error:
A 'DynamicResourceExtension' cannot be set on the 'Source' property of
type 'Binding'. A 'DynamicResourceExtension' can only be set on a
DependencyProperty of a DependencyObject.
I have searched for days to find a solution and while others have faced similar problems the solutions have yet to solve my problem.
Here is my code for the model:
public class Model : ObservableObject
{
#region Properties
private string name;
public string Name
{
get { return this.name; }
set { this.name = value; }
}
private string balance;
public string Balance
{
get { return this.balance; }
set { this.balance = value; }
}
#endregion
My ViewModel:
public class ViewModel : ObservableObject
{
private ObservableCollection<Model> modelcollection;
public ObservableCollection<Model> ModelCollection
{
get { return modelcollection; }
set
{
modelcollection= value;
RaisePropertyChangedEvent("ModelCollection");
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChangedEvent("Name");
}
}
private string _balance;
public string Balance
{
get { return _balance; }
set
{
_balance = value;
RaisePropertyChangedEvent("Balance");
}
}
And finally the XAML of my view for the combobox:
<ComboBox MinWidth="100" SelectedValue="{Binding combovalue, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="Name">
<ComboBox.Resources>
<vm:ViewModel x:Key="CollectionKey"/>
</ComboBox.Resources>
<ComboBox.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding ModelCollection, Source={StaticResource CollectionKey}, UpdateSourceTrigger=PropertyChanged}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Thank you all so much in advance.
EDIT:
So I have moved in a direction; right or wrong is yet to be decided.
I think I have traced the problem to be outside the combobox itself so more context is needed here.
The comobobox is on the second tab of a tab control. Each tab item has its own data context pointing to its own view model. Data is entered on the first tab and I want that data to show up in the combobox on the second tab.
If I put a combobox on the first tab then that combobox updates with changes in the observable collection as entered on the first tab. So the issue, (I think), is that the combobox on the second tab is trying to bind to two different view models at the same time. One for the items source and a different one for the selected value.
There was a suggestion in another thread to use x:Reference for the data context but I can't seem to figure out the correct syntax for that.
If your still reading this then any help is really appreciated.
In the end I never got the combobox to populate from the other view model. I am still unsure if this is possible or not.
The solution that finally worked for me was to just combine everything I needed for binding into a single view model. It made the view model a bit heavy but cut down a lot on the XAML so I guess that's a win.
Related
I'm trying to set a default value into a combo box when the application is first loading using the MVVM pattern and it looks like this is all the time unset, combo box being all the time empty when the page loads.
This is my xaml:
<ComboBox Grid.Row="0" Margin="10,0,0,0" Grid.Column="1"
SelectedItem="{Binding Path=JuiceOperations.SelectedItemOption, Mode=TwoWay}"
SelectedIndex="{Binding Path=JuiceOperations.SelectedComboBoxOptionIndex, Mode=TwoWay}"
SelectedValue="{Binding Path=JuiceOperations.SelectedComboBoxOptionIndex, Mode=TwoWay}"
ItemsSource="{Binding Path=JuiceOperations.JuiceOptions}" />
This is the view model code, with its default constructor:
public JuiceViewModel()
{
juiceOperations.SelectedComboBoxOptionIndex = 0;
juiceOperations.SelectedItemOption = "Cola";
}
where I am trying to set the default value of the combo box.
And this is how the properties looks like:
private List<string> juiceOptions = new List<string> { "Cola", "Sprite", "Fanta", "Pepsi" };
private string selectedItemOption = string.Empty;
private int selectedComboBoxOptionIndex = 0;
public int SelectedComboBoxOptionIndex
{
get
{
return this.selectedComboBoxOptionIndex;
}
set
{
this.selectedComboBoxOptionIndex = value;
this.OnPropertyChanged("SelectedComboBoxOptionIndex");
}
}
public List<string> JuiceOptions
{
get
{
return this.juiceOptions;
}
set
{
this.juiceOptions = value;
}
}
public string SelectedItemOption
{
get
{
return this.selectedItemOption;
}
set
{
this.selectedItemOption = value;
this.OnPropertyChanged("SelectedItemOption");
}
}
When selecting an item from combo box the selection is updated into the model and also into the view, so it is working as expected but when the page is first loaded even if the "SelectedComboBoxOptionIndex" and "SelectedItemOption" are being called and their value updated the view of the page is not updated and the empty string is being shown into the combo box where I was expected to see the "Cola" value, instead of the empty string.
Can someone explain me what I am doing wrong and how should I set the default "Cola" value into the combo box ?
Only bind the SelectedItem property of the ComboBox to the SelectedItemOption source property and set the latter to the string "Cola" in the view model. This should work:
<ComboBox Grid.Row="0" Margin="10,0,0,0" Grid.Column="1"
SelectedItem="{Binding Path=JuiceOperations.SelectedItemOption}"
ItemsSource="{Binding Path=JuiceOperations.JuiceOptions}" />
public JuiceViewModel()
{
juiceOperations.SelectedItemOption = "Cola";
}
Don't mix SelectedItem, SelectedIndex and SelectedValue. You only need one.
mm8 above absolutely right, that should fix your issue.
On a side note, what you have there will work for a static selection list, but consider using an ObservableCollection<string> instead of a List<string>. The former implements INotifyCollectionChanged, which allows the view to be notified if there has been a change in the collection. When you bind an Observable Collection to the view, the view automatically subscribes to the CollectionChanged event. You will need this if you ever need to add or remove options at run time. Side note, OnCollectionChanged will not fire if you simply modify an item, for that you would still need to callOnPropertyChanged("JuiceOptions") in the setter.
something like this (with the appropriate private backing field):
public ObservableCollection<string> JuiceOptions
{
get
{
return this.juiceOptions;
}
set
{
this.juiceOptions = value;
this.OnPropertyChanged("JuiceOptions");
}
}
The value of juiceOperations.SelectedItemOption, that is, "Cola", is not the same "Cola" stored in the ItemsSource. You would need to do something like juiceOperations.SelectedItemOption = juiceOperations.JuiceOptions.First().
I am developing windows phone app .In app,I want to put multiple check box.I able to put multiple check box.But when i checked on check box i want getting its content(check box content).For that i am use checked event and also click event but i cant get result as i want.My xaml code is as below:
<ListBox Name="hobbylist" ItemsSource="{Binding}" Margin="0,0,10,10" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Name="hobbycheck" Content="{Binding Path=Title}"
IsChecked="{Binding IsSelected}" ClickMode="Release"
Click="CheckBox_Click" ></CheckBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Please help me ...
I think you are using the Checkbox not correctly according to its purpose.
Checkbox should represent a state (e.g. yes/no) regarding a subject. Still, you just have to use the Checked event when the checkbox gets checked and Unchecked otherwise.
So in the Checked event, get the content you wish.
Edit
You have to maintain this with the MVVM pattern somehow. For that, there are plenty of examples in the internet, I am sure you can handle that.
Instead of having Click="CheckBox_Click", use the Check event :
private void CheckBox_Checked (Object sender, EventArgs e)
{
var currentCheckBoxItem = sender as CheckBox;
if (currentCheckBoxItem.IsChecked == true)
{
//you manipulation here...
}
}
Still. this might just not work, because you haven't provided enough details of your matter.
Edit 2 A little of MVVM...
First, make a Hobby model class, with a single string property (you might change your mind later to add more properties, Idk) :
public class Hobby : INotifyPropertyChanged
{
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
OnPropertyChanged();
}
}
private bool _isSelected;
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
OnPropertyChanged();
}
}
//You can add some multiple properties here (***)
public Hobby (string hobbyName, bool isSelected)
{
Name = hobbyName;
IsSelected = isSelected;
}
//INotifiyPropertyChanged interface member implementation ...
}
(* ) For example, a short description and then bind it on the View. The major advantage of this MVVM pattern is logic separation, so if something has to change, the separation of each component makes it easier.
Second, create a ViewModel class (you should implement INotifyPropertyChanged interface) :
public class HobbiesViewModel : INotifyPropertyChanged
{
private ObservableCollection<Hobby> _hobbies;
public ObservableCollection<Hobby> HobbiesCollection
{
get
{
return _hobbies;
}
set
{
_hobbies = value;
OnPropertyChanged();
}
}
//Constructor
public HobbiesViewModel
{
HobbiesCollection = new ObservableCollection<Hobby>();
}
//INotifyPropertyChanged interface member implementation ...
}
Third, create an instance of the ViewModel (the ObservableCollection). Use this quick help out : In the App.xaml.cs, create a static object and use it through the app as you need it :
public partial class App
{
//This already exists in your app's code, but I've written it to
//make an idea where to write the Hobbies object
public static PhoneApplicationFrame RootFrame { get; private set; }
public static HobbiesViewModel Hobbies;
//Again, the already existing constructor
public App()
{
...
Hobbies = new HobbiesViewModel();
}
Now, you almost have it all set; You have the Model, you have the ViewModel, all that's left is to create the connection with the View. This can be easily done through binding. The ViewModel represents the DataContext of your control (in your case the LongListSelector, so in that View's (Page's) constructor, write the following statement :
yourListControlName.DataContext = App.Hobbies;
Now the binding is the only thing left. This is done in XAML code. I won't put a whole chunk of XAML code here, cause you know best how your control looks like. Still, judging by the short sample you provided, there a few adjustments only :
The items source of the list XAML control will be bound to the ObservableCollection object name of the ViewModel representing the control's DataContext. A bit fuzzy, huh? To be clearer, in this case, you need to write ItemsSource="{Binding HobbiesCollection}", the ObservableCollection. Also, in the template, you should have that CheckBox which is bound on your Model's properties :
<DataTemplate>
<StackPanel Orientation="Horizontal"> //StackPanel is kinda useless if you have
//only one child control in it. But I wrote
//according to your code.
<Checkbox Content="{Binding Name}" IsChecked="{Binding IsSelected, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
Now, here things are a bit unclear to me. Why would you use the Checkbox? I've thought of the next possible scenario : You come with some string of your hobbies through deserialization of the Json Data. To add them to the ViewModel, you need only :
App.Hobbies.HobbiesCollection.Add(new Hobby("firstHobbyFromJson", true));
App.Hobbies.HobbiesCollection.Add(new Hobby("secondHobbyFromJson", true));
This would make all hobbies already selected in the View. I guess, you would add some other hobbies, the user doesn't have which are not selected and could add them now :
App.Hobbies.HobbiesCollection.Add(new Hobby("aNewHobby", false));
App.Hobbies.HobbiesCollection.Add(new Hobby("anotherNewHobby", false));
At this point, the user has all its previous hobbies in the list and as well some new hobbies you provided him. After his selection is done, if you need to serialize the Json with only the selected hobbies, you could get like this :
var userHobbies = App.Hobbies.HobbiesCollection.Where(h => h.IsSelected);
or with a foreach and get only those hobby objects which have the IsSelected property as true.
Good luck!
I found a Simpler solution.
My Model
You need to use two variables otherwise you may get an 'stackoverflowexception'
public class ModelObj
{
public int position { set; get; }
public bool isChecked
{
get { return IsChecked; }
set { IsChecked = value; }
}
public bool IsChecked;
}
Code to be added in xaml:
isChecked in xaml sets the ListView Checkbox
Mode=TwoWay updates the isChecked boolean value of the model class
<CheckBox IsChecked="{Binding isChecked , Mode=TwoWay}" Checked="checkBox_Checked" >
c# Code that handles the event
private void checkBox_Checked(object sender, RoutedEventArgs e)
{
foreach (ModelObj obj in listItem)
{
if (obj.isChecked == true)
{
int selectedPosition = obj.position;
}
}
}
I have an strange problem with binding in WPF.
There is a simple sample of what i'm doing:
public class Project
{
private string _title;
public string Title
{
get { return _title; }
set
{
_title= value;
RaisePropertyChanged("Title");
}
}
}
public class People
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name= value
RaisePropertyChanged("Name");
}
}
private Project _project;
public Project Project
{
get { return _project; }
set
{
_project= value;
RaisePropertyChanged("Project");
}
}
}
Now I bound a grid to an instance of People in the view and it can bind controls to Project and Name of People class, but I really can't understand why I can not bind to Project.Title.
I write my XAML code like this:
<TextBox Text="{Binding Name}"/>
<Combobox .... SelectedItem="{Binding Project}"/>
<TextBox Text="{Binding Project.Title}"/>
The first two controls above get bounded correctly but the last TextBox doesn't. I have no idea why it can access to Project but not Project.Title? It's an another weird thing I've already seen in WPF!
Perhaps your combo box selection is not setting the selected value without using Mode=TwoWay:
<Combobox .... SelectedItem="{Binding Project, Mode=TwoWay}"/>
Once the Project is set, the property is set, the Title will show.
Try "Path=Project.Title".
Worked for me in a same case.
if your DataContext is an instance of your Person object it should work. you can check your bindings at runtime with Snoop (http://snoopwpf.codeplex.com/) btw. give it a try :)
you can also do
<TextBox DataContext="{Binding Project, Mode=OneWay}" Text="{Binding Title}"/>
Thank you everyone,but the problem wasn't what i thought.Actually i used PropertyChanged.Fody to inject INotifyPropertyChanged into properties,but it seems it doesn't do what i expected.I implemented INotifyPropertyChanged myself and it works fine now.
I am binding a Collection at run time to a Combobox and I would like to set the Index after to 0. I could not find a straight answer to what I want.
_stationNames = new ObservableCollection<string>(_floorUnits.Unit.Select(f => f.Name));
_stationNames.Insert(0, "All");
stationsComboBox.ItemsSource = _stationNames;
stationsComboBox.SelectedIndex = 0;//Doesn;t work
Xaml
<ComboBox x:Name="stationsComboBox" Grid.Row="1" Grid.Column="1" Text="{Binding Name}"
SelectionChanged="StationComboBoxSelectionChanged" VerticalAlignment="Center" Margin="3"
SelectedIndex="0"/>
It sounds like you're trying to use it like you would with WinForms. WPF is a slightly different beast and a lot more powerful regarding bindings.
I recommend reading a bit on MVVM to get the most benefit from WPF. By binding the XAML to a view model class (rather than trying to wire things up in Code-behind) you will find you can accomplish what you want with a lot more flexibility without oodles of code.
For instance: Given the following VM:
public class MyViewModel: INotifyPropertyChanged
{
public ObservableCollection<string> StationNames
{
get;
private set;
}
public Something()
{
StationNames = new ObservableCollection<string>( new [] {_floorUnits.Unit.Select(f=>f.Name)});
StationNames.Insert(0, "All");
}
private string _selectedStationName = null;
public string SelectedStationName
{
get
{
return _selectedStationName;
}
set
{
_selectedStationName = value;
FirePropertyChanged("SelectedStationName");
}
}
private void FirePropertyChanged(string propertyName)
{
if ( PropertyChanged != null )
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
You can set your view's (XAML form) DataContext to an instance of the ViewModel and update your combo box definition to:
<ComboBox x:Name="stationsComboBox" Grid.Row="1" Grid.Column="1"
ItemsSource="{Binding Path=StationNames}" SelectedItem={Binding Path=SelectedStationName} VerticalAlignment="Center" Margin="3"
SelectedIndex="0"/>
From here whenever the combo box selection changes, the VM's SelectedStationName updates to reflect the current selection, and from anywhere in the VM code, setting the VM's SelectedStationName will update the combo's selection. (I.e. implementing a Reset button, etc.)
Normally though, with something like what you've suggested, I would be looking at binding directly to the Units collection. (or VM's derived from units if they themselves can be viewed/edited.) In any case it should give you a bit of a starting point to start researching into WPF bindings.
I have made a tree View in wpf Using MVVM .
it is working fine but here is one problem that leaf node contains some checkboxes and user have only two options either to select one or none .
So here how i can restricted user to select maximum only one cold drink.
I did one trick but it didn't work that when i have already selected a drink and then i select another one than i set the last selected value in the observable collection to false but it doesn't affect on view and selected check boxes remains selected although in collection only one option's value is true.
I cant use radio button instedof checkbox becasue user can select none of the options and i cant give an additional option for none of the above.
If any one have any solution so please let me know I'll be very thankful.
updated question:
i think i didn't define my problem in a proper way so i am giving my code snipperts here hope by this i'll get the solution o f my problem...
My View Model Class
namespace TestViewModels
{
public class ViewModel :ViewModelBase
{
private ObservableCollection<AvailableProducts> _MyTreeViewProperty
public ObservableCollection<AvailableProducts> MyTreeViewProperty
{
get { return _MyTreeViewProperty
set { _MyTreeViewProperty value;
RaisePropertyChanged("MyTreeViewProperty");}
}
}
public class AvailableProducts
{
private string _BrandName;
public string BrandName
{
get { return _BrandName
set { _BrandName = value; }
}
private bool _IsExpanded;
public bool IsExpanded
{
get
{
return _IsExpanded;
}
set
{
_IsExpanded = value;
}
}
private ObservableCollection<ProductTypes> _MyProductTypes
public ObservableCollection<ProductTypes> MyProductTypes
{
get { return _MyProductTypes}
set { _MyProductTypes= value; }
}
}
public class ProductTypes
{
private string _ProductTypeName;
public string ProductTypeName
{
get { return _ProductTypeName;
set { _ProductTypeNamevalue; }
}
private ObservableCollection<ProductSubTypes> _ProdSubTypes;
public ObservableCollection<ProductSubTypes> ProdSubTypes
{
get { return _ProdSubTypes;}
set { _ProdSubTypes;= value; }
}
}
public class ProductSubTypes
{
private string _ProductSubTypeName;
public string ProductSubTypeName
{
get { return _ProductSubTypeName;
set { _ProductSubTypeName;}
}
private int _ParentID;
public int ParentID
{
get { return _ParentID;}
set { _ParentID;= value; }
}
private bool _IsAssigned;
public bool IsAssigned
{
get { return _IsAssigned; }
set
{
_IsAssigned = value;
if _ParentID;!= 0)
{
//updating data in database
//Calling and setting new collection value in property
//issue : updated collection sets in setter of MyTreeViewProperty but before calling getter
// it comes to IsAssigned getter so view doesnt get updated collection of MyTreeViewProperty
}
RaisePropertyChanged("IsAssigned");
}
}
}
}
View
<Page x:Class="ShiftManagerViews.Pages.ProductTreeSelection
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
DataContext="{Binding ProductsTree, Source={StaticResource Locator}}"
mc:Ignorable="d" Width="870" Height="665"
>
<TreeView Margin="10,10,0,13" ItemsSource="{Binding MyTreeViewProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="800" Height="Auto" MinHeight="400" MaxHeight="800">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:AvailableProducts}"
ItemsSource="{Binding MyProductTypes}">
<WrapPanel>
<Image Width="20" Height="20" Source="/ShiftManagerViews;component/Images/12.bmp"/>
<Label Content="{Binding BrandName}" FontSize="14"/>
</WrapPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:ProductTypes}"
ItemsSource="{Binding ProdSubTypes}">
<WrapPanel>
<Image Width="18" Height="15" Source="/ShiftManagerViews;component/Images/12.bmp"/>
<Label Content="{Binding ProductTypeName}" FontSize="13"/>
</WrapPanel>
</HierarchicalDataTemplate>
<!-- the template for showing the Leaf node's properties-->
<DataTemplate DataType="{x:Type local:ProductSubTypes}">
<StackPanel>
<CheckBox IsChecked="{Binding IsAssigned, Mode=TwoWay}" Content="{Binding ProductSubTypeName}" Height="25">
</CheckBox>
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
What about using a ListBox to display sub-items instead of a TreeView? You can style that so the items contain a CheckBox to show IsSelected instead of highlighting the item.
I'd suggest your user interface is wrong. If the user can only pick one then it would be better to swap these for radio buttons and add a "None of the above" option. That'll then give you the behaviour you want for free and your UI will be more intuitive.
EDIT: Since you say you can't add a "None" option and want to use a checkbox (even though I strongly disagree on checkboxes where a radio button is more appropriate - a common UI error)...
The technical problem you are probably facing is that an ObservableCollection only raises notification events if the collection itself changes. i.e. Only if items are added or removed. It does not raised events when items within the collection change, therefore the changing the status of the checkbox in the code will not raise the event for the UI binding to act on.
One solution to this to write a custom class that extends ObservableCollection that does provide this behaviour
From MSDN:
If you need to know if someone has changed a property of one of the
items within the collection, you'll need to ensure that the items in
the collection implement the INotifyPropertyChanged interface, and
you'll need to manually attach property changed event handlers for
those objects. No matter how you change properties of objects within
the collection, the collection's PropertyChanged event will not fire.
As a matter of fact, the ObservableCollection's PropertyChanged event
handler is protected—you can't even react to it unless you inherit
from the class and expose it yourself. You could, of course, handle
the PropertyChanged event for each item within the collection from
your inherited collection
I upvoted Rachel's answer, it is a common way in WPF to databind sets of radio buttons or check boxes. If you still want to go the tree view way, below code works. All view related code is in the view, so below code follows MVVM principles. If you are a MVVM purist you can put the code behind and a TreeView control in a user control if you do not want any code behind.
XAML:
<TreeView ItemsSource="{Binding Path=Drinks}">
<TreeView.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding .}" Checked="OnCheckBoxChecked" Unchecked="OnCheckBoxUnchecked" Loaded="OnCheckBoxLoaded" />
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Code behind + VM:
public partial class Window1
{
public Window1()
{
InitializeComponent();
DataContext = new VM();
}
private void OnCheckBoxChecked(object sender, System.Windows.RoutedEventArgs e)
{
foreach (CheckBox checkBox in _checkBoxes.Where(cb => cb != sender))
{
checkBox.IsChecked = false;
}
(DataContext as VM).CurrentDrink = (sender as CheckBox).Content.ToString();
}
private void OnCheckBoxUnchecked(object sender, System.Windows.RoutedEventArgs e)
{
(DataContext as VM).CurrentDrink = null;
}
private void OnCheckBoxLoaded(object sender, System.Windows.RoutedEventArgs e)
{
_checkBoxes.Add(sender as CheckBox);
}
private List<CheckBox> _checkBoxes = new List<CheckBox>();
}
public class VM
{
public List<string> Drinks
{
get
{
return new List<string>() { "Coffee", "Tea", "Juice" };
}
}
public string CurrentDrink { get; set; }
}
I did one trick but it didn't work that when i have already selected a
drink and then i select another one than i set the last selected value
in the observable collection to false but it doesn't affect on view
and selected check boxes remains selected although in collection only
one option's value is true.
Make sure that your child objects (AvailableProducts
and SubProductTypes) also implement INotifyPropertyChanged, this will make sure that the UI receives changes when modify the object.
Once all of you objects update the UI properly you will be able to layer in, and test, whatever custom business logic you need.
So if you have a product type that can only have one sub chosen, you could add a property on ProductType called OnlyAllowOneChild. Whenever, a child object raises a IsAssigned changed event, the parent can set false all other children. This of course requires you to have the parent either register for the children's PropertyChangedEvent, or got grab an EventAggregator (MVVMLight Messenger, or PRISM EvenAggregator) and create a messaging system.
Finally i am succeeded to solve my problem.
on Is Assigned property i am updating my database values and calling a method in view using MVVM Light messaging and passing currently selected leaf's parent id in it as a parameter...
Added a property in class Product Types to expand the parent node of the last selected leaf..
In view's method i am refreshing data context's source and passing currently selected leaf's parent id tO the VM to set its Is Expanded property value to true...
By this my view is working perfectly as same as i want...
If any body have solution better than this than I'll be happy to know.