Silverlight context menu: how to determine which menu was clicked? - silverlight

I have the following context menu:
<ListBox x:Name="sectionList" Margin="56,8,15,0" FontSize="64" SelectionChanged="SectionList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="Hide this section from this list" Click="ContextMenuItem_Click" />
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<TextBlock Text="{Binding DisplayName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
As you can see, each displayed item has its own context menu. Each context menu is hooked up to the same event handler:
private void ContextMenuItem_Click(object sender, RoutedEventArgs e)
{
}
From this method, how can I tell which context menu was clicked? I want to know what the DataContext for the corresponding DataTemplate is.

You can get the item the ListBoxItem is bound to by casting the sender as a FrameworkElement to get access to the DataContext:
(sender as FrameworkElement).DataContext
You can then cast this to the appropriate model class and access the details you need. e.g.:
((sender as FrameworkElement).DataContext as ItemViewModel).DisplayName

If you put a breakpoint inside the event handler ContextMenuItem_Click, you will then be able to examine the properties of sender and e. You will probably find your answer there.
One way to do this is to hover over those words. Another would be to use the Immediate Window. Type in sender and a dot to get intellisense.

If you use <StackPanel Tag="{Binding}"> then ((FrameworkElement)sender).Tag will return the DataContext object (you'll have to cast it before use, of course).

Related

wpf access lisbox selected item if it isn't string

I have a listbox which displays Name property from an array of Movie objects
<ListBox Name="listBox1" SelectionChanged="listBox1_SelectionChanged">
<ItemsControl ItemsSource="{Binding}" >
<ItemsControl.ItemTemplate >
<DataTemplate >
<TextBlock Name="textBlock1" Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ListBox>
How can I access the text of the textBlock that's inside the ListBox in Code?
I must use the value of the Name property in my code
The selected item reported by the listbox exposes you the object that owns the Name property bound in the TextBlock. At this point the game is over.
When you do the above every textblock inside the itemscontrol has a name textblock1 that too with a scope limited to each item container.
If you want each of those textblocks individually, I usually do something like:
<TextBlock Text="{Binding Name}" Loaded="TextBlock_Loaded"/>
And in the code register those textboxes in whatever way you wish. A list probably,
List<TextBlock> TextBlockList = new List<TextBlock>();
private void TextBlock_Loaded(object sender, RoutedEventArgs e)
{
TextBlockList.Add((TextBlock)sender);
}
And for example, access the stuff as:
String FirstItem = TextBlockList.ElementAt(0).Text;

Silverlight mvvm dynamic controls

How do create controls dynamically in the mvvm pattern?
The code I'm trying to port:
Parent control:
ObservableCollection History = new ObservableCollection();
private void Save_Click(object sender, RoutedEventArgs e)
{
ChildControl cc = new ChildControl();
History.Add(cc);
}
if you use ContentControl, you can simply bind to your History collection
<ListBox ItemsSource="{Binding History}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<ContentControl Content="{Binding }"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The above will show a list of your controls.
One thing to consider though is that with your implementation, the VM knows about View Objects, It is cleaner to use pure data in your VM and have the view worry about how to display itself.
Assuming that "ChildControl" derives from UserControl, the XAML from each of these controls will be automatically displayed when the ItemsSource is set.
<ListBox ItemsSource="{Binding History}">
</ListBox>

Retrieving WPF control states (checkboxes, etc.) at runtime

I have a simple Windows Phone 7 project and am not using MVVM.
I have a group of check-boxes and some other controls that determine certain statuses in the UI. Let's say on checking a check-box I get an event where I have some code and would like to know the state of other check-boxes and elements in there too. Is this possible without MVVM? The root visual does not give me the main UI class (launched in main.xaml) so there seems no way to find other peer controls.
let's say I have a Listbox with checkboxes, which are databound to an xml to a Name element.
<DataTemplate x:Key="myTemplate">
<StackPanel Orientation="Horizontal">
<CheckBox Name="chkBox" Checked="chkBox_Checked" Tag="{Binding name}">
<TextBlock Text="{Binding name}" FontSize="16" />
</CheckBox>
</StackPanel>
</DataTemplate>
This is used in a list
<ListBox x:Name="lst" SelectionMode="Single" ItemTemplate="{StaticResource myTemplate}" />
Checking an item gets me into the chkbox_Checked event. How do I determine the value of all the check-boxes in this group?
I see that lst.Items can give me the name value of the checkboxes, which is the data value they get bound to, but I am not able to cast the item to a checkBox type to inspect the isChecked value.
Provided your controls a Name in your xaml, you can reference them by this identifier in your code behind.
E.g.
<Button Content="Button" Name="button1" Click="button1_Click" />
and
private void button1_Click(object sender, RoutedEventArgs e) {
button1.Content = "Clicked";
}

Getting the SelectedItem from a combobox in a DataTemplate

Lets say I've got a DataTemplate like so
<DataTemplate x:Key="Body">
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding Path=Person.Children}"></ComboBox>
<Button Click="Button_Click">Hello</Button>
</StackPanel>
</DataTemplate>
Which shows a list of ComboBoxes followed by a button.
Now, on clicking the button I need to discover the value in the combo next to the button pressed. I can get the data context as below but can't work out how to get the combos SelectedItem
private void Button_Click(object sender, RoutedEventArgs e)
{
// Can get the data context
var p = ((Button)sender).DataContext as Person;
// How to get the value in the combo ...?
}
you can also reference the combobox in your codebehind if you give it a name. However its cleaner to use a separate class to do your logic than the code behind. Such as a viewmodel.
then you could also do something like this...
<DataTemplate x:Key="Body">
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding Path=Person.Children}"
SelectedItem="{Binding Path=SelectedChild}"
IsSynchronizedWithCurrentItem="True"/>
<Button Command="{Binding Path=ButtonCommand}">Hello</Button>
</StackPanel>
</DataTemplate>
Instead of using the Click event handler, use a Command and bind the CommandParameter property to the ComboBox.SelectedItem. Then in your command's executed logic, you can use the parameter.

Get visual underlying ItemTemplate of an ItemsControl in ContextMenu.MenuItem.Click event handler?

First take a look at my code:
<ListBox ItemsSource="{Binding}" SelectionMode="Multiple"
ItemTemplate="{StaticResource ContactTemplate}">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Name="mnuEdit" Header="_Edit" Click="MenuItem_Click" />
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
I want, the when the user right-clicks an individual ListBoxItem in the ListBox, it should be passed (or the index of it or whatever a way to find the item that the ContextMenu popped-out on.
You need to define ItemContainerStyle or ItemsTemplate for the ListBox and add ContextMenu there. Now you will be inside the SelectedValue(DataContext)
You can set the Contextmenu for your 'ContactTemplate', so that when you right click your ContextMenu will have the Data on which you clicked(From MenuItem.DataContext)
Another way, which assumes your rightclick might have already set that ListBoxItem as the Selected. In Menu Click event you can get the SelectedIndex by ((FrameworkElement)sender).DataContext
<MenuItem DataContext="{Binding ElementName=lstBox,Path=SelectedIndex}" ..../>
Try this:
private void MenuItem_Click(object sender, RoutedEventArgs e) {
var listItem = (((FrameworkElement)sender)).DataContext; //Cast however you want

Resources