ContextMenu in DataTemplate Binding issue - c#

I have a context menu in LongListSelector.
This list is created and updated in runtime.
<phone:PanoramaItem Header="{Binding Path=LocalizedResources.SavedGamesHeader, Source={StaticResource LocalizedStrings}}" Orientation="Horizontal">
<phone:LongListSelector Margin="0,0,-22,2" ItemsSource="{Binding SavedGames}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="12,2,0,20" Width="432">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="Remove" Click="RemoveSave_OnClick"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<Image Margin="10,5,10,0" Height="173" Width="248" Source="{Binding Screen}" Stretch="Fill" HorizontalAlignment="Left"></Image>
<StackPanel Width="311" Margin="8,5,0,0" HorizontalAlignment="Left">
<TextBlock Tap="Save_OnTap" Tag="{Binding SavedGame}" Text="{Binding SaveName}" TextWrapping="Wrap" Margin="10,0" Style="{StaticResource PhoneTextExtraLargeStyle}" FontSize="{StaticResource PhoneFontSizeMedium}" Foreground="White" FontWeight="Bold" FontFamily="Arial Black" HorizontalAlignment="Left" />
<TextBlock Text="{Binding GameName}" TextWrapping="Wrap" Margin="10,-2,10,0" Style="{StaticResource PhoneTextSubtleStyle}" HorizontalAlignment="Left" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Text="Created on:" Margin="10,-2,10,0" Style="{StaticResource PhoneTextSubtleStyle}" />
<TextBlock Text="{Binding Created}" TextWrapping="Wrap" Margin="5,-2,10,0" Style="{StaticResource PhoneTextSubtleStyle}" />
</StackPanel>
</StackPanel>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</phone:PanoramaItem>
Here's the method that handles click event on menu item
private void RemoveSave_OnClick(object sender, RoutedEventArgs e)
{
var menuItem = (MenuItem)sender;
var saveViewModel = menuItem.DataContext as SavesViewModel;
EmuStorageMgr.Instance.DeleteSave(saveViewModel.SavedGame.SaveFolder);
App.ViewModel.RescanSaves();
}
The following method populates the SavedGames list
public ObservableCollection<SavesViewModel> SavedGames { get; private set; }
public void RescanSaves()
{
SavedGames.Clear();
var saves = EmuStorageMgr.Instance.GetSaves();
foreach (var save in saves)
{
SavedGames.Add(new SavesViewModel(save));
}
this.IsSavesLoaded = true;
NotifyPropertyChanged("SavedGames");
}
So, when the SavedGames collection is populaed for the first time it work perfect, but when the collections changes (delete some old items, add new) I observe some strange behaviour. When the OnClick event is fired I see menuItem.DataContext is not for the menu item I clicked but for some old menu items which were deleted.

I can't leave a comment on you're post so I'll say here:
This is a known problem and one that I have also. I haven't found any way to fully resolve this issue and haven't seen any recent solutions. You can see my post hereto ensure the issue is in line with yours.
The only solution I've seen so far is described here in a msdn blog from '11. It identifies the problem in the Silverlight Framework and he provides a workaround which I implemented. Include the class file in your project and make use of the XAML tags, and it will allow your contextmenu keep in sync with the parent's datacontext. I've ran into a small side-effect using it, so it's only a band aid.
I also found tell from another forum that it's a known issue with no solution, but a patch may be found at codeplex here. My issue with the patch is I couldn't figure out how to implement it, and also the LLS (which is what I'm using the ContextMenu with) has migrated directly into the SDK, so I was stuck.
That's all I've dug up on the problem, hope it helps. If someone else has anymore to add please do.
Update:
Using some of what was in the above provided links, I think I have a slightly better solution. In the ContextMenu Unloaded event, refresh the view. Something like:
private void add_but_up(object sender, RoutedEventArgs e)
{
ContextMenu conmen = (sender as ContextMenu);
conmen.ClearValue(FrameworkElement.DataContextProperty);
}
This is essentially what the patch in the blog does. Only in a completely different context. So my issues were an inability to use functions like ScrollTo(). Doing this in the code behind of the actual page seems fix the ContextMenu binding issue.

Related

Binding Errors with WPF TabControl

I have the following XAML...
<TabControl Grid.Row="0" Grid.Column="1" Grid.RowSpan="2"
Name="customerTab"
ItemsSource="{ Binding DetailViewModels }"
SelectedItem="{Binding SelectedDetailViewModel, Mode=TwoWay}"
TabStripPlacement="Top">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}" />
<TextBlock Text="*" Visibility="{Binding HasChanges, Converter={StaticResource BooleanToVisibilityConverter}}" />
<Button Command="{Binding CloseCommand}" Style="{StaticResource closeButtonStyle}" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
Basically, I have a listview where I can click on a record to view detail. The detail record gets displayed in the tab control.
You can see I have a button which is bound to a command that closes the tab.
When I close the tab, the following binding error displays...
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.TabControl', AncestorLevel='1''. BindingExpression:Path=TabStripPlacement; DataItem=null; target element is 'TabItem' (Name=''); target property is 'NoTarget' (type 'Object')
I am not totally sure of the issue. Does this mean that the detail viewmodels cannot climb back up the hierarchy to the tab control when it closes?
The actual application works as designed, I just want to address this error so it does not keep coming up every time I close a tab.
The CloseCommand is a delegate command. Here is that code along with the method that it runs.
public DelegateCommand CloseCommand { get; private set; }
CloseCommand = new DelegateCommand(OnClose);
public void OnClose()
{
OnTabClosed?.Invoke(InstanceId);
}
OnTabClosed is an action that closes the tab and the InstanceId is simply a GUID of the detail viewmodel.
I did search online and found a way to hide the message, but I am disinclined to do that for fear of hiding more legitimate binding errors.
How do I fix this? What is the best way to debug?
Edit
Here is the code that handles the closing of the tab item...
private void HandleTabClosed(Guid instanceId)
{
DetailViewModels.Remove(DetailViewModels.First(vm => vm.InstanceId == instanceId));
}
I just made the test, and I find no error, but I do it a bit differently, so hope will be good for you :
In XAML, I use a "Tag" for buttons (very useful when you use templates).
Taking your code, that would be something like that :
<TabControl Grid.Row="0" Grid.Column="1" Grid.RowSpan="2"
Name="customerTab"
ItemsSource="{ Binding DetailViewModels }"
SelectedItem="{Binding SelectedDetailViewModel, Mode=TwoWay}"
TabStripPlacement="Top">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}" />
<TextBlock Text="*" Visibility="{Binding HasChanges, Converter={StaticResource BooleanToVisibilityConverter}}" />
<Button Content="X" Click="Button_Click" Tag="{Binding InstanceId}" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
Then on my "OnClick" event I will look which Instance I may remove, then remove it :
private void Button_Click(object sender, RoutedEventArgs e)
{
Button item = (Button)sender;
long instanceId = (long)item.Tag;
GroupResults selectedGroup = this.MyFullList.FirstOrDefault(x => x.InstanceId == instanceId);
if(selectedGroup!=null)
{
this.MyFullList.Remove(selectedGroup);
}
}
It's not really the same way as you did, but it works fine. I always use Tags when I work on templates, and until now never got any problem.

How do I make a user control display as pop up in windows 8.1 c# and xaml

I have a page that displays list of items. How do I make a user control to display detailed information about the item that is clicked (selected) in c# xaml.
If anyone can also suggest link to either a blog post or article that explains how to do this in details
Though this is not the kind of questing SO is for, I'll answer anyway:
What you are looking for is probably a flyout. You can read a quickstart on this here
EXAMPLE
You can add the flyout to an other UIElement with the AttachedFlyout attached property:
<Grid x:Name="RootGrd">
<FlyoutBase.AttachedFlyout>
<Flyout x:Name="MainFlt">
<Border BorderBrush="White" BorderThickness="3" Margin="0,0,0,10">
<StackPanel>
<TextBlock Text="{Binding Prop1}"/>
<TextBlock Text="{Binding Prop2}"/>
<TextBlock Text="{Binding Prop3}"/>
<Button Content="Close" Click="Button_Click"/>
</StackPanel>
</Border>
</Flyout>
</FlyoutBase.AttachedFlyout>
<ListView x:Name="MainLvw" SelectionChanged="MainLvw_SelectionChanged" Background="DeepSkyBlue">
<ListView.ItemTemplate>
<DataTemplate>
<Border BorderBrush="White" BorderThickness="3" Margin="0,0,0,10">
<StackPanel>
<TextBlock Text="{Binding Prop1}"/>
<TextBlock Text="{Binding Prop2}"/>
<TextBlock Text="{Binding Prop3}"/>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
And then in the code-behind, you call FlyoutBase.ShowAttachedFlyout() to show the flyout:
private void MainLvw_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var sndr = (ListView)sender;
var item = (SampeClass)sndr.SelectedItem;
RootGrd.DataContext = item;
FlyoutBase.ShowAttachedFlyout(RootGrd);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MainFlt.Hide();
}
You can find an example solution on my github, which shows this implemented: GitHub repo

TiltEffect on longListSelector Items, windows phone 8

This may sound really NOOBI!
I have a LongListSelector for showing some items in my app, and I wanted to add this cool effect called TiltEffect to the items so they show some interaction as user taps on one of the them.
For that matter I searched the internet and came up with this link on MSDN and I have done as instructed there. I downloaded the code sample, added the discussed class to my project and in the MainPage.xaml I added the following lines:
xmlns:local="clr-namespace:MyNamespace"
local:TiltEffect.IsTiltEnabled="True"
alnd also in the class TiltEffect.cs I added LongListSelector as a TiltableItem like this:
static TiltEffect()
{
// The tiltable items list.
TiltableItems = new List<Type>() { typeof(ButtonBase), typeof(ListBoxItem), typeof(LongListSelector),};
UseLogarithmicEase = false;
}
Now the problem is that when any of the items on the LongListSelector is tapped, the whole LongListSelector tilts instead of only the tapped item.
please help!
I found the answer to my problem here
I wrapped my DataTempalte in a ListBoxItem, now it looks like this:
<phone:LongListSelector x:Name="MyLongListSelector"
Margin="0,0,0,0"
ItemsSource="{Binding My_Items}"
SelectionChanged="MyLongListSelector_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<ListBoxItem >
<StackPanel Margin="0,0,0,7" local:TiltEffect.IsTiltEnabled="True" MinWidth="460">
<StackPanel.Background>
<ImageBrush Stretch="Fill" ImageSource="/Assets/Photos/items.png"/>
</StackPanel.Background>
<TextBlock Text="{Binding Title}"
TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"
TextAlignment="Center"
Margin="0, 5, 0, 15" FontFamily="Assets/Fonts/BNazanin.ttf#B Nazanin"/>
</StackPanel>
</ListBoxItem>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
could you try adding type that you used as a jumplist item to The tiltable items Collection instead of LongListSelector.

Silverlight: ComboBox Behavior

really simple problem, but I guess I have just the wrong definition of combobox:
I'd like to get a simple thing like:
http://www.c-sharpcorner.com/uploadfile/mahesh/combobox-in-silverlight/
But whenever I add a combobox (or a listbox) and set the itemssource, it shows directly all items and I dont have a textbox-like selection.
My approach was quite simple:
In XAML I define:
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Style="{StaticResource styleStdWidth}" Text="Spieler 1:" />
<ListBox x:Name="lsbPlayerOne" ItemTemplate="{StaticResource dtName}" Width="300" />
<TextBox x:Name="txtPlayerOnePoints" Style="{StaticResource stylePlayerWidth}" />
</StackPanel>
<DataTemplate x:Name="dtName">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" FontSize="35" FontWeight="Bold" x:Name="txbname"/>
</StackPanel>
</DataTemplate>
And in Code behind I just set the ItemsSource with a List, which has data.
Since the ListBox gets bigger every time I add a item, it gets uglier and uglier.
Am I missing a property, which I didnt find? I did not see anything...
Sorry for the confusing question :)
P.S.: I tried the same as in the example shown in the link. Sadly I cant open the sample project.
Matthias Müller
Your question is unclear. But you are not implementing a combobox in the code you have shown. Why don't you use a combobox and set your itemsource to the list that contains the fields you want to use?
<ComboBox ItemSource={Binding Names}/>

Binding data in C# and XAML?

I'm trying to use binding with C# and a XAML SemanticZoom control in my Metro app, but honestly I'm at a loss as to how to do it. Here's the XAML code I've gotten so far by piecing together from questions, articles, etc:
<SemanticZoom x:Name="boardZoom" Height="626" Margin="10,132,10,0" VerticalAlignment="Top">
<SemanticZoom.ZoomedInView>
<GridView IsSwipeEnabled="True" x:Name="ItemsGridView">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="10,10,0,0"
HorizontalAlignment="Left" Background="White">
<TextBlock Text="{Binding Title}" TextWrapping="Wrap" Width="200" Height="300"
FontFamily="Global User Interface" FontSize="40" Foreground="Black"
VerticalAlignment="Center" HorizontalAlignment="Left"/>
<Image Source="{Binding Image}" Height="60" Width="60"
VerticalAlignment="Center" Margin="0,0,10,0" Visibility="{Binding isImage}" />
<TextBlock Text="{Binding Category}" TextWrapping="Wrap" Width="200"
FontFamily="Global User Interface" Foreground="Black"
VerticalAlignment="Center" HorizontalAlignment="Left"/>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</SemanticZoom.ZoomedInView>
<!--Didn't include SemanticZoom.ZoomedOutView since I'm still trying to get the ZoomedIn one working first-->
</SemanticZoom>
And my C# code:
List<PinStore.pin> pins = PinStore.CopyFromStream(response.GetResponseStream()); //returns a list of PinStore.pin objects, which have name, type, Image, isImage, and Category objects
System.Collections.ObjectModel.ObservableCollection<SemanticZoomed.zoomedIn> toSource = new System.Collections.ObjectModel.ObservableCollection<SemanticZoomed.zoomedIn>(); //should I be using ObservableCollection or something like List<> here?
foreach (PinStore.pin pin in pins)
{
SemanticZoomed.ZoomedIn toAdd = new SemanticZoomed.ZoomedIn(); //class with Title, Image, isImage, and Category objects
if (pin.type == "text")
{
toAdd.Title = pin.name;
toAdd.Image = null;
toAdd.isImage = Visibility.Collapsed;
toAdd.Category = pin.category;
}
toSource.Add(toAdd);
}
ItemsGridView.DataContext = toSource;
I've not had much experience in XAML/C#, and zero experience with binding. I'm not getting any errors, but I've noticed that if I replace ItemsGridView.DataContext = toSource; with ItemsGridView.ItemsSource = toSource; a blank stackpanel shows up in the GridView, and I can't seem to find a way to fill that with the Title and Category values I specify. Thanks!
Well you should first consider creating a ResourceDictionary so you can save your item style. Then you can set the ItemStyle to the Resource Dictionary.
But regardless you need to do: ItemsGridView.ItemsSource = toSource; If you do not choose to Bind the toSource in the GridView xaml.
Also make sure the SemanticZoomed.zoomedIn object implements the INotifyPropertyChanged interface, And calls the event properly. And make sure the Title, Image, Category, etc are public properties that call the event when edited. and Also you need make sure pin.Text is an actual value. {Making sure}.
If you want to learn more about data binding check out how they do it in C# & XAML with Windows 8 {Should be the same thing}:
http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh464965.aspx

Categories

Resources