I'm trying to create a JIT pivotviewer and I have been kinda struggling a bit. Could someone clear my confusion on how the cxml is dynamically created? Also how should the information be set up for me to request it? I currently have it sitting inside of my database, do I need to create an xml doc for it to load from or can it pull it straight from the db?
For building a JIT PivotViewer collection you start by downloading the JIT example built by Microsoft.
Look around in the solution, when getting started the most important bit is the CollectionFactories project. To create a collection using data from your database you need to create your custom CollectionFactory.
Your custom collectionfactory extends the CollectionFactoryBase class:
class MyCustomCollection : CollectionFactoryBase
the class needs to implement the MakeCollection method, all this method has to do is create an instance of Collection class and add CollectionItems to it.
public override PivotServerTools.Collection MakeCollection(CollectionRequestContext context) {
return MakeCollection();
}
private static PivotServerTools.Collection MakeCollection() {
PivotServerTools.Collection collection = new PivotServerTools.Collection();
collection.Name = "MyImages";
ItemImage[] fileList = ImageListFromDatabase();
foreach (ItemImage image in fileList) {
collection.AddItem(image.Name, image.ImageUrl.ToString(), image.Description, image, null);
}
return collection;
}
Now to use this collection and see it in action, you need to provide the name of the collection for the PivotViewer Silverlight application (PivotServer) in the solution:
default.aspx
<param name="initParams" value="cxml=MyImages.cxml" />
Related
I'm planning to create some pages which display data from an external SQL Server with Orchard CMS. It looks like I need to write a new module to implement this function. Is there any example or idea to implement this requirement?
Yes, you will need to write a new module, which provides a new content part and a content part driver. That driver will be responsible for fetching the data from the external SQL Server, which you will set to a property on the shape you will be returning from your driver. The shape's view will then display your data.
This tutorial will walk you through writing a custom content part: http://docs.orchardproject.net/en/latest/Documentation/Writing-a-content-part/
When you do, make sure not to create the content part Record type, since you will not be storing and loading data from the Orchard database - you want to load data from an external database. These are the steps you should follow:
Create a new module
Create a content part class
Have your part inherit from ContentPart, not ContentPart<TRecord> since there won't be any "TRecord".
Create a content part driver
On the Display method, return a shape by calling the ContentShape method. Make sure to add the SQL data access logic within the lambda. If you do it outside of that lambda, that data access code will be invoked every time the content item using your content part is invoked. Although that sounds as if that is exactly what you want, there's a subtlety here that involves Placement.info, which you can use to determine when your shape will actually be rendered or not. If the placement logic determines that your shape should not be rendered, then you don't want to access your external data for nothing.
Create a Placement.info file to configure the shape's placement (within the context of the content item being rendered).
Create the Razor view for the shape that you return in step 3.2.
Create a Migrations class that will define your custom content part, and any content types to which you want to add your part to. See http://docs.orchardproject.net/en/latest/Documentation/Understanding-data-access/ for more information on how to create migrations.
PS. Instead of implementing your data access code directly in the driver, I recommend you implement that in a separate class. Because you know, separation of concerns and such. You can then inject that service into your driver. To have your service class be registered with the service container, make sure that you define an interface for it, that itself derives from IDependency.
Some sample pseudo code:
Service code:
public interface IMyExternalDataStore : IDependency {
IList<MyExternalDataRecord> GetMyData();
}
public class MyExternalDataStore : IMyExternalDataStore {
public IList<MyExternalDataRecord> GetMyData() {
// Connect to your SQL Server database, perhaps using EF, load the data and return it. Could of course also be simply a DataSet.
}
}
Content Part:
public class MyExternalDataPart : ContentPart {
// Nothing here, unless you want to include some properties here that influence the data that you want to load. If so, you'll also want to implement the Editor methods in your content part driver, but I'm keeping it simple.
}
Content Part Driver:
public class MyExternalDataPartDriver : ContentPartDriver<MyExternalContentPart> {
private readonly IMyExternalDataStore _dataStore;
public MyExternalDataPartDriver(IMyExternalDataStore dataStore) {
_dataStore = dataStore;
}
protected override DriverResult Display(SlideShowProPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_MyExternalData", () => {
// Notice that we're performing the data access here within the lambda (the so called "shape factory method").
var data = _dataStore.GetMyData();
// Notice that I'm creating a property called "MyData"on the shape (which is a dynamic object).
return shapeHelper.Parts_MyExternalData(MyData: data));
}
}
}
Razor view for the Parts_MyExternalData shape:
Filename: Parts.MyExternalData.cshtml
#{
var records = (IList<MyExternalDataRecord>)Model.MyData;
}
<ul>
#foreach(var record in records) {
<li>#record.ToString()</li>
}
</ul>
Placement.info:
<Placement>
<Place Parts_MyExternalData="Content:0"/>
</Placement>
Migrations:
public class Migrations : DataMigrationImpl {
public int Create() {
// Define your content part so that you can attach it to any content type from the UI.
ContentDefinitionManager.AlterPartDefinition("MyExternalDataPart", part => part.Attachable());
// Optionally, define a new content type here programmatically or attach it to an existing type.
return 1;
}
}
I am a beginner in MEF. According to my requirement I have to show the multiple plugin UI according to the selection of plugin. For that I have to pass plugin related data to the external plugin UserControl.
[InheritedExport(typeof(IConnect))]
public interface IConnect{}
Below code is using to initializing the external UI from the main application,
[ImportMany(typeof(IConnect))]
public IEnumerable<Lazy<IConnect>> Plugins;
....
var catalog = new DirectoryCatalog(#"C:\TestDll\");
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
var childControl = SelectedPlugin as UserControl;
//Here I have to pass the required data to the usercontrol. How to do this?
Dockpanel.Children.Add(childControl );
Could you please suggest a way to pass data to the external user control
Our entire team here at work has been using MEF for years now, and I'm reasonably familiar with how it works.
To get everything bootstrapped off the ground, the first thing to do is ensure that a common MEF container is shared between your main application and the user control in your external assembly.
If you don't have a common MEF container, then your MEF imported classes will never be able to communicate with the host application, as they will be living in separate MEF universes.
Once you have a common container, anywhere you want to bootstrap a class out of the container, you can use something like this:
var test = MefContainer.GetExportedValue<ITest>();
test.Run();
Q. How do I add MEF to my project?
A. Using NuGet, search for "microsoft composition", and add MEF 2.
Q. So how do we create this shared MEF container?
A. As follows:
Follow through a tutorial such as From Zero to Proficient with MEF.
Create a class library that is shared between your imported control, and the host application.
In this class library, create a singleton class called MefContainer. This means that anybody that wants to grab something out of the MEF container can reference this singleton to obtain the MEF container. The MEF container contains classes from all of the auto-discovered assemblies in the directories that we want to scan.
Q. How do I communicate with the user control?
A. Add this class to your shared class library:
public interface ITest
{
string SharedValue { get; set; }
}
[Export(typeof(ITest))]
public class Test : ITest
{
[ImportingConstructor]
public Test()
{
}
public string SharedValue { get; set; }
}
Now, both the host app and the user control can grab an instance of the same class out of the MEF container:
var test = MefContainer.GetExportedValue<ITest>();
var result = test.SharedValue;
By default, classes that are obtained from the MEF container are singleton's, unless we explicitly say that we want non-shared classes.
Q. How about adding Reactive Extensions (RX)?
It's ok to have a class with shared values. But it's nicer if one component can fire events off, and any other component can listen to this event.
To do this, add RX to your project using NuGet (search for "reactive extensions", add "Reactive Extensions - Main Library").
Add a Subject to your shared class:
private Subject<string> MyEvent { get; set; }
Now, if you have a MEF reference to this shared class, you can send an event out:
var t = MefContainer.GetExportedValue<ITest>();
t.MyEvent.OnNext("hello");
And, any other class can subscribe to these events:
var t = MefContainer.GetExportedValue<ITest>();
t.MyEvent.Subscribe(
o =>
{
Console.Write(o);
});
If code is already running in the MEF composition container, then there is no need to use MefContainer to get at the container. You can simply MEF import the shared communication class using the constructor:
public interface IClassRunningInContainer
{
}
[Export(typeof(IClassRunningInContainer))]
public class ClassRunningInContainer : IClassRunningInContainer
{
[ImportingConstructor]
public ClassRunningInContainer(ITest t)
{
t.OnNext("Hello, world!");
}
}
Final Notes
Don't make the mistake of using MEF as a general dependency injection (DI) solution. You will run into roadblocks further down the road, as MEF is does not have the level of built in diagnostics to find out if things have gone wrong, compared to a dedicated dependency injection solution, such as Unity.
The ideal pattern is to use MEF for importing whole assemblies, then use Unity as your day to day DI container.
Every application contains some settings that are configurable. These settings can more or less put into two categories:
Appearance of application: example can be window location, window size, default options on views etc.
Business rules: these settings will be used by business logic.
In architecture that I implemented, View has its own project (WPF) and ViewModel has its own project (class library). From the lofical standpoint, View should be responsible of loading / saving view related settings, and ViewModel should be responsible for loading / saving business settings.
View settings are easy to handle. Create needed properties in Settings (app.config), and its easy to you can easily load save them.
However, ViewModel cannot access app.config settings through the built-in mechanisms that are Available in View project.
First idea I had was to make some helper methods that will allow me to read / write settings in app.config from ViewModel. What is your opinion? Am I complicating stuff here, or this is acceptable way of handling applic\tion settings?
There are three ways you could go here.
Add a reference to System.Configuration.dll and have your ViewModel project use the ConfigurationManager normally.
Have the ViewModel project ask for the configuration information it needs via constructors or other methods of Dependency Inversion, and have the View project pass it in.
Put the ViewModels and Views in the main application project.
Personally, I would go for option 3 unless there is some reason they need to be in separate assemblies. If they need to be separate, then I would favor option 1 because it's simpler.
Here's a cleaner option, if you would like to keep your assemblies separate and keep your ViewModels testable:
In your ViewModel project, add an interface which provides methods or properties for retrieving and saving business settings. Have your ViewModels accept this interface as a dependency in their constructors.
In your View project, add a class which implements this interface and talks with Settings
eg,
namespace ViewModel
{
public interface IBusinessSettingsStore
{
public string SomeSetting { get; set; }
public int AnotherSetting { get; set; }
}
public class SomeViewModel
{
private IBusinessSettingsStore _businessSettings;
public SomeViewModel(IBusinessSettingsStore businessSettings)
{
_businessSettings = businessSettings;
}
private void DoSomething()
{
Console.WriteLine(_businessSettings.SomeSetting);
_businessSettings.AnotherSetting = 10;
}
}
}
namespace View
{
public class BusinessSettingsStore : IBusinessSettingsStore
{
public string SomeSetting
{
get => Settings.Default.SomeSetting;
set => Settings.Default.SomeSetting = value;
}
public int AnotherSetting
{
get => Settings.Default.AnotherSetting;
set => Settings.Default.AnotherSetting = value;
}
}
}
I've been very impressed with this library: https://www.nuget.org/packages/UserSettingsApplied/. It basically allows you to serialize whatever you want to the user's roaming app config without any effort. It seems well thought out and well tested. This allows the view model to easily persist settings in the app.config.
FYI it is totally OK for the View project to reference View Model. More than that it is pretty much mandatory, so your view can do all of its persistence through the view model layer.
I have a project in WPF with a lot of UserControls, some user controls uses Kinect KinectColorViewer.xaml
I want to handle the sensor discovering and setup (conect, disconect, etc) in main window and serve it to my UserControls, how is the best way to do it?
Here is the project that explains my question.
If you prefer, here are the github link.
From your example code,
Assuming you want to maintain as much of the already available code from Microsoft, you will want to set up a reference to the KinectSensorManager on initializing your application. My constructor normally looks something like this:
private readonly KinectSensorChooser sensorChooser = new KinectSensorChooser();
public KinectSensorManager KinectSensorManager { get; private set; }
public MainViewModel()
{
// initialize the Kinect sensor manager
KinectSensorManager = new KinectSensorManager();
KinectSensorManager.KinectSensorChanged += this.KinectSensorChanged;
// locate an available sensor
sensorChooser.Start();
// bind chooser's sensor value to the local sensor manager
var kinectSensorBinding = new Binding("Kinect") { Source = this.sensorChooser };
BindingOperations.SetBinding(this.KinectSensorManager, KinectSensorManager.KinectSensorProperty, kinectSensorBinding);
}
The KinectSensorManager is just a helper class. You can rewrite code to easily avoid using it, but it doesn't do anything bad (does a lot of nice stuff for you) so I've just keep using it. Also, since I'm assuming you want to re-use as much code as possible, we want to maintain its usage.
For your control, you can extend KinectControl which will set up a bunch of helpful items for you. So...
public partial class KinectUserControl : KinectControl
{
...
}
This will give your control access to a lot of override-able functions that listen in to various events (like KinectSensorChanged). Check our the KinectColorViewer code and you can see how it overrides this function, which allows it to automatically start displaying new data if you swap Kinects.
When declaring your control in the XAML you can now add a reference to the KinectSensorManager:
<my:KinectUserControl KinectSensorManager="{Binding KinectSensorManager}" />
Because your control now has a KinectSensorManager property, it should pass through to your KinectColorViewer control as well.
I'm pretty new with Prism and after playing a bit around, there a few questions that arise. I'm trying to create a modular application that basically contains a map control in a shell window. The plugin modules offer different tools for interacting with the map. Some of the modules are pretty independent and simply display pins on the map.
1st question: How would RegionManager come into play for the module-specific classes (presenters) that must interact with the main map control? Usually in a RegionManager you register a specific view which is linked to a ViewModel, but in my case there is one single view (the map view) with multiple presenters acting on it.
2nd question: I need to be able to open several windows (shells) -- a bit like an MS Word document -- that should all be extended by the plugin modules. In a single-shell environment, when the module specific classes were instantiated, they could use the Dependency Injection Container to get a reference to the RegionManager or the Shell itself in order to get access to the map control. However with multiple shells, I don't see how to get access to the map control of the right shell. The dependency container has references to object global to the application, not specific for the shell I'm currently working in. Same is true for the EventAggregator.
Any input would be very welcome,
Ed
After hours of reading Prism-related articles and forums I've come across the article "How to build an outlook style application" on Erwin van der Valk's Blog - How to Build an Outlook Style Application.
In one part of the architecture, a Unity Child Container was used to resolve type instances. That's exactly what I needed for the answer to my 2nd question: I needed to have "scoped" (by window) dependency injection (ex: window scoped EventAggregator, Map control, etc.)
Here's how I create a new window:
private IShellWindow CreateNewShell(IRegionManager regionManager)
{
IUnityContainer childContainer = this.Container.CreateChildContainer();
... register types in child container ...
var window = new ShellWindow();
RegionManager.SetRegionManager(window, regionManager);
window.Content = childContainer.Resolve<MapDocumentView>();
return window;
}
So MapDocumentView and all its components will be injected (if needed) window-scoped instances.
Now that I can have scoped injected objects, I can get the window-scoped map in my module-based MapPresenter. To answer my 1st question, I defined an interface IHostApplication which is implemented by the Bootstrapper which has a MapPresenterRegistry property. This interface is added to the main container.
Upon initialization, the modules will register their presenters and upon the window creation, they will be instantiated.
So for the module initialization:
public void Initialize()
{
...
this.hostApplication.MapPresenterRegistry.Add(typeof(ModuleSpecificMapPresenter));
...
}
The code that initializes the map window:
private void View_Loaded(object sender, RoutedEventArgs e)
{
// Register map in the == scoped container ==
container.RegisterInstance<IMap>(this.View.Map);
// Create map presenters
var hostApplication = this.container.Resolve<IHostApplication>();
foreach (var mapPresenterType in hostApplication.MapPresenterRegistry)
{
var mapPresenter = this.container.Resolve(mapPresenterType) as IMapPresenter;
if (mapPresenter != null)
{
this.mapPresenters.Add(mapPresenter);
}
}
}
The module-specific MapPresenter:
public ModuleSpecificMapPresenter(IEventAggregator eventAggregator, IMap map)
{
this.eventAggregator = eventAggregator;
this.map = map;
this.eventAggregator.GetEvent<AWindowSpecificEvent>().Subscribe(this.WindowSpecificEventFired);
// Do stuff on with the map
}
So those are the big lines of my solution. What I don't really like is that I don't take advantage of region management this way. I pretty much have custom code to do the work.
If you have any further thoughts, I would be happy to hear them out.
Eduard
You have one main view and many child views, and child views can be added by different modules.
I'm not sure that the RegionManager class can be applied in this situation, so I would create a separate global class IPinsCollectionState
which must be registered as singleton in the bootstrapper.
public interface IPin
{
Point Coordinates { get; }
IPinView View { get; }
//You can use a view model or a data template instead of the view interface, but this example is the simplest
}
public interface IPinsCollectionState
{
ObservableCollection<IPin> Pins { get; }
}
Your main view model and different modules can receive this interface as a constructor parameter:
public class MapViewModel
{
public MapViewModel(IPinsCollectionState collectionState)
{
foreach (var item in collectionState.Pins)
{ /* Do something */ };
collectionState.Pins.CollectionChanged += (s, e) => {/* Handle added or removed items in the future */};
}
//...
}
Example of a module view model:
public class Module1ViewModel
{
public Module1ViewModel(IPinsCollectionState collectionState)
{
//somewhere in the code
collectionState.Pins.Add(new Module1Pin());
}
}
The second question can be solved in many different ways:
Application.Current.Windows
A global MainViewModel which contains the list of ShellViewModels and if you add new view model it will be displayed in new window. The bootstrapper is single for all windows.
Some kind of shared state which is passed to the constructor of the bootstrapper.
I don't know how these windows are related between themselves, and I don't know which way is the best, maybe it is possible to write an application with separated windows.