I have a c# wpf question.
I am binding a MenuItem to list that is dynamic. Every object on the list is a new sub MenuItem to the main one.
All the items are Checkable and implement the events of checked and unchecked.
The problem is that even before the first opening of the main MenuItem by the user I want the checked and unchecked events to appear (they seem to apear only the first time the user opens the main MenuItem even though add items are added to the binded list before that).
I can do it manually (even though It looks horrible) but when the main MenuItem opens up for the first time the events are called also, and it creates a mess.
So basiclly I need a way to "force" the main MenuItem to create it's children when I tell it to so that the checked and unchecked events will work.
I have tried everything, and even UpdateLayout did not work. Even when I open the menu from the WindowLoaded evet I need to keep it open even after the end of the event and only than it creates the childrens (I thought I could open it and close it real fast so it will be unnoticed to the user).
I hope my question was clear enough.
I thank you in advance. :-)
Since it is an event on the menu it kind of makes sense. When you say manually what are you doing? I would just create a helper and call it on load and by the event. Create a private List Bool to store the status of the check and only run the real event code if the status changes.
Related
I have a Tcl/Tk program. In it I have a combobox, like so:
set cb [ttk::combobox .cb -state readonly -textvariable selection -postcommand [list choices .cb]]
The proc choices runs when the combobox posts, which is what I want. My question is, how do I detect when the combobox unposts?
I've tried both binding on <<ComboboxSelected>> and setting a variable trace on selection. The problem with each is that they only fire when the user actually changes the selection. I need some way to always detect when the combobox unposts.
Thanks!
edit
What I'm trying to accomplish: When the combobox posts it presents the user with a list of options. I don't expect the user to know what the options mean, therefor I am highlighting the options visually in a different area of my program. I have this highlighting triggering and working well with -postcommand. The issue is to know when to turn the highlighting back off.
<<ComboboxSelected>> doesn't fire if the user doesn't change the selected value.
<Leave> and <FocusOut> fire too soon (e.g. as soon as the box posts).
The combobox's popdown is actually its own nest of windows, and if your combobox is called .cb then the popdown has the imaginative name .cb.popdown (note that this implementation and is not guaranteed). If you add a binding to that widget's <Unmap> event you'll get to see the unposting; <Unmap> events are exactly the notifications sent when a window ceases to be displayed in the virtual desktop layer sense (as opposed to just ceasing to be visible, say because there's another window on top; there's events for that too, but they're not cross-platform).
The tricky bits:
The popdown is usually created when needed, i.e., the first time it appears. You need the window to exist (but not necessarily be visible) before you bind to it. You can get the handle of the popdown widget with ttk::combobox::PopdownWindow, which will make the widget if it doesn't already exist. (It's part of the implementation, but it is more likely to be stable than the name.)
set popdown [ttk::combobox::PopdownWindow .cb]
bind $popdown <Unmap> {yourCallback %W}
It is possible to dig around within the internal arrangement of the popdown, but I don't recommend it; it's much more likely to change without warning.
Binding to the toplevel has the usual issues with events also being delivered for subwindows. Your callback should check that the event it has been given is actually for the toplevel:
proc yourCallback {w} {
if {$w ne [winfo toplevel $w]} { return }
# The rest of your code here...
}
The window name of the listbox used by ttk::combobox is:
set popdown [ttk::combobox::PopdownWindow .combobox].f.l
I believe this is what you need.
bind <Leave> $popdown mycommand
We have a main window that launches a child window. That child window dynamically loads custom usercontrols. In the contructor of these usercontrols, I pass a master object which, from this master object, a usercontrol specific viewmodel is generated and assigned as its datacontext.
All of this is working quite well. However, I jst discovered that when I close the child window at least some of my custom usercontrols are still active. How am I supposed to clean up my controls/viewmodels? Nothing seems to get called until the main window is closed. No destructor, no Dispatcher.ShutdownStarted, no dispose is available, no closing event, nothing I can find.
Anyone know what is supposed to be done to properly clean up after the window is closed?
I believe you need to think precisely about what is responsible for creating your views and your viewmodels, and what is responsible for determining whether or not something can close or not, etc.
It is usually a good idea for whatever that created something to destroy it. Therefore, if your child window is creating custom user controls it perhaps should be responsible for removing them. However, I believe if none of your objects has a reference (or strong event subscription) it should be eventually garbage collected. You could implement a finalizer/destructor and output a Debug.String to the output window to see when this might eventually happen. A good memory profiler could also be a good idea. However, it is also likely that you need more precise control of telling your ViewModel when it has been closed.
It's hard to say exactly what should happen in your scenario because it really depends on your exact and specific setup. Let me describe to you a scenario I had in my application. I had several views that were being displayed in tab pages. The tab pages had an X button to close the tab, and my View contained a hosted Windows Forms control that needed to have .Dispose() called to clean up resources as well as it needed to be informed of when to unsubscribe from composite commands in the file menu system. So, initially, I had a problem... how does my ViewModel unsubscribe from commands when the tab pages remove's the view? How does the View which is contained in a WPF control know when it has been removed? here's what I came up with
The tab page itself should not be telling my program if a view can or can not be closed
I needed the ability to cancel the closing event in case of program logic (File saved? Yes/no/cancel)
I needed the ability to detect when it was closed so I could cleanup/unregister at that exact moment
My solution was to implement an interface in my viewmodel called IRemovable which exposed a Removable boolean and a Remove() method which returns a boolean (was removed or not). My tab control only displayed the X button if Removable was true, Tab Control's Closing fired the Remove() of the IRemovable ViewModel and if it returned false it set the event args Canceled property to true if the ViewModel's Remove returned false.
Therefore, the remove of the view model could prompt the user for confirmation, unregister from commands, etc. The view could handle Closed event and call Dispose on any Windows Forms components etc. (of course I had to check if my View.DataContext is IRemovable).
Anyway, I know this isn't an exact answer but hopefully it helps you come up with some thoughts on how to solve your own problem
I am using a standard TreeView in a WinForms application and everything works fine except for one issue:
Parts of the system need to change depending on the selected TreeNode, which works fine using the AfterSelect event.
However, sometimes the TreeView will get cleared completely resulting in an empty selection which does not trigger this event.
At the momemnt I am calling the event callback manually to fix this issue.
This is obviously dangerous, since I will forget to call this function somewhere. Is there a "correct" way to do this?
Thank You!
This is by design. The underlying native Windows controls only generate notifications for things you cannot figure out yourself. The ListBox control for example doesn't have any event that tells you an item got added or removed. Which is because there is no way for the user to add or remove items. Similarly, there's no way for the user to remove the nodes from a tree view.
These kinds of changes requires code that you write. Since it is your code, you cannot not know that these changes happened. If you want an event then you'll have to raise it yourself. Beware that this is harder than it looks, the TreeNodeCollection class doesn't reliably let you generate an event for programmatic changes to the node collection. It doesn't behave like an ObservableCollection. You are definitely better off by not needing this event.
I have a simple WPF with a menu, a toolbar and a ListView in a GridView. The menu and toolbar actions are bound to commands.
I have <CommandBinding> that defines when commands should be executed (CanExecute). Some commands, such as "Create New Item" should always be executed, so they are bound to a "e.CanExecute = true;" function.
However, when the user selects all items in the list using Ctrl-A, and then presses Delete, my application runs a BackgroundWorker that deletes the items from the server and then sets the ItemsSource of the list view to the new data collection, which is empty.
This sometimes causes all commands in the menu and toolbar to be disabled. Note that their keyboard shortcuts still work, but the actions are disabled in the menu and toolbar.
This doesn't always happen, and I failed to find a rule to when it does happen.
Did anyone run into a similar behavior or has any idea what might cause it?
Thanks.
Without code it may be hard. It looks like CanExecute() is not called. Set breakpoint in it and check. I assume you are using RoutedCommands. If yes, the problem may appear because MenuItem.CommandTarget is not set, and WPF tries to find CommandBindings somewhere up the tree, beyond your actual command bindings. If this is the case, set CommandTarget to proper value. Also you may want to call CommandManager.InvalidateRequerySuggested() and see what happens.
I've done a lot of searching on SO and google around this problem, but can't seem to find anything else to try.
I have a MainView (window) that contains a tab control. The tab control binds to an ObservableCollection of ChildViews (user controls). The MainView's ViewModel has a method that allows adding to the collection of ChildViews, which then creates a new tab. When a new tab is created, it becomes the active tab, and this works fine. This method on the MainView is called from another ViewModel (OtherViewModel).
What I am trying to do is set the keyboard focus to the first control on the tab (an AutoCompleteBox from WPFToolkit*) when a new tab is created. I also need to set the focus the same way, but WITHOUT creating a new tab (so set the focus on the currently active tab).
(*Note that there seem to be some focus problems with the AutoCompleteBox--even if it does have focus you need to send a MoveNext() to it to get the cursor in its window. I have worked around this already).
So here's the problem. The focusing works when I don't create a new tab, but it doesn't work when I do create a new tab. Both functions use the same method to set focus, but the create logic first calls the method that creates a new tab and sets it to active. Code that sets the focus (in the ChildView's Codebehind):
IInputElement element1 = Keyboard.Focus(autoCompleteBox);
//plus code to deal with AutoCompleteBox as noted.
In either case, the Keyboard.FocusedElement starts out as the MainView. After a create, calling Keyboard.Focus seems to do nothing (focused element is still the MainView). Calling this without creating a tab correctly sets the keyboard focus to autoCompleteBox.
Any ideas?
Update:
Bender's suggestion half-worked.
So now in both cases, the focused element is correctly the AutoCompleteBox. What I then do is MoveNext(), which sets the focus to a TextBox. I have been assuming that this Textbox is internal to the AutoCompleteBox, as the focus was correctly set on screen when this happened. Now I'm not so sure. This is still the behavior I see when this code gets hit when NOT doing a create. After a create, MoveNext() sets the focus to an element back in my MainView.
The problem must still be along the lines of Bender's answer, where the state of the controls is not the same depending on whether a new tab was created or not. Any other thoughts?
Final Update
As noted, majocha's suggestion worked.
I wanted to update this in case anyone happened upon this same problem with the AutoCompleteBox. It appears that setting focus does not activate it in the UI--you need to do a MoveNext on it to move focus forward once to the control's internal Textbox. This is based on my debugging experience, which may not be 100% scientific. If I have time, I will attempt to create a small repro project and submit it to the WPFToolkit team.
You can try defering the focus change with
Dispatcher.BeginInvoke(MyChangeFocusAction, DispatcherPriority.ContextIdle);
It will get queued after layout and properties updates are done.
I don't think it's best practice, but it works for me.
The control must be visible to be focused, you may try to defer focusing by subscribing to the IsVisibleChanged event, something similar to the following should work:
public static void setFocusLate(this Control control)
{
DependencyPropertyChangedEventHandler handler = null;
handler = delegate
{
control.Focus();
control.IsVisibleChanged -= handler;
};
control.IsVisibleChanged += handler;
}