My tab item is bound to a viewmodel via the content of its contentcontrol
<TabItem>
<ContentControl Content="{Binding MyVm}" />
</TabItem>
View-ViewModel matching set in the resources of my main :
<DataTemplate DataType="{x:Type MyViewmodelType}">
<MyView />
</DataTemplate>
No problems here, binding works.
On my view, i have a behavior which populate the view's control with data fetched somewhere.
This assignment is done after the InitializeComponent of my view.
My problem is, at this time when my view's data is set, its datacontext is not yet assigned, and the data doesn't go all the way to the datacontext.
When the datacontext get set, the bindings are resolved and all the data already in my view is erased. Of course, i need all my view's properties to be in the Two-Way mode.
How can i keep the view data when resolving the bindings for the first time ?
As tagaPdyk suggested, waiting after my view is fully initialized and then loading my data is the good thing to do. Not sure about MVVM compliance but it works.
Related
I'm learning WPF and MVVM. I'm curious about what happens in a particular situation.
Assuming that my view model implements INotifyPropertyChanged, the situation is where my code has already constructed my view model and then assigns it to my window's DataContext.
At the point in time that I assign the view model to DataContext, the value in my view model may be different than the value in the XAML element. And so I'm curious about which value wins.
I assumed the XAML element would pull in all the values from my view model but that is not what seems to be happening. Changes made to my view model correctly notify and update the XAML elements. But those changes made before I set DataContext are not reflected in the XAML elements.
Can anyone confirm my interpretation is correct? I've Googled extensively but could not find anything on this specific issue. Yet that seems to be the behavior in my application. Would appreciate someone else perspective or a link to a more detailed discussion.
I'm curious about the situation where my view model implements INotifyPropertyChanged, my code builds my view model and then assign it to my windows DataContext.
The problem is, at that stage where I assign to DataContext, the value in the XAML element may not match my view model. So which one wins.
Based on my testing, it appears that the value already in the XAML element wins. And if I want it set to the value in my view model, I must set it somehow or have my view model send a new property-changed notification.
Sounds like your changing your data template to show a hardcoded value rather than the default value provided by the binding.
For example in a TextBlock you can only assign the Text property once, either via a binding syntax where the value is sourced from the DataContext, or a static value.
<TextBlock Text="{Binding Path=Display}"/> <- only uses the DataContext
<TextBlock Text="123"/> <- only shows the static value
If you try and set the Text property twice, you get an error:
<TextBlock Text="{Binding Path=Display}">
<TextBlock.Text>
123
</TextBlock.Text>
</TextBlock>
You can provide the binding with a fallback value when there is no valid value available via the DataContext such as an exception being thrown, but the DataContext value wins when it provides a value:
<TextBlock Text="{Binding Path=Display, FallbackValue=123}" />
If you want to set a default value, you might be best to set a default in the constructor of the DataContext class and leave the binding in the Xaml to only source from the DataContext
I have a very general question and I'm not quite sure if this one has asked/answered before.
I have a Model (Workflow) in my application. Currently I'm assigning the Model to the DataContext of my window / view, but actually I want to create a ViewModel around the Workflow and assign this ViewModel to the DataContext.
The problem is, that the window and views are created using DataTemplates and lists where only the model is assigned, since everything is created in the remote backend. The front-end gets the information about the model which is associated automatically in the DataContext when view is created.
Of course I can create the ViewModel manually when the DataContext is set. But then I need to change the DataContext and set it to the ViewModel and the old DataContext is gone. Besides I have to do it manually although it could be easily done in XAML using a resource.
Is there a pattern that copes with this requirement? I haven't found anything.
Thanks
Martin
You can simply add a DataTemplate into a particular view's Resources section:
<DataTemplate DataType="{x:Type ViewModels:YourViewModel}">
<Views:YourView />
</DataTemplate>
In this particular case, the YourView view will be rendered whenever an object of type YourViewModel is found in the UI and the view model will implicitly be set as the YourView.DataContext property value. Using this DataTemplate, you can display the YourView view like this:
<ContentControl Content="{Binding PropertyOfTypeOfYourViewModel}" />
Note that this DataTemplate should be declared in a Resources section outside of the YourView view and in scope of the ContentControl.
I explain my issue as I'm quite new to UI design :
I have a main View which displays a TreeView on its left part. When an element is selected I'd like to show a description of the Item on the right on the same window. The design of this description depends on the nature of the Item.
So I created a View per Item Type corresponding to the different possible design.
Now When I click on the TreeView I have no idea how to show the corresponding view on the right of the same window. (I'm not asking about catching the event, just displaying a view within another view, like if I dynamically plotted a control).
Is it possible ? If not what kind of approach would you suggest ?
Many Thanks.
This seems like a great candidate for a Data Template.
Basically, create a content presenter and bind its content property to the TreeView's SelectedItem property. Now, create data templates for each of your types (using the DataType property) in the ContentTemplate property.
Now, the correct data template will be chosen with the correct data whenever you select something in your tree view.
As far as a separate dispatcher goes, I'm not sure, but I'm also not sure what scenario would require one.
More information can be found in this SO question.
Sample:
<ContentPresenter Content="{Binding Path=SelectedItem, ElementName=TreeView}">
<ContentPresenter.ContentTemplate>
<DataTemplate DataType="{x:Type Type1}">
<!-- Bunch of stuff-->
</DataTemplate>
<DataTemplate DataType="{x:Type Type2}">
<!-- Bunch of stuff-->
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
I have a listbox in WPF that will contain a list of ResultsViewModel items, however the actual runtime type of these objects could be
CalculateResultsViewModel,
ScenarioResultsViewModel,
GraphResultsviewModel etc etc,
all of which extend the base abstract class ResultsViewModel.
Each of these view models should be rendered differently in the ListBox so needs a different DataTemplate. I can do that just with XAML easy enough. The difficulty is that when the viewmodels are either "processing" or when they have failed", I need them to display a DataTemplate for "processing" or "errored" which I can only so far do with Triggers. That however then means I can't use the DataTemplateSelector or a basic XAML style.
The only solution I can think of (not clean I know) is to set the DataTemplate programmatically in the SetResult() method of each viewmodel class, which is what gets called when the processing completes either successfully or with an error. In that DependencyProperty I can look at the return code and then programatically set the DataTemplate depending on the sucess/failure result. The only problem is I cannot figure out how to
Obtain a DataTemplate resource from a ResourceDictionary just using c# code - bearing in mind Im calling all of this from the viewmodel class, not the window code-behind .xaml.cs file so it doesn't have access to the properties of Window
having only a handle to the viewmodel class, somehow obtain a reference to the ListBoxItem that contains it and then programmatically set the DataTemplate on this container.
Can anyone point me in the right direction?
you can take the magic with implicit datatemplates
<ListBox ItemSource={Binding YourResults}>
<ListBox.Resources>
<DataTemplate DataType={x:Type CalculateResultsViewModel}>
<Grid></Grid>
</DataTemplate>
<DataTemplate DataType={x:Type ScenarioResultsViewModel}>
<Grid></Grid>
</DataTemplate>
<DataTemplate DataType={x:Type GraphResultsviewModel }>
<Grid></Grid>
</DataTemplate>
</ListBox.Resources>
</ListBox>
for "processing" or "errored" viewmodels you can specify a adorner overlay in all yout datatemplates (ok but you must use the triggers)
hope this helps
Say I have a WPF application (exe) that has this in the MainWindow.xaml:
<Grid>
<extraControls:MyMVVMUserControl MyDependencyProperty="{Binding Something}"/>
<extraControls:MyUserControl MyDependencyProperty="{Binding Something}" />
</Grid>
and my MainWindow.xaml.cs looks like this:
public MainWindow()
{
DataContext = new MainWindowVM();
InitializeComponent();
}
And my MainWindowVM.cs has a property setup for Something that notifies on property changed.
The user controls are made in a separate dll. As you may guess, MyMVVMUserControl has the DataContext set to a view model.
public MyMVVMUserControl()
{
DataContext = new MyMVVMUserControlVM();
InitializeComponent();
}
MyUserControl does not have a DataContext set in the code behind.
So the interesting thing is that they both have MyDependencyProperty setup exactly the same.
But the MVVM version does not work.
After digging in a bit, I found that the {Binding Something} in MainWindow.xaml is using the View Model setup for the MyMVVMUserControl as the DataContext (rather than the DataContext set in MainWindow.cs (set to MainWindowVM)).
And my question is why?
Why would WPF look inside the user control and use it's DataContext for a binding that is in the actual application?
(NOTE: I know I can get around this by setting the source in the binding, but I want others to be able to use my user controls. But with this issue, I now have a built-in "gotcha" for anyone I want to use my user controls.)
I think I understand you problem, and I'm gonna to give a solution that works for me (I had this problem before). The think is that seams that you are setting the DataContext for you MyMVVMUserControl in code behind, and then it take the bindings from that.
The solution I found for this, is to set the datacontext in code behind, but not at the user control. Set the datacontext for the UserControl's child item. For instance, supose this is the Xaml of your UserControl:
<UserControl ... x:Name="userControl">
<Grid x:Name="rootContainer">
...
</Grid>
</UserControl>
Then in the code behind set the rootContainer's data context, in this way all visual children can access to the control data context, and also the user control datacontext is empty.
...
rootContainer.DataContext = new UserControlViewModel();
...
Hope this may helps you to solve your issues...
You really shouldn't ever set the DataContext of a UserControl from inside the UserControl. By doing so, you are preventing any other DataContext from getting passed to the UserControl, which defeats one of WPF's biggest advantages of having separate UI and data layers.
WPF objects only inherit their DataContext from the parent object if the DataContext is not set to anything else. When your MyMVVMUserControl is being created, you are setting the DataContext to a new MyMVVMUserControlVM, which prevents the DataContext from being inherited from MainWindow.
So its normal that your MVVMUserControl would have it's DataContext set to your MyMVVMUserControlVM, because you set it explicitly in the UserControl's constructor.
This is by-design. UI objects in WPF/MVVM are only meant to be visual representations of the data layer, so it wouldn't make much sense to set the data layer and then try to bind your properties to something that is not on the data layer.
For example, take this line of code:
<UserControl DataContext="{Binding ClassA}" Content="{Binding Name}" />
This would bind the Content property to UserControl.DataContext.Name, which is ClassA.Name. It wouldn't make much sense if this would result in binding to UserControl.Parent.DataContext.Name, as the binding should refer to to the current object's DataContext, and not the Parent's DataContext.
So the only time I ever set the DataContext of a UserControl from inside the UserControl itself is if the UserControl is its own separate object that is never meant to interact with data from the rest of the application. Which so far has been never :)
Typically my UserControls are almost always one of two things:
Either a visual representation of a ViewModel (or Model), such as a CustomerUserControl for a CustomerViewModel, in which case I pass them the DataContext they need when they get used
For example,
<local:CustomerUserControl DataContext="{Binding SelectedCustomer}" />
or
<DataTemplate DataType="{x:Type local:CustomerModel}">
<local:CustomerUserControl />
</DataTemplate>
Or a self-sustained UI object that receives any external data it needs via custom DependencyProperties, and does any additional logic in the code-behind the control, such as a DatePicker control that has a SelectedDate dependency property, or a CalculatorUserControl with dependency properties for Equation and Value
<local:DatePickerUserControl SelectedDate="{Binding SomeDate}" />
<local:CalculatorUserControl Equation="{Binding SomeString}"
Value="{Binding SomeDouble}" />
In your case, it sounds like you should be using the first case, and should be passing a ViewModel into your UserControl containing the data it needs.
<extraControls:MyMVVMUserControl DataContext="{Binding MyMVVMUserControlVM}"
MyDependencyProperty="{Binding Something}">
or
<extraControls:MyMVVMUserControl MyDependencyProperty="{Binding Something}">
<extraControls:MyMVVMUserControl.DataContext>
<viewModels:MyMVVMUserControlVM />
</extraControls:MyMVVMUserControl.DataContext>
<extraControls:MyMVVMUserControl />