Technical code into the ViewModel in wpf? - wpf

I have a UserControl with some custom dependency properties bound to a clr property in the ViewModel. The ViewModel has application logic where I deal with the TextPointer/TextRange classes with a FlowDocument.
Should I put that stuff into the code-behind of the UserControl or in the ViewModel?
ranges.Clear();
TextRange range = new TextRange(boundXamlDocument.ContentStart, boundXamlDocument.ContentEnd);
foreach (var block in boundXamlDocument.Blocks)
{
if (block is Paragraph)
{
Paragraph p = block as Paragraph;
//if paragraph has Strikethrough, then do not loop its inlines.
if (p.TextDecorations.Contains(TextDecorations.Strikethrough[0]))
{
TextRange tr = new TextRange(p.ContentStart, p.ContentEnd);
ranges.Add(tr);
}
else
{
foreach (var run in p.Inlines)
{
if (run.TextDecorations.Contains(TextDecorations.Strikethrough[0]))
{
TextRange tr = new TextRange(run.ContentStart, run.ContentEnd);
ranges.Add(tr);
}
}
}
}
}

I only bother to design custom/user controls when I have a concept that won't fit well into any of the usual controls (rare to never), or I have custom control behavior that I want to reuse (more common).
The more abstract your control can be, the more reusable it will be. Although, making it so abstract that no one would get any benefit from it would be doing too much :)
If you have application logic, it is best to define it in the view model (or model) when at all possible. When that logic changes, it won't break other users of your control.
If a feature of the control isn't specific to the exact presentation/user input style, and is specific to that instance of the control, you should probably put it in the view model.
Edit:
From your comments, it seems that the code you are trying to write depends on UI elements (TextBlock text decorators). This means it must and should go in the view.

Related

MVVM design choice regarding responsibility of ViewModel for simple states

I've recently started to delve into MVVM architectural pattern. I've understood large parts of it but still few doubts remain regarding how much responsibility ViewModel should take on behalf of View.
In other words, how dumb should View be?
For example, for simple state coordination like clearing TextView after user presses SubmitButton. This kind of state coordination requires no more than one-liner to implement using some of the popular data-binding frameworks.
For example in pseudo-ReactiveCocoa:
textView.text <~ submitButton.pressed.map { _ in "" }
However, Martin Fowler wrote in his Presentation Model,
The Presentation Model contains the logic that says that the composer field is only enabled if the check box is checked, so the when the view updates itself from the Presentation Model, the composer field control changes its enablement state
which suggests that even the simple logic like clearing out TextView after pressing Button should be encapsulated inside ViewModel.
Such design choice leads to something like this (again, in pseudo-ReactiveCocoa):
// In View
viewModel.submitButtonPressed <~ submitButton.pressed
textView.text <~ viewModel.textViewText
// In ViewModel
textViewText <~ viewModel.submitButtonPressed.map { _ in "" }
Although it leads to better encapsulation of logics while assuming view with the job of binding only (making it dumb), it does make code a lot more verbose and lead to tighter coupling between View and ViewModel (by requiring ViewModel to be aware of SubmitButton).
I'm still new to MVVM pattern in general and learning stuff every day.
How much responsibility should ViewModel take?
In other words, must View be completely dumb and only handle simple binding (connect its UI elements to bindable property provided by ViewModel) or is it okay for View to handle fairly simple logic like the above?
On a side note, is tight coupling between View and ViewModel okay in MVVM?
In general, the ViewModel takes all responsibility. More specifically, in your scenario, the ViewModel wouldn't know about the submitButton, but rather the View would know that the ViewModel exposes a command (an ICommand) called SubmitCommand, and have the submitButton bind to that command.
Sometimes it can get a bit more involved to completely separate the actions and corresponding logic, for instance when there's no binding available for a command for a specific event. But in those cases a fairly simple attached behavior (i.e. InvokeCommandAction and friends, see the documentation) can bridge that gap to coax flow so the logic can go in to the ViewModel.
Very rarely, there are scenarios (of which none come to mind currently) where it gets so involved that I just skip the whole idea, and separate as much as possible, rather than to have to work out three months later exactly what the hell is going on. But those cases are rare indeed.
In other words, must View be completely dumb and only handle simple binding
It's quite good, when view contains data bindings only, but IRL complex views can contain some view-specific logic. E.g., since single view model could be connected to a several views, focus management is a view's prerogative. Another sample is a logic like "hide element A if element B is disabled", or "change color from A to B if button is checked", etc.
XAML frameworks provide several techniques to make view logic more well-composed: commands, triggers, attached behaviors, value converters. But sometimes you actually need code-behind.
For example, for simple state coordination like clearing TextView
after user presses SubmitButton
To be more clear. This is not a view logic, and must be placed in view model:
public class ViewModel
{
private string someText;
public string SomeText
{
get { return someText; }
set
{
if (someText != value)
{
someText = value;
OnPropertyChanged();
}
}
}
private ICommand submitCommand;
public ICommand SumbitCommand
{
if (submitCommand == null)
{
submitCommand = new RelayCommand(() =>
{
// do submit
// clear text
SomeProperty = null;
});
}
return submitCommand;
}
}
XAML:
<TextBox x:Name="SomeTextBox" Text="{Binding SomeText}"/>
<Button Content="Submit" Command="{Binding SubmitCommand}">
But this is a view logic:
public MyWindow()
{
InitializeComponent();
// SomeTextBox should have initial focus
Loaded += (sender, args) => SomeTextBox.Focus();
}
is tight coupling between View and ViewModel okay in MVVM?
Ideally all components should be loosely coupled, but view must know about view model properties to perform data binding.

wpf how to add different commands to keybindings in a control based on datacontext of item

Originally I added to the input bindings of the actual treeviewitem on the loaded event like this:
void MultiSelectTreeViewItem_Loaded(object sender, RoutedEventArgs e)
{
this.InputBindings.Add(new KeyBinding(ApplicationCommands.SelectAll, new KeyGesture(Key.A, ModifierKeys.Control)));
SignalViewModel svm = this.DataContext as SignalViewModel;
if (svm != null)
{
this.InputBindings.Add(new KeyBinding(DaedalusGraphViewer.GraphViewer.AddSignalsCommand, new KeyGesture(Key.Enter)));
}
BitViewModel bvm = this.DataContext as BitViewModel;
if (bvm != null)
{
this.InputBindings.Add(new KeyBinding(DaedalusGraphViewer.GraphViewer.OpenNewBusDialogCommand, new KeyGesture(Key.Enter)));
}
}
the problem with this is that if I want to use the treeviewitem elsewhere and have different commands, I would have to make a new treeviewitem class each time. I am definitely violating MVVM here and coupling too much so I want to fix this old code (been trying to adopt mvvm practices lately, but there is still a lot of old stuff that I didn't do correctly).
What I would like is a way to attach the keybinding in xaml, but I am still a little hazy on what determines whether a keybinding works. is a keybinding only available if the item on which the keybinding exists is in focus? can you access parent keybindings or child keybindings of the currently focused item? Based on my testing it looked like you can't access keybindings from the parent and I read another stackoverflow post that made it seem like you can't access children either. Is that the case?
I just need a nice customizeable way to set keybindings on different tiers of a treeview that is templateable so that I don't have to make new classes every time.
edit:
it occurs to me that one possible solution is to attach the input bindings to the textbox at each tier with a different command for each, then stretch the textbox to fill the item and put the focus on the textbox instead of the treeview. is that the best option? ideally I kind of wish hierarchicaldatatemplate had input bindings or something.

Implementing Telerik VirtualQueryableCollectionView with MVVM pattern

I have an application that was implemented using the Telerik RadGridView control and Caliburn.Micro MVVM framework. Because of some performance problems, I needed to implement the Telerik VirtualQueryableCollectionView in place of the direct control-to-ObservableCollection binding that was being used. The original code has the ItemsSouce property of the RadGridView was bound to the Prices property of the view model. I had to eliminate that binding and this in the code-behind:
public PricingView(PricingViewModel vm)
{
InitializeComponent();
var dataView = new VirtualQueryableCollectionView()
{ LoadSize=20, VirtualItemCount = vm.Prices.Count };
dataView.ItemsLoading += (sender, e) =>
{
var view = sender as VirtualQueryableCollectionView;
if (dataView != null)
{
view.Load(e.StartIndex, vm.Prices.Skip(e.StartIndex).Take(e.ItemCount));
}
};
this.PricesGridView.ItemsSource = dataView;
}
Since this code only deals with UI specific functionality and it is specific the the view implementation, I am comfortable that this code belongs in the code-behind rather than the ViewModel as it would be a departure from ther MVVM pattern to put a reference to VirtualQueryableCollectionView in the ViewModel. The part that I am not happy with is passing the reference to the ViewModel into the constructor of the View. Is there a good way to get the reference in the code-behind without having to pass the reference in the constructor?
Or is there a better way to do all of this?
My application is implemented with MVVM Light, in my case I used the VirtualQueryableCollectionView class in the ViewModel instead the View.
I did so because I think this class is very similar to the ObservableCollection although it is not part of the core classes.
Actually, VirtualQueryableCollectionView is not limited to the Telerik controls but many other standard controls like the ListView.
The fetch is in my case implemented in the Model.
void MainViewModel()
{
this.Traces = new VirtualQueryableCollectionView<MyEntityClass>()
{
// ViewModel also manages the LoadSize
LoadSize = this.PageSize,
VirtualItemCount = myModel.TotalCount
};
this.Traces.ItemsLoading += (s, args) =>
{
this.Traces.Load(args.StartIndex,
myModel.FetchRange(args.StartIndex, args.ItemCount));
};
}
Not sure what "performance problems" means, but I'm going to assume that means that when you fill the collection from the UI thread it blocks the application long enough it appears unresponsive.
There are two common solutions for this. First is to simply fill your collection from a background thread.
The naive implementation is to simply push the loading onto a ThreadPool thread, then use the Dispatcher to marshall the calls to add items to the ObservableCollection onto the UI thread.
A nicer approach (one that doesn't involve the ViewModel at all) is to use asynchronous bindings. You configure the fallback to some value that indicates to the user you are loading. Sometimes (depending on the situation) you can use a PriorityBinding to gradually fill your UI.
Other alternatives are to load and cache your data beforehand while displaying a splash screen. They're a bit different in WPF, it isn't like the old "display this form for a bit while I do work, then show the main form" mode of winforms. And, of course, there is always the classic data pagination. Its tough to code, but effective. Actually, I should say its tough in the UI. Its easy now in code (database.Skip(pageNumber * pageSize).Take(pageSize)).

What are the differences between using ItemsSource and foreach loop to assign data in a ListView?

Is there any differences between following code snippets?
I'm using VS 2010, .NET 4, WPF
Code Snippet 1:
List<EPutAway> listEPutAway = new List&ltEPutAway>();
// assign some data in listEPutAway here
lvPutWaySearch.ItemsSource = listEPutAway; // lvPutWaySearch is a ListView
Code Snippet 2:
List<EPutAway> listEPutAway = new List<EPutAway>();
// assign some data in listEPutAway here
foreach (var ePutAway in listEPutAway)
{
lvPutWaySearch.Items.Add(ePutAway); // lvPutWaySearch is a ListView
}
There is a very big difference.
In the first scenario, you are binding to the listEPutAway collection. This means that if the collection implements INotifyCollectionChanged, any changes to it will automatically be reflected in the control that binds to it.
Of course, in this specific example, List (which class exactly is that?) probably does not implement this interface. Usually when binding you elect to bind to an ObservableCollection<T> for this specific reason.
In the second scenario, you provide the list of items to the control manually. The data in the control is then completely independent from anything else that might be going on in your application.
One of the major attractions of WPF is specifically support for data binding, so "the WPF way" is the first scenario (and declaring the binding in XAML as well).
As a sidenote, you should have in mind that it isn't possible to use Items (manual population) and ItemsSource (data binding) at the same time.

How do you call identically named properties on different types which don't share an interface?

I have a DataTemplate that needs to set the IsSelected property on an ItemsControl's container (such as TreeViewItem, ListViewItem or ComboBoxItem). However, it doesn't know the type of the container until it's passed in to it. Since IsSelected isn't part of a common base class or interface, nor is it a common dependency property registered with AddOwner to the various classes (Duh, MS!!! WTF not?!!), I ended up with this mess...
if (container is TreeViewItem) {
(container as TreeViewItem).IsSelected = true;
return;
}
if (container is ListBoxItem) {
(container as ListBoxItem).IsSelected = true;
return;
}
if (container is ComboBoxItem) {
(container as ComboBoxItem).IsSelected = true;
return;
}
...which not only is verbose, but requires me to modify it if I ever use a different ItemsControl that uses different container types! Not good!
Sure I could enhance it a little by putting this logic in extension methods (damn C# for not having extension properties!!) called IsContainerSelected and SetContainerSelected and putting them on UIElement, then moving the above code inside there, but it's just making the outside neater. The inside is still a mess.
My only other thought is to use reflection and look for an IsSelected property and use that if found, but I'm always leery of doing things like that. However, since there isn't a common interface or base class, I'm not really sure I have a choice here.
For context, I'm sharing a complex data template between several different ItemsControls and the template itself has controls that can receive focus such as checkbox and textbox. However, when those controls receive focus via the mouse, the underlying container item doesn't get selected and whatever was selected before remains so.
My workaround is to use an attached behavior that utilizes the preview events to intercept the focus before it happens and set the underlying item accordingly, which works great when I've hard-coded TreeViewItem or ListBoxItem, etc., but I don't want to hard-code the type since the control shouldn't really care. So that's the part that breaks down.
Ugh!!! Why didn't MS just register the same attached property or at least create an ISelectableContainer interface?!!
I have read your answer, and it does make sense - in your case, IsSelected may obviously be part of the ViewModel, and that seems to be the best solution in your case.
But you asked for further explanation about C# dynamic features. C# 4.0 now has some dynamic functionalities, which allow us to create code that would only be possible in languages like Python, Ruby or JavaScript. This, of course, has its cost - a dynamic abuse would not only make code slower, but also more confusing - because you would lose compile-time errors and IntelliSense.
I have written a simple example so you may understand it better:
public class ClassOne
{
public int SameProperty { get; set; }
}
public class ClassTwo
{
public int SameProperty { get; set; }
}
public class ClassThree
{
public string SameProperty { get; set; }
}
public partial class Form1 : Form
{
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
dynamic wrapper = new ClassOne();
wrapper.SameProperty = 5;
wrapper = new ClassTwo();
wrapper.SameProperty = 15;
wrapper = new ClassThree();
wrapper.SameProperty = "Now it is a string!";
// And now a run-time error...
wrapper.AnotherProperty = "And this won't work...";
}
}
As you can see, wrapper has no definite type whatsoever - a dynamic reference will allow any kind of method or property invocation, since the actual binding will only be made during run-time, not compile-time.
Of course, this example is very naive, but sometimes dynamic code may be useful - it is a good option to avoid explicit reflection, or to avoid long if...else statements based on type (like your snippet above).
I'm not sure that I fully understand your problem, but you could try adding an IsSelected boolean to your model and then binding that property against the Item control it's contained in. That way, you just have to worry about setting that property in the model, regardless of the container.
Per #mdm20's answer, he suggested modifying the ViewModel, which is of course normally what you want to do. However this is a purely view-related issue (keyboard navigation-related) and isn't reflected in the ViewModel at all, nor in this case should it be.
But that gave me an idea! Since I'm using a custom control to render the item in whichever items control (via its data template) it's being added to, that control naturally does have multiple instances (all of which are pointing to the same ViewModel instance), which is what I want!
Therefore, rather than adding the IsSelected to the ViewModel, I added it to the user control itself, then I just bind to that within the data template for the respective ItemsControl which I do know about. I can then set the IsSelected property in the code-behind for the user control as needed (i.e. during the preview mouse events, etc.) and the underlying ItemsControl responds appropriately! Works great and keeps the ViewModel clean since neither the model, nor the viewmodel need to know about it. The IsSelected remains purely in the UI which is where in this particular case it should be!

Resources