wpf surface 2.0 ElementMenuItem - c#

I tried to implement a simple Menu with wpf for the surface 2.0/pixelsense.
<s:SurfaceWindow x:Class="MenuTrial.SurfaceWindow1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://schemas.microsoft.com/surface/2008"
xmlns:MenuTrial="clr-namespace:MenuTrial"
xmlns:Properties="clr-namespace:MenuTrial.Properties"
Title="MenuTrial"
>
<Grid Name="MenuGrid" Height="102" VerticalAlignment="Bottom">
<s:ScatterView HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<s:ScatterView.Resources>
<Image x:Shared="false" x:Key="IconPhoto" Source="Resources\Icons\photo.png"/>
<Image x:Shared="false" x:Key="IconCopy" Source="Resources\Icons\copy.png"/>
</s:ScatterView.Resources>
<s:ScatterViewItem Height="139"
Width="224"
Orientation="-23"
Background="#FF787878">
<s:ElementMenu
Name="MainMenu"
ActivationMode="AlwaysActive"
ActivationHost="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type s:ScatterViewItem}}}"
>
<s:ElementMenuItem Header="Menu1"/>
<s:ElementMenuItem Header="Menu2"/>
<s:ElementMenuItem Header="{x:Static Resources:Resources.IconPhoto}" Icon="{StaticResource IconPhoto}">
<s:ElementMenuItem Header="{x:Static Resources:Resources.Copy}" Icon="{StaticResource IconCopy}" Command="{x:Static MenuTrial:SurfaceWindow1.ShowMessageCommand}" CommandParameter="{Binding Path=Header, RelativeSource={x:Static RelativeSource.Self}}"/>
<s:ElementMenuItem Header="Menu 3.2" />
<s:ElementMenuItem Header="Menu 3.3"/>
</s:ElementMenuItem>
</s:ElementMenu>
</s:ScatterViewItem>
</s:ScatterView>
<TextBlock x:Name="textMessage" Width="500" Margin="40" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Bottom" FontFamily="Segoe360" FontSize="17" />
</Grid>
The problem is, I get an unknown bild mistake. Key can't be NULL or something would it be in english. At the Header="{x:Static Resources....
It is exactly like in the Surface samples. I just wanted to show a message when the menu item was clickt.
Can anyone please help me? Thx

If you define this MenuItem under Resources section you need to provide it with a x:Key value. Resources can't be declared without Key -
<s:ElementMenuItem Header="{x:Static Resources:Resources.IconPhoto}"
Icon="{StaticResource IconPhoto}"
x:Key="MyMenuItem">
....
</s:ElementMenuItem>

Related

How can I make a GridViewItem as a draggable object instead of a DataTemplate in XAML?

I have a XAML file which should make it possible to drag GridViewItems inside a GridView. Now I'm using an ItemSource for the GridView items and a DataTemplate to show them in the way I want them to be shown. That works. The following problem occured: Since I started using DataTemplate, the GridViewItems are not draggable. I can only drag the DataTemplate. That's weird, so the only part I can use to drag, is the area left and right of the GridViewItems because this is used for margin.
Why is the DataTemplate the 'draggable' control instead of the GridViewItem? I have tried numerous fixes but none seem to work out well.. I can ofcourse make it work without a DataTemplate, but it's much cleaner to use it like this.
<GridView Name="canvas" ItemsSource="{Binding GridviewItemList}" CanReorderItems="{Binding CanvasCanReorder}" CanDragItems="{Binding CanvasCanDrag}" ReorderMode="Enabled" AllowDrop="True" VerticalAlignment="Center" Width="660" Height="110" IsSwipeEnabled="False" ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.HorizontalScrollMode="Disabled">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:MainPageItems">
<GridViewItem Name="{x:Bind GvName}" Margin="13 0 15 0">
<Border Width="100" Height="100" Background="{x:Bind BdBackground, Mode=OneWay}">
<TextBlock Height="60" Width="30" FontSize="40" Text="{x:Bind TbText, Mode=TwoWay}" Margin="{x:Bind TbMargin, Mode=TwoWay}"></TextBlock>
</Border>
</GridViewItem>
</DataTemplate>
</GridView.ItemTemplate>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="DragItemsCompleted">
<core:InvokeCommandAction Command="{Binding CanvasDragCompleted}"></core:InvokeCommandAction>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</GridView>
Thanks in advance!
When you add GridViewItem in the DataTemplate, there are two ListViewItemPresenter in one GridViewItem. Please check it in the Live Visual Tree.
In UWP apps for Windows 10, both ListViewItem and GridViewItem use ListViewItemPresenter; the GridViewItemPresenter is deprecated and you should not use it. ListViewItem and GridViewItem set different property values on ListViewItemPresenter to achieve different default looks.
For more info, please refer Item containers and templates.
If you want to set Margin to the GridViewItem, we should be able to set the GridViewItem style in the GridView.ItemContainerStyle.
For example:
<GridView Name="canvas" ItemsSource="{Binding GridviewItemList}" CanReorderItems="{Binding CanvasCanReorder}" CanDragItems="{Binding CanvasCanDrag}" ReorderMode="Enabled" AllowDrop="True" VerticalAlignment="Center" Width="660" Height="110" IsSwipeEnabled="False" ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.HorizontalScrollMode="Disabled">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:MainPageItems">
<Border Width="100" Height="100" Background="{x:Bind BdBackground, Mode=OneWay}">
<TextBlock Height="60" Width="30" FontSize="40" Text="{x:Bind TbText, Mode=TwoWay}" Margin="{x:Bind TbMargin, Mode=TwoWay}"></TextBlock>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="Margin" Value="13 0 15 0"/>
</Style>
</GridView.ItemContainerStyle>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="DragItemsCompleted">
<core:InvokeCommandAction Command="{Binding CanvasDragCompleted}"></core:InvokeCommandAction>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</GridView>

ListBox binding not working in test configuration

I'm having trouble with binding a ListBox and I can't for the life of me figure out what's wrong. Most of the time it works fine, but in a special test configuration I have for my application it doesn't work and it's driving me crazy. I've literally stared at it for hours and tried all sorts of things. It's gotta be a binding issue, but I can't find it. There aren't any exceptions or binding errors being thrown that I can see.
The test configuration is identical to my debug configuration, but with an additional compilation symbol. It allows me to test the WPF application without running the entire software stack. It's an "offline mode" for all intents and purposes.
<ribbon:Ribbon Height="45">
<ribbon:Ribbon.ApplicationMenu>
<ribbon:RibbonApplicationMenu Width="56">
<ribbon:RibbonApplicationMenuItem Header="New Campaign" Command="{Binding Path=AddCampaign}" ImageSource="images\new.png"/>
<ribbon:RibbonApplicationMenuItem Header="Save Campaigns" Command="{Binding Path=Save}" ImageSource="images\save.png" />
<ribbon:RibbonApplicationMenuItem Header="Import Campaign" Command="{Binding Path=ImportCampaign}" ImageSource="images\campaign-import-128x128.png"/>
<ribbon:RibbonApplicationMenuItem Header="Export Campaign" Command="{Binding Path=ExportCampaign}" ImageSource="images\campaign-export-128x128.png" />
<ribbon:RibbonApplicationMenuItem Header="Terms of Use" Command="{Binding Path=Eula}" ImageSource="images\terms.png"/>
<ribbon:RibbonApplicationMenuItem Header="Resources" Command="{Binding Path=Resources}" ImageSource="images\resource.jpg"/>
<ribbon:RibbonApplicationMenuItem Header="About" Command="{Binding Path=About}" ImageSource="images\resource.jpg"/>
<ribbon:RibbonApplicationMenu.AuxiliaryPaneContent>
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label Width="130" Content="Campaign"/>
<Label Width="60" Content="Duplicate"/>
<Label Width="50" Content="Delete"/>
</StackPanel>
<ListBox ItemsSource="{Binding Path=Repository.Campaigns}"
SelectedItem="{Binding Path=SelectedCampaign, Mode=TwoWay}"
ItemContainerStyle="{StaticResource ListBoxItemStyle}"
Height="212"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Hidden">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=Name}" Width="130" />
<Button Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.DuplicateCampaign}"
CommandParameter="{Binding Path=Name}" Width="60">
<Button.Template>
<ControlTemplate>
<Border HorizontalAlignment="Center" VerticalAlignment="Center" >
<Image Source="/asdf;component/images/duplicate.png" Width="24" Height="24"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<Button Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.RemoveCampaign}"
CommandParameter="{Binding Path=Name}" Width="50">
<Button.Template>
<ControlTemplate>
<Border HorizontalAlignment="Center" VerticalAlignment="Center" >
<Image Source="/asdf;component/images/delete.png" Width="24" Height="24"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="View Archived"
Command="{Binding Path=ArchivedCampaigns}"></Button>
</StackPanel>
</ribbon:RibbonApplicationMenu.AuxiliaryPaneContent>
<ribbon:RibbonApplicationMenu.FooterPaneContent>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<ribbon:RibbonButton Label="LOGOUT" Command="{Binding Path=Logout}" />
<ribbon:RibbonButton Label="EXIT" Command="{Binding Path=Exit}" />
</StackPanel>
</ribbon:RibbonApplicationMenu.FooterPaneContent>
</ribbon:RibbonApplicationMenu>
</ribbon:Ribbon.ApplicationMenu>
Here's my login method where the window is created and the DataContext is bound. UITEST is my offline mode configuration.
private void Login()
{
MainVM = new ViewModel.MainWindowVM();
_mainWindow = new RibbonMainWindow
{
DataContext = MainVM
};
//Prompt user for login.
#if UITEST
_loggedIn = true;
MainVM.LoadData();
#else
var loginWindow = new Login();
var login = new ViewModel.LoginVM();
loginWindow.DataContext = login;
loginWindow.ShowDialog();
if (loginWindow.DialogResult != null) _loggedIn = loginWindow.DialogResult.Value;
#endif
if (_loggedIn && MainVM.Loaded)
{
_mainWindow.ShowDialog();
}
}
Edit: As near as I can guess, it might be due to using the legacy RibbonControlsLibrary from the pre .NET 4.5 days. I retargeted the software to .NET 4.6.1 last year so I switched to the Ribbon built-in to .NET and now it works oddly enough. If I try to mess with anything else in the window it just seems to break again. Like if I try to strongly-type the DataContext in the window.
As near as I can guess, it might be due to using the legacy RibbonControlsLibrary from the pre .NET 4.5 days. I retargeted the software to .NET 4.6.1 last year so I switched to the Ribbon built-in to .NET and now it works oddly enough. If I try to mess with anything else in the window it just seems to break again. Like if I try to strongly-type the DataContext in the window.

Binding ElementName in menuitem's header

i try to bind the TextBox's text in MenuItem's header to MenuItem's Tag property.
but it won't work correct, always get Null in Tag property.
the code is like below...
<Button x:Name="Button1" Content="Test" HorizontalAlignment="Left" Width="182" Height="34" VerticalAlignment="Top" Margin="160,113,0,0">
<Button.ContextMenu>
<ContextMenu PlacementTarget="{Binding ElementName=Button1}" Placement="Bottom">
<MenuItem Tag="{Binding ElementName=TextBox1, Path=Text}" Click="MessageBox_ShowTag">
<MenuItem.Header>
<Grid Height="25" MinWidth="153">
<Label Content="Label1" Width="86" HorizontalAlignment="Left" VerticalContentAlignment="Center"/>
<TextBox x:Name="TextBox1" VerticalContentAlignment="Center" Margin="91,0,0,0"/>
</Grid>
</MenuItem.Header>
</MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
When click on menuitem, call the MessageBox to show the tag in MenuItem
( MessageBox.Show( ( sender as MenuItem ).Tag?.ToString() ); )
MessageBox has show but content is always empty.
Result:
how can i bind to textbox?
I don't know why you have to bind it like that. An alternative would be to bind to a property (here: MyText) that implements INotifyPropertyChanged, and then pass the DataContext to the menu like this:
<Button x:Name="Button1" Content="Test" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Button.ContextMenu>
<ContextMenu Placement="Bottom" DataContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem>
<MenuItem.Header>
<Grid Height="25" MinWidth="153">
<Label Content="Label1" Width="86" HorizontalAlignment="Left" VerticalContentAlignment="Center"/>
<TextBox Name="TextBox1" Text="{Binding Path=MyText}"
VerticalContentAlignment="Center" Margin="91,0,0,0"/>
</Grid>
</MenuItem.Header>
</MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
And then not relay on Click event to get the TextBox value at all.
If you want to know why your binding doesn't work, its because your MenuItem can't find an object named TextBox1 in its Namescope. If you must (namescopes are a bit tricky), you may make it work by creating a new Namescope for your MenuItem and registering the name for the TextBox:
NameScope.SetNameScope(mi1, new NameScope());
mi1.RegisterName("TextBox1", TextBox1);
where mi1 is the name of your MenuItem, then your binding will work:
<Button x:Name="Button1" Content="Test" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Button.ContextMenu>
<ContextMenu Placement="Bottom">
<MenuItem Tag="{Binding ElementName=TextBox1, Path=Text}" Click="MessageBox_ShowTag" Name="mi1">
<MenuItem.Header>
<Grid Height="25" MinWidth="153">
<Label Content="Label1" Width="86" HorizontalAlignment="Left" VerticalContentAlignment="Center"/>
<TextBox Name="TextBox1" VerticalContentAlignment="Center" Margin="91,0,0,0"/>
</Grid>
</MenuItem.Header>
</MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
Also, avoid x:Name whenever you can. It can cause some nasty memory leaks. Use Name instead.
Like mentioned in the comment also, there could be better solution to actual problem you are trying to solve.
But anyhow if you want solution for your specific problem it can be solved by using x:Reference in place of ElementName like this:
<MenuItem Tag="{Binding Source={x:Reference TextBox1}, Path=Text}"/>
ElementName is not working because VisualTree is different. In case interested read further here - ElementName v/s x:Reference.
Try binding via RelativeSource:
<TextBox x:Name="TextBox1" Text="{Binding Path=Tag, RelativeSource={RelativeSource AncestorType={x:Type MenuItem}}}" VerticalContentAlignment="Center" Margin="91,0,0,0"/>

How to display a button or label when right clicking on a ListBox item

I'm new to WPF and MVVM, I've build few things, and now tryining to display a delete "button" when user right clicks on a ListBox item.
My listbox looks like this righ now
<ListBox DisplayMemberPath="QUERYNAME"
SelectedValuePath="USERQUERYID"
ItemsSource="{Binding RS.SavedQueryList, UpdateSourceTrigger=PropertyChanged}"
SelectedValue="{Binding RS.SelectedValue, UpdateSourceTrigger=PropertyChanged}"
Height="300" HorizontalAlignment="Left" Name="listBox2" VerticalAlignment="Top" Width="101" Margin="521,74,0,0" TabIndex="0">
Thanks
You can add the button and label (in fact, any element you want) to a ContextMenu and assign that ContextMenu to ListBoxItems. For example, in my Window, I'll have something like this:
<Window.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="Delete This Item" Margin="10"/>
<Button Content="Delete"/>
</StackPanel>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
This will use the power of Styles to apply a customized ContextMenu to all ListBoxItems the window. After that you can bind Button.Command to your ViewModel.
<ListBox DisplayMemberPath="QUERYNAME"
SelectedValuePath="USERQUERYID"
ItemsSource="{Binding RS.SavedQueryList, UpdateSourceTrigger=PropertyChanged}"
SelectedValue="{Binding RS.SelectedValue, UpdateSourceTrigger=PropertyChanged}"
Height="300" HorizontalAlignment="Left" Name="listBox1" VerticalAlignment="Top" Width="101" Margin="521,74,0,0" TabIndex="0">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete">
<MenuItem.Icon>
<Image Width="16" Height="16" Source="pack://application:,,,/Img/Delete.png" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
<ListBox.ContextMenu>
</ListBox>
Obviously you'll need to use some Command with your MenuItem...
you can do that by using the MVVM light behavior EventToCommand see http://msdn.microsoft.com/en-us/magazine/dn237302.aspx
Set the event to MouseRightButtonUp

Enabling ContextMenu on a Topmost Window

I have a window with Topmost="True".
<Window ... bunch of code ....
Topmost="True" >
Doing this now effectively disables all context menus on the form. The menus are defined in the XAML, like this:
<StackPanel Width="120" Height="50" MouseMove="Drag_MouseMove">
<Image Source="{Binding" />
<TextBlock Text={Binding}" />
<StackPanel.ContextMenu>
<ContextMenu Name="myMenu" StaysOpen="True">
... bunch of code ...
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
Is there a way to re-enable context menus? I'm also willing to consider alternatives to Topmost="True".
I can't reproduce your problem. I've created a new project using this near-code to yours and context menu does show.
Maybe the problem comes from something else? like the bindings? (talking from experience)
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Topmost="True">
<Grid>
<StackPanel Width="120" Height="50" Background="Gray">
<TextBlock Text="yo" />
<TextBlock Text="yo" />
<TextBlock Text="yo" />
<TextBlock Text="yo" />
<TextBlock Text="yo" />
<TextBlock Text="yo" />
<TextBlock Text="yo" />
<TextBlock Text="yo" />
<StackPanel.ContextMenu>
<ContextMenu Name="myMenu" StaysOpen="True">
<MenuItem Header="hello" />
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
</Grid>
</Window>
I suspect that the menu is showing just fine. However, the menu is not a top level item so it ends up behind your topmost MainWindow. I've got the same problem and have not yet found the answer as to how to make sure that the menu always shows.

Categories

Resources