I'm trying to understand data context and how properties within different viewmodels are applied to a window in WPF.
Let's say I have a simple sample form with the following codebehind:
XAML Code Behind
public partial class pageTest : Page
{
public pageTest ()
{
InitializeComponent();
this.DataContext = new AnotherClass();
}
}
}
Now, let's assume we have a property in the AnotherClass class that is a boolean called Visible. This visible value is used to collapse and show a particular element.
Now, my confusion lies in understanding how to manipulate this Visible property from another ViewModel. Seeing that I create a particular instance of the AnotherClass class, what would be the proper method of changing the Visible property from another ViewModel at another point in time?
Hmm ... usually you'll try to avoid code behind in WPF and go the MVVM way.
Regardless of that, you'll have to either make that property static, so it lives across instances, or inject the instance using Dependency Injection (DI), so whomever needs to change it has access to that object.
For a (biased) mvvm review, you can check out this article.
I highly suggest going that way and probably looking DI as well, since they are plenty of frameworks do help you with that (ninject and autofac pop to mind, but google it up, there's plenty).
Related
I have a 'public static' class that gets called on application startup. In this class, I'm trying to set the "IsEnabled" and "IsChecked" properties of several check-boxes. I had no problem doing this in MainWindow.xaml.cs but when I try to reference the check-boxes in my custom class, the check-box names aren't resolving in Intellisense/auto-complete. I also get the error, "The name 'cbx_NameOfMyBox' does not exist in the current context"
How can I access control properties outside of MainWindow.xaml.cs?
namespace Widget
{
public static class StartupSequence
{
public static void Begin()
{
GetDomain.Start();
cbx_GpoUpdate.IsEnabled = false;
return;
}
}
}
SUGGESTIONS:
You need to implement MVVM and bind the data.
If you are going to use static class to share data, then i would suggest using singleton class. You should not make the class static. You should make the constructor of the class as private. Then, create a static property which can return your class. (just do some google search to learn about singleton)
SOLUTION TO YOUR ISSUE (as a quick fix) :
You are doing it in the opposite direction. Main purpose of static property is that it can be accessed from anywhere in the project (provided the namespaces are properly referenced). So, instead of trying to access your control from the static class, do it the other way. In your xaml.cs (Control's code behind), like when the control is loaded or initiated or somewhere suitable, add like,
cbx_GpoUpdate.IsEnabled = StartupSequence.your_boolean_property_for_this
You need to have a boolean property in your static class to store the required data and when the control is initiated, you refer it. You can also created different other properties for different controls and in each controls' code behind you can refer them whenever they are loaded or a button is clicked or in any other event scenario.
Note: I started exactly the way you are doing it (in code behind) but after several months and projects later, i learned it the hard way that MVVM pattern is the best for WPF. Now, 3 years straight, all my projects are in MVVM. Start to learn MVVM and move to it as soon as possible. Cheers.
I'm working on an app that has a "day" and "night" color palette that can change automatically. We're using Xamarin Forms and, for historical reasons, we're not using XAML but I speak XAML so I'm going to use it in this post.
I've approached it by creating a base type with a property for relevant colors like "dark text" or "header background", then implementing that type for both schemes. Then, I made a type that references one of those and raises a PropertyChanged even if it changes. So a day->night transition involves setting the property, then anything in the UI bound to a path like "ColorScheme.DarkText" changes. Nice.
Now I've got a ViewModel that wants to have different colors for some items in a list. I want those colors backed by this day/night change system, but I might have designed myself into a corner. I'll show you what I did and how I want to redesign, but I'm curious if there's a clever way to go about it without causing other problems.
Here's a VM for an item I'm binding to, let's all assume there's nothing unexpected in ViewModelBase:
public class ItemViewModel : ViewModelBase {
public string IconColorName { get...; set...; }
public string IconText { get...; set...; }
}
That ViewModel's contained in another boring ViewModel that makes up the rest of the page:
public class PageViewModel : ViewModelBase {
public ObservableColorScheme ColorScheme { get...; set...; }
public ObservableCollection<ItemViewModel> Items { get...; set...; }
}
OK, so what I'm going for is I'd like XAML for my item's template to look something like:
<StackLayout>
<StackLayout.Children>
<Label TextColor={Binding IconColor, Converter={StaticResource StringToColorConverter} />
...
</StackLayout.Children>
</StackLayout>
Right. OK. So now here's the problem. I can imagine building that IValueConverter and setting it up so it has the same concept of the right color scheme, then using the string value here to get the appropriate property. But I have a problem: there can only be one source for a binding, right? I need the color to change if EITHER the ColorScheme or IconColorName changes. My hunch is WPF could do that, but Xamarin can't?
The most obvious solution I've thought of is some kind of extra ViewModel, in XAML-unfriendly format for brevity:
public class ColorViewModel : ViewModelBase {
public Color Color { get...; set...; }
public ColorViewModel(string colorName, ObservableColorScheme colorScheme) {
colorScheme.PropertyChanged += (s, e) => {
if (e.PropertyName == colorName) {
Color = colorScheme.Get(colorName);
}
}
Color = colorScheme.Get(colorName);
}
}
I do NOT like this. These items are created and destroyed a lot, so that means that event handler needs to be unsubscribed. I don't want to have to think about that, and I can assume a maintenance programmer will forget. I've thought about retooling it to use a WeakReference for the event subscription but... that's getting really icky.
So I'm not really sure how to proceed, short of making the Page here detect color scheme changes and manually update its child views. That feels icky too. I've been thinking about it for a couple of days and nothing nice is presenting itself.
I'm open to "you're doing this terribly wrong, and there's some feature that would make this dramatically easier for you". I'm suspicious that feature is Styles, which I'm not using because 1) the aforementioned lack of using XAML and 2) our project is older than Style support in Xamarin Forms. Feel free to tell me to throw this design away, but please don't do so without showing me a quick example of the better way!
I don’t know xamarin nor C#, so maybe I’ll use the wrong terms, but this is how I would approach this problem:
I assume you have some kind of ViewModel hierarchy and you know the root of this hierarchy.
I would create a ColorScheme class with a static getter of the current color scheme and getters for each color. So you can create a subclass for day and night scheme. Also a void ApplyTo(ViewModelBase). I would create an ViewModelBase interface which has an void UpdateColorScheme() and List Items().
Ok, now, each ViewModel can use the UpdateColorScheme method to setup the view will be created.
Probably there is some kind of event to change the color scheme. This could be a button or a clock based trigger. This event sets the correct ColorScheme and simply calls ColorScheme.CurrentScheme().ApplyTo(rootViewModel). The ApplyTo method walks down the ViewModel hierarchy and calls UpdateColorScheme() for each ViewModel.
This isn’t very fancy but your don’t have to create dozens of objects for something which will change rarely (only twice a day). You only have one instance of ColorScheme and be instance for each Color and a separate method for color settings. But you don’t have to create and register events listeners all the time. The base class will enforce the maintenance programmer to use this concept so he can not forget to setup a event listener and you use the same code for setting up and updating the view.
And a little side note: opinion based questions are not allowed on Stack Overflow. There is a Core Review Page of StackOverflow, I think this question belongs there.
I am aware there are a couple of questions similar to this one, however I have not quite been able to find a definitive answer. I'm trying to dive in with MVVM, and keep things as pure as possible, but not sure how exactly to go about launching/closing windows while sticking to the pattern.
My original thinking was data bound commands to the ViewModel triggering code to start a new View, with the View's DataContext then set to it's ViewModel via XAML. But this violates pure MVVM I think...
After some googling/reading answers I came across the concept of a WindowManager (like in CaliburnMicro), now if I was to implement one of these in a vanilla MVVM project, does this go in with my ViewModels? or just in the core of my application? I'm currently separating out my project into a Model assembly/project, ViewModel assembly/project and View assembly/project. Should this go into a different, "Core" assembly?
Which leads on a bit to my next question (relates somewhat to the above), how do I launch my application from an MVVM point of view? Initially I would launch my MainView.xaml from App.xaml, and the DataContext in the XAML would attach the assigned ViewModel. If I add a WindowManager, is this the first thing that is launched by my Application? Do I do this from the code behind of App.xaml.cs?
Well it mainly depends on how your application looks like (i.e. how many windows opened at the same time, modal windows or not...etc).
A general recommendation I would give is to not try to do "pure" MVVM ; I often read things like "there should be ZERO code-behind"...etc., I disagree.
I'm currently separating out my project into a Model assembly/project,
ViewModel assembly/project and View assembly/project. Should this go
into a different, "Core" assembly?
Separating views and ViewModels into different assemblies is the best thing you can do to ensure you won't ever reference something related to the views in your viewModel. You'll be fine with this strong separation.
Separating Model from ViewModel using two different assemblies could be a good idea too, but it depends on what your model looks like. I personally like 3-tier architectures, so generally my model is the WCF client proxies and are indeed stored in their own assembly.
A "Core" assembly is always a good idea anyway (IMHO), but only to expose basic utility methods that can be used in all the layers of your application (such as basic extension methods....etc.).
Now for your questions about views (how to show them...etc), I would say do simple. Personally I like instantiating my ViewModels in the code-behind of my Views. I also often use events in my ViewModels so the associated view is notified it should open another view for example.
For example, the scenario you have a MainWindow that should shows a child window when the user click on a button:
// Main viewModel
public MainViewModel : ViewModelBase
{
...
// EventArgs<T> inherits from EventArgs and contains a EventArgsData property containing the T instance
public event EventHandler<EventArgs<MyPopupViewModel>> ConfirmationRequested;
...
// Called when ICommand is executed thanks to RelayCommands
public void DoSomething()
{
if (this.ConfirmationRequested != null)
{
var vm = new MyPopupViewModel
{
// Initializes property of "child" viewmodel depending
// on the current viewModel state
};
this.ConfirmationRequested(this, new EventArgs<MyPopupViewModel>(vm));
}
}
}
...
// Main View
public partial class MainWindow : Window
{
public public MainWindow()
{
this.InitializeComponent();
// Instantiates the viewModel here
this.ViewModel = new MainViewModel();
// Attaches event handlers
this.ViewModel.ConfirmationRequested += (sender, e) =>
{
// Shows the child Window here
// Pass the viewModel in the constructor of the Window
var myPopup = new PopupWindow(e.EventArgsData);
myPopup.Show();
};
}
public MainViewModel ViewModel { get; private set; }
}
// App.xaml, starts MainWindow by setting the StartupUri
<Application x:Class="XXX.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
...
StartupUri="Views/MainWindow.xaml">
I have more of an architectural question. I'm trying to implement MVP in C# as follows:
IView creates Presenter
IPresenter has a property IView which holds View, that is bound to it
View CAN be Form, but Presenter does not distinguish between Form and non-Form types, so View can be swapped and the solution is to be testable
What I sometimes need to do, is to open some other form. E.g., I have Browser view with DataGrid and when I double-click on a grid item or select something and click Edit button, Edit event is raised and Presenter acts.
Now, Presenter needs to open a Editor view, which is also a Form, but the problem is, presenter should not construct the Form itself, because then it is impossible to Mock the View.
I'm pretty struggling with the proper concept. My code looks something like this:
var editorView = new EditorForm();
editorView.Presenter.Entity = SelectedEntity;
editorView.ShowDialog(View as Form);
Under the hood, EditorForm constructor constructs the presenter and assigns this (View instance) to the presenter:
public EditorForm()
{
Presenter = new EditorPresenter(this);
InitializeComponents();
}
From the View perspective, I can swap it to MockView simply by implementing the Mock and then instantiating the same Presenter from MockView's constructor.
I was searching for some other Q&A here and over the web but did not find anything suitable.
Thank you for all your hints.
If I understand your conception,
I suggest you to project the Edit presentation issue according to MVP pattern as you did with main view.
So create IEditView and EditPresenter and finally in main presenter create instance of EditPresenter. Generally control the edit view through its presenter.
After some brainstorming with some friends, we came to the conclusion, the best way to handle the case of instantiating different set of Views for production (FormViews) and different set for testing (MockViews) is constructing them in some context - in my case, Spring context is an option.
So far, I consider this as an answer for the problem. If you have some more clever solution, please feel free to share!
I am currently working in a small windows forms project in C# using Visual studio 2008.
I have added a custom class to the project, but in this class I am unable to access the forms controls (like listbox, textbox, buttons ) in order to programmatically change their properties.
The class file has using system.windows.forms included and all files are in the same namespace.
Surprisingly, I am also unable to access the controls in the form1 class itself, unless I create a method in the class and then intellisense pops up the names of the various controls.
in the custom class however, intellisense does not show the names of the controls at all.
Appreciate if someone coudl shed some light on why this could be happening.
Thanks
Encapsulation means your separate class shouldn't be talking directly to the controls. You should, instead, expose properties and methods on your (outer) Control - for example:
public string TitleText {
get {return titleLbl.Text;}
set {titleLbl.Text = value;}
}
For more complex operations it may be preferable to use a method; properties are fine for simple read/write for discreet values.
This provides various advantages:
you can, if required, abstract the details to an interface (or similar)
you can change the implementation (for example, use the Form's Text for the title) without changing the calling code
it is just... nicer ;-p
Your class needs a reference to the form for this to work. The reason for this is that the form is not a static class so you can have multiple instances of it.
The best way of giving it the reference would probably be to pass it in the classes constructor. Then the class would have a reference to the form and could use that reference to change the controls.
An alternative option that you could use if you are 100% sure that you will have only one instance of your form open is to add a public static property to the forms class that returns the instance of the form. That property would then be available to be used in your other class.
Also, make sure that your controls are public, or better add public methods to your form that can be used to manipulate the controls indirectly.
The controls in Form1 will be private
partial class Form1
{
//elided other good stuff
private System.Windows.Forms.Button button1;
}
So no, you can't access this directly from another class.
You could make it public as #abatishchev suggests (but that would be a really bad idea).
A better plan would be to use properties as #Marc Gravell suggests.
You would still need to pass a reference to the form to the class that you wish to have consume the properties though (as pointed out by #Rune Grimstad).
You are trying to write a class in your application that directly asks the UI for data. This isn't usually considered a very good idea. The class should be entirely concerned with it's own purpose. You should design properties or events for the specific bits of data that the class needs access to and not necessarily pass it the entire form, maybe just the values that it needs to work with or change.
Take a look at how this could be implemented using the MVP pattern (sample code): Implementing MVC with Windows Forms
UPDATE: The code in the class you mention should in fact be part of the form's presenter, which has a reference to the form (through the IView interface). That is how you should be designing your UI code, not by directly accessing other Form's private parts.