Is it possible to unsubscribe an event handler from an protected override void?
protected override void OnViewLoaded(object sender, ViewLoadedEventArg e)
{
base.OnViewLoaded(sender, e);
list = VisualTreeUtil.FindFirstInTree<ListView>(Application.Current.MainWindow, "ListView");
ConfigureAndSuperviseInputControls(this.list);
ScrollViewer scroll = VisualTreeUtil.FindFirstInTree<ScrollViewer>(this.list);
scroll.ScrollChanged+=new ScrollChangedEventHandler(scroll_ScrollChanged);
}
void scroll_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ConfigureAndSuperviseInputControls(this.list);
ScrollViewer sb = e.OriginalSource as ScrollViewer;
if (sb.ContentVerticalOffset==sb.ScrollableHeight)
{
scroll.ScrollChanged-=new ScrollChangedEventHandler(scroll_ScrollChanged);
}
}
My problem is that i dont get acces to the scroll obejct in the scroll_ScrollChanged Method.
This code is not tested but can't you simple cast the sender object to the ScrollViewer and unsubscribe from the event like that:
protected override void OnViewLoaded(object sender, ViewLoadedEventArg e)
{
base.OnViewLoaded(sender, e);
list = VisualTreeUtil.FindFirstInTree<ListView>(Application.Current.MainWindow, "ListView");
ConfigureAndSuperviseInputControls(this.list);
ScrollViewer scroll = VisualTreeUtil.FindFirstInTree<ScrollViewer>(this.list);
scroll.ScrollChanged+=new ScrollChangedEventHandler(scroll_ScrollChanged);
}
void scroll_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ConfigureAndSuperviseInputControls(this.list);
ScrollViewer scroll = (ScrollViewer)sender;
if (scroll.ContentVerticalOffset==scroll.ScrollableHeight)
{
scroll.ScrollChanged-=new ScrollChangedEventHandler(scroll_ScrollChanged);
}
}
Sender should be a reference to the object that you require.
protected override void OnViewLoaded(object sender, ViewLoadedEventArg e)
{
base.OnViewLoaded(sender, e);
list = VisualTreeUtil.FindFirstInTree<ListView>(Application.Current.MainWindow, "ListView");
ConfigureAndSuperviseInputControls(this.list);
ScrollViewer scroll = VisualTreeUtil.FindFirstInTree<ScrollViewer>(this.list);
scroll.ScrollChanged+=new ScrollChangedEventHandler(scroll_ScrollChanged);
}
void scroll_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
ConfigureAndSuperviseInputControls(this.list);
ScrollViewer sb = sender as ScrollViewer;
if (sb.ContentVerticalOffset==sb.ScrollableHeight)
{
scroll.ScrollChanged-=new ScrollChangedEventHandler(scroll_ScrollChanged);
}
}
Related
I am trying to make an app to generate a tierlist.
Each tier consists of a flowlayout and you basically move the controls around by drag-and-drop.
The problem is that even though I can move the elements with drag-and-drop, the element is always added to the end of the list, and not where you drop the pointer.
Is there any way to maintain order during drag-and-drop?
These are the methods that are in the flowlayout
private void flow_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void flow_DragDrop(object sender, DragEventArgs e)
{
((UserControl1)e.Data.GetData(typeof(UserControl1))).Parent = (Panel)sender;
}
While these are from the usercontrol:
private void UserControl1_MouseDown(object sender, MouseEventArgs e)
{
this.DoDragDrop(this, DragDropEffects.Move);
}
You can opt this solution to reorder the dropped controls into a FlowLayoutPanel control. The part that utilizes the Control.ControlCollection.GetChildIndex and Control.ControlCollection.SetChildIndex methods.
Let's say you have a custom Control or UserControl named DragDropControl:
public class DragDropControl : Control
{
public DragDropControl()
{
AllowDrop = true;
BackColor = Color.LightSteelBlue;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
TextRenderer.DrawText(e.Graphics, Text, Font,
ClientRectangle, Color.Black,
TextFormatFlags.HorizontalCenter |
TextFormatFlags.VerticalCenter);
}
}
Note: From what I see in the images, just use a simple Label control instead.
Let's create a custom FlowLayoutPanel and encapsulate all the required functionalities to not repeat that in your implementation for each FLP.
public class DragDropFlowLayoutPanel : FlowLayoutPanel
{
public DragDropFlowLayoutPanel()
{
AllowDrop = true;
}
[DefaultValue(true)]
public override bool AllowDrop
{
get => base.AllowDrop;
set => base.AllowDrop = value;
}
The custom FLP implements the mouse, drag and drop events of its children as well.
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
if (e.Control is DragDropControl)
{
e.Control.DragOver += OnControlDragOver;
e.Control.DragDrop += OnControlDragDrop;
e.Control.MouseDown += OnControlMouseDown;
}
}
protected override void OnControlRemoved(ControlEventArgs e)
{
base.OnControlRemoved(e);
e.Control.DragOver -= OnControlDragOver;
e.Control.DragDrop -= OnControlDragDrop;
e.Control.MouseDown -= OnControlMouseDown;
}
Handle the child controls MouseDown event to do the drag:
private void OnControlMouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var control = sender as DragDropControl;
DoDragDrop(control, DragDropEffects.Move);
}
}
Handle the DragEnter and DragOver methods and events of the FLP and its children to set the drop effect.
protected override void OnDragEnter(DragEventArgs e)
{
base.OnDragEnter(e);
if (e.Data.GetDataPresent(typeof(DragDropControl)))
e.Effect = DragDropEffects.Move;
}
protected override void OnDragOver(DragEventArgs e)
{
base.OnDragOver(e);
if (e.Data.GetDataPresent(typeof(DragDropControl)))
e.Effect = DragDropEffects.Move;
}
private void OnControlDragOver(object sender, DragEventArgs e)
{
if (e.Data.GetData(typeof(DragDropControl)) is DragDropControl ddc)
{
var p = PointToClient(new Point(e.X, e.Y));
if (GetChildAtPoint(p) == ddc)
e.Effect = DragDropEffects.None;
else
e.Effect = DragDropEffects.Move;
}
}
Finally, call from the DragDrop method override and event the DropControl method and pass the DragEventArgs param.
protected override void OnDragDrop(DragEventArgs e)
{
base.OnDragDrop(e);
DropControl(e);
}
private void OnControlDragDrop(object sender, DragEventArgs e)
{
DropControl(e);
}
The dropped control takes the index of the control under the mouse position if any otherwise it will be inserted at the end of the Controls collection.
private void DropControl(DragEventArgs e)
{
if (e.Data.GetData(typeof(DragDropControl)) is DragDropControl ddc)
{
var p = PointToClient(new Point(e.X, e.Y));
var child = GetChildAtPoint(p);
var index = child == null
? Controls.Count
: Controls.GetChildIndex(child);
ddc.Parent = this;
Controls.SetChildIndex(ddc, index);
}
}
}
Put it all together.
public class DragDropFlowLayoutPanel : FlowLayoutPanel
{
public DragDropFlowLayoutPanel()
{
AllowDrop = true;
}
[DefaultValue(true)]
public override bool AllowDrop
{
get => base.AllowDrop;
set => base.AllowDrop = value;
}
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
if (e.Control is DragDropControl)
{
e.Control.DragOver += OnControlDragOver;
e.Control.DragDrop += OnControlDragDrop;
e.Control.MouseDown += OnControlMouseDown;
}
}
protected override void OnControlRemoved(ControlEventArgs e)
{
base.OnControlRemoved(e);
e.Control.DragOver -= OnControlDragOver;
e.Control.DragDrop -= OnControlDragDrop;
e.Control.MouseDown -= OnControlMouseDown;
}
protected override void OnDragEnter(DragEventArgs e)
{
base.OnDragEnter(e);
if (e.Data.GetDataPresent(typeof(DragDropControl)))
e.Effect = DragDropEffects.Move;
}
protected override void OnDragOver(DragEventArgs e)
{
base.OnDragOver(e);
if (e.Data.GetDataPresent(typeof(DragDropControl)))
e.Effect = DragDropEffects.Move;
}
protected override void OnDragDrop(DragEventArgs e)
{
base.OnDragDrop(e);
DropControl(e);
}
private void OnControlDragOver(object sender, DragEventArgs e)
{
if (e.Data.GetData(typeof(DragDropControl)) is DragDropControl ddc)
{
var p = PointToClient(new Point(e.X, e.Y));
if (GetChildAtPoint(p) == ddc)
e.Effect = DragDropEffects.None;
else
e.Effect = DragDropEffects.Move;
}
}
private void OnControlDragDrop(object sender, DragEventArgs e)
{
DropControl(e);
}
private void OnControlMouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var control = sender as DragDropControl;
DoDragDrop(control, DragDropEffects.Move);
}
}
private void DropControl(DragEventArgs e)
{
if (e.Data.GetData(typeof(DragDropControl)) is DragDropControl ddc)
{
var p = PointToClient(new Point(e.X, e.Y));
var child = GetChildAtPoint(p);
var index = child == null
? Controls.Count
: Controls.GetChildIndex(child);
ddc.Parent = this;
Controls.SetChildIndex(ddc, index);
}
}
}
This code i am using to focus of a entry, its a custon entry
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Entry.IsFocusedProperty.PropertyName )
{
//place1. this code is use to focus
}
// place2. here enter the text when the user written
}
How can i know if the user is writting? but dont enter to both places.
Option 1:You could set the TextProperty to check the user editing .
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Entry.IsFocusedProperty.PropertyName)
{
//place1. this code is use to focus
}
if (e.PropertyName == Entry.TextProperty.PropertyName)
{
//place2. this code is use to edit
var content = Element.Text;
}
}
Option 2:
You could set the TextChanged of the Entry .
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Element.TextChanged += Element_TextChanged;
}
}
private void Element_TextChanged(object sender, TextChangedEventArgs e)
{
// var content = Element.Text;
}
I have to work with touch monitors and sometimes with mouse and normal monitors.
So for drag and drop the for the first would be
private void lvAllowedPPtab2_StylusButtonDown(object sender, StylusButtonEventArgs e)
and for the second
private void ListBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
after that I have to execute the same code using sender and e.
I didn't get to make a common code routine.
The two event are similar and both have the GetPosition event.
I might have taken the wrong road but I have tought to something like:
Type eventType;
if (_e is StylusButtonEventArgs)
eventType = typeof (StylusButtonEventArgs);
else
eventType = typeof(MouseEventArgs);
but then I don't know how to cast e to event type.
Thank you
you can call them both with that
private void listView_StylusButtonDown(object sender, StylusButtonEventArgs e) { CommonCode(sender, e); }
private void listView_PreviewMouseLeftButtonDown(object sender, MouseEventArgs e) { CommonCode(sender, e); }
and then tell inside common code
private void CommonCode(object sender, object _e)
{
//Sender is common
ListView parent = (ListView)sender;
string strListViewButtonName = (sender as ListView).Name;
if (_e is StylusButtonEventArgs)
... (_e as StylusButtonEventArgs).GetPosition(parent));
else
... (_e as MouseEventArgs).GetPosition(parent));
}
Better implementation (thanks to Eli Arbel):
private void listView_StylusButtonDown(object sender, StylusButtonEventArgs e) { CommonCode(sender, e.GetPosition((ListView)sender)); }
private void listView_PreviewMouseLeftButtonDown(object sender, MouseEventArgs e) { CommonCode(sender, e.GetPosition((ListView)sender)); }
private void CommonCode(object sender, Point p)
{
//Sender is common
ListView parent = (ListView)sender;
string strListViewButtonName = (sender as ListView).Name;
//you don't need getPosition since P is known
}
I have many labels on the form, and every label invokes same method with different argument(which belongs to label text/name). Here is the code:
//"res" is an array
private void label1_Click(object sender, EventArgs e)
{
checkresult(res[0]);
}
private void label2_Click(object sender, EventArgs e)
{
checkresult(res[1]);
}
private void label3_Click(object sender, EventArgs e)
{
checkresult(res[2]);
}
private void label4_Click(object sender, EventArgs e)
{
checkresult(res[3]);
}
private void label5_Click(object sender, EventArgs e)
{
checkresult(res[4]);
}
private void label6_Click(object sender, EventArgs e)
{
checkresult(res[5]);
}
private void label7_Click(object sender, EventArgs e)
{
checkresult(res[6]);
}
private void label8_Click(object sender, EventArgs e)
{
checkresult(res[7]);
}
private void label9_Click(object sender, EventArgs e)
{
checkresult(res[8]);
}
I just want to precise my code by defining only one method for all labels. How can i do it?
A pseudocode may look like this:
label1.Click += label_Click(object sender, EventArgs e);
label2.Click += label_Click(object sender, EventArgs e);//SAME HANDLER
label3.Click += label_Click(object sender, EventArgs e);//SAME HANDLER
....
and after
private void label_Click(object sender, EventArgs e)
{
if(sender == label1)
checkresult(res[0]);
else if(sender == label2)
checkresult(res[1]);
...
...
}
First let all of your labels use the same Label_Click event.
private void Label_Click(object sender, EventArgs e)
{
Label temp = sender as Label;
if (temp != null)
{
string labelName = temp.Name;
string labelId = labelName.Substring(5, labelName.Length);
int id = int.Parse(labelId) - 1;
checkresult(res[id]);
}
}
You could set anonymous delegates in when you make the event handler
label1.Click += (s,e) => {checkresult(res[0]); };
label2.Click += (s,e) => {checkresult(res[1]); };
label3.Click += (s,e) => {checkresult(res[2]); };
In WinForms, set your Index to Tag of Label and set each OnClick event to same EventHandler
private void lbl_Click(object sender, EventArgs e)
{
checkresult(res[Convert.ToInt32((sender as Label).Tag)]);
}
I just wanna find out if there's a way I could minimize code clutter in my application.
I have written code/s similar to this:
private void btnNext_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
btnNext.Opacity = 1;
}
private void btnNext_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
btnNext.Opacity = 0.5;
}
private void btnShowAll_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
btnShowAll.Opacity = 1;
}
private void btnShowAll_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
btnShowAll.Opacity = 0.5;
}
private void btnPrev_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
btnPrev.Opacity = 1;
}
private void btnPrev_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
btnPrev.Opacity = 0.5;
}
private void btnSearch_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
btnSearch.Opacity = 1;
}
private void btnSearch_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
btnSearch.Opacity = 0.5;
}
private void btnSearchStore_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
btnSearchStore.Opacity = 1;
}
private void btnSearchStore_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
btnSearchStore.Opacity = 0.5;
}
private void btnCloseSearch_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
btnCloseSearch.Opacity = 1;
}
private void btnCloseSearch_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
btnCloseSearch.Opacity = 0.5;
}
private void btnHome_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
btnHome.Opacity = 1;
}
private void btnHome_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
btnHome.Opacity = 0.5;
}
and so on and so forth...
Do I need to create a 'function' that will run initially? Or do I have to create another class just so I can 'organize' them?
Any suggestions?
You could rewrite all those functions into 2:
private void FadeBtn_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
Button btn = (Button)sender;
btn.Opacity = 1;
}
private void FadeBtn_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
Button btn = (Button)sender;
btn.Opacity = 0.5;
}
And then point all of the buttons MouseEnter and MouseLeave events to those functions.
You need to have ChangeButtonOpacity method:
private void ChangeButtonOpacity(Button button, double newOpacity)
{
button.Opacity = newOpacity;
}
And you can implement your handlers as:
private void btn_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
ChangeButtonOpacity((Button)sender, 1);
}
private void btn_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
ChangeButtonOpacity((Button)sender, 0.5);
}
In this way you will need only two handlers.
Create a Mouse Enter Event and register all the buttons with it. Inside the method you will notice I cast the sender object as a button. So what ever button calls it you can perform this opacity action on.
private void ButtonMouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
Button button = (Button) sender;
button.Opacity = 1;
}
As far I can see, in your case you can shorten to:
private void btn_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
(sender as Button).Opacity = 1;
}
private void btn_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
(sender as Button).Opacity = 0.5;
}
In the designer, you can choose these event handlers then instead of creating new ones for each button.
Perhaps you can use the Tag property of the button if your not using it for anything else, Then you can do the following.
private void btn_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
(sender as Button).Opacity = (double)((sender as Button).Tag);
}
private void btn_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
(sender as Button).Opacity = 0.5;
}
This would allow you to setup different values for different buttons using only two handlers.