Using MEF, how to export a view for an ItemsControl? - c#

enter code hereMaybe the title is not so specific.
The situation which I'm having is. I've got an ItemsControl where I insert many ViewModels, and this ItemsControl should have to show the View through DataTemplates.
So, I write these in a ResourceDictionary:
And then, I add this ResourceDictionary to the ApplicationResources.
This is so redundant and tiredsome.
I'm using MVVM also, so I was thinking if could be a way to use MEF to discover the corresponding the View that should draw. I was investigating that creating a custom attribute tag could be a good idea to simplify these redundant code, maybe adding this tag in the view telling it that this ViewModel should draw for this View, but I get lost with MEF.
The plan is to remove the ResourceDictionary.
Can you lend me a little hand?
Thanks in advance.

In my host WPF application, I added this Import:
[ImportMany("ApplicationResources", typeof(ResourceDictionary))]
public IEnumerable<ResourceDictionary> Views { get; set; }
code behind for the ResourceDictionary:
[Export("ApplicationResources", typeof(ResourceDictionary))]
public partial class ItemView : ResourceDictionary
{
public ItemView()
{
InitializeComponent();
}
}
For reference, the Xaml for the example ResourceDictionary looks like this:
<DataTemplate DataType="{x:Type local:ItemViewModel}">
...
</DataTemplate>
in WPF application, before the main window:
// Add the imported resource dictionaries
// to the application resources
foreach (ResourceDictionary r in Views)
{
this.Resources.MergedDictionaries.Add(r);
}

[System.ComponentModel.Composition.InheritedExport(typeof(ProblemView))]
public abstract class ProblemView : UserControl // or whatever your Views inherit
{
public abstract Type ViewModelType { get; }
}
[System.ComponentModel.Composition.InheritedExport(typeof(ProblemViewModel))]
public abstract class ProblemViewModel : BaseViewModel // or whatever your ViewModels inherit
{
}
// in your App class
{
[ImportMany(typeof(ProblemView))]
public ProblemView[] Views { get; set; }
[ImportMany(typeof(ProblemViewModel))]
public ProblemViewModel[] ViewModels { get; set; }
void MarryViewViewModels()
{// called during MEF composition
foreach (ProblemView view in Views)
{
foreach(ProblemViewModel vm in ViewModels)
{
if(Equals(view.ViewModelType, vm.GetType())
{// match -> inject the ViewModel
view.DataContext = vm;
break;
}
}
}
}
}
// example of usage
public partial class SomeView : ProblemView
{
public override Type ViewModelType { get { return typeof(SomeViewModel); } }
}

Let me explain you how to setup something like this. You can look for further information in official documentation
Best implementation would be using interface and duck typing.
public interface IModule {
DataTemplate Template { get; set; }
string Name{get;set;}
...
}
Then for each plugin, inherit this interface
[Export(typeof(IModule ))]
public class SampleModule : IModule {
private DataTemplate template;
public DataTemplate IModule.Template {
get { return this.teplate; }
set { this.template = value; }
}
private string name = "SamplePlugin";
public string IModule.Name{
get { return this.name ; }
set { this.name = value; }
}
...
}
Class SampleModule is in separate assembly while IModule is in common with both Application and every module assembly.
Now you need to load every module available to application. This code snippet is from window of application
...
[ImportMany]
public IEnumerable<IModule> ModulesAvailable {get;set;}
...
public void LoadModules(string path) {
DirectoryCatalog catalog = new DirectoryCatalog(path);
catalog.ComposeParts(this);
}
Now you can just use foreach loop and add them to Application Resource
foreach(IModule module in ModulesAvailable) {
Application.Current.Resources.Add(module.Template, module.Name);
}
This is just concept and code is not tested.
I ssed MEF in my high-school final project I did few months ago, so you could take a look at my code. It is spreadsheet application with formula support where all operations and operands are loaded as plugins so it is very flexible.

Related

C# Wpf mvvm keep multiple ViewModels with model sychronized

I've data architecture issues. My goal should be to have bidirectional data communication
between ViewModels and the Model classes. I've one window with different usercontrols. Each usercontrol
has it's own data, but some properties are shared between these.
For each ViewModel I implemented two functions for synchronize the model and the viewmodel.
The model should kept updated, so I implemented in the PropertyChanged event the method call SyncModel.
This is so far not so nice, because when I call the constructor the method call chain is:
constructor -> SyncViewModel -> Property setter -> PropertyChanged -> SyncModel
Here is some sample code to understand my problem better:
public class SampleModel
{
public string Material { get; set; }
public double Weight { get; set; }
public double Length { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public object SharedProperty { get; set; }
}
public class SampleViewModelA : AbstractViewModel
{
public string Material
{
get
{
return _Material;
}
set
{
if (value != _Material)
{
_Material = value;
OnPropertyChanged(nameof(Material));
}
}
}
public double Weight
{
get
{
return _Weight;
}
set
{
if (value != _Weight)
{
_Weight = value;
OnPropertyChanged(nameof(Weight));
}
}
}
public object SharedProperty
{
get
{
return _SharedProperty;
}
set
{
if (value != _SharedProperty)
{
_SharedProperty = value;
OnPropertyChanged(nameof(SharedProperty));
}
}
}
public SampleViewModelA(SampleModel Instance) : base(Instance) { }
public override void SyncModel()
{
//If I wouldn't check here, it would loop:
//constructor -> SyncViewModel -> Property setter -> PropertyChanged -> SyncModel
if (Instance.Material == Material &&
Instance.Weight == Weight &&
Instance.SharedProperty == SharedProperty)
return;
Instance.Material = Material;
Instance.Weight = Weight;
Instance.SharedProperty = SharedProperty;
}
public override void SyncViewModel()
{
Material = Instance.Material;
Weight = Instance.Weight;
SharedProperty = Instance.SharedProperty;
}
private string _Material;
private double _Weight;
private object _SharedProperty;
}
public class SampleViewModelB : AbstractViewModel
{
//Same like SampleViewModelA with Properties Length, Width, Height AND SharedProperty
}
public abstract class AbstractViewModel : INotifyPropertyChanged
{
//All ViewModels hold the same Instance of the Model
public SampleModel Instance { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public AbstractViewModel(SampleModel Instance)
{
this.Instance = Instance;
SyncViewModel();
}
protected virtual void OnPropertyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
SyncModel();
}
public abstract void SyncModel();
public abstract void SyncViewModel();
}
The real problem is, that the SharedProperty need to be updated between the SampleViewModelA and the SampleViewModelB. First I thought the Observer Pattern could help me, but the SharedProperties are to various to make it work with generic interfaces. Then I thought a datacontroller with change events could help me like this
public class SampleDataController
{
public SampleModel Instance { get; set; }
public delegate void SynchronizeDelegate();
public event SynchronizeDelegate SynchronizeEvent;
public void SetSharedProperty(object NewValue)
{
if (Instance.SharedProperty != NewValue)
{
Instance.SharedProperty = NewValue;
SynchronizeEvent?.Invoke();
}
}
}
If it would do it like this my AbstractViewModel would only communicate with the controller instead of the instance. The SyncModel function would call methods like SetSharedProperty instead of directly access.
The MainViewModel code could look like this.
public class SampleMainViewModel
{
public SampleViewModelA ViewModelA { get; set; }
public SampleViewModelB ViewModelB { get; set; }
public SampleDataController Controller { get; set; }
public SampleMainViewModel()
{
ViewModelA = new SampleViewModelA(Controller);
ViewModelB = new SampleViewModelB(Controller);
Controller.SynchronizeEvent += ViewModelA.SyncViewModel;
Controller.SynchronizeEvent += ViewModelB.SyncViewModel;
}
}
This would cause the problem, that the source for the SynchronizeEvent call is also
subscribed to the event itself. This wouldn't cause a infinity loop because I check if
values are equal to the new state, but it seems very ugly to me. There must be a better
way than this.
In my project I have 8 ViewModels and multiple model classes where I need to sychronize the data with
different shared properties.
I'm thankful for any help and hope the problems are so far understandable.
You already use a SampleMainViewModel which is composed of the other view model classes SampleViewModelA and SampleViewModelB.
Now all you have to do is to move all the properties that are shared between the view models/views (like the SharedProperty, but also Material and Weight) to the composed SampleMainViewModel or to a shared class in general. This way all your controls can bind to the same data source.
Also the communication between Model --> View Model should only take place via events: the Model can notify the View Model by exposing e.g., a DataChanged event. There is no real bi-directional communication/dependency between Model and View Model. That's the main characteristic of MVVM: the uni-directional dependency of the participating components - realized by implementing events, commands and especially by utilizing data binding.
The follwoing example shows how you bind your controls to shared properties and to unshared properties (those that are attributes of the specialized view model classes).
MainWindow.xaml
<Window>
<Window.DataContext>
<SampleMainViewModel />
</Window.DataContext>
<StackPanel>
<UserControlA Material="{Binding Material}"
SharedProperty="{Binding SharedProperty}"
UnsharedPropertyA="{Binding ViewModelA.UnsharedPropertyA}" />
<UserControlB Material="{Binding Material}"
SharedProperty="{Binding SharedProperty}"
UnsharedPropertyB="{Binding ViewModelB.UnsharedPropertyB}" />
</StackPanel>
</Window>
SampleMainViewModel.cs
public class SampleMainViewModel : INotifyPropertyChanged
{
public SampleViewModelA ViewModelA { get; }
public SampleViewModelB ViewModelB { get; }
/* Properties must raise INotifyPropertyChanged.PropertyChanged */
public string Material { get; set; }
public double Weight { get; set; }
public object SharedProperty { get; set; }
// Example initialization
public SampleMainViewModel(SomeModelClass someModelClass)
{
this.ViewModelA = new SampleViewModelA();
this.ViewModelB = new SampleViewModelB();
this.Material = someModelClass.Material;
this.Weight = someModelClass.Weight;
this.SharedProperty = someModelClass.SharedProperty;
someModelClass.DataChanged += UpdateData_OnDataChanged;
}
private void UpdateData_OnDataChanged(object sender, EventArgs args)
{
var someModelClass = sender as SomeModelClass;
this.Material = someModelClass.Material;
this.Weight = someModelClass.Weight;
this.SharedProperty = someModelClass.SharedProperty;
}
}
SampleViewModelA.cs
public class SampleViewModelA : INotifyPropertyChanged
{
public object UnsharedPropertyA { get; set; }
}
SampleViewModelB.cs
public class SampleViewModelB : INotifyPropertyChanged
{
public object UnsharedPropertyB { get; set; }
}
"Your suggestion cause the disadvantage, that my separated ViewModels
are no longer encapsulated. And if I would move all my code with
shared properties to the MainViewModel, the class would end up very
large"
To address your comment: if you insist in having a view model per each control including duplicating properties etc., then you must take a different approach.
Also moving the shared/duplicate code out of your view models does not break encapsualtion - assuming that those classes do not contain duplicated code only.
But note that a view model per each control is not recommended. You have a view/page - an aggregation of multiple controls - which has a defined data context. All controls in this view share the same data context - usually, as views are structured context related.
That's why the FrameworkElement.DataContext is inherited by default.
Having a view model for each control makes things overly complicated and leads to a lot of duplicated code - and not only duplicate properties like in your example. You will find yourself duplicating logic too. And talking about testability, if you duplicate logic you will duplicate unit tests too.
This is because you are dealing with the same data and the same model classes.
You usually extract duplicate code to a separate class that is the referenced by the types that depend on this duplicate code. Refactoring your view model classes with this "no duplicate code" policy in mind would end up moving the "shared" properties to a separate class. Since we are talking about the data context of the same view, this separate class would be the view model class that is assigned to the DataContext of the page. I'm trying to say that your approach is doing the exact opposite: you duplicate code (and call it encapsulation). If the class ends up being very large because it contains a lot of properties then you may review your UI design - maybe you should split your big page into more pages with more concise content. This may will improve UX too.
Generally, there is nothing wrong with having a view model with some more properties. If your view model class contains lots of logic too, you can extract this logic to separate classes.
You can still use the pattern of the previous example, which is to listen to data changed events of the Model.
Either you implement a very general event like the above DataChanged event or several more specialized events like a MaterialChanged event. Also make sure to inject the same model instances into each view model.
The following example shows how you can have multiple different view model classes that expose the same data, where all these view model classes update themselves by observing their model classes:
MainWindow.xaml
<Window>
<Window.DataContext>
<SampleMainViewModel />
</Window.DataContext>
<StackPanel>
<UserControlA DataContext="{Binding ViewModelA}"
Material="{Binding Material}"
Weight="{Binding Weight}"
SharedProperty="{Binding SharedPropertyA}" />
<UserControlB DataContext="{Binding ViewModelB}"
Material="{Binding Material}"
Weight="{Binding Weight}"
SharedProperty="{Binding SharedPropertyB}" />
</StackPanel>
</Window>
SampleMainViewModel.cs
public class SampleMainViewModel : INotifyPropertyChanged
{
public SampleViewModelA ViewModelA { get; }
public SampleViewModelB ViewModelB { get; }
// Example initialization
public SampleMainViewModel()
{
var sharedModelClass = new SomeModelClass();
this.ViewModelA = new SampleViewModelA(sharedModelClass);
this.ViewModelB = new SampleViewModelB(sharedModelClass);
}
}
SampleViewModelA.cs
public class SampleViewModelA : INotifyPropertyChanged
{
/* Shared properties */
public string Material { get; set; }
public double Weight { get; set; }
public object SharedProperty { get; set; }
private SomeModelClass SomeModelClass { get; }
// Example initialization
public SampleViewModelA(SomeModelClass sharedModelClass)
{
this.SomeModelClass = sharedModelClass;
this.Material = this.SomeModelClass.Material;
this.Weight = this.SomeModelClass.Weight;
this.SharedProperty = this.SomeModelClass.SharedProperty;
// Listen to model changes
this.SomeModelClass.DataChanged += UpdateData_OnDataChanged;
this.SomeModelClass.MaterialChanged += OnModelMaterialChanged;
}
// Example command handler to send dat back to the model.
// This will trigger the model to raise corresponding data chnaged events
// to notify listening view model classes that new data is available.
private void ExecuteSaveDataCommand()
=> this.SomeModelClass.SaveData(this.Material, this.Weight);
private void OnModelMaterialChanged(object sender, EventArgs args)
{
var someModelClass = sender as SomeModelClass;
this.Material = someModelClass.Material;
}
private void UpdateData_OnDataChanged(object sender, EventArgs args)
{
var someModelClass = sender as SomeModelClass;
this.Weight = someModelClass.Weight;
this.SharedProperty = someModelClass.SharedProperty;
}
}
SampleViewModelB.cs
public class SampleViewModelB : INotifyPropertyChanged
{
/* Shared properties */
public string Material { get; set; }
public double Weight { get; set; }
public object SharedProperty { get; set; }
private SomeModelClass SomeModelClass { get; }
// Example initialization
public SampleViewModelB(SomeModelClass sharedModelClass)
{
this.SomeModelClass = sharedModelClass;
this.Material = this.SomeModelClass.Material;
this.Weight = this.SomeModelClass.Weight;
this.SharedProperty = this.SomeModelClass.SharedProperty;
// Listen to model changes
this.SomeModelClass.DataChanged += UpdateData_OnDataChanged;
this.SomeModelClass.MaterialChanged += OnModelMaterialChanged;
}
// Example command handler to send dat back to the model.
// This will trigger the model to raise corresponding data chnaged events
// to notify listening view model classes that new data is available.
private void ExecuteSaveDataCommand()
=> this.SomeModelClass.SaveData(this.Material, this.Weight);
private void OnModelMaterialChanged(object sender, EventArgs args)
{
var someModelClass = sender as SomeModelClass;
this.Material = someModelClass.Material;
}
private void UpdateData_OnDataChanged(object sender, EventArgs args)
{
var someModelClass = sender as SomeModelClass;
this.Weight = someModelClass.Weight;
this.SharedProperty = someModelClass.SharedProperty;
}
}
A variation of the first solution (which aimes to eliminate duplicate code) is to refactor your binding source, that exposes the shared properties, by extracting those properties to new classes according to their responsibilities.
For example, you can have your MainViewModel expose a MaterialViewModel class that encapsulates material related properties and logic. This way MaterialViewModel can be mnade available globally.
Given that you follow the one-data-context-class per view principle, you can limit the scope of the shared properties to specific pages by having only their specific view model classes expose the same MaterialViewModel instance:
MainWindow.xaml
<Window>
<Window.DataContext>
<MainViewModel />
</Window.DataContext>
<StackPanel>
<MaterialControl DataContext="{Binding MaterialViewModel}"
Material="{Binding Material}"
Weight="{Binding Weight}" />
<UserControlB ... />
</StackPanel>
</Window>
MainViewModel.cs
public class MainViewModel : INotifyPropertyChanged
{
// Since defined in 'MainViewModel' the properties of 'MaterialViewModel'
// are globally shared accross pages
public MaterialViewModel MaterialViewModel { get; }
/* View model classes per page */
public ViewModelPageA PageViewModelA { get; }
// If 'ViewModelPageB' would expose a 'MaterialViewModel',
// you can limit the visibility of 'MaterialViewModel' to the 'ViewModelPageB' DataContext exclusively
public ViewModelPageB PageViewModelB { get; }
// Example initialization
public SampleMainViewModel()
{
var sharedModelClass = new SomeModelClass();
this.MaterialViewModel = new MaterialViewModel(sharedModelClass);
this.ViewModelPageA = new ViewModelPageA(sharedModelClass);
// Introduce the MaterialViewModel to a page specific class
// to make the properties of 'MaterialViewModel' to be shared inside the page only
this.ViewModelPageB = new ViewModelPageB(sharedModelClass);
}
}
MaterialViewModel.cs
public class MaterialViewModel : INotifyPropertyChanged
{
public string Material { get; set; }
public double Weight { get; set; }
private SomeModelClass SomeModelClass { get; }
// Example initialization
public MaterialViewModel(SomeModelClass sharedModelClass)
{
this.SomeModelClass = sharedModelClass;
this.Material = this.SomeModelClass.Material;
this.Weight = this.SomeModelClass.Weight;
// Listen to model changes
this.SomeModelClass.MaterialDataChanged += OnModelMaterialChanged;
}
// Example command handler to send dat back to the model.
// This will also trigger the model to raise corresponding data chnaged events
// to notify listening view model classes that new data is available.
// It can make more sense to define such a command in the owning class,
// like SampleMainViewModel in this case.
private void ExecuteSaveDataCommand()
=> this.SomeModelClass.SaveData(this.Material, this.Weight);
private void UpdateData_MaterialChanged(object sender, EventArgs args)
{
var someModelClass = sender as SomeModelClass;
this.Material = someModelClass.Material;
this.Weight = someModelClass.Weight;
}
}

Accessing ViewModel by inheriting a View in MvvmCross

I want to access my ViewModel from a class which is not the View. Is it OK if I do the following? Is this breaking the pattern?
namespace MyApp
{
public class GameView
{
protected new GameViewModel ViewModel
{
get { return (GameViewModel)base.ViewModel; }
}
}
}
// Derived class
namespace MyApp
{
public class InAppPurchase: GameView
{
public void BuyCoins()
{
ViewModel.PurchasedCoins += ViewModel.CoinsForSale;
}
}
}
If you want to access a ViewModel from whichever place you want you might want to send messages (MvxMessage) and handle them within the ViewModel (publish/subscribe with IMessenger). This is the proper way to communicate between ViewModels or ViewModels and other components like services in the Mvvm pattern.

How to access App.Current properties in Windows Universal Apps

I am trying to bind to App.Current.XYZ properties in my View, however this doesn't seem to be possible, here's an example of what I have:
sealed partial class App : Application
{
public MyClassType MyClass { get; private set; }
...
And here is the View:
<Page ...
DataContext="{Binding MyClass, Source={x:Static Application.Current}}">
So, this isn't possible because x:Static is no longer supported in Windows Universal (or WinRT), so I have tried exposing the application property through a property in the code-behind, like this:
public MyClassType MyClass
{
get
{
return Application.Current.MyClass;
}
}
This doesn't work either! There is no intellisense for MyClass, it's completely missing. I have also tried App.Current and still no luck.
Any ideas why my property is not visible through Application.Current.? Or if there is any way I can bind to this property directly through XAML?
You need to cast Application.Current to your type like so:
public MyClassType MyClass
{
get
{
return ((App)Application.Current).MyClass;
}
}
Here is something that may work for you:
Create two classes:
public class MyDataProvider
{
private static readonly MyDataContainer _myDataContainer = new MyDataContainer();
public MyDataContainer MyDataContainer { get { return _myDataContainer; } }
}
public class MyDataContainer
{
public MyClassType MyClass { get; private set; }
...
}
Then in App.xaml define this static resource:
<resources:MyDataProvider x:Key="MyDataProvider"/>
Now you should be able to use data binding like this in your XAML code:
Attribute="{Binding MyDataContainer.MyClass, Source={StaticResource MyDataProvider}}"
In your case you could tweak the code so that MyDataContainer is actually your app:
public class MyDataProvider
{
public Application App { get { return Application.Current; } }
}
and write your data binding like this:
Attribute="{Binding App.MyClass, Source={StaticResource MyDataProvider}}"
In general however I would not use the App class as a provider for sources for data binding. For separation of concerns I would use something like I have above with MyDataProvider and MyDataContainer

Ninject Form Clarification

I have a ModuleLoader : NinjectModule which is where I bind everything.
Firstly I use
Bind<Form>().To<Main>();
to Bind a System.Windows.Forms.Form to my Main form.
Is this correct?
Secondly in the Program.cs I use this:
_mainKernel = new StandardKernel(new ModuleLoader());
var form = _mainKernel.Get<Main>();
Where _mainKernel is a ninject standard kernel.
Then I use Application.Run(form)
Is this correct?
I'm unsure as to what to bind together when it comes to Windows.Forms.
Thanks for any help.
You shouldn't really be binding to System.Windows.Forms.Form. Ninject is primarily meant for binding interfaces to concrete types so that you can pass around dependencies as interfaces and switch out the concrete implementation at runtime/during tests.
If you just want to use Ninject to create your Form in this way though, you'd simply use Bind<MyForm>().ToSelf() then do kernel.Get<MyForm>(). If you are requesting the concrete type directly though and it doesn't take any dependencies, there's not much point in using Ninject to initialise it.
In your situation, if your form implements an interface then you would do: Bind<IMainForm>().To<MainForm>() and request the interface type from Ninject. Usually your interface shouldn't be bound to the concept of a "form" though, it should be agnostic of the implementation (so later you could produce a CLI and website version and simply swap the Ninject bindings).
You could use the Model-View-Presenter design pattern (or a variant) to achieve this like:
public interface IUserView
{
string FirstName { get; }
string LastName { get; }
}
public class UserForm : IUserView, Form
{
//initialise all your Form controls here
public string FirstName
{
get { return this.txtFirstName.Text; }
}
public string LastName
{
get { return this.txtLastName.Text; }
}
}
public class UserController
{
private readonly IUserView view;
public UserController(IUserView view)
{
this.view = view;
}
public void DoSomething()
{
Console.WriteLine("{0} {1}", view.FirstName, view.LastName);
}
}
Bind<IUserView>().To<UserForm>();
Bind<UserController>().ToSelf();
//will inject a UserForm automatically, in the MVP pattern the view would inject itself though
UserController uc = kernel.Get<UserController>();
uc.DoSomething();

Auto-generate a Wrapper class in C# using Composition

This should be simple, but I can't find anything out there.
I have a class in one assembly (a shared library -- it's a set of proxy classes for a Web Service)
I have a class in another assembly (web project)
There is a class called "Profile" which is in the Proxy assembly.
There is a set of classes that "use" a Profile in the web project.
When there is no user logged in, a GenericProfile is used.
Following the principle of "separation of concerns"....
The Proxy assembly is used by other projects and is concerned with only the Web Service stuff.
The web project just has web stuff in there
However, now there is this need for a "GenericProfile" -- think of it as "Guest User".
The logical thing to do is to build an interface called IProfile and cause both classes to derive from it. But that would create a circular dependency between the two assemblies.
The next best idea is to create a 3rd assembly called MyInterfaces and put the IProfile in there -- but that causes a violation of the Separation of Concerns principle in my opinion. At the very least, one instance of this problem seems too small a reason to spring for making an extra module in my solution.
Enter the wrapper class -- or the Composite wrapper class (whatever you want to call it)
I'm looking for something that ends up generating something like this below. Is there a tool or Visual Studio extension that will do it? Maybe a .tt file?
namespace WebProject
{
public interface IProfile
{...}
class MyWrapperClass : IProfile
{
Proxy.Profile _profile;
public MyWrapperClass(Proxy.Profile proxy)
{
_profile = proxy;
}
public string IProfile.Property1{ get { return _profile.Property1; } set { _profile.Property1 = value; } }
public string IProfile.Property2{ get { return _profile.Property2; } set { _profile.Property2 = value; } }
public string IProfile.Property3{ get { return _profile.Property3; } set { _profile.Property3 = value; } }
}
}
In Visual Studio 2017
Create your class
namespace WebProject
{
public interface IProfile
{...}
class MyWrapperClass : IProfile
{
private IProfile _wrapped;
}
}
locate your cursor on the IProfile of class MyWrapperClass : IProfile and hit ctrl-. select Implement interface through _wrapped. No need for ReSharper.
I don't completely understand what you are trying to accomplish, but below is how I would generate a wrapper class with ReSharper.
Personally if my employer doesn't want to pay for ReSharper, I buy it. It makes me a better developer. I strongly suggest you consider acquiring it as an investment in your career. Anti-Disclaimer - I am not at all connected with or sponsored by ReSharper.
add the interface to the class you wish to be the wrapping class
class MyWebElement : IWebElement { }
Find/Click "Delegate implementation of "YourInterfaceHere" to a new field
Select your options
Click finish and enjoy your new class
class MyWebElement : IWebElement
{
private IWebElement _webElementImplementation;
public IWebElement FindElement(By #by)
{
return _webElementImplementation.FindElement(#by);
}
public ReadOnlyCollection<IWebElement> FindElements(By #by)
{
return _webElementImplementation.FindElements(#by);
}
public void Clear()
{
_webElementImplementation.Clear();
}
public void SendKeys(string text)
{
_webElementImplementation.SendKeys(text);
}
public void Submit()
{
_webElementImplementation.Submit();
}
public void Click()
{
_webElementImplementation.Click();
}
public string GetAttribute(string attributeName)
{
return _webElementImplementation.GetAttribute(attributeName);
}
public string GetCssValue(string propertyName)
{
return _webElementImplementation.GetCssValue(propertyName);
}
public string TagName
{
get { return _webElementImplementation.TagName; }
}
public string Text
{
get { return _webElementImplementation.Text; }
}
public bool Enabled
{
get { return _webElementImplementation.Enabled; }
}
public bool Selected
{
get { return _webElementImplementation.Selected; }
}
public Point Location
{
get { return _webElementImplementation.Location; }
}
public Size Size
{
get { return _webElementImplementation.Size; }
}
public bool Displayed
{
get { return _webElementImplementation.Displayed; }
}
}
If I was faced with your original problem, I'd put IProfile in your shared library, alongside the Profile class. Your web project can then implement the GenericProfile class that it needs, nothing else needs to know about it, and other clients of the library can do the same as needed. It would also be useful for testing the library.

Categories