What is the optimal solution to design big screens and tablets?
the view looks good on phones but when on tablets or big screens, the buttons and text entries looks stretched and unprofessional.
I can add padding but is there a better solution than that?
I see that the new pre-release of Xamarin forms version 3 doesn't support #medai. But does it account for this issue in another way?
The Xamarin.Forms Page class has a SizeChanged event we can use to determine the available screen-size at runtime. We can adjust the UI based on the Width or Height of the screen.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
SizeChanged += MainPageSizeChanged;
}
void MainPageSizeChanged(object sender, EventArgs e)
{
imgMonkey.WidthRequest = Math.Min(this.Width, 400);
}
}
And Xamarin.Forms provides a static Idiom property on the Device class that we can use to check the device type.
if (Device.Idiom == TargetIdiom.Phone)
{
buttonAbout.HeightRequest = 25;
buttonAbout.WidthRequest = 40;
}
else
{
buttonAbout.HeightRequest = 40;
buttonAbout.WidthRequest = 70;
}
Detail refer to Adaptive UI with Xamarin.Forms.
You can use VisualStateManager to achieve this task.
Find more information on how to get started at https://xamarinhelp.com/visualstatemanager-xamarin-forms-phase-1/
Related
can someone explain how can I fix it...
I use Metro Framework downloaded from GitHub and when I use two metro tile I get form like on image bellow.
But I want when click on "Theme" or "Color" to change like default. You can see on top not change color and window not change to dark theme but only metro text box, metro label but metro panel it's OK.
private void metroTileSwitch_Click(object sender, EventArgs e)
{
var m = new Random();
int next = m.Next(0, 13);
metroStyleManager.Style = (MetroColorStyle)next;
}
private void metroTile1_Click(object sender, EventArgs e)
{
metroStyleManager.Theme = metroStyleManager.Theme == MetroThemeStyle.Light ? MetroThemeStyle.Dark : MetroThemeStyle.Light;
}
Thank you for help.
Be sure of that :
step 1- items that doesn't change theme , theme property is set to Default example:
this.Theme = MetroThemeStyle.Default;
step 2- set owner of metroStyleManager to this form :
metroStyleManager1.Owner = this;
step 3- if problem still you need to connect each item to metroStyleManager example :
this.StyleManager = metroStyleManager1;
metroTextBox1.StyleManager = metroStyleManager1;
//etc...
I wrote an Visual Studio 2013 extension that observes Windows.Forms designer windows. When a developer is changing controls in the designer window, the extension tries to verify that the result is consistent with our ui style guidelines. If possible violations are found they are listed in a tool window. This all works fine.
But now I would like to mark the inconsistent controls in the designer window, for example with a red frame or something like this.
Unfortunately, I did not find a way to draw adornments on controls in a designer window. I know that you can draw those adornments if you develop your own ControlDesigner, but I need to do it from "outside" the control's designer. I only have the IDesignerHost from the Dte2.ActiveWindow and can access the Controls and ControlDesigners via that host. I could not find any way to add adornments from "outside" the ControlDesigners.
My workaround for now is to catch the Paint-Events of the controls and try to draw my adornments from there. This doesn't work well for all controls (i.e. ComboBoxes etc), because not all controls let you draw on them. So I had to use their parent control's Paint event. And there are other drawbacks to this solution.
I hope someone can tell me if there is a better way. I'm pretty sure that there has to be one: If you use Menu->View->Tab Order (not sure about the correct english menu title, I'm using a german IDE), you can see that the IDE itself is able to adorn controls (no screenshot because it's my first post on SO), and I'm sure it is not using a work around like me. How does it do that?
I've been googling that for weeks now. Thanks for any help, advice, research starting points....
UPDATE:
Maybe it gets a little bit clearer with this screenshot:
Those blue numbered carets is what Visual Studio shows when selecting Tab order from the View menu. And my question is how this is done by the IDE.
As mentioned I tried to do it in the Paint event of the controls, but e.g. ComboBox doesn't actually support that event. And if I use the parent's Paint event I can only draw "around" the child controls because they are painted after the parent.
I also thought about using reflection on the controls or the ControlDesigners, but am not sure how to hook on the protected OnPaintAdornments method. And I don't think the IDE developers used those "dirty" tricks.
I believe you are seeking for BehaviorService architecture. The architecture with supporting parts like Behavior, Adorner and Glyph and some examples is explained here Behavior Service Overview. For instance
Extending the Design-Time User Interface
The BehaviorService model enables new functionality to be easily layered on an existing designer user interface. New UI remains independent of other previously defined Glyph and Behavior objects. For example, the smart tags on some controls are accessed by a Glyph in the upper-right-hand corner of the control (Smart Tag Glyph).
The smart tag code creates its own Adorner layer and adds Glyph objects to this layer. This keeps the smart tag Glyph objects separate from the selection Glyph objects. The necessary code for adding a new Adorner to the Adorners collection is straightforward.
etc.
Hope that helps.
I finally had the time to implement my solution and want to show it for completeness.
Of course I reduced the code to show only the relevant parts.
1. Obtaining the BehaviorService
This is one of the reasons why I don't like the service locator (anti) pattern. Though reading a lot of articles, I didn't came to my mind that I can obtain a BehaviorService from my IDesignerHost.
I now have something like this data class:
public class DesignerIssuesModel
{
private readonly BehaviorService m_BehaviorService;
private readonly Adorner m_Adorner = new Adorner();
private readonly Dictionary<Control, MyGlyph> m_Glyphs = new Dictionary<Control, MyGlyph>();
public IDesignerHost DesignerHost { get; private set; }
public DesignerIssuesModel(IDesignerHost designerHost)
{
DesignerHost = designerHost;
m_BehaviorService = (BehaviorService)DesignerHost.RootComponent.Site.GetService(typeof(BehaviorService));
m_BehaviorService.Adornders.Add(m_Adorner);
}
public void AddIssue(Control control)
{
if (!m_Glyphs.ContainsKey(control))
{
MyGlyph g = new MyGlyph(m_BehaviorService, control);
m_Glyphs[control] = g;
m_Adorner.Glyphs.Add(g);
}
m_Glyphs[control].Issues += 1;
}
public void RemoveIssue(Control control)
{
if (!m_Glyphs.ContainsKey(control)) return;
MyGlyph g = m_Glyphs[control];
g.Issues -= 1;
if (g.Issues > 0) return;
m_Glyphs.Remove(control);
m_Adorner.Glyphs.Remove(g);
}
}
So I obtain the BehaviorService from the RootComponent of the IDesignerHost and add a new System.Windows.Forms.Design.Behavior.Adorner to it. Then I can use my AddIssue and RemoveIssue methods to add and modify my glyphs to the Adorner.
2. My Glyph implementation
Here is the implementation of MyGlyph, a class inherited from System.Windows.Forms.Design.Behavior.Glyph:
public class MyGlyph : Glyph
{
private readonly BehaviorService m_BehaviorService;
private readonly Control m_Control;
public int Issues { get; set; }
public Control Control { get { return m_Control; } }
public VolkerIssueGlyph(BehaviorService behaviorService, Control control) : base(new MyBehavior())
{
m_Control = control;
m_BehaviorService = behaviorService;
}
public override Rectangle Bounds
{
get
{
Point p = m_BehaviorService.ControlToAdornerWindow(m_Control);
Graphics g = Graphics.FromHwnd(m_Control.Handle);
SizeF size = g.MeasureString(Issues.ToString(), m_Font);
return new Rectangle(p.X + 1, p.Y + m_Control.Height - (int)size.Height - 2, (int)size.Width + 1, (int)size.Height + 1);
}
}
public override Cursor GetHitTest(Point p)
{
return m_Control.Visible && Bounds.Contains(p) ? Cursors.Cross : null;
}
public override void Paint(PaintEventArgs pe)
{
if (!m_Control.Visible) return;
Point topLeft = m_BehaviorService.ControlToAdornerWindow(m_Control);
using (Pen pen = new Pen(Color.Red, 2))
pe.Graphics.DrawRectangle(pen, topLeft.X, topLeft.Y, m_Control.Width, m_Control.Height);
Rectangle bounds = Bounds;
pe.Graphics.FillRectangle(Brushes.Red, bounds);
pe.Graphics.DrawString(Issues.ToString(), m_Font, Brushes.Black, bounds);
}
}
The details of the overrides can be studied in the links posted in the accepted answer.
I draw a red border around (but inside) the control and add a little rectangle containing the number of found issues.
One thing to note is that I check if Control.Visible is true. So I can avoid to draw the adornment when the control is - for example - on a TabPage that is currently not selected.
3. My Behavior implementation
Since the constructor of the Glyph base class needs an instance of a class inherited from Behavior, I needed to create a new class. This can be left empty, but I used it to show a tooltip when the mouse enters the rectangle showing the number of issues:
public class MyBehavior : Behavior
{
private static readonly ToolTip ToolTip = new ToolTip
{
ToolTipTitle = "UI guide line issues found",
ToolTipIcon = ToolTipIcon.Warning
};
public override bool OnMouseEnter(Glyph g)
{
MyGlyph glyph = (MyGlyph)g;
if (!glyph.Control.Visible) return false;
lock(ToolTip)
ToolTip.Show(GetText(glyph), glyph.Control, glyph.Control.PointToClient(Control.MousePosition), 2000);
return true;
}
public override bool OnMouseLeave(Glyph g)
{
lock (ToolTip)
ToolTip.Hide(((MyGlyph)g).Control);
return true;
}
private static string GetText(MyGlyph glyph)
{
return string.Format("{0} has {1} conflicts!", glyph.Control.Name, glyph.Issues);
}
}
The overrides are called when the mouse enters/leaves the Bounds returned by the MyGlyph implementation.
4. Results
Finally I show screenshot of a example result. Since this was done by the real implementation, the tooltip is a little more advanced. The button is misaligned to all the comboboxes, because it's a little too left:
Thanks again to Ivan Stoev for pointing me to the right solution. I hope I could make clear how I implemented it.
Use the System.Drawing.Graphics.FromHwnd method, passing in the HWND for the designer window.
Get the HWND by drilling down into the window handles for visual studio, via pinvoke. Perhaps use tools like Inspect to find window classes and other information that might help you identify the correct (designer) window.
I've written a C# program to get you started here.
I wonder if it's possible to customize my C# application (winforms) to get a better design, I made a PSD (photoshop document) so I can generate png jpeg... pictures if I need them.
Example of a form like the one I want :
Indeed as it was pointed out in the comments, it is easy to use WPF (indows Presentation Foundation) to achieve that result, but if you really need that it must be made in windows forms I can help you with that...
ControlBox and Border
It seens that your form does not have a control box (minimize, maximize and close buttons)
to achieve that you can set
form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
I'm not sure if that galaxy behind your form is part of the application so i'll be considering that it is not
To achieve that irregular shape of the form we have to do a workaround here
Irregular Shape of the Form
we are going to set a Color to TransparentKey, so everything in the form in that specific color will be transparent, like it does not exists (if you click in that part it will go into de desktop or whatever application you have behind in your form)
So let's use a specific color which we will probably dont use in the form
form.TransparencyKey = Color.FromArgb(111, 111, 111); //You can do it by the editor
So in order to make that white part we are going to use an Panel and a PictureBox outsite of the Panel trying to copy the shape of your image
Stylized Inputs
To make it easier and reusable I'm going to make a userControl in this one
the usercontrol will have
a Panel called HighLightPanel, its dock property will be set to Fill
a Panel called BackColorPanel, it will be inside the HighLightPanel
a PictureBox called InputPicture, its dock property will be set to Left, it will be inside BackColorPanel and its acessor will be public
a TextBox called TextBox, its dock property wil be set to fill, it will be inside BackColorPanel, the BorderStyle Property set to None, you should set the size and font you most desize in this one, I'm going to use Segoe UI; 15,75pt and its acessor will be public
Now we have to make some properties in our UserControl to make it work without work in other controls
First in the SizeChanged event of the HighLightPanel we will make the BackColorPanel be exacly two points smaller in every direction and its position to 1;1 so we can see the HighLightPanel
private void HighlightPanel_SizeChanged(object sender, EventArgs e)
{
this.BackColorPanel.Size = new Size(
HighlightPanel.Width - 2,
HighlightPanel.Height - 2);
}
Now we will create two propertys to handle the Highlight Color
public Color HighlightBorderColor { get; set; }
public Color NonHighlightBorderColor { get; set; }
And in the Enter and Leave Property of our TextBox we are going to change the HighlightPanel
private void TextBox_Enter(object sender, EventArgs e)
{
HighlightPanel.BackColor = HighlightBorderColor;
}
private void TextBox_Leave(object sender, EventArgs e)
{
HighlightPanel.BackColor = NonHighlightBorderColor;
}
So now every time the user enter the Input it will appear that the Input has an Border in the specified Color
Now to enhance its usability to developers we will make some wrappers in its controls to be easier change property of child controls in the editor
public Image InputImage
{
get { return InputPicture.Image; }
set { InputPicture.Image = value; }
}
public PictureBoxSizeMode InputImageLayout
{
get { return InputPicture.SizeMode; }
set { InputPicture.SizeMode = value; }
}
public char PasswordCharacter
{
get { return TextBox.PasswordChar; }
set { TextBox.PasswordChar = value; }
}
public bool ShowInputImage
{
get { return InputPicture.Visible; }
set { InputPicture.Visible = value; }
}
In the InputImage set the picture you want for the User and the Key
Insert the two controls in the position you like
Position of the Form
if you want your form to be moveable without the border you will have to use this snippet, it is more easy in WPF
#region MoveForm
Point LastPoint;
bool ShouldMove;
private void form_MouseDown(object sender, MouseEventArgs e)
{
LastPoint = e.Location;
ShouldMove = true;
this.TransparencyKey = Color.FromArgb(111, 111, 111);
}
private void form_MouseUp(object sender, MouseEventArgs e)
{
ShouldMove = false;
}
private void form_MouseMove(object sender, MouseEventArgs e)
{
if (ShouldMove)
{
this.Location = new Point(
this.Location.X - LastPoint.X + e.X,
this.Location.Y - LastPoint.Y + e.Y);
}
}
#endregion
If you need a lot of special graphics effects learning WPF will indeed be a sound investement.
If all you want is that login screen, it is trivial in Winforms and doesn't take any horrible hacks as you've been told..
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.BackColor = System.Drawing.Color.LavenderBlush;
this.TransparencyKey = System.Drawing.Color.LavenderBlush;
this.ControlBox = false;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Text= "";
These seven lines are all it takes for a form to be transparent. I copied them from the Designer code; you can simply set the 7 Properties in the property grid.
Now add a panel, dock it to the bottom and give it the right color; add a picturebox and your other controls and you are set.
To create the two input groups you also need just a few regular controls and only a few simple lines of code:
You place one Panel, BorderStyle = FixedSingle; and add a Label and a TextBox to it. The Label has AutoSize = False; and both ImageAlign and TextAlign are set to MiddleLeft. You assign an image to the Label's Image and prefix the Text with enough blanks to not overlap. Obviously you should define a PasswordChar for the 2nd TextBox. Now all you need is to script the Enter and Leave events to change the BackColor of the respective Panels between, say SystemColors.Control and SystemColors.MenuHighlight. Size the Labels to almost fill the Panels and you are done. Less code than the WPF version, I'd bet.
If you need such input an controls again and again, simply create Usercontrols for each type you need!
Here is an example of the limits you will hit: Wouldn't it be nice to add a dropshadow effect to the image? It is doable in Winforms. But it would involve painting that effect; this would take at least 15 or 20 lines of involved code instead of simply turning the effect on with (estimated) 1-3 simple lines.
Do you need any nice hover effects? Not easy, to say the least..
These limits will be all over the place, so it really depends on how fancy your requirements will get.
Maybe you should use this example as a starter to compare the two techniques and to warm you up to WPF?
Im making a program with many many pages... and in my design, the buttons will eventually get stacked up, so its getting harder and harder to work the more there are.
This question is a clone of this topic.
However, i didn't really get the answer since they were talking about xaml and wpf.
I've also tried to make multiple windows forms, hide and show them to split it up.
But when i hide and show a wndow, its very very easily to see the GUI fading in and out which looks ugly.
I want an instant hide/show function so it looks like its just 1 program with 1 window and now switching.
So what are the tecniques to make a big windowsforms program more managable?
You may create a couple of UserControls, organize and separate your logic on them. Then you may use String Array to store your control names and iterate througth items to display apropriate view. The form may have Panel as container and Dock Style defined as Fill. The simplefied code will look like:
public class MyContainer:Control
{
public MyContainer(string szControlName, UserControl nControl)
{
UserControlName = szControlName; MyControl = nControl;
}
public string UserControlName { get; set; }
public UserControl MyControl { get; set; }
}
In main form:
public List<MyContainer> MyNavigationArray;
public void InitArray()
{
MyNavigationArray = new List<MyContainer>(MyFormPageCount);
for (int i = 0; i < MyFormPageCount; i++)
{
MyNavigationArray.Add(new MyContainer(TheNameOfUserControl, new PredefinedUserControl()));
}
}
private void NextButton_click(object sender, EventArgs e)
{
MyContainer mYcn = this.panel1.Controls[0] as MyContainer;
int nCurPos = MyNavigationArray.IndexOf(mYcn);
if (nCurPos < MyNavigationArray.Count)
{
panel1.Controls.Clear();
MyContainer c = MyNavigationArray[nCurPos + 1];
panel1.Controls.Add(c);
c.Dock = DockStyle.Fill;
}
}
All information stored inside user controls will be in your array and can be used later.
Hope this helped.
I am working on a project in c# using windows forms.
me and the group I am in want to make it so that when the user hovers their mouse over an image, in our case a card, that a larger image of that card appears next to the mouse arrow, much in the same way a tool tip would work.
I don't think you can use a tool tip to do this i have tried looking everywhere,
any advice or examples would be great thank you very much
You may want to look at this Code Project Article
It shows you how to create an OwnerDrawn ToolTip with an Image.
Thanks for the responses I got everything figured out.
What I wanted to do was that when I moused over a certain area a different image for that area would popup in the same way that a tool tip did. So after some research I figured out how to create my own tool tip class.
here's an example.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
CustomToolTip tip = new CustomToolTip();
tip.SetToolTip(button1, "text");
tip.SetToolTip(button2, "writing");
button1.Tag = Properties.Resources.pelican; // pull image from the resources file
button2.Tag = Properties.Resources.pelican2;
}
}
class CustomToolTip : ToolTip
{
public CustomToolTip()
{
this.OwnerDraw = true;
this.Popup += new PopupEventHandler(this.OnPopup);
this.Draw +=new DrawToolTipEventHandler(this.OnDraw);
}
private void OnPopup(object sender, PopupEventArgs e) // use this event to set the size of the tool tip
{
e.ToolTipSize = new Size(600, 1000);
}
private void OnDraw(object sender, DrawToolTipEventArgs e) // use this to customzie the tool tip
{
Graphics g = e.Graphics;
// to set the tag for each button or object
Control parent = e.AssociatedControl;
Image pelican = parent.Tag as Image;
//create your own custom brush to fill the background with the image
TextureBrush b = new TextureBrush(new Bitmap(pelican));// get the image from Tag
g.FillRectangle(b, e.Bounds);
b.Dispose();
}
}
}
A simple way to do is to hide/show a picture box at specified location. Another method is to load & draw (paint) an image using GDI API.