how do UserControls get access to a textbox's value in MainWindow? - c#

The UserControls are put into MainWindow but they don't instantiate each other - they don't have owner-member relationship.
I need the back-end code of UserControls to be able to get the value from a TextBox of MainWindow. I have been told to use data binding but I don't really know what to be bound in UserControls.
Create an interface:
interface Interface_ProSimIP
{
string ProSimIP_Text { get; set; }
}
In MainWindow ViewModel:
string Interface_ProSimIP.ProSimIP_Text
{
get
{
return ProSimIP.Text;
}
set
{
}
}
In MainWindow View:
<TextBox x:Name="ProSimIP" Text="{Binding Path=ProSimIP_Text, Mode=OneWay}..."
I don't know am I right to do it this way and I don't know how to implement the interface in UserControls code behind.

You could use the same DataContext (view model) for the parent window and the user controls. Set the DataContext property of the window to an instance of a view model class where you implement your logic and then bind to properties of the view model from the XAML views of the window and the user controls. Then the window and the controls effectively share the same "back-end" code.
This pattern is known as MVVM and it's the recommended pattern to use when developing XAML based UI applications. You should learn it. The following MSDN page might be provide a good starting point for you: https://msdn.microsoft.com/en-us/library/hh848246.aspx.
Another (worse but maybe faster to adopt if you don't know anything about nor follow the MVVM pattern) approach would be to get a reference to the window from the UserControl using the Window.GetWindow method, and then access any control that's defined in the window directly:
var window = Window.GetWindow(this) as MainWindow:
if (window != null)
string text = window.ProSimIP.Text;
You should note that this kind of code doesn't follow follow best practices when it comes to developing loosely coupled, maintainable and testable applications though.

Related

Opening a second Window from MainWindow following MVVM and loose coupling

At first: This App and Question is for learning purpose
I'm on a new application and facing the problem that I want to open a Window when the user clicks on a Button in the MainView. In the past I'd have designed a Command which just creates the new Window and displays it
new RelayCommand((x)=>new SecondWindow().Show());
Now with this new Project I'm trying to fully decouple all classes from each other. To achieve this my App consists of 4 Assemblies (BL, COM, DAL and UI).
As in each WPF Application, the App starts with the MainWindow.xaml. The MainWindow.cs will create it's instance of MainWindowViewModel:
public ViewModel VM {get; private set;}
public class MainWindow(){
VM = new ViewModel();
InitializeComponent();
}
(which already violates loose coupling) (Any tips on how to make it better?)
My last attempt is to create an instance of my second Window inside my main window
<Window.Resources>
<local:SecondWindow x:Key="sw"/>
</Window.Resources>
and pass it as a CommandParameter to my Command
CommandParameter="{StaticResource sw}"/>
new RelayCommand((x)=> ((Window)x).Show());
This solution works but has one big disadvantage - the second window get's created immediately after the app starts - and so does it's ViewModel which starts some heavy processes (DB Connections etc.)
I've heard something abour IoC principle but I really don't know how to use it with an wpf application.
You are thinking along the right lines.... you basically have to create a List of ViewModels as your application starts up, then you can switch between them as the user presses buttons and pass the name of the ViewModel as a CommandParameter to your Command handler....
You might find this link to Rachel Lim's Blog
https://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/
Also, I'm not going to post any code here coz it simply gets too complicated. So here is a download to just about the simplest example I could come up with
http://www.mediafire.com/download/3bubiq7s6xw7i73/Navigation1.rar
Download and un-RAR it (with win RAR) You will need to step though the code, figure out what its doing and how its doing it then modify it to suit your needs... Or modify your needs to suit the code.....
The example is a modification of Rachel Lim example. It simply contains Views and ViewModels, there are no Models or data. It demonstrates switching between two different Views.
UPDATE 1
With specific reference to the demo code.... Your VMs are added to a static collection of VMs (see AddViewModel function), each View ( the DataTemplate associates View with ViewModel) is selected when you click a button for example, by calling 'SelectViewCommand' which in turn sets Current_ViewModel to the selected ViewModel... the corrisponding ContentControl is then updated to display that currently selected View...
I know is confusing and very difficult to explain
When you press a button to 'change Views' you are actually changing the value of the property that your ContentControl is bound to, so you have to call the correct SelectViewCommand in the SAME instance of the class that your ContentControl is bound too...
In the demo you'll see that in the 'LogOn_View' I call
Command="{Binding DataContext.SelectViewCommand, ElementName=Base_V}"CommandParameter="Main_ViewModel"
Here I am calling the SelectViewCommand in the Base_ViewModel (x:Name="Base_V" in Base_View XAML), That's because I want to change the View that is displayed in the Base_View's 'ContentControl'
In Main_View I call
Command="{Binding SelectViewCommand}" CommandParameter="MainV1_ViewModel"
Here I am calling the SelectViewCommand in the Main_ViewModel, That's because I want to change the View displayed in the MainView's 'ContentControl'....
I typically create a WindowService class for managing window changes/dialogs in MVVM. Having "View" code in the ViewModel (i.e. Window.Show()) goes against MVVM principles. For example:
public class WindowService : IWindowService
{
public void ShowDialog<T>(ViewModelBase viewModel) where T : IApplicationDialog
{
IApplicationDialog dialog = (IApplicationDialog)Activator.CreateInstance(typeof(T));
dialog.Show();
}
}
And then your call from the ViewModel would look something like:
windowService.ShowDialog<SecondWindow>(new SecondWindowViewModel());
If you're using DI, you can pass a reference to the IoC container to the window service and create the window instances from that rather than using Activator.CreateInstance (i prefer the DI approach personally)

WPF - MVVM view model first

I am building a large scale WPF app - kind of a desktop that hosts multiple modules such as multiple Terminal windows over RS232/Ethernet, Register analyzer, automation tools, etc.
I am working with MVVM architecture where my view (XAML) instantiate the corespondent viewmodel in its resource section. and the view model is set in the data-context of the view.
in this method the view created first.
however, I red about another method called VM first, meaning view model is instantiated before the view, and I understood the theory that stands behind it. What I didn't understand is when and who instantiate the view and how it happens without coupling to the view.
I'll be more than happy to hear your thoughts, and please if someone can supply code samples it would be great..
Thanks in advance.
I'm using MVVM heavily in my projects and can share my view on this.
In my projects the view never instantiates any VM. Usually I have some kind of manager which takes care that the corresponding VM is created.
This I'm assign to the datacontext of some top-level UI control (Window for instance). The view is always defined by a style where the target type is set to the type of the view model.
The startup code just creates a Window and the main viewmodel. The VM is assigned and the rest is done by the WPF (.net) runtime so to say.
So I have a large style file, where all the styles for each viewmodel defines the corresponding view (usually a usercontrol).
This is the way I'm doing things, there are for sure others too.
hth
In my WPF / MVVM applications I use ViewModels with two constructors - one for design time (no paramaters - mock version of required components are set directly) and another for runtime (required components are injected as parameters via IoC). This allows for (mock) data to be displayed inside the Visual Studio designer for UI testing purposes.
So the simple case looks like ...
public class MainViewModel : ViewModelBase
{
private IDataFactory _DataFactory;
public MainViewModel()
{
_DataFactory = new DesignTimeMockDataFactory();
LoadData();
}
[PreferredConstructor]
public MainViewModel(IDataFactory dataFactory)
{ _DataFactory = dataFactory; }
public void LoadData()
{ DataItems.AddRange(_DataFactory.GetDataItems()); }
public ExtendedObservableCollection<DataItem> DataItems { get; private set; }
}
The design time usage can be set directly in the XAML ...
<Window x:Class="MainView"
d:DataContext="{d:DesignInstance Type=MainViewModel, IsDesignTimeCreatable=True}"
...
The run-time ViewModel is set in the code behind of the View ...
public MainView()
{
InitializeComponent();
var viewModel = SimpleIoc.Default.GetInstance<MainViewModel>();
DataContext = viewModel;
Loaded += (s, e) => viewModel.LoadData();
}
The View's Loaded event is set to call the LoadData() method of the ViewModel to trigger data loading, once the View is displayed. If LoadData() is slow, it can be changed into an async method to prevent the UI from blocking.
For those of you complaining that this is a too tightly coupled construct, my view is that is exactly how they are supposed to be. Although the View and ViewModel are separate entities, each View knows exactly what type of ViewModel it requires, and that's unlikely to change over the project development life-cycle. Using a Locator type class to hide the ViewModel constructor calls is an unnecessary level of abstraction in my opinion.
To decouple the view from the view-model, something else needs to instantiate the view model and manage its lifetime and sharing. That job might fall to an IoC container, or simple, manual dependency injection. It's entirely up to you.
E.g. from Paul Stovell's article:
public CalculatorView(CalculatorViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
It all depends on you're trying to achieve by decoupling. One reason might be so that you can have multiple views over the same view-model - in that case, whatever creates the views needs to also create the view-model.
Another may be to swap the view-model of an existing view out with another view-model without destroying the view. In that case, maybe you already have two existing view-models and you assign them to the view's DataContext as required.
view.DataContext = viewModels[0];
view.DataContext = viewModels[1];
when your application grows you usually face these decisions. Usually you have "always" both elements together the View and the ViewModel it's not about what comes first it's more like what will you use to instantiate the two elements (view and viewmodel).
For larger projects, when I had the need, I used a class called ViewModelResolver. It obviously has an interface IViewModelResolverso it can be injected nicely.
It can either return a ViewModel based on convention based on type or a string representation and uses reflection to instantiated it.
You can also pass in a ViewModel (or type) and get the matching view with the passed in view model as DataContext (view ViewModel marriage) or you can define other custom scenarios that you need for instantiating either view or ViewModel.
hope that helps
So the main point is to have an intermediate class that acts like some sort of factory service that takes car of bringing views and view models together and instantiate them.
This gives you more freedom and a good place to separate out those decisions from the ViewModel directly.

Creating control instance in viewmodel

In my program I'm trying to design an output window to display logging information. For right now I'm binding to a string and updating the info as soon as log data comes in.
Ex:
<FlowDocument>
<Paragraph>
<Run DataContext="{Binding}" Text="{Binding OutputText}"/>
</Paragraph>
</FlowDocument>
(The flow document is inside a rich textbox)
In my viewmodel this is how I'm updating my outputtext
OutputText += loggingInfoString;
The problem is that strings are immutable data types and I don't like the idea of creating a new string every single time new data comes in. It's an unnecessary overhead.
RichTextBox has a method called AppendText which I assume will use something like a Stringbuilder in order to add to the string. The problem I'm having is being able to access the AppendText in the ViewModel.
I thought about making an instance of RichTextBox inside the ViewModel and binding the RichTextBox to the one in the ViewModel. I'm thinking that this violates MVVM but I'm not entirely sure. Is there another way to go about this? Or should I just create the RichTextBox instance inside the ViewModel?
Ex:
// ViewModel
RichTextBox Output;
// Update Method
Output.AppendText(loggerInfoText);
// Xaml
<RichTextBox DataContext="{Binding Output}" />
Thanks in advance!
You create an interface like so
interface IAppender{
void Append(string appendText);
}
You inject this interface into your viewmodel and you implement it in your view.
This means that in your viewmodel code you simply do
appender.Append(loggerInfoText);
And in your view you implement the interface by adding text to the richtext.
Based on the implementation of your view and viewmodel, depending on where the viewmodel is created you can inject the interface in the viewmodel. Suppose the viewmodel is created in the view you get something like this:
class View : UserControl, IAppender{
View(){
InitializeComponent();
DataContext = new YourViewModel(this);
}
void Append(string appendText){
//add text to richttext
}
}
public class YourViewModel : ViewModelBase{
private IAppender _appender;
public YourViewModel(IAppender appender){
_appender = appender;
}
}
This should get you started I hope
Note that this is pseudo code, not tested not even ran it through a compiler.
Passing the richttext to the viewmodel is indeed not MVVM. The idea is to have separation of concern. Via my interface approach this is not violated.
As alternatives to injecting a dependency (which even though decoupled, makes injection of views a pain in the ass) which is implemented by your control:
First, you can use StringBuilder internally to build your string.
public class MyViewModel : ViewModelBase
{
private StringBuilder sb;
private string Content
{
return sb.ToString();
}
protected Append(string text) {
sb.Append(text);
PropertyChanged("Content");
}
}
then bind Content property to your XAML element. This way you won't have allocations/deallocations in your ViewModel and you don't need to hassle with DI to inject your View/Control into the ViewModel (even though it's abstracted by the interface).
However, this assumes that you are going have avoid this allocations everywhere. If you only want it in a certain type of application (i.e. Windows Store App) but not in your ASP.NET or Desktop app, the second alternative may be much more attractive (especially for other similar scenarios):
You can use a custom Behavior to achieve this, as seen as answer in this question. Behaviors are reusable and you won't have to do this kind of decisions within the ViewModel, allowing you to differently handing this per platform or even per View.
And it simplifies your ViewModel and you won't have to bother how to inject the View that implements the IAppender into your ViewModel (can cause troubles in View-first approach, where the View gets resolved by the IoC and which gets the ViewModel injected into the View to be set as DataContext)

MVVM when to create a viewmodel for a control?

Or should I only create viewmodels for the domain data being represented? While reading on MVVM, I came across this:
"The ViewModel is responsible for these tasks. The term means "Model of a View", and can be thought of as abstraction of the view, but it also provides a specialization of the Model that the View can use for data-binding. In this latter role the ViewModel contains data-transformers that convert Model types into View types, and it contains Commands the View can use to interact with the Model. "
http://blogs.msdn.com/b/johngossman/archive/2005/10/08/478683.aspx
If the viewmodel is a model of the view, then doesn't it make sense to put properties of the view in the viewmodel rather than on the code behind of the view itself?
I guess in making a custom control I just have a hard time deciding when I should just add a property to the control's code behind and when it is worthwhile to make a viewmodel for the control to represent it. Honestly I kind of feel that moving all of the control's view related properties to the viewmodel would clean up the code behind of the control leaving only the control logic.
However, if I were to change things like this, then at times when an item needs properties from the control itself I can no longer use {Binding ElementName = control, Path=property} and have to instead get the data context of the parent (because the current datacontext would be on the individual subitem of the observable collection.
Basically I was considering whether I should move properties from Class GraphViewer into a GraphViewerViewModel and then just bind to it.
Code is worth a million words so:
public class GraphViewerViewModel :DependencyObject
{
private const int DEFAULT_PEN_WIDTH = 2;
private const int DEFAULT_GRAPH_HEIGHT = 25;
public SignalDataViewModel _SignalDataViewModel
{
get;
set;
}
public PreferencesViewModel _PreferencesViewModel
{
get;
set;
}
}
Meanwhile
public class SignalDataViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
ObservableCollection<SignalViewModel> _signals;
public ObservableCollection<SignalViewModel> Signals
{
get
{
return _signals;
}
private set
{
_signals = value;
}
}
ObservableCollection<SignalViewModel> _AddedSignals;
public ObservableCollection<SignalViewModel> AddedSignals
{
get
{
return _AddedSignals;
}
private set
{
_AddedSignals = value;
}
}
it is a pain to type:
PenWidth="{Binding RelativeSource = {RelativeSource AncestorType={x:Type DaedalusGraphViewer:GraphViewer}},
Path = _GraphViewerViewModel._SignalDataViewModel._AxisDivisionUnit.GraphPenWidth, Mode=OneWay}"
and I'm wondering if it is worthwhile to make the change or whether I'm misunderstanding what a view model should be used for in mvvm.
I guess in making a custom control I just have a hard time deciding when I should just add a property to the control's code behind and when it is worthwhile to make a viewmodel for the control to represent it. Honestly I kind of feel that moving all of the control's view related properties to the viewmodel would clean up the code behind of the control leaving only the control logic.
In general, a custom control is 100% View layer code. As such, it really falls outside of MVVM entirely.
The main goal when making a custom control to be used within an application being designed with MVVM is to make sure that you design and build the custom control in a way that it is fully compatible with data binding. This will allow it to be used within your View layer of your application exactly like other controls.
As such, this pretty much guarantees that you'll have code behind, since implementing Dependency Properties really requires code behind. You also don't want to set the DataContext of a custom control within the control (since you want to inherit the data context of the user control or window using the control).
Basically I was considering whether I should move properties from Class GraphViewer into a GraphViewerViewModel and then just bind to it.
If the types are specific to your domain, then this is really typically more of a UserControl being used by your application. In that case, creating a ViewModel and just binding is likely good.
If this is, on the other hand, a true custom control that's made to be completely general purpose (ie: usable by anybody in any application), then keeping it as a "pure view" custom control typically means that you 1) won't take a dependency on any ViewModels or domain specific objects, and 2) not set the data context (which means no view model).

Having trouble deciding how to wire up a UserControl with MVVM

I've been doing the best I can to try to stay true to the separation recommended by the MVVM pattern. One thing I haven't figure out how to do correctly has to do with initializing my UserControls.
My most recent example of this has to do with a library that I wrote to talk to some low-level hardware. That assembly happens to have a UserControl that I can simply drop into any GUI that uses this hardware. All that is necessary for it to work is to set a reference to the object that has access to the low level methods.
However, that's where my problem lies -- currently, the UserControl is added to the GUI via XAML, where I define the namespace and then add the UserControl to my window. Of course, I have no control over its creation at this point, so the default constructor gets called. The only way to set the necessary reference for hardware control involves calling a method in the UC to do so. The ViewModel could feasibly call a method in the Model, e.g. GetController(), and then call the method in the UserControl to set the reference accordingly. The GUI can pass a reference to the UserControl to the ViewModel when said GUI creates the ViewModel, but this violates MVVM because the ViewModel shouldn't know anything about this control.
Another way I could deal with this is to not create the UserControl in XAML, but instead do it all from code-behind. After the ViewModel gets initialized and retrieves an initialized UserControl (i.e. one that has the low-level object reference set), it can set the Content of my Window to the UserControl. However, this also violates MVVM -- is there a way to databind the Content of a Window, TabControl, or any other element to a UserControl?
I'd like to hear if anyone has had to deal with this before, and if they approached it the first or second way I have outlined here, or if they took a completely different approach. If what I have asked here is unclear, please let me know and I'll do my best to update it with more information, diagrams, etc.
UPDATE
Thanks for the responses, guys, but I must not have explained the problem very well. I already use RelayCommands within the UserControl's ViewModel to handle all of the calls to the hardware layer (Model) when the user clicks in the control in the UserControl itself. My problem is related to initially passing a reference to the UserControl so it can talk to the hardware layer.
If I create the UserControl directly in XAML, then I can't pass it this reference via a constructor because I can only use the default constructor. The solution I have in place right now does not look MVVM-compliant -- I had to name the UserControl in XAML, and then in the code-behind (i.e. for the View), I have to call a method that I had added to be able to set this reference. For example, I have a GUI UserControl that contains the diagnostics UserControl for my hardware:
partial class GUI : UserControl
{
private MainViewModel ViewModel { get; set; }
public GUI( Model.MainModel model)
{
InitializeComponent();
ViewModel = new MainViewModel( model, this.Dispatcher);
ViewModel.Initialize();
this.DataContext = ViewModel;
diagnostics_toolbar.SetViewModel( ViewModel);
user_control_in_xaml.SetHardwareConnection( model.Connection);
}
}
where the outer class is the main GUI UserControl, and user_control_in_xaml is the UserControl I had to name in the GUI's XAML.
Looking at this again, I realize that it's probably okay to go with the naming approach because it's all used within the View itself. I'm not sure about passing the model information to user_control_in_xaml, because this means that a designer would have to know to call this method if he is to redo the GUI -- I thought the idea was to hide model details from the View layer, but I'm not sure how else to do this.
You will also notice that the main GUI is passed the Model in the constructor, which I assume is equally bad. Perhaps I need to revisit the design to see if it's possible to have the ViewModel create the Model, which is what I usually do, but in this case I can't remember why I had to create it outside of the GUI.
Am new to MVVM myself but here's a possible solution:
Create a property in your VM that is of the object type (that controls the hardware) and bind it to an attached property on your UserControl. Then you could set the property in your VM using dependency injection, so it would be set when the VM is created. The way I see it, the class that talks to the hardware (hardware controller) is a service. The service can be injected to your view model and bound to your UserControl. Am not sure if this is the best way to do it and if it is strict enough to all the MVVM principles but it seems like a possible solution.
if your question is: How do i show my viewmodel in the view? then my solution is always using viewmodelfirst approach and datatemplates.
so all you have to do is wire up your viewmodel via binding to a contentcontrol.content in xaml. wpf + datatemplates will do the work and instantiate your usercontrol for your viewmodel.
You are right, the ViewModel shouldn't know about anything in the View - or even that there is such a thing as a View, hence why MVVM rocks for unit testing too as the VM couldn't care less if it is exposing itself to a View or a test framework.
As far as I can see you might have to refactor things a little if you can. To stick to the MVVM pattern you could expose an ICommand, the ICommand calls an internal VM method that goes and gets the data (or whatever) from the Model, this method then updates an ObservableCollection property of the data objects for the View to bind to. So for example, in your VM you could have
private ICommand _getDataCommand;
public ICommand GetDataCommand
{
get
{
if (this._getDataCommand == null)
{
this._getDataCommand = new RelayCommand(param => this.GetMyData(), param => true);
}
return this._getDataCommand;
}
}
private void GetMyData{
//go and get data from Model and add to the MyControls collection
}
private ObservableCollection<MyUserControls> _uc;
public ObservableCollection<MyUserControls> MyControls
{
get
{
if (this._uc == null)
{
this._uc = new ObservableCollection<MyUserControls>();
}
return this._uc;
}
}
For the RelayCommand check out Josh Smiths MSDN article.
In the View you could either call the ICommand in the static constructor of your UC - I am guessing youwould need to add an event in your class for this - or call the ICommand from some sort of click event on your UC - maybe just have a 'load' button on the WPF window. And set the databinding of your UC to be the exposed observable collection of the VM.
If you can't change your UC at all then you could derive a new class from it and override certain behaviour.
Hope that helps a bit at least, like I say, have a look at Josh Smiths MVVM article as he covers the binding and ICommand stuff in there brilliantly.
If you set the DataContext of the Window or UserControl containing thisUserControl to the main view model, the user control can call SetHardwareConnection() on itself in its Loaded event (or DataContextChanged event handler).
If that's not possible because you're saying the UserControl is 'fixed', you should derive from it or wrap it up in another UserControl, which would serve as a MVVM 'adapter'.
(In order to bind the window: you could make the MainViewModel a singleton with a static Instance property and use DataContext="{x:Static MyClass.Instance}". A nice way to get things going quickly)
Note; this is based on my understanding that MVVM works because of Bindings.. I always bind the control to a ViewModel, not pass a ViewModel as a parameter.
Hope that helps!

Categories

Resources