ViewModel properties handling - wpf

Few words about my MVVM-based WPF app. I've defined MainWindowViewModel:
public class MainWindowViewModel : ViewModelBase
{
...
public ViewModelBase CurrentViewModel {get; set;}
...
}
This is data context for my MainWindow.xaml. This property has it's own template binding to specific View (depends on which 'inner' view model is currently included). This MainWindowViewModel is listening for Mvvm-Light Messenger message which changes current view model. Now my problem.
I'd like to assign there LoginViewModel with property SelectedUser. I'm getting property of SelectedUser from another ViewModel, where I'm executing this command:
this.UserSelectedCommand = new RelayCommand(() =>
{
LoginViewModel viewModel = new LoginViewModel();
viewModel.SelectedLogin = this.SelectedUserFromList;
MessageHelper.SendViewModel(viewModel); //change CurrentViewModel
viewModel.RaisePropertyChanged("SelectedLogin");
});
My LoginViewModel.cs has defined default value of SelectedLogin in constructor.
So in ViewModel which is responsible for displaying list of users I'm selecting one, I have this value in SelectedUserFromList property and I'd like to go back to login View with selected user. Which means I'd like to assign new LoginViewModel with SelectedLogin to CurrentViewModel property form MainWindowViewModel.
After executing UserSelectedCommand I can see proper View which is binded to LoginViewModel, but I have everywhere default values of properties.
I guess that because of this
<DataTemplate DataType="{x:Type vm:LoginViewModel}">
<views:LoginView/>
</DataTemplate>
I do have proper ViewModel in CurrentViewModel (with changed SelectedLogin) but template is loading LoginViewModel again (so constructor sets default values). Am I right? Because I can't see any other reasons.
EDIT
Ok, now I'm sure that DataTemplate is creating new instance of LoginViewModel (this one with default values). But what now? I fixed it with Singleton, but I'm not sure if this is good solution.

Related

DependencyProperty to ViewModel

I have two DependencyProperties TBLocation & TBBroadcastLocation in MyUserControl.
For TBLocation I get information from another element called MyTextBox.
When TBLocation gets set, I set TBBroadcastLocation with TBLocation's Point information.
And now I would like to make TBBroadcastLocation data available to MyViewModel so that it has TBLocation's data indirectly available to it.
How could I do that or do we have a better approach?
It seems to me as if you are asking 'How can I bind a property of a UserControl to a property of a view model'. You really should read the basics of data binding before asking these questions here. For future reference, please read the Data Binding Overview page at MSDN.
Given that you still have not provided enough information, I will assume that your property is of type string. In this case, your view model will need a standard property of type string to bind to your DependencyProperty... this property must implement the INotifyPropertyChanged interface:
private string viewModelProperty = string.Empty;
public string ViewModelProperty
{
get { return viewModelProperty; }
set { viewModelProperty = value; NotifyPropertyChanged("ViewModelProperty"); } }
}
Make sure that the DataContext of the Window that has your UserControl in it is set to an instance of the view model class:
In the MainWindow constructor:
DataContext = new ViewModelClass();
Or in XAML:
<DataTemplate DataType="{x:Type ViewModels:ViewModelClass}">
<Views:yourView />
</DataTemplate>
Then you simply bind with a Two Way binding:
<YourNamespace:MyUserControl
TBBroadcastLocation="{Binding ViewModelProperty, Mode=TwoWay}" />

Getting Value from ViewModel through DataContext WITHOUT Binding?

New to WPF. I am creating UserControls that need read access to the ViewModel state to do their thing. I currently use the following technique:
public partial class ControlBar : UserControl
{
private static readonly DependencyProperty URLProperty =
DependencyProperty.Register("URL", typeof(string), typeof(ControlBar),
new UIPropertyMetadata(null));
public ControlBar()
{
InitializeComponent();
SetBinding(URLProperty, "CurrentPage.URL");
Pin.Click += Pin_Click;
}
private void Pin_Click(object sender, RoutedEventArgs e)
{
var URL = (string)GetValue(URLProperty);
}
}
Is this the correct way and is it not overkill to set up a long-term binding for each variable I need access to? Or can you do something like:
GetValue(new Path("CurrentPage.URL.....
I made up the above obviously.
Thanks!
In general data-binding is the way to go. However sometimes when you are creating controls that have view-specific concerns for which data-binding will not be appropriate.
In those cases you will want to be able to interact with the DependencyProperty to set it and know when it changes. I have been following a pattern that I picked up from a Charles Petzold article in MSDN magazine.
My answer to another question shows the pattern for creating a DependencyProperty for a UserControl Stack Overflow: Dependency Property In WPF/SilverLight
Again, data-binding to a view model will likely solve your problem, but a DependencyProperty may come in useful depending on the situation.
Update in response to comment:
In many situations you can data bind your in a UserControl without using a DependencyProperty. For example if you have a TextBlock that displays a name you would put a TextBlock in the XAML of the UserControl
<TextBlock Text="{Binding Path=NameString}" />
In the view model which is present in the DataContext you would have a property NameString and if the TextBlock is to update the display when the NameString property changes the view model should implement INotifyPropertyChanged and the property should fire the PropertyChanged event with the name of the property sent along with the event.
protected string _NameString;
public string NameString
{
get { return _NameString; }
set { _NameString = value: Notify("NameString"); }
}
Where Notify is a method that checks the PropertyChanged event for null and sends the event if not null.
This works well if everywhere that you want to use the UserControl has a view model with a Name property. The great thing is that the UserControl can pick up on the DataContext of wherever it is hosted and bind to an external view model.
When you want to start binding the same UserControl to different properties is one place that you may want to use a DependencyProperty. In that case you could make a UserControl with a DependencyProperty and bind it to different properties
<my:SampleControl NameString="{Binding Path=GivenName}" />
<my:SampleControl NameString="{Binding Path=FamilyName}" />
And then have an internal view model that the DependencyProperty change handler updates when the bound property changes.
Update: No DependencyProperty or binding
You can always add an ordinary C# property to the UserControl and pass the data in that way.
public MyClass Data { get; set; }
Then in the code-behind of the UserControl you can simply use the property:
if (this.Data != null)
{
this.textBox1.Text = Data.NameString;
}
Update in response to comment:
Another way to access the view model in code is to cast the DataContext to your view model type:
MyClass data = this.DataContext as MyClass;
if (data != null)
{
// do something
this.textBox1.Text = data.NameString;
}

How to bind back to the dependency property

I have a custom user control that exposes a DepenencyProperty (ImageData).
I've placed this user control on a page and I bind it's ImageData property to a property of my page's ViewModel (photo).
<localControls:PhotoPicker ImageData="{Binding Path=Photo, Mode=TwoWay}"/>
When the user interact with the control setting the controls ImageData property the Photo property of my viewmodel is updated == Perfect. However if the ViewModel changes the value of Photo, the ImageData property of PhotoPicker is not changed. What could I be missing in getting data from the ViewModel back down to the user control?
UPDATE:
Upon further investigation it seems that the setting from the ViewModel back to the control via the binding, through the dependencyproperty does not fire the setter of the dependency property wrapper property. What a mess. I need to know when that happens, if i can't do that in the setter of the wrapper property where should I do it?
UPDATE 2:
Seems that the only way to find about changes to the DependencyProperty is to add a PropertyChangedCallback in the PropertyMetadata when Registering the property.
Sounds like your view model doesn't send property changed notifications? Extremely simplified, your view model must look something like this:
public class MyViewModel : INotifyPropertyChanged
{
private object photo;
public object Photo
{
get { return this.photo; }
set { this.photo = value; this.OnPropertyChanged("Photo"); }
}
// ...
}

Silverlight UserControl and his own Viewmodel hosted in a View

I want to make a reusable UserControl as:
A VIEW with its own VIEWMODEL where is the logic data recovery
This UserControl (or View ?) has a button 'OK' to target a RELAYCOMMAND in his viewmodel
I'm hosting this 'UserControl' in another VIEW ('MainPage'), who, herself, has its viewmodel
My question is:
How can I target the properties of VIEWMODEL of my 'MainPage' with the values outlined by my UC ?
As long as your user control is contained in your main page it will inherit the main pages view model. This is the default and it applies unless you explicitly change the data context through data binding or code.
If your user control binds to it own view model then you could let the main view model contain an instance of the child view model and expose it through a public property. Now you could set the data context of your user control by binding the DataContext property to the property on the main view model.
Finally if your child view model has a reference to the main view model then they will be able to communicate as needed.
Edit:
I'll try to setup a simple example:
First the view models:
public class MainPageViewModel
{
public MainPageViewModel()
{
ChildViewModel = new ChildViewModel(this);
}
public ChildViewModel {get; private set; }
public ICommand OkCommand { get { // return the command here }}
}
public class ChildViewModel
{
private MainPageViewModel _parentViewModel;
public ChildViewModel(MainPageViewModel parentViewModel)
{
_parentViewModel = parentViewModel;
}
// Returns the command from the main page view model
public ICommand OkCommand { get { return _parentViewModel.OkCommand; } }
// Other properties as well
}
Here we have the main view model that has the child view model as a property. The child view model exposes the OkCommand that returns the value from the main view model.
Now in your main page xaml you can do the following:
<uc:MyUserControl DataContext="{Binding ChildViewModel}" />
Here you insert your user control and set it's data context to the child user control view model.

WPF + MVVM - How to bind a property to the parent view's data context

Working with the MVVM pattern, I have a pair of view model classes that represent a two-tier data hierarchy, each with a corresponding UserControl that represents its view. Both view model classes implement INotifyPropertyChanged and the root level view model exposes a property that is relevant to both its own view and the child view.
The root level view acquires the root level view model as its data context and explicitly assigns a data context to its contained view. However, it also needs to bind one of the properties of the child view to the above-mentioned shared property. Here is how I have attempted to achieve this, but it's not working:
<UserControl x:Name="rootView">
<StackPanel>
<!-- other controls here -->
<my:ChildView
DataContext="{Binding Path=SelectedChild}"
EditingMode="{Binding ElementName=rootView, Path=DataContext.EditingMode />
</StackPanel>
</UserControl>
Although there are no runtime binding errors and the child view correctly binds to the appropriate child view model instance, its EditingMode property is never set. I have run tests to verify that the corresponding view model property is being modified and that it is notifying this change via INotifyPropertyChanged, but the binding fails to detect it.
Is there a better way to declare this binding or have I made a more basic architectural error?
Many thanks for your advice,
Tim
Update: As requested, I am posting some code to show a very simplified version of my views and view models, together with the results of an experiment that I have conducted that may provide some additional clues.
// The relevant parts of the ParentViewModel class
public class ParentViewModel : INotifyPropertyChanged
{
// Although not shown, the following properties
// correctly participate in INotifyPropertyChanged
public ChildViewModel SelectedChild { get; private set; }
public ContentEditingMode EditingMode { get; private set; }
}
// The relevant parts of the ChildViewModel class
public class ChildViewModel : INotifyPropertyChanged
{
// No properties of ChildViewModel affect this issue.
}
// The relevant parts of the ParentView class
public partial class ParentView : UserControl
{
// No properties of ParentView affect this issue.
}
// The relevant members of the ChildView class
public partial class ChildView : UserControl
{
public static readonly DependencyProperty EditingModeProperty =
DependencyProperty.Register(
"EditingMode",
typeof(ContentEditingMode),
typeof(PostView)
);
public ContentEditingMode EditingMode
{
get { return (ContentEditingMode)GetValue(EditingModeProperty); }
set { SetValue(EditingModeProperty, value); }
}
}
// The enumeration used for the EditingMode property
public enum ContentEditingMode
{
Html,
WYSYWIG
}
My intention is that the DataContext of the parent view instance will be assigned an instance of ParentViewModel and it will, in turn, assign the value of its SelectedChild property to the DataContext of the nested ChildView. All of this seems to work correctly, but the problem arises because the binding between ParentViewModel.EditingMode and ChildView.EditingMode does not work.
In an attempt to test whether there is a problem with my binding expression, I introduced a TextBlock adjacent to the ChildView and bound it similarly to the ParentViewModel.EditingMode property:
<UserControl x:Name="rootView">
<StackPanel>
<!-- other controls here -->
<TextBlock Text="{Binding ElementName=rootView, Path=DataContext.EditingMode}" />
<my:ChildView
DataContext="{Binding Path=SelectedChild}"
EditingMode="{Binding ElementName=rootView, Path=DataContext.EditingMode />
</StackPanel>
</UserControl>
In this test, the TextBlock is correctly updated every time the source property changes. However, if I set a breakpoint on the setter of ChildView.EditingMode, it never gets hit.
I'm baffled !
The simplest way to fix this is in your view model. Implement an EditingMode property in the child view model and bind to it. That way, you don't have to make any kind of guesses about what the right way to establish the binding might be; also, it's something that you can test outside of the UI.
Edit
Actually the right solution is not quite as simple, but it's worth knowing how to do.
What you want is for EditingMode in the child control to efficiently inherit its value from the parent control. Does that sound like something that anything else in WPF does? Like just about every framework element that implements dependency properties?
Implement EditingMode as a dependency property in both the parent and child UserControls and use property value inheritance, as described here. That takes the inheritance behavior out of the view model entirely and puts it where it belongs.
See if you can just use a full path to get the editing mode of the selected child:
<my:childView
DataContext="{Binding SelectedChild}"
EditingMode="{Binding SelectedChild.EditingMode />

Resources