Im trying to position a GTK# dialog in the center of a window,also i would like to make the parent window non editable when this dialog appears.
I tried setting the parent property and of the dialog and set it's position to center on parent.(The parent windows position is always centered,the parent appers centered but a portion of it is below the taskbar)
What im i doing wrong?
UPDATE:
I tried setting the transcientfor property.
mywin d = new mywin();
d.Parent = this;
d.WindowPosition = WindowPosition.CenterOnParent;
d.TransientFor = this;
d.WidthRequest = 360;
d.HeightRequest =260;
d.Resizable = false;
d.Show ();
Also i get this error in Application Output when i do this
(myapp:5844): Gtk-WARNING **: Can't set a parent on a toplevel widget
(myapp:5844): Gdk-CRITICAL **: inner_clipboard_window_procedure: assertion 'success' failed
UPDATE:
Calling the dialog from parent
protected void OnButton7Clicked (object sender, EventArgs e)
{
var mydiag = new mydiag( this );
if ( ( (Gtk.ResponseType) mydiag.Run() ) == Gtk.ResponseType.Ok ) {
// do whatever here...
}
}
Dialog code
using System;
namespace myproj
{
public partial class mydiag : Gtk.Dialog
{
public mydiag (Gtk.Window parent)
{
this.Build ();
this.Title = parent.Title + " more info";
this.Icon = parent.Icon;
this.Parent = parent;
this.TransientFor = parent;
this.SetPosition( Gtk.WindowPosition.CenterOnParent );
this.ShowAll();
}
}
}
The problem is being reported here:
(myapp:5844): Gtk-WARNING **: Can't set a parent on a toplevel widget
Your mywin class is not a Gtk.Dialog, but probably a Gtk.Window. You should create your main window this way:
namespace Whatever {
public class MainWindow: Gtk.Window {
public MainWindow()
: base( Gtk.WindowType.Toplevel )
{
this.Title = "Gtk# App";
this.Build();
}
private void Build() {
// create your widgets
}
// more things...
}
Suppose now that you need to open a dialog for some function in your app.
namespace Whatever {
public class MainWindow: Gtk.Window {
// ...more things
private void OnWhatever() {
var dlg = new DlgMoreInfo( this );
if ( ( (Gtk.ResponseType) dlg.Run() ) == Gtk.ResponseType.Ok ) {
// do whatever here...
}
dlg.Destroy();
}
}
}
Finally, you need to create your dialog DlgMoreInfo centered, etc.
namespace Whatever {
public class DlgMoreInfo : Gtk.Dialog {
public DlgMoreInfo(Gtk.Window parent) {
this.Build();
this.Title = parent.Title + " more info";
this.Icon = parent.Icon;
this.TransientFor = parent;
this.SetPosition( Gtk.WindowPosition.CenterOnParent );
this.ShowAll();
}
private void Build() {
// Create widgets here...
// Buttons
this.AddButton( Gtk.Stock.Cancel, Gtk.ResponseType.Cancel );
this.AddButton( Gtk.Stock.Ok, Gtk.ResponseType.Ok );
this.DefaultResponse = Gtk.ResponseType.Ok;
}
}
}
You can only create dialogs which are childs of a top level window; never a window can be a child of another one.
Note that this code does not use the designer of Xamarin Studio. If you use the designer, then call HideAll() just before ShowAll(), if you need to use the widgets, or move the call to Build() after the call to SetPosition().
Hope this helps.
Related
Goal: add an image above an UIAlertController's Title label by subclassing UIAlertController and adding new line characters, \n, to the title string to make space for the UIImageView
Desire
Current
As one can see, able to add the image to the UIAlertController successfully but the image is not being spacing/placed above the Title. It appears to be adding to the center of the alert. How to space the image correctly above the UIAlertController title?
Current code:
namespace XamarinFormsApp1.Extensions
{
public class AlertController : UIAlertController
{
private string originalTitle;
private string spaceAdjustedTitle;
private UIImageView imageView = null;
private CoreGraphics.CGSize previousImgViewSize
= CoreGraphics.CGSize.Empty;
public override UIAlertControllerStyle PreferredStyle
{
get
{
return UIAlertControllerStyle.Alert;
}
}
public override string Title
{
get
{
return originalTitle;
}
set
{
if (Title != spaceAdjustedTitle ||
string.IsNullOrEmpty(Title) ||
string.IsNullOrEmpty(spaceAdjustedTitle))
{
originalTitle = value;
}
}
}
public void setTitleImage(UIImage image)
{
if (this.imageView == null)
{
UIImageView imageView = new UIImageView(image);
this.View.AddSubview(imageView);
this.imageView = imageView;
return;
}
imageView.Image = image;
}
public override void ViewDidLayoutSubviews()
{
if (imageView == null)
{
base.ViewDidLayoutSubviews();
return;
}
// Adjust title if image size has changed
if (previousImgViewSize != imageView.Bounds.Size)
{
previousImgViewSize = imageView.Bounds.Size;
adjustTitle(imageView);
}
// Position `imageView`
var linesCount = newLinesCount(imageView);
var padding = Constants.Padding(PreferredStyle);
var x = View.Bounds.Width / 2.0;
var y = padding + linesCount * lineHeight / 2.0;
CoreGraphics.CGPoint cgPoint = imageView.Center;
cgPoint.X = (nfloat)x;
cgPoint.Y = (nfloat)y;
imageView.Center = cgPoint;
base.ViewDidLayoutSubviews();
}
private void adjustTitle(UIImageView imageView)
{
var linesCount = (int)newLinesCount(imageView);
var lines = Enumerable
.Range(1, linesCount)
.Select(i => "\n")
.Aggregate((c, n) => $"{c}{n}");
spaceAdjustedTitle = lines + (originalTitle ?? "");
Title = spaceAdjustedTitle;
}
private double newLinesCount(UIImageView imageView)
{
return Math.Ceiling(
imageView.Bounds.Height / lineHeight);
}
private float lineHeight
{
get
{
UIFontTextStyle style = this.PreferredStyle
== UIAlertControllerStyle.Alert
? UIFontTextStyle.Headline
: UIFontTextStyle.Callout;
return (float)UIFont
.GetPreferredFontForTextStyle(style)
.PointSize;
}
}
struct Constants
{
static float paddingAlert = 22;
static float paddingSheet = 11;
public static float Padding(UIAlertControllerStyle style)
{
return style == UIAlertControllerStyle.Alert
? Constants.paddingAlert
: Constants.paddingSheet;
}
}
}
}
Note: Credit to #stringCode for image and swift solution, see.
UIAlertViewController is not meant to be subclassed.
An extract from the documentation says:
You could still get the UI you desire by using a UIViewController with transparency on the View and a subview with the layout you desire.
You would need to also set these two properties: ModalTransitionStyle and ModalPresentationStyle to UIModalTransitionStyle.CrossDissolve and UIModalPresentationStyle.OverCurrentContext respectively if you want your custom UIAlertController to behaves the same as a UIAlertController
Update:
This is what I meant you could do:
In the Main.Storyboard drop a UIViewController and update the design as you wish. Following the image you posted above I created the UI as seen below:
That's an Image, 2 UILabels for the Title and Message and 3 buttons for the 3 different actions (Default, Destroy, Cancel). All these controls are inside a UIView with White background. For the example I called it ContentView
Adding the 3 button on the UI seems to be the easiest way to work with this and then hide/show them when you are about to present your alert. You could also create the buttons on the fly based on the actions you wanna show. This is up to you.
Create a ViewController Class, I called it NiceAlertController, and assign it to the ViewController in the Storyboard. Also, make sure to create back properties (Outlets) for all the UIControls (Label, Button, Image, etc) so you can access it from the ViewController class.
Here more information about how to work with iOS Storyboard on the designer
Now in your class you will need to add the code to make it work.
In your class to make the view transparent you will need to add this to your ViewDidLoad method:
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.View.BackgroundColor = UIColor.Clear.ColorWithAlpha(0.2f);
this.View.Opaque = false;
}
Also, we could mimic the way UIAlertControllers are created and create our method like that one:
public static NiceAlertController Create(string title, string message, UIImage image = null)
{
//New instance of your ViewController UI
var storyboard = UIStoryboard.FromName("Main", NSBundle.MainBundle);
var alertController = storyboard.InstantiateViewController(nameof(NiceAlertController)) as NiceAlertController;
//Using the same transition and presentation style as the UIAlertViewController
alertController.ModalTransitionStyle = UIModalTransitionStyle.CrossDissolve;
alertController.ModalPresentationStyle = UIModalPresentationStyle.OverCurrentContext;
//This assumes your properties are called Title, Message and Image
alertController.Title = title;
alertController.Message = message;
alertController.Image = image;
return alertController;
}
The 3 properties used above (Title, Message and Image) looks like this:
public new string Title { get; private set; }
public string Message { get; private set; }
public UIImage Image { get; private set; }
Why these properties? because by the time you create the class the Controls on the view are not yet available. They will be available only after the View is loaded. This is why we will need to add other changes like the one below.
Here we are setting the values to the Controls on the UI
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
this.titleLabel.Text = Title;
this.messageLabel.Text = Message;
//If you don't set an image while Create, it will use the default image you set on the Designer.
if (Image != null)
{
this.imageView.Image = Image;
}
}
Now from any other ViewController you can call this ViewController as you would call an AlertViewController:
private void ShowMyAlertController()
{
var alert = NiceAlertController.Create("Hello", "My nice alert controller");
this.PresentViewController(alert, true, null);
}
And it should look like this:
To handle the Actions (What to do when the buttons are tapped) you could create specific methods like:
public void AddDefaultAction(string title, Action action)
{
//Logic here
}
public void AddCancelAction(string title, Action action)
{
//Logic here
}
public void AddDestructiveAction(string title, Action action)
{
//Logic here
}
Hope this gives you the idea of how to create custom UIViewcontroller and make it look like a UIAlertViewController.
Hope this helps.-
I am feeling kind of stupid at the moment, because everywhere I read this is a normal procedure, and I just cannot find why I am not able to do it also!
So, the situation is the following, I have a Parent Form and a Child Form. The Child Form has a public property. From the Parent Form, i want to access the Child Form public property, and I can't.
My code is the following:
Parent code:
namespace myProgram.UserInterfaces
{
public partial class ProjectNew : Form
{
public ProjectNew()
{
InitializeComponent();
}
private void ButtonSelectCustomer_Click(object sender, EventArgs e)
{
using (Form f = new ProjectCustomerList())
{
this.SuspendLayout();
f.ShowDialog(this);
}
this.Show();
}
}
}
Child code:
namespace myProgram.UserInterfaces
{
public partial class ProjectCustomerList : Form
{
public EntCustomer _selectedCustomer = new EntCustomer();
public EntCustomer SelectedCustomer {
get
{
return _selectedCustomer;
}
}
public ProjectCustomerList()
{
InitializeComponent();
}
// --- other code ---
}
}
After the using (Form f = new ProjectCustomerList()) i would like to do the following: var sCustomer = f.SelectedCustomer;, but when I do this, Visual Studio doesn't recognize the Child Form public property.
What am I doing wrong? :|
This is normal with inheritance, since f in your case is handled as a simple Form.
You could typecast it to ProjectCustomerList to access the Property.
The is operator is also useful.
if (f is ProjectCustomerList)
{
(f as ProjectCustomerList).SelectedCustomer =...;
}
or simply
using (ProjectCustomerList f = new ProjectCustomerList())
{
f.SelectedCustomer =...;
}
seen var in other comments, works too
using (var f = new ProjectCustomerList())
{
f.SelectedCustomer =...;
}
I am programming an Application on Xamarin.IOS. I have a Tabbed Layout as for my Main View and all the UIElements are set in the Storyboard. Now, what i need to do, because i want to implement IAds,
i want my Application to be a Split view, with the IAd View Controller as the Detail View, and my usual TabbedLayout as the main view.
So, yeah, my precise question would be:
As all my Layout is loaded from the Storyboard: How can i pass an instance of the View that gets loaded usually to my SplitViewController?
Any tips you can give, are helpful, i really need this for my work!!
To provide some Code:
I am trying to load my initial View (Which is the TabBarController) like this in the AppDelegate.cs:
SplitViewContoller splitView = new SplitViewContoller();
IADViewController iAdVC = new IADViewController (splitView);
Console.WriteLine ("Root" + Window.RootViewController);
Window.RootViewController = iAdVC;
That is working fine, except that the view that usually appears doesn't get loaded... The IAD shows up but the rest of the screen is an empty TabBarController.
Here is my SplitViewController:
public class SplitViewContoller : UISplitViewController
{
UIViewController masterView, detailView;
public SplitViewContoller () : base()
{
// create our master and detail views
masterView = new TabBarController();
detailView = new IADViewController (new TabBarController());
// create an array of controllers from them and then
// assign it to the controllers property
ViewControllers = new UIViewController[]
{ masterView, detailView }; // order is important
}
public override bool ShouldAutorotateToInterfaceOrientation
(UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
The View that i want to be at the bottom of my screen:
(See Monotouch.Dialog and iAds for details)
public partial class IADViewController : UIViewController
{
private UIViewController _anyVC;
private MonoTouch.iAd.ADBannerView _ad;
public IADViewController (UIViewController anyVC)
{
_anyVC = anyVC;
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
View.AddSubview (_anyVC.View);
Version version = new Version (MonoTouch.Constants.Version);
if (version > new Version (6,0))
{
try {
_ad = new MonoTouch.iAd.ADBannerView (MonoTouch.iAd.ADAdType.Banner);
_ad.Hidden = true;
_ad.FailedToReceiveAd += HandleFailedToReceiveAd;
_ad.AdLoaded += HandleAdLoaded;
View.BackgroundColor = UIColor.Clear;
_anyVC.View.Frame = View.Bounds;
View.AddSubview (_ad);
} catch {
}
} else {
Resize ();
}
}
public override void DidRotate (UIInterfaceOrientation fromInterfaceOrientation)
{
base.DidRotate (fromInterfaceOrientation);
Resize ();
}
public override void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
Resize ();
}
void Resize ()
{
UIView.Animate (.25,
() => {
if (_ad !=null && _ad.Hidden == false) {
_anyVC.View.Frame = new RectangleF (0, 0, this.View.Bounds.Width, this.View.Bounds.Height - _ad.Frame.Height);
} else {
_anyVC.View.Frame = View.Bounds;
}
});
if(_ad!=null)
_ad.Frame = new RectangleF (0, _anyVC.View.Bounds.Height, this.View.Bounds.Width, _ad.Frame.Height);
}
void HandleAdLoaded (object sender, EventArgs e)
{
if (_ad == null)
return;
_ad.Hidden = false;
Resize ();
}
void HandleFailedToReceiveAd (object sender, AdErrorEventArgs e)
{
if (_ad == null)
return;
_ad.Hidden = true;
Resize ();
}
}
If anyone else need this, i solved it with the following lines of code now.
Storyboard = UIStoryboard.FromName ("MainStoryboard", null);
initialViewController = Storyboard.InstantiateInitialViewController () as UITabBarController;
// If you have defined a root view controller, set it here:
IADViewController iAdVc = new IADViewController (initialViewController);
Window.RootViewController = iAdVc;
// make the window visible
Window.MakeKeyAndVisible ();
As the Form of System.Windows.Forms inherits from Control, I was wondering if there is a way to create a Custom Form and its Designer with some options (shortcuts) to create a title or somthings like that.
I tried this, but nothings happend, the Form I calles ManagedForm
[Designer(typeof(ManagedFormDesigner))]
public class ManagedForm : Form{
//code here
}
[PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
public class ManagedFormDesigner : ControlDesigner {
private DesignerActionListCollection actionLists;
public override DesignerActionListCollection ActionLists {
get {
if (actionLists == null) {
actionLists = new DesignerActionListCollection();
actionLists.Add(new ManagedFormDesignerActionList(this.Component));
}
return actionLists;
}
}
}
public class ManagedFormDesignerActionList : DesignerActionList {
private ManagedForm managedForm = null;
private DesignerActionUIService designerActionUISvc = null;
public ManagedFormDesignerActionList(IComponent component) : base(component) {
this.managedForm = component as ManagedForm;
this.designerActionUISvc =
GetService(typeof(DesignerActionUIService))
as DesignerActionUIService;
}
public override DesignerActionItemCollection GetSortedActionItems() {
DesignerActionItemCollection items = new DesignerActionItemCollection();
items.Add(new DesignerActionMethodItem(this, "CreateTitle", "Create Title", "Appearence", true));
return items;
}
public void CreateTitle() {
Panel pTitulo = new Panel();
pTitulo.Size= new Size(100,25);
pTitulo.Dock = DockStyle.Top;
(this.Component as ManagedForm).Controls.Add(pTitulo);
}
}
Action list are show when you click on the little arrow on the control inside a form (or on a component on the bottom of the designer if the object is a component).
Other things you can do is to manage verbs.
Verbs Handling is implemented on the ControlDesigner class (ManagedFormDesigner in your case).
You can see verbs clicking right mouse button or on the bottom of the properties (i.e. TabControl ha 2 verbs, add tab and remove tab).
You can implement verbs adding to ControlDesigner (or ComponentDesigner) class something like this
private DesignerVerbCollection _verbs;
public override DesignerVerbCollection Verbs
{
get
{
if (_verbs == null)
{
_verbs = new DesignerVerbCollection();
_verbs.Add(new DesignerVerb("Create Title", new EventHandler(MyCreateTitleHandler)));
}
return _verbs;
}
}
private void MyCreateTitleHandler(object sender, EventArgs e)
{
// Do here something but take care to show things via IUIService service
IUIService uiService = GetService(typeof(IUIService)) as IUIService;
}
I have used the code from this blog, as below but abridged, and I see the WinForm inside my main window, but the sample text I placed on it in a label is not visible.
[System.Windows.Markup.ContentProperty("Child")]
public class WinFormsHost : HwndHost
{
public WinFormsHost()
{
var form = new ChildForm();
Child = form;
}
private System.Windows.Forms.Form child;
public event EventHandler<ChildChangedEventArgs> ChildChanged;
public System.Windows.Forms.Form Child
{
get { return child; }
set
{
HwndSource ps = PresentationSource.FromVisual(this) as HwndSource;
if (ps != null && ps.Handle != IntPtr.Zero)
{
throw new InvalidOperationException("Cannot set the Child property after the layout is done.");
}
Form oldChild = child;
child = value;
OnChildChanged(oldChild);
}
}
private void CheckChildValidity()
{
if (child == null || child.Handle == IntPtr.Zero)
{
throw new ArgumentNullException("child form cannot be null");
}
}
public Boolean ShowCaption
{
get
{
CheckChildValidity();
return (GetWindowStyle(Child.Handle) & WindowStyles.WS_BORDER) == WindowStyles.WS_CAPTION;
}
set
{
if (child == null)
{
this.ChildChanged += delegate
{
if (value)
{
SetWindowStyle(Child.Handle, GetWindowStyle(Child.Handle) | WindowStyles.WS_CAPTION);
}
else
{
SetWindowStyle(Child.Handle, GetWindowStyle(Child.Handle) & ~WindowStyles.WS_CAPTION);
}
};
}
else
{
if (value)
{
SetWindowStyle(Child.Handle, GetWindowStyle(Child.Handle) | WindowStyles.WS_CAPTION);
}
else
{
SetWindowStyle(Child.Handle, GetWindowStyle(Child.Handle) & ~WindowStyles.WS_CAPTION);
}
}
}
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
CheckChildValidity();
HandleRef childHwnd = new HandleRef(Child, child.Handle);
SetWindowStyle(childHwnd.Handle, WindowStyles.WS_CHILD | GetWindowStyle(childHwnd.Handle));
WindowsFormsHost.EnableWindowsFormsInterop();
System.Windows.Forms.Application.EnableVisualStyles();
SetParent(childHwnd.Handle, hwndParent.Handle);
return childHwnd;
}
}
And:
<Window x:Class="WinFormsHost"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
xmlns:cc="clr-namespace:XTime.Shell.WinformsHost"
Title="Hosting Form In WPF">
<cc:WinFormsHost ShowCaption="False">
<wf:Form/>
</cc:WinFormsHost>
</Window>
<cc:WinFormsHost ShowCaption="False">
<wf:Form/>
</cc:WinFormsHost>
Your XAML embeds a System.Windows.Forms.Form object inside the WinFormsHost. Which is what you got, just a blank form with no child controls embedded inside it. It looks like you made an attempt at creating your own in the WinFormsHost constructor, assigning the Child property, but your XAML is overriding it so you are just left with a blank form again.
I put a ChildForm class inside the same namespace:
using System.Windows.Forms;
using System.Drawing;
...
public class ChildForm : System.Windows.Forms.Form {
public ChildForm() {
this.BackColor = Color.FromKnownColor(KnownColor.Window);
var lbl = new Label { Text = "Hello world" };
this.Controls.Add(lbl);
}
}
And updated the XAML to:
<cc:WinFormsHost ShowCaption="False">
<cc:ChildForm/>
</cc:WinFormsHost>
To get:
Set the FormBorderStyle to None to get rid of the border. Etcetera.
Setting the form's TopLevel property to false and Visible property to true is the much simpler way to turn a Form into a child control btw. I left it this way since you hinted you might want to give a Delphi window the same treatment. In which case you might want to go back to your original approach again, creating the child in the form class constructor and just omitting the content assignment in the XAML.