Can I Remove a MenuItem from ContextMenu in WP7 - windows-phone-7

I'm looking for a method - if at all possible - of removing a MenuItem control from a ContextMenu in Windows Phone 7.
Here's a simplified version of my XAML:
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
[ -- Content -- ]
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="view attributes" Tag="ATTRIBUTES" Click="ViewSelectedResultAttributes" />
<toolkit:MenuItem Header="view groups" Tag="GROUPS" Click="ViewSelectedResultGroups" />
<toolkit:MenuItem Header="view webpage" Tag="ONLINE" Click="ViewWebPage" />
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now, not all of the items in the bound collection have a website associated with them, and for those items I wish to remove the MenuItem with the tag ONLINE (i.e. the last MenuItem).
But I can't find a way of achieving this.
I've also thought of adding the ContextMenu and all the MenuItems programmatically so that I could conditionally add each MenuItem but I can't seem to find an event such as OnItemDataBound or OnDataBinding, etc.
Can anyone help me out?
UPDATE: just to be more specific, I don't want to remove a MenuItem from the ContextMenu on every bound item in the ListBox, I only want to remove a MenuItem on specific items in the ListBox when the bound object fails a condition.
Let's say my ListBox contains 3 bound items:
ListItem_1,
ListItem_2,
ListItem_3
Now, let's say that the object bound to ListItem_2 has one of its properties as NULL; In this case ListItem_2 should have one of the MenuItem controls from its ContextMenu removed, whereas ListItem_1 and ListItem_3 should still have this MenuItem.
What would be ideal is an event which allows me to capture each item as it's being bound, and which also exposes the ContextMenu. The ListBox.Items collection simply returns the same collection of objects that I assigned to be the data source, whereas a collection of, say, ListBoxItems would be more useful - does this exist?

First, give a name to your context menu to be able to retrieve it easily from the code-behind:
<toolkit:ContextMenu x:Name="ContextMenu">
From there, you can access the items using this.ContextMenu.Items. So just remove the ones you don't need anymore:
var item = this.ContextMenu.Items.OfType<MenuItem>().First(m => (string)m.Tag == "ONLINE");
this.ContextMenu.Items.Remove(item);

Related

WP7: Listbox item template doesn't work when edited?

**UPDATED**
Just something quick, hope you guys can help me but i'm having this problem where I open up my wp7 project in blend and i edit the listbox item template and i finish it but. I save everything and go back to VS2010 for Windows phone and hit debug but i look at the phone and i have no items showing up at all. The listbox is just blank.
Code:
<ListBox toolkit:TiltEffect.IsTiltEnabled="True" x:Name="ListBox1" FontSize="42.667" FontFamily="Segoe WP SemiLight" IsSynchronizedWithCurrentItem="False" d:LayoutOverrides="VerticalAlignment">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="sp">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu IsZoomEnabled="False" >
<toolkit:MenuItem Header="Delete" Click="Delete_Click" Name="MenuItem1" />
<toolkit:MenuItem Header="Edit" Click="Edit_Click"/>
<toolkit:MenuItem Header="View" Click="View_Click"/>
<toolkit:MenuItem Header="Share.." Click="Share_Click"/>
</toolkit:ContextMenu>
Quick Brief
The app I'm making is a simple note app which saves notes in to a folder in the isolated storage. It successfully retrieves the items but i just want to make it so that it has the title and a brief description. This is all in one item. I've got to that point and the 2 textblocks have ="{Binding}" this basically just adds the title I'm assuming but i also added the ="{Binding}" to the second textblock so its basically showing the title for both of them. Is there a way to bind it to a specific item? like the second textblock, how can i bind that so that it shows 1st 12 characters inside a text file so basically it just shows the title and a brief description?
Maybe you have designtime-only data?
In case you're using Mvvm Light DataService approach, you define 2 DataServices: one for designtime and another for realtime.
Just random assuming. it would be nice to see some sample.
UPD: you posted wrong code, this one is about ContextMenu. I dont see binding there.
But again, generally talking, there shouldnt be any problems. You just deserialize data into model, say
public class Note
{
public string Name {get; set; }
public string Content; {get; set; }
}
And then you have List (or even ObservableCollection if you want realtime changes like renaming). And then you just bind
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Content}"/>
If you want to have a strict limit for Content/Description of 12 characters, you can add either Converter and take only 12 first characters, or introduce new property
class Note
{
***
public string Description { get { return Content.Substring(0, 12); } }
}
UPD2:
Ok, lets start from the very beginning. First, MVVM is recommended pattern for Wp7 applications. I believe, you can google info about it yourself, but here are the most important parts:
Model. Keeps your data (in your case, it is notes names and description).
ViewModel. This is abstract view. You have all logic here, you have all data prepared to be rendered here, but VM have no idea how to render data. In your case, a list of notes would be here.
View. Here is description of your ui. In your case, ListBox would be here.
So, first, make a new project, then use NuGet to install latest Mvvm Light (for example). After installing, you should see folders for viewmodels and models.
Create new class Note, like i described before. It would be your model.
Now, go to viewmodel. In a constructor, add a list of Notes there, call it ListOfNotes. Add manually several items to the list and initialize them (add some random values for Names and Contents fields).
Now, go to view. In the top of the file, there should be something like DataContext = "{Binding MainViewModel, Source={StaticResource ViewModelLocator}}". Inside of the view, add ListBox. It should be something like
<ListBox ItemsSource="{Binding ListOfNotes}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Content}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So, what would happen now. When you would run your app, your view would be initialized. It would get MainViewModel (because is it set as DataContext, in step 4). In the constructor of MainViewModel, a ListOfNotes would be initialized (see step 3). Then, when page would load ListBox, it would try to find ListOfNotes inside of DataContext (MainViewModel in our case). It should find your list of Notes, and then, every element of the ListBox would be associated with every element of your ListOfNotes. As it is described in DataTemplate, it would try to get Note.Name and Note.Content.

How to make repeating textblocks in Windows Phone 7?

Databinding still confues me and I am not sure how to essential make these controls repeat for each bound piece of data I have.
<Grid>
<TextBlock FontSize="25" Text="this is a header"></TextBlock>
<TextBlock Height="30" HorizontalAlignment="Left" Margin="19,36,0,0" Name="txt" Text="line under the header" VerticalAlignment="Top" />
<TextBlock Height="30" FontSize="25" HorizontalAlignment="Left" Margin="306,9,0,0" Name="textBlock2" Text="530" VerticalAlignment="Top" Width="91" />
<TextBlock Height="30" HorizontalAlignment="Left" Margin="305,42,0,0" Name="textBlock3" Text="30" VerticalAlignment="Top" Width="91" />
</Grid>
If my data source would have a count of 50. I would expect to see 50 of these groupings(I probably need to get a scroll bar though).
Not sure how to do this though. I need some sort of datatemplate I guess? Also "line under the header" should be clickable and highlight.
I think you need to use the control named "ItemsControl". Not a derived class, not a ListBox, just plain simple ItemsControl.
Either in code or in XAML, you set the ItemsControl's ItemsSource property to any collection containing your items.
In XAML (either in VS or Blend, to do it WYSIWYG in Blend you must somehow provide design data) you set the ItemsControl's ItemTemplate to a DataTemplate that contains the XAML subtree you want to repeat for every item in your collection.
Inside the DataTemplate, replace "line under the header" with the Button control, with Content="line under the header", and style it however you want. Then, add CallMethodAction to your button. It only takes 2 clicks in Blend, the first one is on "Assets" window. Specify TargetObject="{Binding}" MethodName="actSubtitleClicked". This way, the framework will call the void actSubtitleClicked() method of the item where user clicked the "line under the header".
For best performance, you should also modify the ItemsControl's ItemsPanel template, replacing StackPanel with VirtualizingStackPanel (again, a few clicks in Blend, the first one is the right click, then "Edit additional templates / ItemsPanel / Edit a copy")

Binding for ListboxItems not updated

I have a Listbox with data-binding to payments of a project. When I add a new payment, the payment will be added to the list. The add-page is also used to edit the payments. The event is called, in debug-mode I can see the changed value of my payment, but the ListBoxItem is not going to be updated. At the end of the add-page an event will be called, which updates the listbox items:
GlobalNotifier.OnPaymentAdded();
The OnPaymentAdded calls a method which only notifies about the property changes:
OnNotifyPropertyChanged("Project");
The code of the listbox:
<ListBox Name="ListPayments" ItemsSource="{Binding Project.Payments}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="10,5,10,0">
<StackPanel>
<TextBlock FontSize="30" Text="{Binding Name}" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Why are new items added, but existing items not updated? Any idea?
What's happening is that although the Project-object is updated, the Payments object (presumably a List) is not.
What you could try is the following:
Whenever the List-object is being manipulated (edited, items removed / added), fire the PropertyChanged-event for Projects
You can also switch the List<Project> to an ObservableCollection<Project>, which surely will fix your problem
If switching to ObservableCollection is out of the question for you, implement an override for the OnNavigatedTo() in the view that shows the list, and call the PropertyChanged-events (Project, Payments etc) from there.
Either one of these should fix your problem - it's all a matter of taste and preferences.
Sounds like your item properties are not dependency properties, or nobody fires propertychanged for them.

Button Styling in XAML

I have customized the button in this way:
<Button BorderBrush="Transparent" Name="DialButton" Click="DialButton_Click" >
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="43" Name="lblNumber" Margin="0,-5,0,0" />
<TextBlock FontSize="12" Margin="5,20,0,0" Name="lblCharacter" />
</StackPanel>
</Button>
Now, when a user presses the button I want the OnPress state to change the color of the labels. I can do this if it's a simple button by changing the Pressed state. But my label is placed inside a stack panel. How can I change the color in this case? Or in which event can I change the colors of the labels from C#.
You can use the PropertyChangeAction in cases like this. You can find this in the behaviors category on the Assets tab in Expression Blend.
Apply this action on the labels. Change the trigger property to the DataTrigger instead of the default EventTrigger. Bind the trigger to the IsPressed property of the DialButton. Add two PropertyChangeActions per TextBlock and set the Value for one of the to true and the other one to false.
Here's an example for one of them. The other is exactly the same.
<TextBlock FontSize="43" x:Name="lblNumber" Margin="0,-5,0,0" Text="25">
<i:Interaction.Triggers>
<ec:DataTrigger Binding="{Binding IsPressed, ElementName=DialButton}" Value="true">
<ec:ChangePropertyAction PropertyName="Foreground">
<ec:ChangePropertyAction.Value>
<SolidColorBrush Color="Red"/>
</ec:ChangePropertyAction.Value>
</ec:ChangePropertyAction>
</ec:DataTrigger>
<ec:DataTrigger Binding="{Binding IsPressed, ElementName=DialButton}" Value="false">
<ec:ChangePropertyAction PropertyName="Foreground">
<ec:ChangePropertyAction.Value>
<SolidColorBrush Color="{StaticResource PhoneForegroundColor}"/>
</ec:ChangePropertyAction.Value>
</ec:ChangePropertyAction>
</ec:DataTrigger>
</i:Interaction.Triggers>
</TextBlock>
If the i: or ec: isn't working, make sure you've got these lines at the top of your xaml file.
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ec="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
You'll need to turn this into a custom control and then you can manage the styling of each component based on the state.
Try this in the click event of button
Button butClicked = (Button)sender;
StackPanel panel1 = (StackPanel)butClicked.Content;
var child1Panel1 = panel1.Children[0] as TextBlock;
child1Panel1.Foreground = new SolidColorBrush(Color.FromArgb(255, 18, 18, 18));
If you're only going to use this button once, probably the easiest way would be to open the .xaml file in Expression Blend, and use Blend to customize the button as you wish, including the state change. If you're using the button in more than one place, do as Matt suggested and make it a custom control (which you can also use Blend to design) that you can reuse.

How to set a visibility of TextBlock bound to a ListBox?

How can I set a TextBlock visibility inside a ListBox. For example
<Grid>
<ListBox Name="myList">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBloxk Name="txtBlock1" Text="{Binding} First Name">
<TextBloxk Name="txtBlock2" Text="{Binding} Last Name">
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
At run time, I want to set the visibility of either textblocks to either Visible or Collapsed.
How can I do that, or can I?
You can use BooleanToVisibilityConverter (or other, custom converter) to change the Visibility according to binding value.
Use VisualTreeHelper if you need to iterate over each of the items in the ListBox. Or, re-bind ListBox to the new set of data and use MarcinJuraszek's suggestion on using a Converter (definitely an easier choice :))

Resources