I have this:
public MyView: UserControl
{
public IList<Person> PersonList { get; set; }
public MyView()
{
//code
}
public void Display(MyData myData)
{
DataContext=myData;
}
//code
}
The XAML for this includes a ComboBox :
ItemsSource="{Binding RelativeSource={RelativeSource Self}, Path=PersonList}"
For some reason this does not work and the combo box does not get populated ( however, If I use the code-behind and I say comboBox.ItemsSource = PersonList then the combo box does got populated ).
Any ideas ?
Regards,
MadSeb
Your property is set to private, and are you sure that you are setting the DataContext.
* EDIT *
Based on the change you made above, you're setting your datacontext incorrectly. Your "PersonList" is anIList<> on your MyView class, but you're setting your data context to something else.
Try adding items to PersonList within MyView and setting this.DataContext = this; Also, as suggested, switch your IList<> to an ObservableCollection<>.
I would also highly suggest reading up on the Model View ViewModel (MVVM) approach. It will help out a lot. Josh Smith has a lot of good articles about the MVVM approach (and has written a good book about it too).
Here's a link to his blog. His book is linked there, as well.
I suspect it's because you're not firing any property-changed events. If you don't notify your UI when the property's value is first set, the binding won't update. Look into the INotifyPropertyChanged interface and implement it in your class.
Similarly, if your IList property isn't an ObservableCollection or doesn't implement INotifyCollectionChanged, then when you add items to the list the databound UI won't reflect this.
I believe your binding statement is the problem.
"{Binding RelativeSource={RelativeSource Self}, Path=PersonList}" is looking for a "PersonList" on the combobox itself.
Are you seeing any binding errors in the output window?
Ideally you'd want to bind to a property in your DataContext (MyData)
Related
I am trying to create a user control using MVVM.
Basically I am trying to wrap a combobox that will pull data from a respository. This will allow me to use the same combobox in many different views in my application. There will be many of the wrapped comboboxes throughout the application.
I was easily able to create this control using a DependencyProperty and code-behind. I am now trying to convert this to MVVM and am having trouble figuring out how to get the value back to /from the ViewModel that in bound to the View where my combobox is located.
Any ideas or suggestions would be greatly appreciated at this point.
Thanks,
Eric
It is perfectly acceptable to use a UserControl that has code behind in it when using MVVM. If you really want to move the functionality out of the UserControl, then move it to whichever parent view models will require it. If you don't want to have the same code repeated in several places, you could encapsulate it in a class and add an instance of that class as a property to each of the relevant view models.
if you have a viewmodel that will pull data from a respository - you can use the same viewmodel in many different viewmodels in your application :)
and if you use a datatemplate your views know how to render this viewmodel
<DataTemplate DataType="{x:Type local:MyPullDataViewmodel}">
<view:MyCoolPullDataShowComboboxUserControl />
</DataTemplate>
It's pretty easy.
Let's say you have:
MyUserControlView.xaml
MYUserControlViewModel.cs
MyMainWindowView.xaml - For your MainWindow view (the one containing the UserControl)
MyMainWindowViewModel.cs - Your MainWindow ViewModel.
And you want to bind List<string> MyListToBind
And leave the code-behind completely empty.
MyUserControlViewModel.cs
public class MyUserControlViewModel
{
private List<string> _MyListToBind;
public List<string> MyListToBind { get; set;}
}
MyMainWindowViewModel.cs
public class MyUserControlViewModel
{
private MyUserControlViewModel _MyControlViewModel;
public MyUserControlViewModel MyControlViewModel { get; set;}
}
MyMainWindowView.xaml
<Window ...
xmlns:my="clr-namespace:NamespaceContainingYourUserControlView>
<my:MyUserControlView DataContext = "{Binding Path= MyControlViewModel}"/>
</Window>
MyUserControlView.xaml
<UserControl ...>
<DataGrid ItemsSource = "{Binding Path= MyListToBind}" .../>
...
</DataGrid>
</UserControl>
This doesn't support ViewModel updating View. To do that You have to use either DependencyProperties as you did instead of normal variables (as i did) or use INotifyPropertyChanged(google it, you'll get tons of examples) and OnPropertyChanged event.
You might read up on DataTemplates they are really useful in data binding.
You can find this usefeul:
http://www.youtube.com/watch?v=BClf7GZR0DQ
I sure as hell did !
Good luck.
I am new to WPF and MVVM Light, I would appreciate if you could help me :-)
I would like to know how to implement a combobox with MVVM Light to do the following:
1) Select an item in the combobox
2) Based on the value selected, change other text fields in the GUI.
Thank you for your help.
Romain
Well:
View:
<ComboBox ItemsSource="{Binding SourceData}" SelectedItem="{Binding SelectedSourceData,Mode=TwoWay}"/>
<TextBlock Text="{Binding SelectedDataInTextFormat}"/>
ViewModel:
public class ViewModel:ViewModelBase
{
public ObservableCollection<Foo> SourceData{get;set;}
public Foo SelectedSourceData
{
get{return _selectedFoo;}
set{_selectedFoo=value;
RaisePropertyChanged("SelectedSourceData");
SelectedDataInTextFormat=Foo.ToString();
}
public string SelectedDataInTextFormat
{
get{return _selectedDataInTextFormat;}
set{_selectedDataInTextFormat=value;
RaisePropertyChanged("SelectedDataInTextFormat");
}
}
Basically, to ensure that your view model is able to receive the updated selected item from the combobox make sure the SelectedItem binding is set to Mode=TwoWay. To ensure that you're pushing data from the viewmodel to the view when a change occuers in the viewmodel make sure you call the RaisePropertyChanged helper class for the property you want updated in the view.
The ListBox control does not implement a Command property. I have to attach some functionality to the SelectionChanged event. Somebody knows how can I do it? Please help me
I prefer using a binding to the SelectedItem and implementing any functionality in the setting of the binding property.
<ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" />
...
public class ViewModel
{
public IEnumerable<Item> Items { get; set; }
private Item selectedItem;
public Item SelectedItem
{
get { return selectedItem; }
set
{
if (selectedItem == value)
return;
selectedItem = value;
// Do logic on selection change.
}
}
}
This is the way where You can Reach the Selection changed events in Your MVVM Application
First Of all i tell you that Command Property only work in Button now we have to Explicitly
binding that property in our Selection Changed event like List box or combo box
in Your XMAL file
<ListBox Name="MyListBox" ItemsSource="{Binding ListItems}" Height="150" Width="150" Margin="281,32,-31,118">
<Local:Interaction.Triggers>
<Local:EventTrigger EventName="SelectionChanged">
<Local:InvokeCommandAction Command="{Binding MyCommand}" CommandParameter="{Binding ElementName=MyListBox,Path=SelectedItem}"/>
</Local:EventTrigger>
</Local:Interaction.Triggers>
</ListBox>
for this you have to add dll Syatem.Windows.Interactivity
now u have to add references in your xaml file namespace like
xmlns:Local="clr-namespace:System.Windows.Interactivityassembly=System.Windows.Interactivity"
in your ViewModel Class you have to define your Command in Con structure
public ViewModel123()
{
MyCommand = new RelayCommand<string>(TestMethod);
}
now create the TestMethod method which can handle the selection changed event
private void TestMethod(string parameter)
{
MessageBox.Show(parameter);
}
i hope this may help u.
Basically you have a few options:
Use the property SelectedItem of ListBox to bind to a property in the backend (ie in view model) and perform logic in the setter as described by Cameron MacFarland.
Use a third party library that has a generic event to command behavior like in the link posted by Pedro Lamas.
If you don't want to use third party libraries or writing logic inside property setter is somehow unacceptable you can create your own behavior for ListBox control. It would subscribe to control's SelectionChanged event and execute a command (the command could be a dependency property exposed by the behavior).
Think this post from Laurent Bugnion will help you solve the problem:
http://geekswithblogs.net/lbugnion/archive/2010/05/19/handling-datagrid.selecteditems-in-an-mvvm-friendly-manner.aspx
The post above mentions the DataGrid but I do think it will work with the ListBox too!
Best regards and Happy New Year!! :)
I would suggest using RelayCommand. Either use the MVVM Light Toolkit or just use the RelayCommand and CommandManager classes from Josh Smith's implementations. I personally use just the two classes, so I don't need the entire toolkit.
While this will definitely work, there might be an easier way depending on what you are doing. It might just be easier to bind an object to the SelectedValue of the ListBox and listen for that value to change.
My silverlight project uses MVVM.For examlpe, I have textbox, that binded to ViewModel property. Textbox content can change from View or ViewModel. I need know when content changed from View. How can I implement this accordingly MVVM?
If your viewmodel has INotifyPropertyChanged/INotifyPropertyChanging implemented then you can hook into it. That works for me.
if you use bindings, you get the information in your setter.
Here is a little example:
XAML:
<TextBox Text="{Binding MyProperty, Mode=TwoWay}" />
C# of your ViewModel:
private string myProperty = "Test";
public String MyProperty
{
get { return myProperty; }
set
{
Debug.WriteLine("Property set");
myProperty = value;
NotifyPropertyChanged("MyProperty");
}
}
Each time, you change the text and the TextBox looses the focus, the setter get called.
If you want to get the setter called each time you hit a key, have a look here. This is a little bit of a quick and dirty solution for triggering the binding ;) A better way would be to write an Behaviour for this.
Hope this helps!
BR,
TJ
I have been wrestling with getting databinding to work in WPF for a little over a week. I did get valuable help here regarding the DataContext, and I did get databinding to work via DependencyProperties. While I was learning about databinding, I came across numerous discussions about INotifyPropertyChanged and how it is better than DPs in many ways. I figured that I would give it a shot and try it out.
I am using Josh Smith's base ViewModel class and my ViewModel is derived from it. However, I'm having a bit of trouble getting databinding to work, and am hoping that someone here can tell me where I'm going wrong.
In my ViewModel class, I have an ObservableCollection<string>. In my GUI, I have a combobox that is bound to this OC, i.e.
<ComboBox ItemsSource="{Binding PluginNames}" />
The GUI's DataContext is set to the ViewModel, i.e.
private ViewModel _vm;
public GUI()
{
InitializeComponent();
_vm = new ViewModel();
this.DataContext = _vm;
}
and the ViewModel has the OC named "PluginNames":
public class ViewModel
{
public ObservableCollection<string> PluginNames; // this gets instantiated and added to elsewhere
}
When the GUI is loaded, a method is called that instantiates the OC and adds the plugin names to it. After the OC is modified, I call RaisePropertyChanged( "PluginNames"). I was expecting that since the WPF databinding model is cognizant of INotifyPropertyChanged, that this is all I needed to do and it would "magically work" and update the combobox items with the plugins that got loaded... but it doesn't.
Can someone please point out what I've done wrong here? Thanks!
UPDATE: I'm not sure why, but now instead of not doing any apparent updating, it's not finding the property at all. I think I'm being really stupid and missing an important step somewhere.
When you're working with INotifyPropertyChanged, there are two things:
You'll need to use properties, not fields
You should always raise the property changed event when you set hte properties.
You'll want to rework this so it looks more like:
private ObservableCollection<string> pluginNames;
public ObservableCollection<string> PluginNames
{
get { return pluginNames; }
set {
this.pluginNames = value;
RaisePropertyChanged("PluginNames"); // This should raise the PropertyChanged event - use whatever your VM class does for this
}
}
That should cause everything to repopulate.
It looks like you've exposed field not property. Bindings works for properties only... Change it to:
public class ViewModel
{
public ObservableCollection<string> PluginNames {get; private set;}
}