I have a MultiView and a Menu in my ASP.NET page - each menu item has a Value property which corresponds to the ViewIndex of the tab to show.
I will sometimes need to set the active view programatically, which works fine for the MultiView, but setting the Selected property of the Menu control is a bit more difficult. I could loop through each item til the value matches the view index I want to show, but this seems a bit hacky.
Any ideas?
I recommend using the MultiView's OnActiveViewChanged event to select the menu item.
protected void myMultiView_ActiveViewChanged(object sender, EventArgs e)
{
int index = ((MultiView)sender).ActiveViewIndex;
myMenu.FindItem(index.ToString()).Selected = true;
}
This way, whenever the view is changed (via SetActiveView(), or otherwise), the menu selection will remain synced. Note that you may also need to set the active view on the OnMenuItemClick event of the menu.
Related
I’m developing a WPF application in MVVM Patern. The application has a command bar and buttons for Save and Delete records.
The application also has a Master Detail form. It’s a User control and a DataGrid.
Master block : Customer Order
Detail block: Customer Order Lines
(one to many relationship).
Problem:
When clicking a button in command bar, different actions need to be performed depending on the focused item.
For an example if I click the Delete button
It should delete the records only in the DataGrid row, when DataGrid has
focus and row(s) selected.
E.g. DeleteRows() Method should be called.
It should delete the entire record if the master block has focus and not datagrid focused.
E.g. DeleteRecord() Method should be called.
As far as I know I can achieve this using Keyboard focus and Logical focus manager.
But I was unable to find out a proper solution. I should consider that, when clicking the delete button I should ignore the focus of the Delete button.
Please help me to overcome this issue with a sample code.
Since you're using the MVVM pattern, I assume that your buttons in the command bar have corresponding ICommands in the view model.
You can bind your DataGrid's SelectedItem property to a view model property (of course, with a two-way binding) and make that decision according to this property value. If it is null, so there's no item currently selected in the DataGrid, and you can delete the whole record. If it is set to an instance, then a row is selected in the DataGrid, and you can delete only one row.
If you need to exactly know which was the last focused element, you can use the Keyboard.PreviewLostKeyboardFocus attached event in your code behind. Or even better, create your own Behavior with a dependency propery that you can bind to your view model.
enum LastFocusedEntityType { None, Record, Row }
class LastFocusedEntityTrackingBehavior : Behavior<UIElement>
{
public static readonly LastFocusedEntityProperty = DependencyProperty.Register(
"LastFocusedEntity",
typeof(LastFocusedEntityType),
typeof(LastFocusedEntityTrackingBehavior),
LastFocusedEntityType.None);
public LastFocusedEntityType LastFocusedEntity
{
get { return (LastFocusedEntityType)this.GetValue(LastFocusedEntityProperty); }
set { this.Setvalue(LastFocusedEntityProperty, value); }
}
protected override void OnAttached()
{
Keyboard.AddPreviewLostKeyboardFocusHandler(this.AssociatedObject, this.PreviewLostKeyboardFocusHandler);
}
private void PreviewLostKeyboardFocusHandler(object sender, KeyboardFocusChangedEventArgs e)
{
if (e.OldFocus is DataGrid)
{
this.LastFocusedEntity = LastFocusedEntityType.Row;
}
else
{
this.LastFocusedEntity = LastFocusedEntityType.Record;
}
}
}
Then you can apply this behavior to your master block container:
<UserControl>
<i:Interaction.Behaviors>
<local:LastFocusedEntityTrackingBehavior LastFocusedEntity="{Binding LastFocusedEntity, Mode=OneWayToSource}"/>
</i:Interaction.Behaviors>
</UserControl>
In your view model, your ICommand's Execute() method should then look at the LastFocusedEntity property value and decide what to do next.
Note: I didn't check this code whether it compiles.
I want to implement visual studio style Add or Remove Ruttons toolstrip like following
in my winforms application, how can I achieve this?
I haven't tried anything on this as I am not sure how to start and I don't have much working experience on winforms.
Please suggest.
At first glance it doesn't look all that difficult.
Just add a ToolStripDropDownButton to your ToolStrip with no image or text. That will make the appearance seem more or less similar.
Add to this drop down button one ToolStripMenuItem with a "Add or Remove Buttons" caption. We'll call it AddRemoveMenuItem.
Now populate AddRemoveMenuItem's child menu items with menu items representing all your configurable ToolStripItems. You can link menu item and configurable tool strip item through the menu item's Tag property (you could also subclass ToolStripMenuItem adding a ToolStripItem LinkedToolStripItem { get; set; } property but I don't think its really worth it).
All these "linked" menu items will have to handle their Click events where they will switch their linked tool strip item's Visible property and synchronize their Checked state accordingly.
I'd do that the following way:
linkedMenuItem.Click += (sender, e) => linkedMenuItem.Checked = !linkedMenuItem.Checked;
linkedMenuItem.CheckedChanged +=
(sender, e) =>
{
var linkedToolStripItem = linkedMenuItem.Tag as ToolStripItem;
if (linkedToolStripItem != null)
{
linkedToolStripItem.Visible = linkedMenuItem.Checked;
}
};
When starting up your application set the linked menu items Checked state accordingly to your app's default settings, user settings, etc. and you are done.
The Items property of a checked list box control in Windows forms is of type object, so my naive hope was that I can add a customized User control as item. (Since, usually, my task is to write logic for background tasks I'm not too familiar with UI programming, so this may be a stupid idea..)
More precisely I want to display two labels and a button in each line of the the checked list box. The first label is supposed to display the name of an object the user can select (so that later on a specific operation will be performed on all checked items). For any item checked, the button is supposed to allow the user to choose a file from which custom settings can be read for performing that operation and the second label should display the choice the user has made using the button (i.e. the file name or something like the string "default settings").
So, in the forms designer, I created a custom control CustomControl1 with label1, label2, button1, and methods to set the text properties, set autosize of the labels and the button to false, defined their size manually. Then in the main window I created the checked list box, to which I added custom controls. The constructor of my main window now looks as follows:
InitializeComponent();
UserControl1 uc1 = new UserControl1();
uc1.setLabel1("label1_text");
uc1.setLabel2("label2_text");
uc1.setButtonText("button_text");
this.checkedListBox1.Items.Add(uc1);
uc1.Visible = true;
This compiles without any error and also runs, but the checked list box shows an empty field. I also experimented with the size of the list box. If I reduce the height so that the check box just fits into it then I do see fragments of the button in the corresponding line, but no label.
Is it possible to use a custom form in a checked list box and if yes, what am I missing?
No, you can't do this.
The listbox only shows a list of elements. The listbox uses the property .ToString() for each objects in the list to show the items.
You need to look for a custom listbox
private void Form1_Load(object sender,EventArgs e)
{
checkedListBox1.Items.Add("IIT");
checkedListBox1.Items.Add("CSE");
checkedListBox1.Items.Add("EEE");
checkedListBox1.Items.Add("ICT");
checkedListBox1.Items.Add("URP");
checkedListBox1.Items.Add("ENGLISH");
checkedListBox1.Items.Add("BANGLA");
checkedListBox1.Items.Add("MATH");
}
private void checkedListBox1_SelectedIndexChanged(object sender,EventArgs e)
{
//var item=checkedListBox1.SelectedItem;
label1.Text=checkedListBox1.SelectedItem.ToString();
}
I have a user interface with a TabControl that initially displays a start page. Other items can be added to it by double-clicking on content in, for example, a DataGrid. New tabs should be selected when they are created. If the document corresponding to the item in the grid is already open, then the existing tab for that document should be opened rather than creating a new one.
I know that I should be able to programmatically select a tab by setting the TabControl's SelectedItem or SelectedIndex properties. However, the desired tab never actually activates. If I set one and then inspect the TabControl's state in the debugger, then both fields seem to update properly. However, after I continue execution, I see that the selected tab remains unchanged in the UI, and if I pause and inspect the TabControl's state again I see that the SelectedItem and SelectedIndex have returned to their previous values. Selecting a tab by clicking on it in the UI, on the other hand, works just fine.
Here's the declaration for the TabControl:
<TabControl x:Name="Tabs" >
<TabItem x:Name="StartPageTab" Header="Start Page" DataContext="{Binding Path=StartPageViewModel}">
...
</TabItem>
</TabControl>
And the code for adding and selecting tabs:
private void _SelectTab(MyViewModel model)
{
TabItem tab;
if (_TryFindTab(model, out tab)) Tabs.SelectedItem = tab;
}
private bool _TryFindTab(MyViewModel target, out TabItem tab)
{
foreach (TabItem item in Tabs.Items)
{
MyViewModel model = item.DataContext as MyViewModel;
if (model != null && model.Equals(target))
{
tab = item;
return true;
}
}
tab = null;
return false;
}
private void _AddTab(MyViewModel model)
{
TabItem tab = new TabItem { DataContext = model, Content = new MyView() };
Binding bind = new Binding { Source = model, Path = new PropertyPath("Name") };
tab.SetBinding(TabItem.HeaderProperty, bind);
Tabs.Items.Add(tab);
Tabs.SelectedItem = tab;
}
It turned out to be related to something I conveniently omitted from the original problem description:
The DataGrid in question was in the content for StartPageTab. I was handling double-clicks on that DataGrid by capturing its MouseDoubleClick event, searching the visual tree to find what DataGridRow was double-clicked (if any), and then raising an event that would eventually be captured by the main window, which would respond by calling either _SelectTab or _AddTab, depending on whether the document in question was already open.
At which point, the call stack would unroll and get back to that MouseDoubleClick event handler. In that handler, I forgot to set the MouseButtonEventArgs's Handled property to true. So WPF kept searching for someone else to handle that click event - and the element that it eventually found would respond by asking for focus, which in turn meant that the original tab needed to get focus back.
Adding e.Handled = true; stopped that whole mess in its tracks, so the new tab could stay selected.
You could try using tab.focus()
I have tabs in my application and this is a quick way to make your selected tab visible.
Have you tried binding to TabItem.IsSelected and updating that in you view model?
In an older C# app I had, using page controls, I was able to force the page active by telling the tab control object to select the tab...
MyTabControlWithMultiplePages.SelectTab(PageIWantShown);
In my windows application i have a context menu with a grid the problem is that I want to disable the ToolStripMenuItem in context menu according to the user previlages.How can i do that. i have done like this but it is not working
private void contextMenuStrip_Machine_Opening(object sender, CancelEventArgs e)
{
toolStripAuthorize.Enabled = INFOpermission.accessAuthorize;
}
but it is not working
You need to set toolStripAuthorize.Enabled to either true or false.
I have no idea what INFOpermission.accessAuthorize is because you didn't show the code that defines that (enum?), but if it's anything other than false, this isn't going to work out like you expect.
I can guarantee that setting the Enabled property of the ToolStripMenuItem that you want to disable to false in the Opening event handler will work. If it's not working for you, you're doing something else wrong, and you need to give us some more information to go on.
If you're stuck, see the sample code here: How to: Handle the ContextMenuStrip Opening Event
EDIT: Armed with new information provided in the comments, I've now isolated the source of the problem. You've assigned the ContextMenuStrip to the RowTemplate of a DataGridView control, and are therefore not able to modify items contained in that context menu in its Opening event handler method.
It turns out that this is a known bug that someone decided was "by design". You can see the original bug report here on Microsoft Connect. The explanation given is that whenever a new row is created based on the RowTemplate (which is how the RowTemplate works), the ContextMenuStrip that you've assigned gets cloned as well. That means the same context menu instance is not used for each row, and whatever properties that you try to set on the original menu items have no effect.
Fortunately, it also gives us a workaround. Like all events, the Opening event passes the actual instance of the ContextMenuStrip that is about to be opened as its sender parameter. This is the context menu whose items you need to modify in order for your alterations to be visible.
So what's the code? It looks like this:
private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
{
ContextMenuStrip cmnu = (ContextMenuStrip)sender;
cmnu.Items[1].Enabled = false;
}
Notice, though, that you'll have to reference the individual menu item that you want to modify by its index. This is just the zero-based position of the item in the menu that you want to modify. You can't use the toolStripAuthorize object like you were trying to do before because a new instance of it has been cloned for each new context menu instance.