I read somewhere that setting DataContext = this in the constructor of a user control is bad practice (can't find where though). Why is this bad practice? What is the alternative?
In general, when someone uses your control they are going to want to set it's data context to their own view model class and bind the properties on your control to their view model.
If you start messing around with the data context internally within the control, and rely on it being set to 'this', either you will prevent their binding from working, or your control won't work as expected because you rely on it not being changed.
Say you have a user control that has a bunch on sub controls on it. What you could do instead is set the DataContext on the sub controls to be your user control class (or whatever you wanted). This would allow you to bind those sub controls to your user control's properties, while still allowing any users of your control to set it's data context to their view model and bind to the properties as well.
Related
I'm using AvalonEdit for displaying formatted text. The application is written in MVVM architecture in C#/WPF.
The problem is that the AvalonEdit control contains a lot of logic, which is accessible only from the control itself. So, say, I want to deal with current selection - for that I have to reach editor.TextArea.Selection - this is not accessible from the viewmodel.
Now my architecture may be shortly described as:
Main view model contains list of DocumentViewModels
DocumentViewModel contains TextDocument
List of DocumentViewModels is bound to DockingManager to be displayed as a list of tabs
DockingManager's DataTemplate is set to my control containing the TextEditor
TextDocument from DocumentViewModel is bound to Document property of TextEditor
Say, that I want to access selected text from the main window's viewmodel. I can reach for DocumentViewModel of the currently active document, but I have no way of accessing the control, which presents it (it's created and managed via the DataTemplate mechanisms of DockingManager)
Usually I solved this kind of problem by passing view to viewmodel via interface - such that viewmodel might have asked view (indirectly) to do something I couldn't bind or pass via commands. But since I have no control over creation of document views, I have no way of using such solution.
How can I access the TextEditor from MainWindowViewModel having its DocumentViewModel only? And how to do that without breaking the MVVM model? (obviously I may try to reach the control via visual tree, but that's hacking and I definitely want to avoid it)
I'd like to create a custom hyperlink control that, when clicked, navigates to a region and parameters specified by bindings to properties in a parent ViewModel. Since I'd like to be able to drop this control into any arbitrary xaml, it cannot have its own ViewModel or Module Manager, which is usually how a Region Manager is obtained.
Is there a way to get a RegionManager object in code-behind, without having to inject it into a ViewModel? I see that there's a static GetRegionManager() method on the RegionManager class, but it takes a dependency property parameter that I don't understand how to use.
Why I'd like to do this in code-behind:
While I could certainly supply the constructor that allows injection of the RegionManager object into the ViewModel, I would like my new Hyperlink control to be more self-contained and independent than that. Involving the ViewModel in this manner means that the navigation is going to take place in the ViewModel, not the new Hyperlink control, which sort of defeats the purpose of having a self-contained Hyperlink control.
It sounds like you want something with the behavior of a button, but with the appearance of a hyperlink. If so, I'd suggest using the existing WPF Button control and styling it appropriately to appear like a hyperlink.
If that fits your purposes, then wherever you use the control you can bind it to a command in whatever viewmodel is used there. Each viewmodel can have an IRegionManager (via constructor injection, for example) and you can use IRegionManager.RequestNavigate to perform whatever navigation is appropriate.
As a side benefit, keeping the logic in the viewmodel allows it to be more easily tested. For example, a unit test could invoke the command on the viewmodel and verify that IRegionManager.RequestNavigate was called with the appropriate parameters.
You can always use the CommonServiceLocator, but that's just evil. Also, you want navigation to happen in a view model (rather than in a view) just to make it testable. If not for that, you could drop mvvm altogether.
Having a HyperLinkViewModel (that receives an IRegionManager and has an associated DataTemplate and/or ControlTemplate) looks very self-contained to me, btw. Just expose it as a property from another view model, and you have a working hyperlink.
The view model is the code-behind of the DataTemplate, in a way.
I guess I'm a little confused as to whether properties like display range should be placed in the model (that gets inherited as a datacontext so that subcontrols can bind to it easily)or whether I should have properties be placed in the graphviewer class, and then let the components that need access to it have their own properties that they bind to the ancestor instead. Is it cleaner to bind to an ancestor control or just to bind off the model? I feel like the latter is cleaner, but then display range is pretty clearly a property of the view.
For example. I have a property AxisdivisionUnit that is needed in a scrollviewer, as well as used by a few thumbs to recalculate position on graph updates. The scrollviewer only appears when a treeview in the top level control (graphviewer) is populated. So I could either put the property axisdivisionunit on the graphviewer and bind the property to properties in the scrollviewer and thumb. Or I could have the thumb and scrollviewer bind to properties in the model (viewmodel if i were better at separating the UI out entirely.
Let me see if I can help..
First off, since you are discussing mainly the presentation of what things look like on your UI, then I do not think that the property should be in your model at all. The real question is whether it belongs in your View or ViewModel.
AxisDivisionUnit, sounds like it is only part of how the graph looks. I'm thinking that it would make more sense for that to be in the view only. If you had some properties describing the limits of your graph that were tied to business logic, then something like that may be better off in the ViewModel since you could possibly want to test that code and if you were to replace the UI you'd still want to enforce those exact same limitations.
I guess ask yourself, "If I were to replace this graph with a totally different graph and UI to display the same data, would I have to enforce this same logic?" If the answer is no, that it is just how you want to display it for this case... then it belongs in the View and you can bind a Control's property to another control's property or use triggers, behaviors, etc. to implement it in the View.
In my C# WPF .NET 4.0 application, I have a listbox containing user control items. What I want is to call some functions from these user controls to the parent form.
Item user controls have binding to the listbox via view model class.
What do you propose.
Thank you,
You can bind a command to your user control the same way as it would be a parent view. Then you can process this command in the appropriate view model.
I'm not entirely clear on what you're trying to do, but it sounds like you have a bunch of user controls and you want those controls to be able to call methods on the containing Window instance.
From inside your controls, you can use the following to get hold of the Window instance:
Window parentWindow = Window.GetWindow(this);
Note though that you can't do this from the control's constructors, because during the constructor the control won't yet have a parent window and the above will return null. The best place to do this would be from the control's Initialized or Loaded events.
I have a user control on which I am planning to switch out the datacontext on certain events. The control has several text boxes and a list view, etc.. etc... The question is will simply saying view.DataContext = new viewModel(); be enough? or will have have to tell all of the property changed events to fire?
Thanks
Yes, WPF will automatically update the UI bindings if the DataContext behind the UI controls changes
Yes. However - you need to consider the scope of the data context change for performance reasons. If your context change affects the entire form - it could slow down the application. Use the profiling tools for WPF to see the affects of this.