I'm trying to change the content of a ContentPresenter to one of my View Model class. I manage to have it shown properly, once I change this content (property) from my model, it doesn't update the ui.
The following lines link my view model classes to their respective ui (setting their data context automatically) :
<DataTemplate DataType="{x:Type vm:WelcomePageViewModel}">
<vw:WelcomePage></vw:WelcomePage>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:UnitPageViewModel}">
<vw:UnitPage></vw:UnitPage>
</DataTemplate>
I want to show the ui using binding:
<ContentPresenter Content="{Binding CurrentChildViewModel}" />
So in my ViewModel class, I have a CurrentChildViewModel property, which is an Instance of a closableViewModel. I first assign it in the constructor.
But now when I change the value of my CurrentChildViewModel, it won't update the ui, even if the property is changed in the viewmodel, the first element assigned will stay.
I don't see what I'm doing wrong here. Maybe I'm not using the right architecture (method) to change the content of an element.
Your help would be much appreciated.
Thanks in advance,
Boris
Make sure to implement INotifyPropertyChanged. The data binding framework doesn't constantly "poll" for changes to the bindings, but relies on the property change framework to fire off the updates for bindings.
Related
I have a WPF application with the following XAML in my MainWindow.xaml.
I don't understand why the DxTaskList constructor is called when I make a call to OnPropertyChanged("Sequences");. As you see below, my tab control is bound to a Sequences list. In the related view model class, I have a Sequences property that I modify, so naturally I need to let the view know, so I make the call to the OnPropertyChanged("Sequences") but I'm trying to understand how WPF works.
Does the entire visual tree get rebuilt when you refresh the binding of a parent? How does that work? Please note that my app uses Prism, so I'm not sure if this makes a difference.
<dxdo:LayoutPanel Caption="TaskList">
<dx:DXTabControl x:Name="TabControl"
ItemsSource="{Binding Sequences}"
SelectionChanged="TabControl_OnSelectionChanged">
<dx:DXTabControl.View>
<dx:TabControlMultiLineView HeaderLocation="Bottom"/>
</dx:DXTabControl.View>
<dx:DXTabControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Name}"></TextBlock>
<views:DxTaskList x:Name="Tasklst"/>
</Grid>
</DataTemplate>
</dx:DXTabControl.ItemTemplate>
</dx:DXTabControl>
</dxdo:LayoutPanel>
Everything appears to be working as it should.
If your Sequences property is an ObservableCollection it will fire NotifyPropertyChanged on any change to the size of the collection. If Sequences is not an ObservableCollection, but is some other IEnumerable then your OnPropertyChanged("Sequences") will do it.
Back to your question:
Let's assume it is not an ObservableCollection. You insert an item and then fire OnPropertyChanged("Sequences"), a new DxTaskList is created (ctor is called) and gets inserted into the visual tree.
Try calling OnPropertyChanged("Sequences") twice in a row, I bet you are only hitting the constructor after the first, and not on the second. If not, it could be because of how the DxTabControl is internally implemented.
I have a property in my ViewModel, I'll call it "Project" which contains several nested lists inside of it. None of such lists has an associated property in the view model since I can show everything in xaml by using triggers and bindings.
My xaml shows the Project hierarchy in a treeview and its details in several views (a content control selects the right view depending on which item is selected on the treeview). One of those "details" is a property for the objects contained in one of the nested lists, I'm showing it in a textbox so the user can edit it, the problem I'm having is I don't see that property updated in the Project property in the VM once I make changes to it in the textbox.
I was told I have to create a property in the VM for that specific object's property I'm trying to edit, I just don't know how since the object is deep inside one of the nested lists of my Project object.
Common mistakes are:
Using OneWay binding mode instead of TwoWay
In XAML:
<TextBox Text="{Binding Path=Name, Mode=TwoWay}" />
Not realizing that the update is not propagated to the VM until after the TextBox lost focus.
this is the default for the TextBox:
<TextBox Text="{Binding Path=Name, UpdateSourceTrigger=LostFocus}" />
You could change it to:
<TextBox Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" />
I have a an object created in Xaml:
<Grid>
<MyObject/>
</Grid>
I need someway to bind the object myObject back to a property in my view model. I dont know whether this is possible, everything ive seen so far binds properties together, but any help would be greatly appreciated.
I am assuming what you want is your ViewModel to hold the actual visual control MyObject in it and your Grid to display it via MVVM.
This is possible through ContentControl in WPF.
Assuming your ViewModel has a property MyObjectView which holds MyObject...
<Grid>
<ContentControl Content="{Binding MyObjectView}" />
</Grid>
Having said that you must take caution that same MyObjectView is not bound to any other content control as that will result in an error
"Specified element is already the logical child of another element.
Disconnect it first"
And if that requirement is possible then you must excercise ContentTemplate option.
Let me know if this helps.
It is possible. It kinda breaks mvvm though.
You can attach an InvokeCommandAction to this object, and bind the CommandParameter to it via ElementBinding. Then in the callback of the command which you defined in the viewmodel, you will have a reference to this object from the CommandParameter.
I feel mysefl confused about how to implement view switching when view model changes. Example of what i'm tring to do:
The control I want to make is something like a wizard control. I have a list of view models added to collection of wizardsteps, and a current item viewmodel. How to display the view of active view model and switch them then active view model changes? How do I bind them?
In WPF I'd use DataTemplate but Silverlight doesn't support x:Type.
<DataTemplate DataType="{x:Type ViewModel1}">
<view:View1 />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModel2}">
<view:View2 />
</DataTemplate>
I think a wizard is a case where you should have one ViewModel for multiple Views.
You could control the visibility of each view with Properties (IsPage1Visible, IsPage2Visible,...), Commands (PreviowsPageCommand, NextPageCommand, CancelComamnd) and all logic in only one VM.
Put all "pages" of the wizard in one UserControl and bind the visilitiy of each with the boolean properties and a BooleanToVisibilityConverter.
Check this out, it talks about non-linear navigation in SL/WPF and how to maintain state. http://karlshifflett.wordpress.com/2010/07/07/non-linear-navigation-in-silverlight-4/
I have question on the checkbox.
First of all,
I have a usercontrol which has a list box like this and this user control will be switched by 2 button and then the data source is changed and then the the displayed officer status will be changed:
When I check the checkbox, Officers[0].IsOnDuty will be changed to true.
The problem is:
When I click another button and switch to another data source, this checked check box is still checked but the Officers[0].IsOnDuty for this data source is false.
How to solve this?
The data context of the list box item is an item for your officers collection, not the collection itself. And using a one way binding is incorrect, as the data source (the officer) will not be updated. So change the DataTemplate to:
<CheckBox IsChecked="{Binding Path=IsOnDuty, Mode=TwoWay}" />
*Here is the list box xaml:
<ListBox ItemsSource="{Binding OfficersCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Officers[0].IsOnDuty, Mode=OneWay}" />
*
The problem with your approach is that once you change the ItemsSource (by switching to the next page) your chekcbox is still bound to the item of the first collection. I think this happens because you explicitly use an indexer for the binding Path=Officers[0].IsOnDuty
Your samplelist box xaml does not really make sense. the ItemsSoruce is a OfficerCollection and your ItemTemplate binds to a collection of Officers too. Depending on what you are trying to accomplish you should do one of the following:
If your are just interested in the first officer (as your sample suggest), add a DependencyProperty FirstOfficer (or a INotifyPropertyChanged) property to your collection and bind to it: IsChecked="{Binding Path=Officers.FirstOfficer, Mode=OneWay}"
If you however are interested in all Officers and want checkboxes for all of them you should create a DataTemplate for the Officer type and use this as the ItemTemplate.
Generally you can stay out of a lot of trouble if you stick with MVVM and really tailor your ViewModel objects very close to what the View needs so you can bind your View to the ViewModel in the simplest possible way. Think of the ViewModel as the View you want to build but without a visual representation.