I am new to MVVM and WPF so this might be a broad or a dumb question, but:
I am using the MVVM pattern and have 1 Viewmodel, several views and a couple of models.
All of the views are just Usercontrols which are put on my mainwindow.xaml.
The view in question is bound to a model wich have several properties, one of which i want to use to dynamically change a picture in the usercontrol.
I am having a very difficult time trying to acces this property and my question is how i do this the "right" MVVM way.
My mainwindow.xaml:
<Window.Resources>
<DataTemplate DataType="{x:Type Model:Device}">
<Canvas>
<View:DeviceUserControl/>
</Canvas>
</DataTemplate>
</Window.Resources>
//---- SNIP----
<Grid Name="grid1">
<ItemsControl ItemsSource="{Binding Devices}" />
</Grid>
DeviceUserControl.xaml
//--- SNIP ---
Image Name="DeviceImage" Source="{StaticResource IconAdd}"/>
DeviceModel
//--- SNIP ---
public enum Typeenum
{
FrequenceGenerator,
Oscilloscope,
Test1,
Test2
};
public Typeenum Type { get { return type; } set { type = value; NotifyPropertyChanged("Type"); } }
I want to change the DeviceImage based on the type of the object. I have tried dependencyproperties, but it didnt work as expected (It returned the same type everytime).
I dont really need the notifyPropertyChanged as i am only interested in changing the image source when the Usercontrol is instantiated.
First of all, you should bind Views to ViewModels, not Models. At least that's what MVVM is all about. Also, if you want something to happen when a property changes, then one way is to subscribe to the PropertyChanged event in your ViewModel (which I assume you know should implement the INotifyPropertyChanged interface) then put your logic on what should happen on the property change there.
Code Sample
this.PropertyChanged += (s,e)=>{
// Your code here.
// e.g. this.MyImageSource = "http://img.com/image.jpg"
}
The code sample assumes that your event for the property changes is called PropertyChanged and that the image control's source is data bound to the MyImageSource property in the ViewModel.
Hope this helps.
Related
I'm doing a paper on code-design and I'm comparing MV-C,P and VM to see which one is the best fit for WPF. During my research I realised that MVVM is the obvious choice cause of the databinding among other criterias.
Even If I know this I have to "prove" this in a sense so I'm creating an application both in MVP and MVVM that does exactly the same thing but handles code differently. With this I will explain the pros and cons with these code-patterns but in my creating with the MVP-application I reached a problem.
I have a model with the "buisness-logic" and my presenter creates a list of these model objects that my view can display.
My problem is how I display them
In MVVM I bind my list to a ListBox cause that is how MVVM is "made" to do.
EG
<Window.Resources>
<DataTemplate DataType="{x:type model:Mymodel}">
//Some DataTemplate Definition
</DataTemplate>
</Window.Resources>
Then binding to my Listbox
<ListBox ItemSources={Binding someProperty} />
It's not fully coded but you get the gesture
But if I've understood correctly, binding with MVP is not how it should be.
You should not bind anything in MVP cause that is not how it is supposed to work, or am I wrong here?
So if I shouldn't bind data, how can I display this list of my model objects in a ListBox so it doesn't say
Model Object
Model Object
Model Object
Model Object
I understand that you should use MVVM for WPF but for the sake of proving why it's better I need to show how MVP can work in WPF also.
When you're using WPF, it is as you said made to work with MVVM, trough the data-binding. MVP was often used with Windows-form where no data-binding was available. If you want your applications to have the same functionality and use the same technology (WPF) you can't avoid using binding or it's at least more difficult to do. As long as you talk through the presenter to your model you're still using MVP. You can decide for yourself if you want to use
Passive View - The presenter handles ALL dialog between the view and model
SuperVising Presenter - The View knows about the model and the presenter handles "difficult-code" that is to much to be handled between the view and model.
If you're using binding I would say (Unsure about it) you're using SuperVising Presenter which is not "recommended", but using MVP in WPF is not recommended either so...
EDIT Example
For instance if you want to display a list you need to have an interface that has a property of a list containing objects you want to display.
public interface myinterface
{
ObservableCollection<YourModel> ListName {get; set;}
}
and then in your presenter just "push" the data to that list
private myinterface _my;
public Presenter(myinterface my)
{ this._my = my;}
_my.ListName = // Add whatever Data you want into this list.
And in your view
<ListBox ItemSource ={Binding ListName}>
<ListBox.ItemTemplate>Set how you want to display the list</ListBox.ItemTemplate>
This is a unclear example but hopefully can give you the idea how MVP works with WPF ( in a small way)
I cannot add as much code as I want to the comment so I'll post an answer. If something is unclear just give me a feedback so I'll give you more details.
From the example you've shown I would go about and make binding from View to Presenter which should be the bridge between View and Model as you can see in here :
( Image from wikipedia article )
View should send events/changes to the presenter and presenter should be the "brain/logic" of the View which decides if it should update the Model or not.
Assuming you've the View like this one :
<UserControl x:Class="EntryNamespace.MeView"
... >
<!-- ListItems should return collection of Presenters -->
<ListView ItemsSource="{Binding ListItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ListView.ItemTemplate>
<DataTemplate>
<!-- Elementcontent should be a property inside Presenter that returns value from Model -->
<Button Content="{Binding ElementContent}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</UserControl>
You can create a Presenter like this one :
class Presenter : INotifyPropertyChanged
{
public ObservableCollection<ListItemPresenter> ListItems
{
get { return GetItems(); }
set { SetItems(value); }
}
ObservableCollection<ListItemPresenter> GetItems()
{
// private logic to retrieve `ListItemPresenter` collection from model
var collection = new ObservableCollection<ListItemPresenter>();
foreach(ListItem listItem in Model.Items)
collection.Add(listItem.GetPresenter());
return collection;
}
void SetItems(ObservableCollection<ListItemPresenter> objects)
{
// private logic to transfer `ListItemPresenter` collection to model
// remember to call NotifyPropertyChanged("ListItems");
Model.Items.Clear();
foreach(ListItemPresenter presenter in objects)
Model.Items.Add(presenter.GetModel());
NotifyPropertyChanged("ListItems");
}
}
You Model can look like this:
public class ListItem
{
ListItemPresenter m_Presenter;
public ListItemPresenter GetPresenter()
{
return m_Presenter;
}
string m_ElementContent;
public string ElementContent
{
get { return m_ElementContent; }
set { m_ElementContent = value; }
}
public ListItem(ListItemPresenter presenter)
{
m_Presenter = presenter;
}
}
Another way to use Presenter can look like such :
Assuming you've similar View just create a Presenter:
public class Presenter
{
ObservableCollection<ListItem> m_ListItems = new ObservableCollection<ListItem>();
public ObservableCollection<List> ListItems
{
get { return m_ListItems; }
}
public Presenter(MeView view)
{
Binding binding = new Binding("ListItems");
binding.Source = ListItems;
view.MeListView.SetBinding(ListView.ItemsSourceProperty, binding);
// other view events, bindings etc.
}
}
It's not the best way of communicating between View and Model indirectly, but should give you small hint. It will be up to you if you want to split your controls that each will have it's own Presenter or if you want one per window.
I am new to wpf and this fancy binding stuff, followed these tutorial and got this XAML:
<Button
x:Name="btn"
Content="refresh"
Command="{Binding RefreshCmd}" />
and this code:
public someClass ()
{
InitializeComponent();
CreateRefreshCmd();
btn.DataContext=this; // without this line it will not work !!
}
public ICommand RefreshCmd
{
get;
internal set;
}
private bool CanExecuteRefreshCmd ()
{
return true;
}
private void CreateRefreshCmd ()
{
RefreshCmd=new RelayCommand(e => RefreshExec(), c => this.CanExecuteRefreshCmd());
}
public void RefreshExec ()
{
// do something fancy here !
}
but without the last line in constructor it will not work.
In the tutorial this line does not exist.
How can i avoid this?
EDIT:
I clicked the databinding with visual studio and got this:
Command="{Binding RefreshCmd, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type my:spielerei}}}"
is this really necessary?
For binding to work, you need to set a data context for bindings to target, so yes, it is necessary. In the Command binding you posted in your edit, the binding is instructed to look for the RefreshCmd property on an ancestor of the Button control of type my:spielerei, which I assume is the containing window type. This is why the explicit setting of DataContext doesn't appear in the tutorial.
Bindings and commands can be used in code-behind, but are much more commonly used with view-models in the MVVM pattern. This involves setting the DataContext of your class to a view-model, which contains the properties and commands you want to bind to. To change your code to follow MVVM, we need a view-model:
public class SomeClassViewModel
{
public SomeClassViewModel()
{
this.RefreshCmd = new RelayCommand(e => RefreshExec(), c => this.CanExecuteRefreshCmd());
}
public ICommand RefreshCmd { get; internal set; }
private bool CanExecuteRefreshCmd()
{
return true;
}
public void RefreshExec()
{
// do something fancy here !
}
}
Then, in the code-behind, create the view-model, and assign it as the data context of the object:
public class SomeClass
{
public SomeClass()
{
InitializeComponent();
this.DataContext = new SomeClassViewModel();
}
}
Notice that all of the code from the SomeClass code-behind file has moved to the view-model - it is now testable, and your XAML controls can communicate with the view-model by binding to properties and executing commands.
Binding will work correctly if there is an object it can bind to. This object is read from DataContext property. If this property is not set there is nothing to bind to. It is why the following line is needed:
btn.DataContext=this;
The tutorial mentioned by you does it in a little bit different way i.e. it sets DataContext in XAML. Please examine MainWindow.xaml file from this tutorial. It contains the following code at the beginning which populates DataContext property:
<Window x:Class="MvvmCommand.MainWindow" DataContext="{Binding Main, Source={StaticResource Locator}}">
When you use a Binding in WPF, by default it sets the binding to the named property on the DataContext of the object that has the property that is bound. So in your example, the DataContext of the button.
This property is inherited down through the tree, so if not set on the Button it will look up the tree all the way to the window that holds the control.
MSDN on binding
Without all your XAML to look through I do have to guess, but I am guessing you haven't set the datacontext of the window that hosts the button. By setting it in the constructor explicitly to this you are setting the source of the binding to the object that has the property, hence why it works.
The normal way to do this is to set the data context to a class that contains the command. The usual design pattern for this is MVVM. The idea of binding is to have separation - it is not like events where you handle them in the code behind, instead it allows you to create a view model or similar class that exposes the commands and bind this to the view. This allows you to do things like unit test the functionality via the view model without having to unit test the view, share view models to multiple views etc.
data context is required to be set so that binding framework can resolve the values
you may have various method of setting the same
first method you've used
another method is to set via xaml
<Window x:Class="Project.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
Idea here is to set the data context to self.
In short, It's not necessary. Do not set datacontext to button, set data context (viemodel) for your page (view) in XAML. Of course your command must be exposed via that viewmodel.
For another question I put up simple example showing command binding and cross viewmodel communication, check it out here https://github.com/mikkoviitala/cross-viewmodel-communication
I am using WPF(4.5) and Caliburn.Micro. I am trying to understand how to have an "event" in my View manipulate other controls in my View.
For instance:
My View has an Expander Control, a Button, and a GridView. The GridView is inside the Expander. When the user clicks the button it calls a method in the VM that populates the gridview with a BindableCollection<>. What I want to have happen is when that collection has more then 1 item I want to Expand the Expander Control automatically.
Ideas?
You can bind to the number of items in a collection:
<Expander IsExpanded="{Binding Path=YourCollection.Length, Converter={StaticResource ResourceName=MyConverter}" />
and then in the window or usercontrol:
<UserControl... xmlns:converters="clr-namespace:My.Namespace.With.Converters">
<UserControl.Resources>
<converters:ItemCountToBooleanConverter x:Key="MyConverter" />
</UserControl.Resources>
</UserControl>
and the converter:
namespace My.Namespace.With.Converters {
public class ItemCountToBooleanConverter : IValueConverter
{
// implementation of IValueConverter here
...
}
}
I wrote this out of my head, so apologies if it contains errors ;)
Also: Make sure your viewModel implements the INotifyPropertyChanged interface, but I assume you already know that.
#cguedel method is completely valid but if you don't want to use Converters (why one more class) then in your view model have another property of type bool maybe called ShouldExpand, well why talk so much, let me show you:
class YourViewModel {
public bool ShouldExpand {
get {
return _theCollectionYouPopulatedTheGridWith.Length() != 0;
// or maybe use a flag, you get the idea !
}
}
public void ButtonPressed() {
// populate the grid with collection
// NOW RAISE PROPERTY CHANGED EVENT FOR THE ShouldExpand property
}
}
Now in your View use this binding instead:
<Expander IsExpanded="{Binding Path=ShouldExpand}" />
As i said before the other solution is well but i like to reduce the number of classes in my solutions. This is just another way of doing it.
This is a question that extends from the originally posted here:
Link to loading-xaml through runtime
I'm working on a WPF MVVM application that loads XAML content dynamically from an external source, very similar as the answer in the post above.
Here is what I got so far:
My View declares an instance of the ViewModel as a resource and creates an instance of that ViewModel
In my ViewModel constructor I'm loading a XamlString property coming from an external source (file or db..)
In my view I have a button that user clicks after ViewModel finishes loading and in the click-event code-behind I'm deserializing the dynamically loaded XAML and add it to my grid.
My question is, how can I eliminate code-behind and automate the logic so the View can render the new xaml section dynamically right after the ViewModel is done getting the XAML content and initializing the string property?
Should I use some kind of Messaging Bus so the ViewModel notifies once the property has been set so the View can add the new content?
What troubles me is the fact that ViewModels do have a reference to Views and should not be in charge of generating UI elements.
Thanks in advance!
Edit:
Just to clarify: in my particular case I am not trying to bind a Business Object or Collection (Model) to a UI element (e.g. Grid) which obviously could be accomplished through templates and binding. My ViewModel is retrieving a whole XAML Form from an external source and setting it as a string property available to the View. My question is: Who should be in charge of deserializing this XAML string property into a UI element and add it programmatically to the my grid once my Xaml string property in the VM is set?
This sounds to me more of like a View responsibility, not ViewModel. But the pattern as i understand it enforces to replace any code-behind logic with V-VM bindings.
I have a working solution now and I'd like to share it. Unfortunately I did not get rid of code-behind completely but it works as I expect it to. Here is how it works(simplified):
I have my simplified ViewModel:
public class MyViewModel : ViewModelBase
{
//This property implements INPC and triggers notification on Set
public string XamlViewData {get;set;}
public ViewModel()
{
GetXamlFormData();
}
//Gets the XAML Form from an external source (e.g. Database, File System)
public void GetXamlFormData()
{
//Set the Xaml String property
XamlViewData = //Logic to get XAML string from external source
}
}
Now my View:
<UserControl.Resources>
<ViewModel:MyViewModel x:Key="Model"></ViewModel:MyViewModel>
</UserControl.Resources>
<Grid DataContext="{StaticResource Model}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel>
<!-- This is the Grid used as a Place Holder to populate the dynamic content!-->
<Grid x:Name="content" Grid.Row="1" Margin="2"/>
<!-- Then create a Hidden TextBlock bound to my XamlString property. Right after binding happens I will trigger an event handled in the code-behind -->
<TextBlock Name="tb_XamlString" Text="{Binding Path=XamlViewData, Mode=TwoWay, UpdateSourceTrigger=LostFocus, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Visibility="Hidden" Loaded="tb_XamlString_Loaded" />
</StackPanel>
</Grid>
Basically I created a hidden TextBlock bound to my XAML String property in the ViewModel and I hooked its Loaded event to an event handler in the code behind of the View:
private void tb_XamlString_Loaded(object sender, RoutedEventArgs routedEventArgs)
{
//First get the ViewModel from DataContext
MyViewModel vm = content.DataContext as MyViewModel;
FrameworkElement rootObject = XamlReader.Parse(vm.XamlViewData) as FrameworkElement;
//Add the XAML portion to the Grid content to render the XAML form dynamically!
content.Children.Add(rootObject);
}
This may not be the most elegant but gets the job done. Like some people say, in MVVM there are some cases like this where little code-behind code is needed. It doesn't hurt and also part of this solution still uses the V-VM Binding principles when using the VM to retrieve and populate the XamlString property and exposing it to the View. If we would like to Unit Test the XAML parsing and loading functionality we could delegate it to a separate class.
I hope someone finds this useful!
I'm having trouble understanding what you're saying, so my answer will be based on my interpretation. You should consider posting a sample (simplified) of what you're trying to do.
1) I think you're misunderstanding what MVVM does. MVVM is mostly a binding-based pattern. Your view model should be exposing properties containing business objects and your view should just be binding to those properties. If I am misunderstanding you, and that's what you are doing, then your problem is that your view needs to be aware of when the properties get updated (after you deserialize your xaml, etc). There are two ways to do this: INotifyPropertyChanged interface on your viewmodel, or make your view model inherit from DependencyObject, and make the properties dependency properties. I won't go into details here, because this is a large subject that you should research on Google before making a decision.
2) Generally speaking, you shouldn't use click events inside your view if you're using MVVM. Instead, create properties on the view model of type ICommand (and create ICommand implementations to match, or use an implementation of DelegateCommand (google it) which will allow you to use delegates to implement the interface. The idea is, your view binds to the property and executes the handler directly inside the viewmodel.
3) If you want to push information from the viewmodel to the view, then you should create an event on the viewmodel and subscribe to it in the view, but this is a last resort, only to be used in cases like displaying a new window, etc. Generally, you should be using binding.
4) To be more specific about what you're doing, you should be binding your Grid's ItemsSource property to some property on the view model. Note, the property on the view model should be of type ObservableCollection<T> if you want to be able to add items and get instant updates.
Hope this helps.
Greetings folks!
I'm running into a problem with WPF databinding that I hope you can help out with. I'm new to WPF but an expereienced developer (VB 3.0-6.0, C#).
Here's the scenario:
I have a C# project called MasterPartsData which contains a number of classes which reprsent different types of parts (capacitor, diode, etc). They inherit from a base class called clsPart.
I have another C# WPF project which contains WPF UserControls (as well as a MainWindow) to visually represent the values stored in an individual MasterPartsData (MPD) object. I've created a private field in the usercontrol to hold the object with a getter and setter.
If I create a binding explicitly in the setter for the populated object:
_capacitor = value;
Binding binding = new Binding();
binding.Source = _capacitor;
binding.Path = new PropertyPath("C0uf");
this.txtC0uf.SetBinding(TextBox.TextProperty, binding);
(with _capacitor being the private object variable and C0uf being the property name)
the value correctly displays.
However I don't wish to have to explicitly create each binding in the code behind. My preference is to create the bindings inline in XAML, perhaps with a DataContext pointing to the object.
Unfortunately every different permutation I've tried fails to work; the text box doesn't show data.
I have a couple of suspicions:
1) The binding is correct, but the text box needs to be refreshed.
2) The binding is confused between the private variable and the properties.
3) Maybe the fact that the class is defined in a different project is causing issues.
4) I'm going mad and should check myself into an asylum before someone gets hurt. :)
Any help you can provide would be most appreciated. I'm more than happy to add more information, but didn't want to clutter the question with pages and pages of source.
With respect to your suspicions:
1) I think the default binding behavior of a TextBox is TwoWay, with a LostFocus update trigger, meaning that your UI focus will have to change to another control before the binding will update, if changes are made in the UI.
If changes are made in the code you need to raise the NotifyPropertyChanged event in order for the binding system to see it.
2) This is probably not the case, but it leaves the impression that you're trying to set bindings on your UserControl properties, which is not the way data binding was designed to be used in this particular kind of use case. What you want is to bind data from non-UI classes to dependency properties on your UserControls.
3) This will never matter, as long as your UI project has a reference to your classes.
4) This is a common reaction people have when beginning to use XAML and WPF. It's like instead of being handed a box of Legos, you just got handed an injection molding machine with insufficient instructions, isn't it?
Overall, this is a situation where you might need to examine your design; elements of the "Model-View-ViewModel" pattern will come in handy. If you're unfamiliar with this, it's a development pattern in which you introduce a "ViewModel" class, perhaps you can call it MasterPartsVM which contains an implementation of INotifyPropertyChanged.
The DataContext of your UserControl would be set to this MasterPartsVM class.
A brief code example, using some generic names. Given a ViewModel class with a small backing class that looks like this:
class PartViewModel : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public PartClass Data { get; set; }
public String SomeVMProperty
{
get { return Data.SomeProperty; }
set
{
if (Data.SomeProperty != value)
Data.SomeProperty = value;
this.PropertyChanged(this, new PropertyChangedEventArgs("SomeVMProperty"));
}
}
}
class PartClass
{
public string SomeProperty { get; set; }
}
The XAML of a basic UserControl would look like this:
<UserControl x:Class="WpfApplication1.PartUserControl"
... >
<Grid>
<TextBox Text="{Binding SomeVMProperty}" Margin="68,77,104,176" />
</Grid>
</UserControl>
To connect your data class to this UserControl, you set the UserControl's DataContext property. If you do this in code, it's a matter of having a reference to your user control and the ViewModel, and then setting the property:
MyUserControlInstance.DataContext = new PartViewModel(); // or some existing PartViewModel
That combination of code should work to produce a textbox whose Text property changes every time the SomeVMProperty property is changed.
In a basic binding scenario, if your class looks like this
public class MasterPartsData
{
private string _c0uf;
public string C0uf
{
get { return _c0uf;}
set { _c0uf = value;}
}
public MasterPartsData()
{
C0uf = "Hello World!";
}
}
your XAML would look like this
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" >
<Window.DataContext>
<local:MasterPartsData />
</Window.DataContext>
<Grid>
<TextBlock Text="{Binding Path=C0uf}" />
</Grid>
</Window>
Note, there are many different approaches to setting the DataContext, you don't necessarily just have to do it in the XAML
Also, typically your MasterDataParts class would implement INotifyPropertyChanged