Can I have a ValueConverter in my ViewModel? - silverlight

I have a combobox bound to a collection, so the user can select one of the items. So far, so good.
The content of the combo box is driven by the item, but also by a value in my viewmodel. Imagine the value in my viewmodel is the language, I have dictionary of descriptions by language in my bound item, and I want to display the correct one.
How should I go about this?

This is a classic example of why the ViewModel exists - you want to have logic which depends on trivial state in the view, as well as the main model.
Imagine you are writing a unit test to run against the ViewModel for this behaviour. You would need the ViewModel to have a property mapped to the selected item. The ViewModel would also have another property which varies according to this selected item as well as the other value in the ViewModel you mentioned.
I think of this as the test-driven approach to ViewModel design - if you can't write a unit test to evaluate it then you haven't got the mix of state and published interfaces right.
So, yes, the ViewModel can solve the problem and if you push all the state down into it you can do the unification within the ViewModel.

Make an observable collection in your viewmodel of type Item. Bind the itemsource of your viewmodel to this observable collection.
public class Item
{
public String description {get;set;}
public String language {get;set;}
public override ToString()
{
return description;
}
}
Selected item would also be bound to a property of type Item as well.
The override of ToString displays the description.
The Selected item propery will have a reference to the selected object property where you can get the language from.

Related

WPF MVVM: View's ListBox with source deep in Model. How to implement?

I'm new to WPF. I need to Bind UI's ListBox to the source that is deep in Model Layer.
App scheme is on picture below. Desc:
My MainWindowViewModel Class has a Scheduler Property (Scheduler Class in Model layer).
Scheduler Class has a CurrentParser Property (Parser Class in Model layer).
Parser Class has a Result field (ParserResultMetaData Class in Model layer).
ParserResultMetaData Class has a Log field (Log is a List(Of String))
Log can be changed only programmatically from model layer (Parser adds lines during it's work).
So my question is how can I bind my ListBox to this List to match MVVM pattern.
As I get it now, ViewModel must have an ObservableCollection(Of String) witch is a copy of my List(Of String) from Model layer.
Somehow you need to notify the UI when a line is added to the collection. There are multiple ways to achieve this, but if the collection is modified from within the model layer, you need a mechanism for communicating this to other layers in one way or another.
Use an ObservableCollection in your Model layer.
While types like ObservableCollection and INotifyPropertyChanged are widely used in MVVM architectures, they are not specific to them and in some cases it can make sense to use them in the model layer directly. Using an ObservableCollection in your Parser class is one way to provide this notification mechanism. You can then bind the ItemsSource of the ListBox to Scheduler.Parser.Result.Log directly and it will update accordingly.
Create a wrapper property in your ViewModel.
If you don't want to use an ObservableCollection in your model, you can expose the List via a property in your ViewModel, for example:
public IEnumerable<string> ParserLog
{
get { return Scheduler.Parser.Result.Log; }
}
Then you need to manually notify the UI when an item is added, so you're gonna need an event (or something equivalent) which tells your ViewModel that the list changed and it needs to raise the PropertyChanged Event for the ParserLog property. Add code like this in your ViewModel:
this.Scheduler.Parser.ResultUpdated += (s, e) => this.RaisePropertyChanged("ParserLog");
This will tell the ListBox to update the items from the ParserLog property.

View only properties (eg: IsSelected) and the Model in MVVM

Consider a WPF app that is being written using MVVM. The app needs to display a list of Employees (FirstName, LastName, Title) and you can select multiple to delete.
The model in this case would be "Employee" and it would implement INotifyPropertyChanged.
The View would be the "EmployeeListView" which would implement the XAML to display a collection of Employees.
The ViewModel would be "EmployeeListViewModel" which would expose an ObservableCollection, that can be bound to the EmployeeListView.
My question is: Where should the "IsSelected" property live?
In the Model? (I dont like this idea, as the model now is exposing a property that is only required by a view and has nothing to do with the actual domain object, also, this property would be useless, if I implemented the view differently and didnt allow deletion of multiple employees at once).
In the "EmployeeListViewModel" as a separate Dictionary collection, that would track whether an employee is selected or not? (Or even just a HashSet containing all selected employees). I dont like this much as the binding in the view is no longer straight forward.
Implement a separate EmployeeViewModel, that wraps the Employee object and exposes the IsSelected property. The EmployeeListViewModel then will expose its collection as a ObservableCollection. I like this solution the best, but I always thought that there is one ViewModel per View and in this case, I have 2 view-models for my view. Is that a deviation from the MVVM pattern or is this the typical way to implement MVVM? (references?)
Create a reusable Generic SelectableItem that wraps each item in the EmployeeList:
Simple example:
public class SelectableItem<T>: INotifyPropertyChanged
{
public bool IsSelected {get;set;} //PropertyChanged(), etc
public T Value {get;set;}
}
then in the ViewModel:
public ObservableCollection<SelectableItem<Employee>> Employees {get;set;}
and in the View:
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}" Content="{Value.FullName}"/>
</DataTemplate>
Then you can retrieve all selected employees just by:
var selectedemployees = Employees.Where(x => x.IsSelected).Select(x => x.Value);

Sorting on Templated Column with converters

My datamodel is like this:
public class ModelA
{
public int ModelId{get;set;}
}
public class ModelB
{
public IEnumerable<ModelA> ChildObjects{get;set;}
}
Now in the Xaml, am using a DataGrid with the ItemSource as List(), and have a template column which binds to ChildObjects with a converter doing the job of getting the first element from ChildObjects and returning the value as that object's ModelId. Now all works fine till now. The issue is when I do sorting on this templated column.
I know one workaround is to have an extra property in ModelB which does the job of what converter is doing and make the sortmemberpath in xaml as that new property name, but that is not what I want as its against the model.
Is there any other perfect way to handle this scenario, as the SortMemberPath can't be made as expression as its just a contant.
You've tagged this MVVM, which I assume means your models are actually view models (or are at least wrapped by view models). That being the case, why wouldn't you add the extra property? After all, it's there to support the view. Your view needs the extra property, so your view model should provide it.

Calling property changed on a bound element

My view model implements INotifyPropertyChanged for properties that it makes available to my view. It makes available a collection of objects that do not implement INotifyPropertyChanged.
My collection is bound to an ItemControl in my view, with an ItemTemplate used to display each item invidually. The item template is bound to the Name attribute of my collection members.
How can i tell my view to update when properties of my collection members change?
You need to either implement INotifyPropertyChanged for the objects in your collection (recommend approach), or you can manually refresh the binding by something like
myItemsControl.GetBindingExpression(
ItemsControl.ItemsSourceProperty).UpdateTarget();
If you're in the ViewModel, you might be able to raise a PropertyChanged event on your Collection class such the following, although I am not sure if that will update the individual items or not
// My PropertyChanged method is usually called RaisePropertyChanged
RaisePropertyChanged("MyCollection");
You can also do what Mirimon suggeted and set the value to null then back again, although personally I would recommend a different approach if possible.
You must implement INotifyPropertyChanged for collection members. Or you can reset your collection in ViewModel:
public void Reset() {
List<TestData> temp = YourCollection;
YourCollection = null;
YourCollection = temp;
}

WPF - Combobox SelectedItem not getting set?

I have a ComboBox that has its ItemsSource bound to a static List<CustomSettings> of options. The ComboBox is part of a form which is bound to a CustomObject class, and one of the properties on that class is a CustomSettingProperty.
I would like to bind the SelectedItem of the ComboBox to the property specified in the CustomObject, however SelectedItem="{Binding Path=CustomSettingProperty}" is not setting the default selected item. Using breakpoints I can see that it is calling the get; method, so I think the problem might be in the fact the CustomSettingProperty is created separately from the List<CustomObject> so WPF does not think it is the same item.
Is there an easy way to do this? Or perhaps an alternative since the CustomSettings class does contain an Id?
If the item that is selected is not the same instance that is contained in the List, you must override Equals() in the CustomObject to let the ComboBox know that it is the same object.
If it's the same instance, maybe it's only a simple thing such as setting the BindingMode to TwoWay:
SelectedItem="{Binding Path=CustomSettingProperty,Mode=TwoWay}"
I found the solution, It was The Prism's Event Aggregator was passed with reference type so That the ui thread stops processing

Resources