Is there a way of hiding Common properties of Web Parts? The Layout or appearance section for example.
I have created a new visual web part and I wan't to make it very easy to edit for the administrators and they don't need the standard layout / appearance settings when they go to 'edit web part'
Any ideas how to hide the base properties from the edit panel? Been searching all over but can't see anything in the documentation.
Here's one way to achieve this. In your EditorPart, mark the container of the other EditorParts as not Visible:
class EditorPartTest : EditorPart
{
protected override void CreateChildControls()
{
Parent.Controls[1].Visible = false;
Parent.Controls[2].Visible = false;
base.CreateChildControls();
}
public override bool ApplyChanges()
{
return true;
}
public override void SyncChanges()
{
}
}
And use it from your web part like this:
public class VisualWebPart1 : WebPart
{
public override EditorPartCollection CreateEditorParts()
{
ArrayList partsArray = new ArrayList();
EditorPartTest editor = new EditorPartTest();
editor.ID = this.ID + "_editorPart";
partsArray.Add(editor);
return new EditorPartCollection(partsArray);
}
}
Then you should get a result like this:
http://joelblogs.co.uk/?attachment_id=10785
Hope this helps!
joel
joelblogs.co.uk
SharePoint Architect Blog
Related
Use Case
A separated template engine that doesn't interfere in any way with normal Razor operation in an AspNetCore (2.X) web app.
Problem
Whilst trying to implement the above, I've created a whole bunch of derived wrapper classes based on RazorViewEngine, RazorViewCompilerProvider, DefaultRazorPageFactoryProvider, DefaultRazorViewEngineFileProviderAccessor and RazorViewEngineOptions in an effort that these can be registered with DI and injected whilst not having side affects in the normal Razor code path. I've succeeded except for one annoying issue, whereby I still need to configure my custom FileProvider (TemplateRepository) within the normal RazorViewEngineOptions rather than my wrapper class.
e.g. In the below code from Startup.cs, even though the file provider is specified in my custom Options object, and that is what is injected into the wrapper classes, the TemplateRepository is not called for a View request unless the second service.Configure is also included (using RazorViewEngineOptions).
services.Configure<TemplateOptions>(options =>
{
options.ViewLocationExpanders.Add(new TemplateNameExpander());
options.ViewLocationFormats.Add("{0}");
options.AreaViewLocationFormats.Add("{0}");
options.FileProviders.Clear();
options.FileProviders.Add(new TemplateRepository(new SqlConnectionFactory(configuration)));
});
services.Configure<RazorViewEngineOptions>(
options =>
{
options.FileProviders.Add(new TemplateRepository(new SqlConnectionFactory(configuration)));
});
This would suggest to me that somewhere in the RazorViewEngine dependency tree the RazorViewEngineOptions is being injected somewhere, but I cannot find it.
Full Source # GitHub
It seems that you have defined your custom RazorViewEngine but you do not tell MVC to use it.
Try to add below codes to add TemplateRazorEngine to MVC view engine.
services.Configure<TemplateOptions>(options =>
{
options.ViewLocationExpanders.Add(new TemplateNameExpander());
options.ViewLocationFormats.Add("{0}");
options.AreaViewLocationFormats.Add("{0}");
options.FileProviders.Clear();
options.FileProviders.Add(new TemplateRepository(new SqlConnectionFactory(configuration)));
});
services.Configure<MvcViewOptions>(options => {
var engine = services.BuildServiceProvider().GetRequiredService<TemplateRazorEngine>();
options.ViewEngines.Add(engine);
});
Late to the party but maybe you will use this in the future. I've also tried a lot of options and in the end I came to the conclusion that child containers would solve my particular issue. Unfortunately the AspNetCore container doesn't support them so I had to implement something quick that might not work in your case. Another option would be to use StructureMap or any other container that supports this functionality.
public class ChildServiceProvider : IServiceProvider, IDisposable
{
private readonly IServiceProvider _child;
private readonly IServiceProvider _parent;
public ChildServiceProvider(IServiceProvider parent, IServiceProvider child)
{
_parent = parent;
_child = child;
}
public ChildServiceProvider(IServiceProvider parent, IServiceCollection services)
{
_parent = parent;
_child = services.BuildServiceProvider();
}
public void Dispose()
{
(_child as IDisposable)?.Dispose();
}
public object GetService(Type serviceType)
{
return _child.GetService(serviceType) ?? _parent.GetService(serviceType);
}
}
And this is how I used it
public class Startup : IStartup
{
public IServiceProvider ChildServiceProvider { get; set; }
IServiceProvider IStartup.ConfigureServices(IServiceCollection services)
{
// Define a wrapper for the RazorViewEngine and it as a singleton
services.AddSingleton<CustomRazorEngine>(serviceProvider =>
{
// get the RazorViewEngine from the childContainer
var razorViewEngine = ChildServiceProvider.GetRequiredService<IRazorViewEngine>();
return new CustomRazorEngine(razorViewEngine);
});
return services.BuildServiceProvider();
}
public void Configure(IApplicationBuilder app)
{
ChildServiceProvider = CreateChildServiceProvider(app);
app.UseMvc();
}
IServiceProvider CreateChildServiceProvider(IApplicationBuilder parentApp)
{
// create the child container from the parentApp and register
// the custom RazorViewEngineOptions that you need for the isolated templating engine
// and whatever custom services that you need
var server = parentApp.ApplicationServices.GetRequiredService<IServer>();
var webHost = WebHost.CreateDefaultBuilder()
.ConfigureServices(services =>
{
services.AddOptions();
services.Configure<RazorViewEngineOptions>(opts =>
{
opts.FileProviders.Clear();
opts.FileProviders.Add(new CustomFileProvider());
});
services.AddMvc();
})
.Build();
return new ChildServiceProvider(parentApp.ApplicationServices, webHost.Services);
}
}
And the custom classes that you would need to implement
public class CustomFileProvider : IFileProvider
{
}
public class CustomRazorEngine
{
private readonly IRazorViewEngine _razorViewEngine;
public CustomRazorEngine(IRazorViewEngine razorViewEngine)
{
_razorViewEngine = razorViewEngine;
}
}
This was tested with dotnet 2.2 but haven't thoroughly tested it to be 100% that there are no performance issues or other hidden ones.
Also would be curious to know if you found another solution :)
So once again we are in the process of converting our existing Java application that was using entirely Swing to using JavaFX. However, the application will not be using JavaFX entirely. This seems to be causing some issues with Alerts/Dialogs and modality. We are currently using Java 8u40.
The main application is basically in a JFrame that has a Menu. The main content pane is JDesktopPane and clicking a MenuItem opens new JInternalFrames within the DeskopPane. Screens we are converting to JavaFX are basically JFXPanels within a JInternalFrame at the moment. Any Alerts/Dialogs that are opened from the JFXPanels are modal to the panel itself, but not to the JInternalFrame, DeskopPane, Menu, etc.
I read in the DialogPane documentation that they are planning to introduce some lightweight dialogs and even possibly InternalFrames in future releases of JavaFX, so maybe we'll just have to wait it out a little longer for this functionality. But, ideally when opening a new Alert/Dialog it would be modal to the entire Application.
EDIT:
Currently doing the following for modal dialogs:
((Stage)getDialogPane().getScene().getWindow()).setAlwaysOnTop(true);
This makes the dialog always appear on top, however the dialog also remains on top of other applications even if our main application is minimized. It also does not block input to any Swing components in the frame.
You can use the following work-around which creates an invisible JDialog when the Alert is shown and disposes the JDialog when the Alert is closed. This approach extends the modality to the whole application, including the Swing part.
// create Alert
Alert alert = new Alert(AlertType.INFORMATION, "Hello");
// create invisible JDialog and "show" it
JDialog dialog = new JDialog();
dialog.setModal(true);
dialog.setUndecorated(true);
dialog.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
SwingUtilities.invokeLater(() -> dialog.setVisible(true));
// show Alert
alert.showAndWait();
// close JDialog after Alert is closed
dialog.dispose();
I don't think i understand your question completely. But here is my guess - You are trying to make an alert window from some JFXPanel that will be modal (i.e. user will not be able to click in your application until she closes that alert window) to your entire application which is written partially using swing components.
If your application would be written in purely JavaFX then you would do something like (Assuming you have created a button somewhere in your JFXPanel)
button.setOnAction(evt -> {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.initModality(Modality.APPLICATION_MODAL);
// This will not work in your code
alert.initOwner(button.getScene().getWindow());
alert.show();
});
but since initOwner requires a javafx.stage.window object passing a swing component won't work in your code. As of Java 8u40 i don't think there is a right way(i.e. not hacks) to set ownership of Alert objects to swing component. Not surprisingly such questions has already been asked here and not answered as of writing this.
For your requirements you can use JOptionPane.showMessageDialog method and its look alike as workaround.
button.setOnAction(evt -> {
JOptionPane.showMessageDialog(desktopPane,"My message");
});
These dialog boxes are modal by default so no work is necessary. You can call these from any event handler methods of JavaFX components.
I've done a little workaround with a small interface which is implemented in my JavaFXFrame:
public interface DialogParent {
void setOnFocusGained(EventHandler<FocusEvent> focusHandler);
void setOnCloseRequest(EventHandler<WindowEvent> closeHandler);
}
And my JavaFXFrame implementation
public class JavaFXFrame implements DialogParent {
private JFrame frame;
private EventHandler<ch.irix.sumadmin.util.FocusEvent> focusGainedHandler;
private EventHandler<javafx.stage.WindowEvent> windowClosingHandler;
public void JavaFXFrame() {
final JFXPanel fxPanel = new JFXPanel();
frame = new JFrame();
frame.add(fxPanel);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
tryClosing(this);
}
});
frame.addWindowFocusListener(new WindowAdapter() {
#Override
public void windowGainedFocus(WindowEvent e) {
if (focusGainedHandler != null) {
focusGainedHandler.handle(new FocusEvent());
}
}
});
}
public void setVisible(boolean visible) {
frame.setVisible(visible);
}
private void tryClosing(WindowListener listener) {
javafx.stage.WindowEvent windowEvent = new javafx.stage.WindowEvent(null, javafx.stage.WindowEvent.WINDOW_CLOSE_REQUEST);
if (windowClosingHandler != null) {
windowClosingHandler.handle(windowEvent);
}
if (!windowEvent.isConsumed()) {
frame.setVisible(false);
}
}
#Override
public void setOnFocusGained(EventHandler<ch.irix.sumadmin.util.FocusEvent> focusGainedHandler) {
this.focusGainedHandler = focusGainedHandler;
}
#Override
public void setOnCloseRequest(EventHandler<javafx.stage.WindowEvent> windowClosingHandler) {
this.windowClosingHandler = windowClosingHandler;
}
}
And showing an Alert:
public static void showAlert(Alert alert) {
DialogPane dialogPane = alert.getDialogPane();
final Stage stage = new Stage();
stage.setScene(dialogPane.getScene());
List<ButtonType> buttonTypes = dialogPane.getButtonTypes();
for (ButtonType buttonType : buttonTypes) {
ButtonBase button = (ButtonBase) dialogPane.lookupButton(buttonType);
button.setOnAction(evt -> {
dialogPane.setUserData(buttonType);
stage.close();
});
}
dialogParent.setOnFocusGained(event -> {
stage.toFront();
});
dialogParent.setOnCloseRequest(Event::consume);
stage.setOnCloseRequest(event -> {
dialogParent.setOnFocusGained(null);
dialogParent.setOnCloseRequest(null);
});
stage.show();
}
Hope this will help you
The portable class library defines the start view model. This scenario generally sounds great but I was considering this. You have written a iOS universal application or Android that needs to change its start screen / view model. If application is a phone, the default view model is login but if it is tablet, you want a different view model as the start. Is there an override or a way to take control of this?
See the Wiki section - https://github.com/MvvmCross/MvvmCross/wiki/Customising-using-App-and-Setup#custom-imvxappstart - this has an example of programmatic switching:
If more advanced startup logic is needed, then a custom app start can be used - e.g.
public class CustomAppStart
: MvxNavigatingObject
, IMvxAppStart
{
public void Start(object hint = null)
{
var auth = Mvx.Resolve<IAuth>();
if (auth.Check())
{
ShowViewModel<HomeViewModel>();
}
else
{
ShowViewModel<LoginViewModel>();
}
}
}
This can then be registered in App using:
RegisterAppStart(new CustomAppStart());
In your App class you could register an AppStart that is a splash screen:
RegisterAppStart<SplashScreenViewModel>()
In that splash screen you could receive a service that verifies if it's a tablet or a phone. You would need to create a plugin to make this verification. (There are other stackoverflow questions showing how to verify this / How to detect device is Android phone or Android tablet? )
public SplashScreenViewModel(ITabletVerificationService tabletVerificationService)
Then you would simply change screen according to this service
if(tabletVerificationService.IsTablet())
{
ShowViewModel<TabletViewModel>
}
else
{
ShowViewModel<LoginViewModel>
}
Hope it helps =)
Here's my implementation of this scenario, if it could help:
PCL:
public enum PlateformType
{
Android,
iPhone,
WindowsPhone,
WindowsStore
}
public interface IPlateformInfos
{
PlateformType GetPlateformType();
}
public class CustomAppStart
: MvxNavigatingObject
, IMvxAppStart
{
public void Start(object hint = null)
{
var plateformInfos = Mvx.Resolve<IPlateformInfos>();
var plateformType = plateformInfos.GetPlateformType();
switch (plateformType)
{
default:
ShowViewModel<MenuViewModel>();
break;
case PlateformType.WindowsPhone:
case PlateformType.WindowsStore:
ShowViewModel<FirstViewModel>();
break;
}
}
}
PCL App.cs:
RegisterAppStart(new CustomAppStart());
UI (ex: WindowsPhone):
public class PlateformInfos : IPlateformInfos
{
public PlateformType GetPlateformType()
{
return PlateformType.WindowsPhone;
}
}
UI Setup.cs:
protected override void InitializeFirstChance()
{
Mvx.RegisterSingleton<IPlateformInfos>(new PlateformInfos());
base.InitializeFirstChance();
}
Pretty simple way.
I am trying to use MvvmCross v3 in one of my applications which consists of activities, content providers and broadcast receivers. However, I am not quite succeeding.
The application consists of a Core PCL which contains logic, models and viewmodels and a Droid application which contains all MonoDroid-specific stuff.
In Core I have an App:MvxApplication class and in Droid I have a Setup:MvxSetup class which creates an App-instance and initialises stuff.
I can use the IOC parts with content providers, broadcast receivers and non-Mvx-activities without problems. When I now want to add an MvxActivity it falls apart.
When the Mvx Activity launches I get an exception "Cirrious.CrossCore.Exceptions.MvxException: MvxTrace already initialized".
Obviously I am initialising things in the wrong order / wrong place. But, I need a pointer in the right direction.
My App Class
public class App
: MvxApplication
{
public override void Initialize()
{
base.Initialize();
InitialisePlugins();
InitaliseServices();
InitialiseStartNavigation();
}
private void InitaliseServices()
{
CreatableTypes().EndingWith("Service").AsInterfaces().RegisterAsLazySingleton();
}
private void InitialiseStartNavigation()
{
}
private void InitialisePlugins()
{
// initialise any plugins where are required at app startup
// e.g. Cirrious.MvvmCross.Plugins.Visibility.PluginLoader.Instance.EnsureLoaded();
}
}
And my setup class
public class Setup
: MvxAndroidSetup
{
public Setup(Context applicationContext)
: base(applicationContext)
{
}
protected override IMvxApplication CreateApp()
{
return new App();
}
protected override IMvxNavigationSerializer CreateNavigationSerializer()
{
return new MvxJsonNavigationSerializer();
}
public override void LoadPlugins(Cirrious.CrossCore.Plugins.IMvxPluginManager pluginManager)
{
pluginManager.EnsurePluginLoaded<Cirrious.MvvmCross.Plugins.Json.PluginLoader>();
base.LoadPlugins(pluginManager);
}
public void RegisterServices()
{
// I register a bunch of singletons here
}
// The following is called from my content provider's OnCreate()
// Which is the first code that is run
public static void DoSetup(Context applicationContext)
{
var setup = new Setup(applicationContext);
setup.Initialize();
setup.RegisterServices();
}
My Content provider's OnCreate():
public override bool OnCreate()
{
Log.Debug(Tag, "OnCreate");
_context = Context;
Setup.DoSetup(_context);
return true;
}
My MvxActivity:
[Activity(Label = "#string/ApplicationName", MainLauncher = true)]
[IntentFilter(new[] { "Settings" })]
public class SettingsView
: MvxActivity
{
public new SettingsViewModel ViewModel
{
get { return (SettingsViewModel) base.ViewModel; }
set { base.ViewModel = value; }
}
protected override void OnViewModelSet()
{
SetContentView(Resource.Layout.Page_SettingsView);
}
}
Short answer (I'm in an airport on mobile)
all the mvx android views will check the setup singleton has been created - https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.Droid/Platform/MvxAndroidSetupSingleton.cs (vnext tree - but similar on v3)
so if you are creating a setup, but not setting this singleton, then you will get a second setup created when you first show a view
i suspect you can just get your setup created via the singleton class, but if this isn't flexible enough for your needs, then please log an issue on github
would also love to see some blogging about this - I've not used custom content providers much (at all!)
I'm trying to put html-formatted labels in the tabs of a TabNavigator.
I saw SuperTabNavigator in the FlexLib but it doesn't seem to do the trick for me.
I found this html button code and was able to inject my own TabBar and have it change the class instantiated by the ClassFactory when a navItem is created.
HtmlTabNavigator:
public class HtmlTabNavigator extends TabNavigator
{
public function HtmlTabNavigator()
{
super();
}
override protected function createChildren():void
{
if (!tabBar)
{
tabBar = new HtmlTabBar(); // inject my class
tabBar.name = "tabBar";
tabBar.focusEnabled = false;
tabBar.styleName = new StyleProxy(this, tabBarStyleFilters);
rawChildren.addChild(tabBar);
if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_3_0)
{
tabBar.setStyle("paddingTop", 0);
tabBar.setStyle("paddingBottom", 0);
tabBar.setStyle("borderStyle", "none");
}
}
super.createChildren(); // ommits original TabBar creation but continues in inheritance chain
}
public function setHtmlLabels( htmlLabels:Array ):void
{
for (var i:uint = 0; i < tabBar.numChildren; i++)
{
var button:Button = tabBar.getChildAt( i ) as Button;
button.label = htmlLabels[ i ];
}
}
}
HtmlTabBar:
public class HtmlTabBar extends TabBar
{
public function HtmlTabBar()
{
super();
navItemFactory = new ClassFactory(HtmlButton);
}
}
Now I'm having problems with the style of the button as it looks like a regular button and not like a tab anymore. It is not apparent to me why this works when a ButtonBarButton is used.
Any ideas are welcome.
Thanks
Stefan
Like you mentioned, I think its best to built your own component for this scenario. You could consider using a textArea with editable=false for the tab portion since I believe htmlText can be displayed in that component.
Edit: Can you maybe modify the SuperTabNavigator and add in a textArea... so the original label for the tab could be blank (if you cant remove it) then have the textArea on top of it.
With best regards,
Following your example, I tried to specialize the TabBar to use a Custom Button with a Mnemonic Label functionality, but I get a compile time error:
1178: Attempted access of inaccessible
property navItemFactory through a
reference with static type
AspMnemonicTabBar.
Reading the Flex Source Code I found it belongs to a private namespace mx_internal. So how could I access it to set a new ClassFactory ??
package
{
import mx.controls.TabBar;
import mx.core.ClassFactory;
public class AspMnemonicTabBar extends TabBar
{
public function AspMnemonicTabBar()
{
super();
navItemFactory = new ClassFactory(AspMnemonicButton);
}
}
}
Alessandro, navItemFactory is in namespace mx_internal. Access it through mx_internal::navItemFactory, or put the following line below your import statements:
use namespace mx_internal;