WPF Application - <Ellipse.InputBindings> - <MouseBinding> - c#

Hi I am new to WPF Development and run into a problem Regarding Mouse Binding of an Ellipse which was created with Item Controls Trough Data Binding. This is the source code. My Problem is that the "CLoadModelFromDisk" Binding is not executed. In another context the Command works without any problems.
<ItemsControl ItemsSource="{Binding JointsModelPartView}" Grid.Row="1" Grid.Column="1">
<ItemsControl.ItemContainerStyle>
<Style TargetType="FrameworkElement">
<Setter Property="Canvas.Left" Value="{Binding posx1}" />
<Setter Property="Canvas.Top" Value="{Binding posy1}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="Point">
<Ellipse Fill="AntiqueWhite"
Stroke="Black"
Width="10"
Height="10"
Margin="-5,-5,5,5"
>
<Ellipse.InputBindings>
<MouseBinding
Command="{Binding CLoadModelFromDisk}"
Gesture="LeftClick"
/>
</Ellipse.InputBindings>
</Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
It would be really nice if somebody could help me with this problem.
This is the code for the context menu which does not work with your solution. Do you have any idea why?
<Ellipse.ContextMenu>
<ContextMenu ItemsSource="{Binding DataContext.ContextActionsView, RelativeSource={RelativeSource AncestorType=ItemsControl}}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Name}"/>
<Setter Property="Command" Value="{Binding RCommand}"/>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Ellipse.ContextMenu>
I already tried to set the Relative Source to the Header and Command but that also does not worked.

In your DataTemplate, the DataContext will be the item displayed in the template -- one of the items in JointsModelPartView. Do those items have a property of type ICommand named CLoadModelFromDisk?
My guess is that they don't, and CLoadModelFromDisk is a member of the same viewmodel as JointsModelPartView. In that case, you need to bind not to the list item, but to the parent viewmodel to which the property actually belongs. That'll be the DataContext of the ItemsControl -- it must be, since the ItemsControl is able to bind to JointsModelPartView.
Try this:
<MouseBinding
Command="{Binding DataContext.CLoadModelFromDisk, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
Gesture="LeftClick"
/>

Related

Command binding to top-level MenuItem of Menu doesn't work

I'm learning WPF and developing a dynamic Menu which is driven by data binding of it's ItemsSource to an ObservableCollection. To do this I have a simple MenuItemViewModel and a HierarchicalDataTemplate for automatic binding of MenuItems to it.
The problem I have is that Command property doesn't work for top level menu items. Despite it is set, a MenuItem doesn't react on mouse click and doesn't get disabled if Command cannot be executed. Simply it's like it's not getting bound.
For lower level menu items though, it works as intended. I think this should be a problem of my HierarchicalDataTemplate but I can't find it, because as I see there's no code in template which might affect command binding of only top-level MenuItems.
MenuItemViewModel implements INotifyPropertyChanged and contains following public properties:
string Text
Uri ImageSource
ICommand Command
ObservableCollection<MenuItemViewModel> Children
HierarchicalDataTemplate for MenuItem in my Window.Resources is as follows:
<HierarchicalDataTemplate DataType="{x:Type common:MenuItemViewModel}"
ItemsSource="{Binding Path=Children}">
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command"
Value="{Binding Command}" />
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}" />
<TextBlock Text="{Binding Text}" VerticalAlignment="Center"/>
</StackPanel>
</HierarchicalDataTemplate>
Can you please point me on my mistake?
EDIT: Top-level MenuItem doesn't contain any children (i.e. Children collection of associated ViewModel is empty).
Thanks to #sTrenat comment I've come to solution below.
<Menu.Resources>
<!-- cancel sharing of image so Icon will work properly -->
<Image x:Key="MenuIcon" Source="{Binding ImageSource}" x:Shared="False"/>
</Menu.Resources>
<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}"
BasedOn="{StaticResource {x:Type MenuItem}}">
<Setter Property="Header" Value="{Binding Text}" />
<Setter Property="Icon" Value="{StaticResource MenuIcon}"/>
<Setter Property="Command" Value="{Binding Command}"/>
<Setter Property="ItemsSource" Value="{Binding Children}" />
<!-- centering MenuItem's Header -->
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{Binding}" />
</DataTemplate>
</Setter.Value>
</Setter>
<!-- setting Icon to null when ImageSource isn't specified -->
<Style.Triggers>
<DataTrigger Binding="{Binding ImageSource}"
Value="{x:Null}">
<Setter Property="Icon" Value="{x:Null}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Menu.ItemContainerStyle>

How to set 2 color background to a TreeView (WPF)

I want to set two color background to a custom tree view (wpf). You can set this propriety in a DataGrid. I could not figure out a way to do it for a tree view.
I also want to set the selection of a element to be as big as the cell.
<TreeView Grid.Row="2" Name="TreeView" DataContext="{Binding Path=TreeModel}" ItemsSource="{Binding TreeItems}" SelectedItemChanged="TreeView_OnSelectedItemChanged">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:NodeViewModel}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding NameNode}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Add" Command="{Binding AddMachinePart_Command}"/>
<MenuItem Header="Remove" Command="{Binding RemoveMachinePart_Command}" IsEnabled="{Binding IsModule}"/>
<MenuItem Header="Edit" Command="{Binding EditMachinePart_Command}" IsEnabled="{Binding IsModule}"/>
<Separator></Separator>
<MenuItem Header="Copy path" Command="{Binding CopyPath_Command}" IsEnabled="{Binding IsModule}"></MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Edit:
When using the solution from
https://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.alternationindex(v=vs.110).aspx suggested #jschroedl
It would be ideal to be as large as the tree view grid like shown in picture below:
You will probably want to use ItemsControl.AlternationIndex in a Style to control how many colors to cycle (2 in your case).
MSDN Docs for ItemsControl.AlternationIndex has an example with ListBox which you can probably adapt to TreeView as well.

WPF MenuItem not filling available ContextMenu space

I'm having a weird problem with a simple ContextMenu using MahApps.Metro without any additional styling. When moving the cursor on top of the text or slightly around it, there is no problem. But when moving it further away, still inside the ContextMenu bounds, the Cursor is no longer on top of the MenuItem. Clicking now also doesn't result in any action at all besides closing the ContextMenu.
<ContextMenu ItemsSource="{Binding ContextItems}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Text}" Command="{Binding Command}"/>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
What am I doing wrong? Why doesn't the MenuItem use the available space?
If your ContextItems holds a collection with viewmodels then I think this could help you (not tested):
<ContextMenu ItemsSource="{Binding ContextItems}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Text}" />
<Setter Property="Command" Value="{Binding Command}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
Command and Text should be the properties on the viewmodel object.
I havent used MahApps.Metro . Though you can override the template like this
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Text}" Command="{Binding Command}"/>
<MenuItem.Template>
<ControlTemplate>
<ContentPresenter Content="{Binding Header,RelativeSource={RelativeSource TemplatedParent}}">
</ContentPresenter>
</ControlTemplate>
</MenuItem.Template>
</MenuItem>
</DataTemplate>
</ContextMenu.ItemTemplate>
I hope this will help.

Add a separator to a Context Menu bound to models in WPF with MVVM Light

I have a context menu in WPF with the following constraints:
Menu items should be bound to a list of models
The menu may contain separators
Menu items can have sub menu items
Menu items may be turned off based on state
The order of the menu items may not change (i.e. menu item 1 must appear above menu item 2, if present)
I have seen solutions where the view model contains a list of controls, however, this is not an acceptable solution.
The approach I've taken almost works.
<ContextMenu DataContext="{Binding Data.ContextMenuViewModel, Source={StaticResource proxy}}"
ItemsSource="{Binding Data.ContextMenuViewModel.MenuItems, Source={StaticResource proxy}}"
Visibility="{Binding CellContextMenuOpen, Converter={StaticResource BoolToVisibilityConverter}}" >
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="CommandParameter" Value="{Binding CommandParameter}" />
<Setter Property="ItemsSource" Value="{Binding SubMenuItems}" />
<Setter Property="IsCheckable" Value="{Binding IsCheckable, FallbackValue=False}" />
<Setter Property="IsChecked" Value="{Binding IsChecked, FallbackValue=False}" />
</Style>
</ContextMenu.ItemContainerStyle>
<ContextMenu.ItemTemplateSelector>
<ccm:MenuItemTemplateSelector>
<ccm:MenuItemTemplateSelector.SeparatorTemplate>
<DataTemplate>
<Separator HorizontalAlignment="Stretch" IsEnabled="False" Margin="0" />
</DataTemplate>
</ccm:MenuItemTemplateSelector.SeparatorTemplate>
<ccm:MenuItemTemplateSelector.MenuItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" />
</DataTemplate>
</ccm:MenuItemTemplateSelector.MenuItemTemplate>
</ccm:MenuItemTemplateSelector>
</ContextMenu.ItemTemplateSelector>
However, I've discovered that some properties in ItemsContainerStyle and the DataTemplate are mutually exclusive. For example, if I were to add a visibility binding to the items container style, the data template wont be applied at all.
The problem with the solution above is that the MenuItem itself wont collapse based on a binding, I can only get the header to collapse. If I did not need the separators, I could put everything in an ItemContainerStyle and be done with it.
Any suggestions would be greatly appreciated.

Layer system for images on a canvas

I am trying to figure out how I can have a layer system for my app. I am adding images to an itemscontrol and they are all rendering one on top of the other.
<ItemsControl Name="canvasDataBinding"
HorizontalAlignment="Center"
Height="512"
Width="512"
VerticalAlignment="Center"
ClipToBounds="True">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Transparent"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Image Source="{Binding Name}"
Width="{Binding Width}"
Height="{Binding Height}">
</Image>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
For testing purposes, I tried adding Panel.Zindex="{Binding Zind}" inside the image control, and decrementing Zind every time a new image was added to the collection, but the images still render on top of each other.
I also thought about having multiple collections, each collection would be its own layer. I dont know how I would implement this with my current code though.
Edit:
I added an ItemContainerStyle:
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Panel.ZIndex" Value="{Binding Zindex}" />
</Style>
</ItemsControl.ItemContainerStyle>
Again I am binding the value of ZIndex to an int that I decrement before the image is added to the collection. It is still rendering one on top of the other.
You need to set your Canvas.Top, Canvas.Left, and Panel.ZIndex in the ItemContainerStyle so the property gets applied to the <ContentPresenter> that wraps each Image.
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Top" Value="{Binding Y}" />
<Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Panel.ZIndex" Value="{Binding Zindex}" />
</Style>
</ItemsControl.ItemContainerStyle>
When your ItemsControl gets rendered, it actually renders like this
<Canvas>
<ContentPresenter>
<Image />
</ContentPresenter>
<ContentPresenter>
<Image />
</ContentPresenter>
<ContentPresenter>
<Image />
</ContentPresenter>
</Canvas>
which is why it doesn't work to set the property on the <Image> itself.

Categories

Resources