Showing and disposing tooltip .NET - c#

I am working with yFiles.Net component which I use for representing dependencies between objects in some SQL database (graph representation).
I need to create tooltip which will appear when I point cursors on some object. That tooltip not contains just text, it contains images also. I know how to make custom class which extends default Tooltip class and then to override methods for drawing custom tooltips.
What i do not know is how to show tooltip when I point on some object on graph, and how to dispose it when I move cursor from object on graph? Can someone help me with this please?

If I understand you correctly, you want to intercept the
ItemHoverInputMode.HoveredItemChanged Event.
I have not tested this nor worked with yFiles before, but according to documentation this should work:
// 'gc' is of type yWorks.yFiles.UI.GraphControl.
var ihim = new ItemHoverInputMode();
ihim.HoveredItemChanged += YourEvenHandler;
gc.InputModes.Add(ihim);
Then check the element in the event handler and display or hide the tooltip.

private CustomTooltip m_tooltip;
private MouseHoverInputMode m_mouseHoverMode;
private void SetupToolTips(GraphEditorInputMode mode)
{
m_tooltip = new CustomTooltip(m_model.TooltipImages);
ItemHoverInputMode itemHoverMode = new ItemHoverInputMode();
itemHoverMode.HoverItems = GraphItemTypes.Node | GraphItemTypes.Edge;
mode.ItemHoverInputMode = itemHoverMode;
m_mouseHoverMode = new MouseHoverInputMode(m_tooltip, textProvider);
mode.MouseHoverInputMode = m_mouseHoverMode;
mode.ItemHoverInputMode.HoveredItemChanged += new EventHandler<HoveredItemChangedEventArgs>(ToolTipEvent);
}
private void ToolTipEvent(object sender, HoveredItemChangedEventArgs e)
{
m_tooltip.Item = e.Item;
}
private void textProvider(object sender, ToolTipQueryEventArgs e)
{
if (m_tooltip.Item is INode || m_tooltip.Item is IEdge)
{
e.ToolTip = " ";
}
}
public class CustomTooltip : ToolTip
{
private void OnPopup(object sender, PopupEventArgs e)
{
}
private void OnDraw(object sender, DrawToolTipEventArgs e)
{
}
}

Related

c# List.Add() unable to add correct values

Program suppose to draw shapes on panel1.
This is code for my main form:
namespace DrawShapes
{
public partial class Form1 : Form
{
List<Shape> myShapeList;
Shape shape;
public Form1()
{
InitializeComponent();
}
public void AddShape(Shape myshape)
{
myShapeList.Add(shape);
}
public List<Shape> MyShapeList
{
get { return myShapeList; }
}
private void Form1_Load(object sender, EventArgs e)
{
myShapeList = new List<Shape>();
shape = new Shape();
}
private void drawMeButton_Click(object sender, EventArgs e)
{
EditShape editShape = new EditShape();
editShape.Shape = shape;
if (editShape.ShowDialog() == DialogResult.OK)
{
this.shape = editShape.Shape;
myShapeList.Add(shape);
panel1.Invalidate();
}
editShape.Dispose();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
int panelWidth = panel1.ClientRectangle.Width;
int panelHeight = panel1.ClientRectangle.Height;
Pen penLine = new Pen(Color.Blue, 1);
Graphics g = e.Graphics;
if (myShapeList != null)
{
foreach (Shape element in myShapeList)
{
label1.Text = element.Width.ToString();
g.DrawRectangle(penLine, element.XCordinates, element.XCordinates, 50, 50);
}
}
}
}
}
and here is code for my edit shape dialog box
namespace DrawShapes
{
public partial class EditShape : Form
{
Shape shape = null;
public EditShape()
{
InitializeComponent();
}
public Shape Shape
{
get { return shape; }
set { shape = value; }
}
private void button1_Click(object sender, EventArgs e)
{
shape.Width = 50;
shape.Height = 50;
shape.XCordinates = int.Parse(textBox1.Text);
shape.YCordinates = int.Parse(textBox2.Text);
shape.Type = 0;
DialogResult = DialogResult.OK;
}
}
}
I am having problem assigning shape object(from Edit Shape form) to myShapeList, all properties are set to 0 for some reason. Please help.
Perhaps the problem is your AddShape method. You seem to be adding shape each time instead of the shape that's getting passed into the method (myshape).
What happens if you do this instead?
public void AddShape(Shape myshape)
{
myShapeList.Add(myshape); // myshapeinstead of shape
}
It seems that you're not actually adding your shape to your shapelist. You're taking in myShape and then trying to add in shape. This should come up as an intellisense error.
public void AddShape(Shape myshape)
{
myShapeList.Add(shape);
}
EDIT: Nevermind, it wouldn't come up as an error because you have a member variable named shape. You're getting zero for everything because it's calling the default constructor for shape.
The big problem is in your call to the edit form. You are adding to the list the same object reference. So when you modify the reference inside the edit form you change all the elements added to the list to the inputs set in the latest call
Change your code to
private void drawMeButton_Click(object sender, EventArgs e)
{
using(EditShape editShape = new EditShape())
{
// Here, create a new instance of a Shape and edit it....
editShape.Shape = new Shape();
if (editShape.ShowDialog() == DialogResult.OK)
{
// Add the new instance to the list, not the same instance
// declared globally. (and, at this point, useless)
myShapeList.Add(editShape.Shape);
panel1.Invalidate();
}
// The using blocks makes this call superflous
// editShape.Dispose();
}
}
Then it is not clear when you call the method AddShape(Shape myshape) but it is clear that you have typo in that method
I have found my mistake.I Created new event handler with wrong parameters. Therefore information that suppose to be passed by my dialog OK button was never correctly assigned. Silly mistake. Thanks guys.

How can I update the label value when the value changes?

I am trying to update "Player's health." when "Player" attacks a target. Player's health is reduced based on the target's return damage.
My Game class (where the label is):
public partial class Game : Form
{
public static Wizard wizard;
public static Assasin assasin;
public Game()
{
InitializeComponent();
}
private void Battle_Click(object sender, EventArgs e)
{
Battle battle = new Battle();
battle.Show();
}
public void Game_Load(object sender, EventArgs e)
{
NameLabel.Text = HeroMaker.className;
if (HeroMaker.wizardChoosen)
{
wizard = new Wizard(HeroMaker.className);
HealthLabel.Text = wizard.Health.ToString();
DamageLabel.Text = wizard.AttackDamage.ToString();
HealthBar.Maximum = wizard.Health;
HealthBar.Value = wizard.Health;
}
}
}
My Battle class (when attacking is happening) :
public partial class Battle : Form
{
Creature troll = CreaturesFactory.CreateCreature(CreatureType.Troll);
public Battle()
{
InitializeComponent();
}
private void AttackTroll_Click(object sender, EventArgs e)
{
Game.wizard.Health -= troll.ReturnDamage;
//TODO: Update the "HealthLabel value."
}
}
The problem is that when I attack the troll, Player's health is decreasing but its not updating on the label. Thanks in advance.
You just need to update the label:
private void AttackTroll_Click(object sender, EventArgs e)
{
Game.wizard.Health -= troll.ReturnDamage;
//TODO: Update the "HealthLabel value."
HealthLabel.Text = wizard.Health.ToString();
//any other things that need to be updated
}
You can also bind the label value like in this question.
Similarly, you can hook up an event such as OnWizardHealthChange that updates the label value whenever the HP changes. This way, you won't need to remember to add HealthLabel.Text = wizard.Health.ToString(); everywhere the health changes. There's an example of this in the question that I linked.
EDIT:
You can try looking in the code-behind where the label is created to see its access modifier (is it public?)
Or, you can try this:
Label healthLabel = (Label)Application.OpenForms["FormName"].Controls.OfType<Label>().First(x=> x.Name == "LabelName");
Note that I haven't tested it but you should be able to at least get the label using this code and then update the value there. Here is a good discussion on accessing controls (such as your label) in another form.

Is there any way to hide the arrow on a ToolStripMenuItem?

Is there any way to hide the arrow on a ToolStripMenuItem? The arrow is enclosed in the red square.
I've found this is very helpful, you can create your own custom ToolStripRenderer inherits from ToolStripProfessionalRenderer, like this:
public class CustomToolStripRenderer : ToolStripProfessionalRenderer
{
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
{
e.ArrowRectangle = Rectangle.Empty;//Don't draw arrow
base.OnRenderArrow(e);
}
}
//and update the Renderer property of your MenuStrip
menuStrip1.Renderer = new CustomToolStripRenderer();
UPDATE
For your requirement, there are some ways to do but I think this is a good way:
public class CustomToolStripRenderer : ToolStripProfessionalRenderer
{
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
{
if (RenderArrow != null) RenderArrow(this, e);
base.OnRenderArrow(e);
}
public new event ToolStripArrowRenderEventHandler RenderArrow;//This will hide the default RenderArrow event which can't help you change the e argument because the default is fired after the Arrow is rendered.
}
//Now you have to create your own List<ToolStripItem> to contain all the items whose arrows should not be rendered
List<ToolStripItem> ItemsWithoutArrow = new List<ToolStripItem>();
//Add a method to add an item to that list
private void SuppressDrawArrow(ToolStripItem item)
{
if (!ItemsWithoutArrow.Contains(item)) ItemsWithoutArrow.Add(item);
}
//Assign custom ToolStripRenderer for your MenuStrip
menuStrip1.Renderer = new CustomToolStripRenderer();
//Now add a RenderArrow event handler, this RenderArrow event is the new we created in the class CustomToolStripRenderer
((CustomToolStripRenderer)menuStrip1.Renderer).RenderArrow += (s, e) =>
{
if(ItemsWithoutArrow.Contains(e.Item)) e.ArrowRectangle = Rectangle.Empty;
};
//Add some item to the ItemsWithoutArrow to test
SuppressDrawArrow(item1ToolStripMenuItem);
Another solution (I like many solutions to a problem :)
public class CustomToolStripRenderer : ToolStripProfessionalRenderer
{
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
{
if(!itemsWithoutArrow.Contains(e.Item)) base.OnRenderArrow(e);
}
public void SuppressDrawArrow(ToolStripItem item){
if (!itemsWithoutArrow.Contains(item)) itemsWithoutArrow.Add(item);
}
public void AllowDrawArrow(ToolStripItem item){
itemsWithoutArrow.Remove(item);
}
private List<ToolStripItem> itemsWithoutArrow = new List<ToolStripItem>();
}
//Use in code
CustomToolStripRenderer renderer = new CustomToolStripRenderer();
renderer.SuppressDrawArrow(item1ToolStripMenuItem);
menuStrip1.Renderer = renderer;
//This solution fits your requirement (draw or don't draw arrow) but if you also want to change such as ArrowColor, the previous solution would be better.
I've found that we can render it freely with many options. That's great :)

Make a radio button input from a form public in C#?

I've got code and i know I'm 99% of the way there. C# coding in MS VS2008.
Basically I have a form that has 4 radio buttons and a Continue button. the user clicks one of the radio buttons and clicks continue, and this all works fine.
However, I want to use the value entered by the user (i.e. if they click the first button, I want a variable equal to 1, 2nd button equals 2 and so on). I tried doing this in various points but the only place I can get it to run is in the private void btnOkClick line, which means I can use the values outside this void, which is what I really want.
I've tried playing around with setting some enums and such (commented out in the code below), but I can't quite get it. I know I must be close but my novice-ness is truly showing as I keep reading posts and can't quite grasp it.
In short, I want to be able to have other classes in my VS2008 project be able to reference whatever value the user selected in the initial form.
namespace AmortClient
{
public partial class frmLoadACTFCST : Form
{
public frmLoadACTFCST()
{
InitializeComponent();
//set the parent of the form to the container
//this.MdiParent = parent;
}
//public enum ACTFCST
//{
// ACT = 1,
// FCST = 2,
// PLAN = 3,
// FiveYearPlan2012=4
//}
//private ACTFCST _actfcst = ACTFCST.ACT;
//public ACTFCST actfcst
//{
// get { return _actfcst; }
// set { _actfcst = value; }
//}
private void frmLoadACTFCST_Load(object sender, EventArgs e)
{
}
private void groupBox1_Enter(object sender, EventArgs e)
{
}
private void btnActual_CheckedChanged(object sender, EventArgs e)
{
}
private void btnForecast_CheckedChanged(object sender, EventArgs e)
{
}
private void btnPlan_CheckedChanged(object sender, EventArgs e)
{
}
private void btn5YrPlan2012_CheckedChanged(object sender, EventArgs e)
{
}
private void btnContinue_Click(object sender, EventArgs e)
{
string ACTFCSTtext = "";
int dataTypeKey = 0;
if (btnActual.Checked)
{
ACTFCSTtext = btnActual.Text;
dataTypeKey = 1;
}
else if (btnForecast.Checked)
{
ACTFCSTtext = btnForecast.Text;
dataTypeKey = 2;
}
else if (btnPlan.Checked)
{
ACTFCSTtext = btnPlan.Text;
dataTypeKey = 3;
}
else if (btn5YrPlan2012.Checked)
{
ACTFCSTtext = btn5YrPlan2012.Text;
dataTypeKey = 4;
}
string msg = "";
msg = ACTFCSTtext + " " + dataTypeKey;
//btn5YrPlan2012
MessageBox.Show(msg);
Close();
}
}
}
Your dataTypeKey and ACTFCSTtext variables need to be declared as instance variables for your Form object if you want to access them from any other methods within your form. If you want to use them with some other form, you can pass them either as constructor arguments, or set some properties of said other form.
So you'd declare them just after the class declaration if you want them to be instance variables. They should still be private, meaning they can only be accessed from within your frmLoadACTFCST class.
public partial class frmLoadACTFCST : Form
{
private string ACTFCSTtext = "";
private int dataTypeKey = 0;
...
EDIT: if you want to access variables from one object in a different object (or static class), your options are as follows...
1) Declare your variables as public instance variables (same as shown above but public; these are known as Properties when you give them getter and setter methods). Your class that needs access to these variables would need to have a reference to the class that owns the variables.
Example:
FormA has a public property named SomeString.
FormB needs to access SomeString.
FormB needs a reference to FormA, and would access the variable as...
formAReference.SomeString
2) Pass the values of the variables as arguments to some method for the class that needs access.
Example:
FormA has a private instance variable named SomeString.
FormB needs access to SomeString.
If FormA instantiates FormB, it can pass the value of SomeString to FormB's constructor...
//From within FormA's code
FormB formB = new FormB(SomeString);
//FormB's constructor
public FormB(string someString)
{
this.someString = someString;
}
Maybe there is a smarter way to do it.
public partial class frmLoadACTFCST : Form
{
public frmLoadACTFCST()
{
InitializeComponent();
actfcst = ACTFCST.ACT;
btnActual.Tag = ACTFCST.ACT;
btnActual.Checked = true;
btnForecast.Tag = ACTFCST.FCST;
btnPlan.Tag = ACTFSCT.PLAN;
btn5YrPlan2012.Tag = ACTFCST.FiveYearPlan2012;
}
public enum ACTFCST
{
ACT = 1,
FCST = 2,
PLAN = 3,
FiveYearPlan2012=4
}
public static ACTFCST actfcst { get; private set; }
private void CheckedChanged(object sender, EventArgs e)
{
// All the buttons uses this Click-event.
actfcst = (sender as Button).Tag as ACTFCST;
}
private void btnContinue_Click(object sender, EventArgs e)
{
MessageBox.Show(actfcst.ToString());
Close();
}
}
The point is that all the buttons calls CheckedChanged when clicked.
Using a static means that others can access the value using something like this:
frmLoadACTFCST.ACTFCST value = frmLoadACTFCST.actfcst;
// Do something based on value.
I hope this helps you in yoyr quest.
If you select a control in design view, the properties window contains an item named "Modifiers". You can make the control public here.
A better way would be to create a new public property on your form that yields the value of the currently selected radio button.

How do I pass variables to a buttons event method?

I need to be able to pass along two objects to the method being fired when I click a button. How do I do this?
So far I've been looking at creating a changed EventArgs:
public class CompArgs : System.EventArgs
{
private object metode;
private Type typen;
public CompArgs(object m, Type t)
{
this.metode = m;
this.typen = t;
}
public object Metode()
{
return metode;
}
public Type Typen()
{
return typen;
}
}
But how would I use it? Is it possible to somehow override the click-event of the button to use a custom eventhandler, which takes CompArgs as a parameter?
private void button1_Click(object sender, EventArgs e)
{
Assembly assembly = Assembly.LoadFile(#"c:\components.dll");
int counter = 0;
foreach (Type type in assembly.GetTypes())
{
if (type.IsClass == true)
{
Button btn = new Button();
btn.Location = new Point(174 + (counter * 100),10);
btn.Size = new Size(95, 23);
btn.Name = type.Name;
btn.Text = type.Name;
btn.UseVisualStyleBackColor = true;
this.Controls.Add(btn);
object obj = Activator.CreateInstance(type);
//I need to pass on obj and type to the btn_Click
btn.Click += new eventHandler(btn_Click);
counter++;
}
}
}
And the event-method where I need it:
private void btn_Click(object sender, CompArgs ca)
{
MessageBox.Show((string)ca.Typen().InvokeMember("getMyName",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
ca.Metode(),
null));
}
Wow, you guys are making this entirely to difficult. No need for any custom classes or method overrides. In this example I just need to pass a tab index number. You can specify whatever you want, so long as your method is expecting that value type.
button.Click += (sender, EventArgs) => { buttonNext_Click(sender, EventArgs, item.NextTabIndex); };
void buttonNext_Click(object sender, EventArgs e, int index)
{
//your code
}
Cant you just set a property or member variable on the form that hosts the button and access these from the button click event?
EDIT: custom button class suggestion after feedback comment (not the same suggestion as above)
class MyButton : Button
{
private Type m_TYpe;
private object m_Object;
public object Object
{
get { return m_Object; }
set { m_Object = value; }
}
public Type TYpe
{
get { return m_TYpe; }
set { m_TYpe = value; }
}
}
Button1Click(object sender, EventArgs args)
{
MyButton mb = (sender as MyButton);
//then you can access Mb.Type
//and Mb.object
}
I'd create a new Button and override the OnClick method. Rather than passing down the EventArgs, pass a new derived class in with your additional members.
On the delegate receiving the event, cast the given EventArgs to the more derived class you're expecting to get, alternatively setup a new Event that will be triggered at the same time when the button is pressed and hook up to that instead to make things more implicit.
Example Code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ButtonEx b1 = new ButtonEx();
b1.OnCustomClickEvent += new ButtonEx.OnCustomClickEventHandler(b1_OnCustomClickEvent);
}
void b1_OnCustomClickEvent(object sender, ButtonEx.CustomEventArgs eventArgs)
{
string p1 = eventArgs.CustomProperty1;
string p2 = eventArgs.CustomProperty2;
}
}
public class ButtonEx : Button
{
public class CustomEventArgs : EventArgs
{
public String CustomProperty1;
public String CustomProperty2;
}
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
if(OnCustomClickEvent != null)
{
OnCustomClickEvent(this, new CustomEventArgs());
}
}
public event OnCustomClickEventHandler OnCustomClickEvent;
public delegate void OnCustomClickEventHandler(object sender , CustomEventArgs eventArgs);
}
You could use the Tag property of the button. You can add a string value to this property from the designer properties window and then pick it up within the handler as so:
private void MyButton_Click(object sender, EventArgs e)
{
string tagValue = ((Button) sender).Tag;
if(tag == "blah")
{
// Do something
}
}
Not sure if this exists in Winforms but it does in WPF: There is a "tag" object on all controls which you can attach any object to. You could save the object that you want to pass and then in the event handler read it back out of the sender object.
private void Button_Click(object sender, RoutedEventArgs e)
{
var note = (sender as FrameworkElement).Tag as Note;
//Do something with note here
}
You can't use your own custom event argument class for a predefined event handler signature. At least, the custom event argument type will never be utilised by any default calls to the handler (which will only ever be of type EventArgs in the case of a button); you could, potentially, call the handler yourself, passing your custom type, however, you would need to have logic in order to cast it back from an EventArgs into that which it had been cast from.
As a possible solution (depending on your situation), consider a composite type to encapsulate the items you require, as with your event argument type, but keep the required instance as an accessible variable which can be utilised from within the event handler, or, at least, by the method/s which the even handler invokes.
For example, define your type...
public class MyType
{
public object AccessibleItem { get; set; }
}
And, in your form class...
private MyType MyTypeInstance = new MyType();
private void Button_Click(object sender, EventArgs e)
{
//here we can set the item, if needs be...
MyTypeInstance.AccessibleItem = new Anything();
//or access the item to use as required...
DoSomeMagicWithMyObject(MyTypeInstance.AccessibleItem);
}
EDIT:
Okay, looking at your current code I can only offer you this for now (it doesn't add the items to the forms control container and it uses a variable iterator within Linq (which I think is either frowned upon or just down-right wrong (?), but hey...):
private void BuildButtonToObjectDictionary()
{
int counter = 0;
var assembly = Assembly.LoadFile(#"c:\components.dll");
var buttonToObjectDictionary = (
from type in assembly.GetTypes()
where type.IsClass && !type.IsAbstract
select new
{
Button = new Button
{
Name = type.Name,
Text = type.Name,
Size = new Size(95, 25),
Location = new Point(175 + (counter * 100), 10),
UseVisualStyleBackColor = true
},
Item = Activator.CreateInstance(type),
Index = counter++
});
}
Would need to see more code to give a better answer, but you could create an event that takes your CompArgs as a parameter and is fired when the buttonEvent is captured
If you open yourForm.Designer.cs file you will see all the code auto generated by VS. Here you can alter the method called when clicking on the button (or add a second method).
this.yourButton.Location = new System.Drawing.Point(211, 51);
this.yourButton.Name = "yourButton";
this.yourButton.Size = new System.Drawing.Size(75, 23);
this.yourButton.TabIndex = 0;
this.yourButton.Text = "yourButton";
this.yourButton.UseVisualStyleBackColor = true;
this.yourButton.Click += new System.EventHandler(this.yourMethodHere(object1, object2);
Hope this helps.

Categories