Interact with the Ok/Accept Or Cancel Button of a RepositoryItemTimeSpanEdit? - winforms

as seen in this post, I need to interact with the button, I mean, save the value of the repository when the user press the OK button, any suggest?

You need to find your TimeSpanEdit control inside of the popup form. You can iterate through popupForm.Controls collection to find out the control with TimeSpanEdit type. Here is example of how to do it. After that you can use TimeSpanEdit.TimeSpan property to get the value of TimeSpanEdit control.
private void OkButton_Click(object sender, EventArgs e)
{
var popupForm = (TimeSpanEditDropDownForm)OwnedForms.FirstOrDefault(item => item is TimeSpanEditDropDownForm);
if (popupForm == null)
return;
var timeSpanEdit = GetAll(this, typeof(TimeSpanEdit)).FirstOrDefault();
if (timeSpanEdit == null)
return;
MessageBox.Show(timeSpanEdit.TimeSpan.ToString());
}
public IEnumerable<Control> GetAll(Control control,Type type)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetAll(ctrl,type))
.Concat(controls)
.Where(c => c.GetType() == type);
}

I think you can use object sender. sender will contains probably TimeSpanEditDropDownForm and there you should get actual value of this form. :)
I presume this code is called from controller is it?
if it is true than you have View.CurrentObject and you must know which property uses this TimeSpanEditDropDownForm so you could do something like this.
private void OkButton_Click(object sender, EventArgs e)
{
MyClass myClass = View.CUrrentObject as MyClass;
TimeSpanEditDropDownForm timeSpanForm = sender as TimeSpanEditDropDownForm;
myClass.CurrentTime = timeSpanForm.CurrentTime;
myClass.Session.CommitChanges();
MessageBox.Show("Ok");
}
I dont know what is name of right attribute wich store TimeSpan inside TimeSpanEditDropDownForm thats thing you must find out but I think it could helps :)

Related

programatically add button click in winforms?

is it possible to add button click event? i want to add controls dynamicly but i don't bind event's to my controls.
this.buttonDeneme = new System.Windows.Forms.Button();
this.buttonDeneme.Location = new System.Drawing.Point(150, 90);
this.buttonDeneme.Name = "button1";
this.buttonDeneme.Size = new System.Drawing.Size(122, 23);
this.buttonDeneme.TabIndex = 0;
this.buttonDeneme.Text = "FileUpload";
this.buttonDeneme.UseVisualStyleBackColor = true;
this.buttonDeneme.Click += ????
#dotTutorial answer is going to work but lot's people still have difficulty with Linq and Lambda expression so if you don't understand it the very basic way to write this is :
this.buttonDeneme.Click += new EventHandler(MyCustomClickHandler);
void MyCustomClickHandler(object sender, EventArgs e)
{
// do whatever you want here
}
but creating multiple button is usually because they wont do the same exact thing so you might want to set the this.buttonDeneme.Tag to some sort of identifier. i prefer using string in there.
then in the click event you can retrieve that value and know what to do. here a corrected version with the Tag used :
this.buttonDeneme.Tag = "SearchBook";
this.buttonDeneme.Click += new EventHandler(MyCustomClickHandler);
void MyCustomClickHandler(object sender, EventArgs e)
{
// for button created above the value when
// the click is called will be "SearchBook"
string sTag = ((Button)sender).Tag.ToString();
if(sTag == "SearchBook")
{
// do stuff for search book
}
else if(sTag == "blablabla")
{
// do other stuff
}
}
The easiest alternative would be to use a lambda expression.
this.buttonDeneme.Click += ((s, e) => {
// The code that handles a click event
});
's' will be the sender object and 'e' the eventargs.

Working with ProgressBar and ComboBox

I'm in trouble with a Marquee ProgressBar. I need to execute a method (refreshList()) to get a List<string>. Then I assign this List to a ComboBox, so ComboBox refreshes with the new Items. As refreshList() take 3 or 4 sec, I wanted to run a Marquee ProgressBar. But I couldn't. ProgressBar is ok, but ComboBox doesn't load new Items.
My refreshList() method:
private void refreshList(List<string> list)
{
albumList.DataSource = null;
albumList.DataSource = list;
}
I have the following code, it works fine:
private void changeDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
fbd.RootFolder = Environment.SpecialFolder.MyComputer;
folderPath = "";
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
refreshList(N.getList(folderPath));
}
}
But I added a ProgressBar and wrote this code:
private void changeDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
fbd.RootFolder = Environment.SpecialFolder.MyComputer;
folderPath = "";
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
bgWorker.WorkerReportsProgress = true;
bgWorker.RunWorkerAsync();
}
}
And I placed refreshList() in doWork() method:
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
refreshList(N.getList(folderPath));
}
But unfortunately this isn't working. Can anybody help me solving this problem? Thanks in advance.
You can use the MarqueeAnimationSpeed and Value properties of the ProgressBar control to stop and start the Marquee. There's no need to use WorkerReportsProgress* as you aren't incrementing a normal progress bar - you just want to "spin" the Marquee.
You can do something like the following:
public Form1()
{
InitializeComponent();
//Stop the progress bar to begin with
progressBar1.MarqueeAnimationSpeed = 0;
//If you wire up the event handler in the Designer, then you don't need
//the following line of code (the designer adds it to InitializeComponent)
//backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
}
private void changeDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
fbd.RootFolder = Environment.SpecialFolder.MyComputer;
folderPath = "";
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
//This line effectively starts the progress bar
progressBar1.MarqueeAnimationSpeed = 10;
bgWorker.RunWorkerAsync(); //Calls the DoWork event
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = N.getList(folderPath); //Technically this is the only work you need to do in the background
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//these two lines effectively stop the progress bar
progressBar1.Value = 0;
progressBar1.MarqueeAnimationSpeed = 0;
//Now update the list with the result from the work done on the background thread
RefreshList(e.Result as List<String>);
}
private void RefreshList(List<String> results)
{
albumList.DataSource = null; //You don't need this line but there is no real harm.
albumList.DataSource = list;
}
Remember to wire up the RunWorkerCompleted event to backgroundWorker1_RunWorkerCompleted via the Properties bar, Events section in the designer.
To begin with, we start the ProgressBar's animation by setting the MarqueeAnimationSpeed property to a non-zero positive number as part of your successful folder selection.
Then, after calling RunWorkerAsync, the code builds your list in the DoWork method, then assigns the result to the DoWorkEventArgs, which get passed to the RunWorkerCompleted event (which fires when DoWork is finished).
In the backgroundWorker1_RunWorkerCompleted method, we stop the progress bar (and set it's value to zero to effectively return it to it's original state), and then we pass the list to the refreshList method to databind it and populate the ComboBox.
Tested using VS2012, Windows Forms, .Net 4.0 (with a Thread.Sleep to emulate the time taken for N.getList)
*WorkerReportsProgress, and the associated ReportProgress method/event are used when you want to increment the progress bar - you can tell the GUI that you are 10% done, 20% done, 50% done etc etc.

Intercepting the value change of SetChildIndex

In a .NET CF-form i have multiple panels. I want to have a property that should always be informed about if a panel is in the front.
Can this be done using the GetChildIndex() method?
If yes, how do i intercept the change to SetChildIndex()?
Thanks in advance
For everybody who is interested for future use:
simply add a new event handler for the Paint event of each panel, for example:
panel1.Paint += new PaintEventHandler(panel1_Paint);
panel2.Paint += new PaintEventHandler(panel2_Paint);
and in each of the event handlers just call a Method which retrieves the state of all the panels like so:
void panel2_Paint(object sender, PaintEventArgs e)
{
GetPanelStates();
}
void panel1_Paint(object sender, PaintEventArgs e)
{
GetPanelStates();
}
void GetPanelStates()
{
Panel2IsInFront = panel2.Parent.Controls.GetChildIndex(panel2) == 0;
Panel1IsInFront = panel1.Parent.Controls.GetChildIndex(panel1) == 0;
}

WPF: How to programmatically remove focus from a TextBox

I want to add a simple (at least I thought it was) behaviour to my WPF TextBox.
When the user presses Escape I want the TextBox he is editing to have the text it had when the user started editing, AND I want to remove the focus from the TextBox.
I don't have any problem setting the text for the value it had in the beginning of the edit.
The problem is to remove the focus of the element. I don't want to move the focus to any other component, I just want the TextBox to lose focus. Will I have to have an invisible element to set the focus so my TextBox can lose focus?
in .NET Framework 4 just Keyboard.ClearFocus();
The code I have been using :
// Move to a parent that can take focus
FrameworkElement parent = (FrameworkElement)textBox.Parent;
while (parent != null && parent is IInputElement && !((IInputElement)parent).Focusable)
{
parent = (FrameworkElement)parent.Parent;
}
DependencyObject scope = FocusManager.GetFocusScope(textBox);
FocusManager.SetFocusedElement(scope, parent as IInputElement);
Since none of the above answers worked for me and the accepted answer does work only for a keyboard focus, I came to the following approach:
// Kill logical focus
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(textBox), null);
// Kill keyboard focus
Keyboard.ClearFocus();
Kills both, logical as well as the keyboard focus.
A bit late to the party, but it was helpful to me so here it goes.
Since .Net 3.0, FrameworkElement has a MoveFocus function which did the trick for me.
You can set the focus to a focusable ancestor. This code will work even if the textbox is inside a template with no focusable ancestors inside that same template:
DependencyObject ancestor = textbox.Parent;
while (ancestor != null)
{
var element = ancestor as UIElement;
if (element != null && element.Focusable)
{
element.Focus();
break;
}
ancestor = VisualTreeHelper.GetParent(ancestor);
}
AFAIK, it is not possible to completely remove the focus. Something in your Window will always have the focus.
For me, it's quite tricky, especially when using with LostFocus binding.
However, my workaround is to add an empty label and focus on it.
<Label Name="ResetFocusArea" Focusable="True" FocusVisualStyle="{x:Null}" />
...
OnKeyDown(object sender, RoutedEventArgs e)
{
//if is Esc
ResetFocusArea.Focus();
}
Using LPL's answer worked for me, but it would also make me unable to select any options in dropdown menues. To combat this, I added a check to see if the focused element was a textbox.
Doing the same check for when pressing enter, my final code looked like this:
public Menu()
{
InitializeComponent();
this.PreviewMouseDown += PreviewMouseDownEventHandler;
this.KeyDown += WindowKeyDownHandler;
}
void ClearFocus()
{
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
if (elementWithFocus is System.Windows.Controls.TextBox tb)
{
if (Keyboard.FocusedElement != null)
{
Keyboard.FocusedElement.RaiseEvent(new RoutedEventArgs(UIElement.LostFocusEvent));
Keyboard.ClearFocus();
}
}
}
private void PreviewMouseDownEventHandler(object sender, MouseButtonEventArgs e)
{
ClearFocus();
}
private void WindowKeyDownHandler(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
ClearFocus();
}
}
With this, I didn't need to add a focuslost to every textbox, and it can easily extend to other elements without breaking compatability with other parts of the program.
In Windows Phone Development, I just did Focus() or this.Focus() in the PhoneApplicationPage and it worked like a charm.
My answer does not adress the above question directly, however, I feel that the wording of it has caused it to become "The Question" about programmatically getting rid of focus. A common scenario where this is needed is for the user to be able to clear focus upon left-clicking the background of a root control, like window.
So, to achieve this, you can create an Attached Behavior that will switch focus to a dynamically created control (in my case, an empty label). It is preferrable to use this behavior on the highest-level elements like windows, as it iterates through it's children to find a panel it can add a dummy label to.
public class LoseFocusOnLeftClick : Behavior<FrameworkElement>
{
private readonly MouseBinding _leftClick;
private readonly Label _emptyControl = new Label() { Focusable = true, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top };
public LoseFocusOnLeftClick()
{
_leftClick = new MouseBinding(new RelayCommand(LoseFocus), new MouseGesture(MouseAction.LeftClick));
}
protected override void OnAttached()
{
AssociatedObject.InputBindings.Add(_leftClick);
AssociatedObject.Loaded += AssociatedObject_Loaded;
}
protected override void OnDetaching()
{
AssociatedObject.InputBindings.Remove(_leftClick);
AssociatedObject.Loaded -= AssociatedObject_Loaded;
}
private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
{
AssociatedObject.Loaded -= AssociatedObject_Loaded;
AttachEmptyControl();
}
private void AttachEmptyControl()
{
DependencyObject currentElement = AssociatedObject;
while (!(currentElement is Panel))
{
currentElement = VisualTreeHelper.GetChild(currentElement, 0);
}
((Panel)currentElement).Children.Add(_emptyControl);
}
private void LoseFocus()
{
_emptyControl.Focus();
}
}
If you want to remove focus from a certain TextBox, just add this line..
textBox.Focusable = false;

C# EventHandler Beautiful Code (How To?)

I admit, it is kind of tiny, but I am looking for better ways to do the following code blocks. They should be self explaining...
private void listBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var listBoxItem = sender as ListBoxItem;
if (listBoxItem != null)
{
var clickObject = listBoxItem.DataContext as ClickObject;
if (clickObject != null)
{
clickObject.SingleClick();
}
}
}
Another ugly one:
private void listBox_SelectionChangedA(object sender, SelectionChangedEventArgs e)
{
var lB = sender as ListBox;
if (lB != null)
StatusBoxA.Text = "Elements selected" + lB.SelectedItems.Count;
}
Yeah, I know, its not near-death-urgent. But I do NOT like the (if != null). Any magic ideas to shorten it even more :-)
Btw, I found some nice info about a similar topic: Loops on Null Items
Nice to read...
I love good, clean code but in most cases, clean & elegant doesn't mean short and smart. Code brevity is good for competitions. Changing an "if not null" statement to a foreach might seem way cooler but it's harder for everyone else working in the project to understand what you are trying to accomplish. Believe me, even you won't remember it a few months later :P. Your code is just fine as it is!
private void listBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var listBoxItem = sender as ListBoxItem;
if (listBoxItem == null) return;
var clickObject = listBoxItem.DataContext as ClickObject;
if (clickObject == null) return;
clickObject.SingleClick();
}
One-liner:
private void listBox_SelectionChangedA(object sender, SelectionChangedEventArgs e)
{
As<ListBox>(sender, (lB) => StatusBoxA.Text = "Elements selected" + lB.SelectedItems.Count);
}
or, nested:
private void listBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
As<ListBoxItem>(sender, (listBoxItem) => {
As<ClickObject>(listBoxItem.DataContext,
(clickObject) => clickObject.SingleClick());
};
}
using this static generic method (T is destination type, input is object to cast, code is a delegate (or lambda expression) to execute on success:
static void As<T>(object input, Action<T> code) where T : class
{
T foo = input as T;
if (foo != null)
code(foo);
}
Since you're using known events from the .NET framework (as opposed to a third party) and from the code it looks like you're only using those methods for specific classes (i.e. ListBoxItems and ListBoxes), there are a few things you know to be true:
sender will never be null
sender will always be a ListBoxItem, or ListBox, respectively
So why use the as operator? Just cast!
Then the first snippet becomes
private void listBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var listBoxItem = (ListBoxItem)sender;
var clickObject = (ClickObject)listBoxItem.DataContext;
clickObject.SingleClick();
}
Note this isn't true in the general case (you wouldn't do this if you were handling all PreviewMouseDown events in that one handler for all Control types), but for event handling code like this, especially in UI code, you can be as certain as you can be of anything, that sender will not be null and sender will be of the type you expect.
Maybe I am just being pedantic but why do you need to cast the sender if you are using the event within its host containers code.
Regardless of who made the change to a list, couldn't you just give your listbox a name and use that.
<ListBox x:Name="listbox1" />
private void listBox_SelectionChangedA(object sender, SelectionChangedEventArgs e)
{
StatusBoxA.Text = "Elements selected" + listbox1.SelectedItems.Count;
}
Or you could even achieve some of this using binding with no code behind.
This is supposed to be the same as the first one, reformatted a little:
private void listBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
ClickObject clickObject;
if (
((sender as ListBoxItem) != null) &&
((clickObject = ((ListBoxItem)sender).DataContext as ClickObject) != null)
)
{
clickObject.SingleClick();
}
}
You can add extensions methods to Form elements, which can then trigger the events:
public static void OnSelectionChanged(this ListBox b, Action<ListBox> a)
{
b.SelectedIndexChanged += (s,e) =>
{
if (s is ListBox)
a(s as ListBox);
};
}
Using the same idea as Utaal's solution, but as an extension method...
public static void As<TSource>(this object item, Action<TSource> action) where TSource : class
{
var cast = item as TSource;
if (cast != null)
action(cast);
}
private void listBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
sender.As<ListBoxItem>(listBoxItem =>
listBoxItem.DataContext.As<ClickObject>(clickObject =>
clickObject.SingleClick()));
}

Resources