Popup window in Silverlight 4 and Prism - silverlight-4.0

In Silverlight and PRISM, what is the good way to open a popup child window which is in one Module by passing a parameter from a ViewModel in different Module.

Create a common interface/class known to both module, called IChildWindowService, register the IChildWindowServe/ChildWindowService in the bootstrapper.
//Highly simplified version
//Can be improved by window reuse, parameter options, stronger eventing
public class ChildWindowService : IChildWindowService
{
public ChildWindowService(IServiceLocator container)
{
_container = container;
}
public void Show<TViewModel>(TViewModel viewModel = null, Action<TViewModel, bool?> callBack = null) where TViewModel is IViewModel
{
var viewName = typeof(TViewModel).Name.Replace("Model", string.Empty);
// In bootstrapper register all instances of IView or register each view one by one
var view = _container.GetInstance<IView>(viewName);
viewModel = viewModel ?? _container.GetInstance<TViewModel>();
view.DataContext = viewModel;
var window = new ChildWindow();
window.Content = view;
var handler = (s,e) => { window.Close(); }
viewModel.RequestClose += handler;
view.Closed += (s,e) => { viewModel.RequestClose -= handler; }
// In silverlight all windows show as Modal, if you are using a third party you can make a decision here
window.Show();
}
}
Create a common CompositePresentationEvent, this event will pass the parameters from point a to point b
public class OpenChildWindowWithParameters : CompositePresentationEvent<ParamEventArgs>{}
The ViewModel in Module A raises the Event.
The Controller in Module B registers and reacts to the Event.
The Controller in Module B takes the child window service as a dependency.
When the event is raised the Controller will create the VM in Module B and pass the parameters to it, from the event, it will also use the Service to display a ChildWindow.

Related

Adding a DeclarativeComponent in a UIComponent at runtime. Oracle JDeveloper 12c

I've been working in this project for abou a week and haven't find a solution to my problem.
For testing purposes I create a simple new DeclarativeComponent which is a panelGroupLayout that contains 2 OutputText. After that I deploy the jar file and add it to my other Fusion web application libraries.
I want to add this DeclarativeComponent in another UIComponent at runtime by pressing a button which contains the next code in the javabean:
`public void addComponent(ActionEvent actionEvent)
{
// Add event code here...
createOutputComponent();
}
private void createOutputComponent()
{
CuadroDeTextoComponent ui = new CuadroDeTextoComponent(); //This is my Declarative Component
UIComponent parentUIComponent = getPglComponente(); This is the panelGrouopLayout in which i want to add my declarativeComponent
addComponent(parentUIComponent, ui);
}
public void addComponent(UIComponent parentUIComponent, UIXDeclarativeComponent childUIComponent)
{
parentUIComponent.getChildren().add(childUIComponent);
AdfFacesContext.getCurrentInstance().addPartialTarget(parentUIComponent);
}`
I have tried draging the declarative component and it works, but when I do it dynamically the component doesn't display
For your component to display you may need to add a PPR refresh to it's parent element :
In your case :
public void addComponent(ActionEvent actionEvent)
{
// Add event code here...
createOutputComponent();
}
private void createOutputComponent()
{
CuadroDeTextoComponent ui = new CuadroDeTextoComponent(); //This is my Declarative Component
UIComponent parentUIComponent = getPglComponente(); This is the panelGrouopLayout in which i want to add my declarativeComponent
addComponent(parentUIComponent, ui);
addPPR(parentUIComponent); //Refresh the parent component
}
public void addComponent(UIComponent parentUIComponent, UIXDeclarativeComponent childUIComponent)
{
parentUIComponent.getChildren().add(childUIComponent);
AdfFacesContext.getCurrentInstance().addPartialTarget(parentUIComponent);
}
public static void addPPR(UIComponent component) {
if (component != null) {
AdfFacesContext.getCurrentInstance().addPartialTarget(component.getParent());
}
}

Remove route from RouteCollection in Asp.Net Core and add new with same route name (nopCommerce-4.00)

I want to remove existing route from RouteCollection and want to add new route with same route name in nopCommerce 4.00 via plugin
Existing route name:
//home page
routeBuilder.MapLocalizedRoute("HomePage", "",
new { controller = "Home", action = "Index" });
I Want to replace it with
routeBuilder.MapLocalizedRoute("HomePage", "",
new { controller = "CustomPage", action = "Homepage" });
I tried several ways but not get any luck.
In my case, I have to replace the robots.txt generation.
I created a new public controller in my plugin, and I copy the original action here:
public class MiscCommonController : BasePublicController
{
#region Fields
private readonly ICommonModelFactory _commonModelFactory;
#endregion Fields
#region Ctor
public MiscCommonController(
ICommonModelFactory commonModelFactory
)
{
this._commonModelFactory = commonModelFactory;
}
#endregion Ctor
#region Methods
//robots.txt file
//available even when a store is closed
[CheckAccessClosedStore(true)]
//available even when navigation is not allowed
[CheckAccessPublicStore(true)]
public virtual IActionResult RobotsTextFile()
{
var robotsFileContent = _commonModelFactory.PrepareRobotsTextFile();
return Content(robotsFileContent, MimeTypes.TextPlain);
}
#endregion Methods
}
After this I create a RouteProvider for my plugin, and I replaced the original route to my own one.
public partial class RouteProvider : IRouteProvider
{
/// <summary>
/// Gets a priority of route provider
/// </summary>
public int Priority => -1;
/// <summary>
/// Register routes
/// </summary>
/// <param name="routeBuilder">Route builder</param>
public void RegisterRoutes(IRouteBuilder routeBuilder)
{
Route route = null;
foreach (Route item in routeBuilder.Routes)
{
if (item.Name == "robots.txt")
{
route = item;
break;
}
}
if (route != null) routeBuilder.Routes.Remove(route);
routeBuilder.MapRoute(
"robots.txt",
"robots.txt",
new { controller = "MiscCommon", action = "RobotsTextFile" }
);
}
}
That's all.
After this implementation, the routing works fine, and the get request landed in my own controller, which is act like the original.
Now, I can replace the generation logic with my own.
I hope it helps.
in the RouteProvider.cs of your plugin write these codes (based on your names):
var lastExistingRoute= routeBuilder.Routes.FirstOrDefault(x => ((Route)x).Name == "HomePage");
routeBuilder.Routes.Remove(lastExistingRoute);
routeBuilder.MapRoute("HomePage", "",
new { controller = "CustomPage", action = "Homepage", });
and the below codes worked for myself version 4.20:
var lastDownloadRoute=routeBuilder.Routes.FirstOrDefault(x => ((Route)x).Name == "GetDownload");
routeBuilder.Routes.Remove(lastDownloadRoute);
routeBuilder.MapRoute("GetDownload", "download/getdownload/{guid}/{agree?}",
new { controller = "AzTechProduct", action = "GetPayed", });
There are two potential ways to deal with this in nopCommerce 4.3 that I see with a quick examination of the code.
First, you could create an IRouteProvider, add your route that has the same signature as the one you wish to 'delete' and make sure the Priority on the provider is greater than 1.
Doing this will basically override the default route built into Nop. This is my preferred method.
public partial class RouteProvider: IRouteProvider
{
public void RegisterRoutes(IEndpointRouteBuilder endpointRouteBuilder)
{
var pattern = string.Empty;
if (DataSettingsManager.DatabaseIsInstalled)
{
var localizationSettings = endpointRouteBuilder.ServiceProvider.GetRequiredService<LocalizationSettings>();
if (localizationSettings.SeoFriendlyUrlsForLanguagesEnabled)
{
var langservice = endpointRouteBuilder.ServiceProvider.GetRequiredService<ILanguageService>();
var languages = langservice.GetAllLanguages().ToList();
pattern = "{language:lang=" + languages.FirstOrDefault().UniqueSeoCode + "}/";
}
}
// Handle the standard request
endpointRouteBuilder.MapControllerRoute("Wishlist", pattern + "wishlist/{customerGuid?}",
new { controller = "MyShoppingCart", action = "Wishlist" });
return;
}
public int Priority => 100;
}
The key to the code above is the Priority value. This route will get added to the list first and will therefore take precedence over the default route. Using this technique eliminates the need to delete the default route.
The second possible method turns out to not work because the endpointRouteBuilder.DataSources[n].Endpoints collection is read only. So, as far as I know, you can't remove mappings from that list after they have been added.

Is it somehow possible to have two master views and one detail view?

If I have for example one master view on the left and one in the middle, each showing oder Java Beans/POJOs, can I use a shared detail view that somehow listens to the active beans of each view and then displays the currently selected one in more detail? A one to one relation is quite easy to manage by using your Context library.
#ViewDocking(areaId ="left", position=1, displayName="Profiles", menuEntry = #WindowMenuEntry(path = "", position=0), accelerator="Shortcut+1")
public class ProfileListView extends BorderPane implements LocalContextProvider {
private final SimpleContextContent content = new SimpleContextContent();
private final SimpleContext context = new SimpleContext(content);
#FXML
private ListView<Profile> listview;
public ProfileListView() {
load();
// add some profiles
listview.getItems().add(new Profile("Profile1"));
listview.getItems().add(new Profile("Profile2"));
listview.getItems().add(new Profile("Profile3"));
// setup selection listener
listview.getSelectionModel().selectedItemProperty().addListener((value, oldProfile, newProfile) -> {
// set active profile and remove old one
content.remove(oldProfile);
content.add(newProfile);
});
// setup double click listener
configureClickListener();
}
private Profile getSelectedProfile() {
return listview.getSelectionModel().getSelectedItem();
}
private void configureClickListener() {
listview.setOnMouseClicked(event -> {
// check if it was a double click
if(event.getClickCount() == 2) {
System.out.println(getSelectedProfile());
// inject into editor pane
// calls the procedure to create a tab in the center area...
}
});
}
private void load() {
FXMLLoaders.loadRoot(this);
}
#Override
public Context getLocalContext() {
return context;
}
}
This is one master view holding a list view of items.
The other one would be the same, docking to the right as another tab and holding POJOs of type 'Action'.
The detail view is here:
#ViewDocking(areaId = "right", displayName = "Properties", accelerator = "Shortcut+2", menuEntry = #WindowMenuEntry(path = "", position = 0), position = 1)
public class ProfilePropertiesView extends BorderPane implements LocalContextProvider, ActiveContextSensitive {
private Context activeContext;
private SimpleContextContent content = new SimpleContextContent();
private SimpleContext context = new SimpleContext(content);
private Profile profile;
private IWindowService service = new NullWindowService();
#FXML
private PropertySheet propertysheet;
public ProfilePropertiesView() {
load();
// retrieve framework service, TODO: use tracker
BundleContext ctx = FrameworkUtil.getBundle(getClass()).getBundleContext();
service = ctx.getService(ctx.getServiceReference(IWindowService.class));
// initialize callback
service.addCallback(title -> {
System.out.println("callback called " + title);
// update the property sheet ui by re-creating the items list
// updateUI();
// we can safely return null
return null;
});
// configure editor factory so the user is able to use a combobox
propertysheet.setPropertyEditorFactory(new CustomPropertyEditorFactory(service));
}
private void load() {
FXMLLoaders.loadRoot(this);
}
#Override
public Context getLocalContext() {
return context;
}
private void contextChanged() {
// find profile information
Profile found = activeContext.find(Profile.class);
// if the found profile is null, ignore it
if (found != null) {
// reset if profile is valid
if (profile != null) {
reset();
}
// create reference and register
profile = found;
register();
}
}
private void register() {
// retrieve observablelist of bean properties if some profile is selected
if(profile != null) {
ObservableList<Item> items = createDetailedList(profile);
propertysheet.getItems().setAll(items);
}
}
private void updateUI() {
// clear property elements and re-create them
reset();
// re-create items
ObservableList<Item> items = createDetailedList(profile);
propertysheet.getItems().addAll(items);
}
private ObservableList<Item> createDetailedList(Object bean) {
ObservableList<Item> list = FXCollections.observableArrayList();
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
Arrays.stream(beanInfo.getPropertyDescriptors()).map(pd -> new DetailedBeanProperty(bean, pd)).forEach(list::add);
} catch (IntrospectionException e) {
e.printStackTrace();
}
return list;
}
private void reset() {
propertysheet.getItems().clear();
}
#Override
public void setActiveContext(Context activeContext) {
this.activeContext = activeContext;
this.activeContext.addContextListener(Profile.class, event -> contextChanged());
// trigger change
contextChanged();
}
}
The current ProfilePropertiesView is just configured to display the properties of the selected profile. I want it to be able to display the current information of the last selected POJO in the UI. That means that if the user selected a Profile from the ListView, that profile should be displayed in the properties view. If he selected an Action from the Table (which is displayed in the center), the properties of the Action should be displayed.
Do I just need to register a new ContextListener for the Action.class
POJO and then call a method to populate the PropertiesView? I was
unsure if this is the right solution...
Yes, just add another ContextListener to the activeContext for every POJO type you want to observe.
Also note that in the constructor of views it's better to use a ServiceTracker instead of looking for the service via BundleContext as the service might not be available yet, depending on the order the bundles are loaded.
You can find a sample which uses a ServiceTracker here: https://stackoverflow.com/a/35974498/506855

Resolve an instance of type 'B' for each instance of type 'A'

I have an interface called specification:
public interface ISpecification { ... }
Many implementations of this can exist within my application and I also have a processor which requires a specification:
public interface IProcessor { ... }
public class Processor : IProcessor
{
public Processor (ISpecification specification) { ... }
}
I am using Autofac (version 3.5.2) as my IOC container, what I would like is to be able to call:
var processors = container.Resolve<IEnumerable<IProcessor>>();
And have one IProcessor returned for each registered ISpecification, is this possible?
This sounds like Autofac's Adapters:
Autofac provides built-in adapter registration so you can register a
set of services and have them each automatically adapted to a
different interface.
var builder = new ContainerBuilder();
// Register the services to be adapted
builder.RegisterType<SaveCommand>()
.As<ICommand>()
.WithMetadata("Name", "Save File");
builder.RegisterType<OpenCommand>()
.As<ICommand>()
.WithMetadata("Name", "Open File");
// Then register the adapter. In this case, the ICommand
// registrations are using some metadata, so we're
// adapting Meta<ICommand> instead of plain ICommand.
builder.RegisterAdapter<Meta<ICommand>, ToolbarButton>(
cmd =>
new ToolbarButton(cmd.Value, (string)cmd.Metadata["Name"]));
var container = builder.Build();
// The resolved set of buttons will have two buttons
// in it - one button adapted for each of the registered
// ICommand instances.
var buttons = container.Resolve<IEnumerable<ToolbarButton>>();

Struggling with passing messages through MVVM Light

I have two view and their corresponding ViewModels and i want to send text from one view to another using MVVM Light as follows
in first viewmodel i am calling the following method
public void NavigatePage()
{
string temp = "temp value";
Messenger.Default.Send("temp");
Frame frame = Window.Current.Content as Frame;
if (frame != null) frame.Navigate(typeof(MyPage), temp);
}
while in page 2 view model i am having the following code
public MyViewModel()
{
Messenger.Default.Register<string>(this, MessageReceived);
}
private string test;
public string Test
{
get { return test; }
set { test = value; RaisePropertyChanged("Test");}
}
private void MessageReceived(string message)
{
Test = message;
}
when i debug my code the ctor of this viewmodel is getting called but the MessageReceived is not getting called hence property Test is never getting set, I am missing something, please help
Is the SecondViewModel actually created before you send the message? You can specify this in the ViewModelLocator class.
In the locator you have to register your viewmodel and CREATE it when the applications starts.
Like this:
SimpleIoc.Default.Register<SecondViewModel>(true);
With the true parameter the SecondViewModel will be created when the application is started! :)