I'm making a media player program and I have the following interface:
public interface IMediaService
{
void Play();
}
Would it be more appropriate to inherit the interface in the view where the MediaElement control resides and access it directly in the implementation of the methods or rather have it in a separate class like this:
public class MediaPlayer : IMediaService
{
private MediaElement _mediaElement;
public MediaPlayer(MediaElement mediaElement)
{
_mediaElement = mediaElement;
}
public void Play()
{
_mediaElement.Play();
//...
}
}
vs inheriting it in the view:
public partial class MainWindow : IMediaService
{
public MainWindow()
{
InitializeComponent();
}
void IMediaService.Play()
{
Player.Play();
//..
}
}
I'm not using MVVM, but those methods might be used as bindings through commands.
The problem I see in the second approach is that my view class will get cluttered really fast.
I'm open to any alternative solutions that I haven't mentioned, this is just what I've come up with atm.
Would it be more appropriate to inherit the interface in the view where the MediaElement control resides and access it directly in the implementation of the methods or rather have it in a separate class like this:
It doesn't really matter as far as MVVM is concerned. There is no right or wrong really. It's depends on the developer's personal preference. If you don't want to pollute your view, you create a separate class. If you don't mind adding some methods to your view, you don't.
The benefit of using a seperate class is that you may reuse it for several different views/MediaElement.
But the view model only cares about the interface itself, i.e. it has no dependency upon the actual implementation of it.
Related
I have tried to use MVVM Light messaging to communicate between different ViewModels, but with time it gets quite messy and hard to understand from where and where to all the messages are flying so I wanted to ask about other solution how to communicate between ViewModels using Interfaces. The provided code works well, but I am not sure if Interfaces are mended to be used this way..
So here I have defined interface and class that implements it:
public interface ISelectProject
{
event EventHandler<SelectedProjectEventArgs> MessageReceived;
void ProjectSelected(...);
}
public class SelectProject : ISelectProject
{
public event EventHandler<SelectedProjectEventArgs> MessageReceived;
public void ProjectSelected(..)
{
MessageReceived?.Invoke(this,new SelectedProjectEventArgs(...));
}
}
Afterward, I inject SelectProject class into these tree ViewModels using constructor injection(code not shown here).
Then in ViewModelA I invoke MessageReceived event and all the other ViewModels subscribe to the event.
public class ViewModelA : ViewModelBase
{
public ViewModelA(ISelectProject selectProject)
{
_selectProject = selectProject;
_selectProject.ProjectSelected;
}
}
public class ViewModelB : ViewModelBase
{
public ViewModelB(ISelectProject selectProject)
{
_selectProject = selectProject;
_selectProject.MessageReceived += (s, data) =>
{
...
};
}
}
public class ViewModelC : ViewModelBase
{
public ViewModelC(ISelectProject selectProject)
{
_selectProject = selectProject;
_selectProject.MessageReceived += (s, data) =>
{
...
};
}
}
My questions are:
1) Does this somehow violate MVVM practice?
2) Is it considered a good practice to communicate between ViewModels like this?
3) Does this solution introduce any risks, for example, memory leaks, etc?
Thank you!
1) Does this somehow violate MVVM pratice?
No. ISelectedProject is basically a shared service. A shared service is a class that provides functionality to several components in a decoupled way. Please refer to this link for more information and an example.
2) Is it considered a good practice to communicate between viewModels like this?
Yes, if you want to keep them decoupled from each other.
3) Does this solution introduces any risks, for example memory leaks, etc.
Using a shared service doesn't introduce any memory leaks by itself. But if your shared service exposes an event and a view model subcribes to this one without unsubscribing from it, the service will keep the view model alive.
So, after some searching on stackoverflow and on google, I did find a few answers on my question but didn't know how to actually implement it for my own use. Which is why I will ask it again here.
Because of my inexperience with wpf combined with that I have never used anything closely resembling it, I made the mistake of going into creating a class diagram which now(maybe) has to be completely changed.
I wasn't sure of how I would go about creating custom blocks, but kind of mapped out the behaviour I needed.
close example of what I was trying to work towards
After realizing I made a mistake after finding out about userControls I tried implementing this into my project.
This is a test I made:
base class
namespace TestTest
{
public abstract partial class TestBase : UserControl
{
public TestBase()
{
InitializeComponent();
}
public virtual void doSomething()
{
Console.WriteLine("ITS WORKING");
}
}
}
Child class
namespace TestTest
{
public partial class TestExtend : TestBase
{
public TestExtend()
{
InitializeComponent();
}
}
}
after this I tried to add testExtended to a canvas but it gave the type error: testExtended is not a UIElement
class diagram (both UIStackBlock and UISideBlock inherit from UIBlock and UIBlock is free to inherit from anything)
I will still need the inheritance I created for filtering out certain blocks(mostly on UIOperations)
Now my real question is, how would I go about adding multiple xaml files and defining the look of them in there without getting in the way of the current inheritance hierarchy I have in place. Or is this even achievable?
Again, I know this is a duplicate.
You can either write DataTemplates that are adjusted per DataType.
Or, you could leave behind inheriting from UserControl(just Inherit from Control or ContentControl) and make each of them a custom control with its unique style and Template.
Given a basic C# library, how do I implement functions of this library into my WPF application to handle appropriately the concepts of Binding and Commands?
I mean, need I write some own wrappers for these library classes in order to implement interfaces such as ICommand or should this be done directly in the library itself?
Some code to get my question more comprehensible:
From the library:
public class Item
{
public string Name { get; set; }
public void DoSomething() { throw new NotImplementedException; }
}
I want to implement the function DoSomething() in my XAML markup without any line of code in that .cs file since that is, from what I've read, the best practice.
(Assuming that an instance of Item is bound to the control)
<Button Command="{Binding DoSomething}"/>
Well, in order to do so, I need to implement the interface ICommand and create a command, but that is, as stated above, unclear to me since I'm using a library here.
Should I write my own Wrapper for the Item class of the API and implement the ICommand interface or is there any other way to archieve this? I've written the library by myself so changes are possible. I'm just not entirely sure about changing the library because if I do so, it is (possibly) bound to WPF.
Hi there if anything your ViewModel should handle any requests on your Model that's it's sole purpose, to get these things to work you need ICommand and if you want some more info here is link with a tutorial on RoutedCommands. If you have your Model and ViewModel defined then you can easily assign tasks to the particular Model through its VM.
P.S. I think you could treat your library as a Model and write a "wrapper" ViewModel to handle operations on it. HTH
UPDATE
Consider following:
class libClass
{
void method()
{
//do something here
}
}
code above would be your model and if you want it to be more readable you could do it this way
class libModel
{
private libClass _libClass;
public libClass LibClass { get; set; }
}
Note
You could implement INotfiyPropertyChanged in your Model to handle any changes if needed of course.
now in your VM how you use the Model
class ViewModel
{
private libModel _libModel;
public libModel LibModel { get; set; }
//after you set up your RoutedCommands
//I declare method within my VM to handle the RoutedCommands don't know
//if it works when you use Property Method
void VMMethod()
{
//use VM's property to invoke desired method from your lib
}
}
and voila! ready "wrapper" for your class with implementation in your VM.
Tip
If you want to know how to do the RoutedCommands here is a link to a tutorial.
Suppose I have 3 classes to handle all database related requests:
public class DB_A{}
public class DB_B{}
public class DB_C{}
and I got 2 windows to interact with user:
window1.xaml;window1.xaml.cs;
window2.xaml;window2.xaml.cs
as window1 & window2 need to interact with database, they need to use functions from previous 3 classes, I created a class DataHandler:
public class DataHandler
{
public DB_A a;
public DB_B b;
public DB_C c;
public DataHandler()
{
a = new DB_A();
b = new DB_B();
c = new DB_C();
}
//some functions... ...
}
now the class DataHandler can handle all database related request, and now i need to pass a instant of DataHandler to both window1 and window2.
I tried to re-write the constructor for both window1 and window2 with parameter, but it does not allow me to do that. After google i know that WPF window form does not allow constructor with parameter.
Is there any way to pass my DataHandler to the two window form classes?
Make DataHandler a singleton, and let the window classes access it.
public class DataHandler
{
//singleton instance
static DataHandler _instance = new DataHandler ();
public DataHandler Instance
{
get { return _instance; }
}
};
Then,
public partial class Window1 : Window
{
DataHandler _dataHandler;
public Window1()
{
InitializeComponent();
_dataHandler = DataHandler.Instance;
}
}
Similarly, write other Window class.
Or even better is, apply some variant of MVP pattern, most likely, MVVM. Read these articles:
Composite Guidance for WPF : MVVM vs MVP
WPF patterns : MVC, MVP or MVVM or…?
Model-View-Presenter Pattern
Model View Presenter
Yes, you can, there are multiple ways to do that,
you make your DataHandler a singleton. ( I do not like this one)
add a public static property to app.xaml.cs that has an instance of your DataHandler class and in your Windows’ constructor take that from app. (it’s a better approach)
add a ViewModel and let that view model present data to both Windows. (I prefer this one!)
If you need an example let me know which one works for you and I will provide one.
Can't you make the DataHandler class to singleton and use it's methods on wherever you want, without re-instantiating the class?
You can have parameters on your Window constructor. Alternatively you could pass it in through a property, set your DataHandler object to a public static property somewhere, or even just make your DataHandler a static class.
There are any number of ways to accomplish this.
You can make DataHandler a singleton.
Since DataHandler has a parameterless constructor, you can create it in the application's resource dictionary, and let objects use FindResource to get it.
One pattern that you'll see pretty commonly, in implementations using the MVVM pattern, is that the view models contain a reference to shared objects, and windows get access to them through binding, though I doubt very much that you're using MVVM.
I've got a WPF MVVM application. One of my views has a user control that needs to be customizable for each installation. It's basically a sketch of the customers installation with some labels etc. bound to a viewmodel.
Now my problem is that this user control is different on each site/installation. One approach is to load the xaml from a file/database runtime using a xaml reader. This works but since my viewmodel is generic I have to bind to methods instead of properties and I can't load a xaml with objectdataprovider.
Currently I'm trying to see if MEF can be used so that I can create the user control as a plug-in. So what I'm looking for now is this:
how can I define a user control with view/view model that exports a contract for MEF
How can my parent view (in my wpf app) load the imported user control
Any tips are appreciated, or maybe someone has a different approach?
I suggest you look into Prism in combination with MEF. It has a notion of Modules (plug-ins in your case) and Regions (mechanism of dynamically loading views).
You will be able to export a view using a simple attribute:
[ViewExport(RegionName = RegionNames.MyRegion)]
public partial class MyView : UserControl {
public MyView() {
this.InitializeComponent();
}
[Import]
public MyViewModel ViewModel {
set { DataContext = value; }
}
}
[Export]
public class MyViewModel : ViewModelBase
[
...
}
And in your main application XAML you will be able to import the plugin's views like this:
<ContentControl Regions:RegionManager.RegionName="{x:Static Infrastructure:RegionNames.MyRegion}"/>
One thing I'd consider is the design where you need to install a custom View for each installation. Instead, I'd look to make that View more generic. This will make your design more simple in the long run. Plus, you are setting up for a maintenance nightmare with a different installation for every installed base.
It's a little difficult to tell from your description, but it sounds like the View is a collection of some kind of an object (some kind of drawing with a label or something). Therefore, I'd treat it as such.
I'd create a base abstract class that describes what every object that your View could show. Since I don't have more information, I'll call this thing a "DrawingObject" for lack of a better term. This class would hold all information common to all objects in your View. Note that ObservableItem is a class that implements INotifyPropertyChanged, and SetProperty sets the value in that base class and raises PropertyChanged.
abstract class DrawingObject : ObservableItem
{
Point mPosition;
public Point Position
{
get { return mPosition; }
set { SetProperty("Position", ref mPosition, value); }
}
String mLabelText;
public String LabelText
{
get { return mLabelText; }
set { SetProperty("LabelText", ref mLabelText, value); }
}
}
Then, derive more custom objects from that base class:
class Counter : DrawingObject
{
public Counter() : base()
{
}
}
Your ViewModel would then just have a collection of these objects, using the base class. The set may be private, because you will probably get the objects from someplace in the constructor (i.e. the database, or a flat file, or...)
class ViewModel : ObservableItem
{
public ViewModel() : base()
{
// Call something to populate DrawingObjects property
PopulateDrawingObjects();
}
ObservableCollection<DrawingObject> mDrawingObjects =
new ObservableCollection<DrawingObject>();
public ObservableCollection<DrawingObject> DrawingObjects
{
get { return mDrawingObjects; }
private set { mDrawingObjects = value; }
}
}
Then, your View would bind to this collection and draw them appropriately (I'll leave that as an exercise for the implementer).
One extension that I didn't show is that the DrawingObject may need to implement the appropriate serialization functionality.
Obviously, this is a rough sketch of the design, and may have a couple of errors (I did it from my head), but hopefully it's enough to go on.