Copy for Treeview Item in wpf - c#

How to enable copy in my treeviewitem so that i can copy the text in treeview selecteditem and paste it somewhere else. I can't find such property in treeview in wpf.
here is my code
<TreeView
SelectedItemChanged="treeView1_SelectedItemChanged"
HorizontalContentAlignment="Stretch">
<TreeViewItem Header="Intution Studio" ItemsSource="{Binding Main}">
<TreeViewItem.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
</TreeViewItem.ItemContainerStyle>
<TreeViewItem.ContextMenu>
<ContextMenu ItemsSource="{Binding}">
<MenuItem Command="Copy">
<!-- (can't enable copy option) -->
<MenuItem.Icon>
<Image Source="Images\copy.png" Width="20" Height="20"/>
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</TreeViewItem.ContextMenu>
<TreeViewItem.Resources>
<HierarchicalDataTemplate DataType="{x:Type TextBlock}">
<!-- ... -->
</HierarchicalDataTemplate>
</TreeViewItem.Resources>
</TreeViewItem>
</TreeView>

Edit: Sorry WPF does not support that.
You should solve this by cloning the underlying data in your model. If you don't have MVVM or must per se clone the visual control, the only reasonable solution seems serializing it to a xaml and then reconstructing it from that.
http://social.msdn.microsoft.com/Forums/en/wpf/thread/209597f0-0e8b-4fbb-a69d-a6479ed96187

Related

contextmenu won't open anymore on datagrid after several updates

I have a wpf datagrid, by a template I create a contextmenu for every row.
Since the grid rows are getting constantly changed it often happens that the contextmenu gets closed when the focused row disappears.
After a while the contextmenu won't open anymore on the entire grid. It happens if the contextmenu is heavily used and there are lots of updates.
I tried to debug this by logging the ContextMenuOpening, contextMenuClosing and MouseRightButtonDown events. The "opening" gets raised but the menu isn't visible. Reopening the window clears the issue.
Currently I am at odds. Can somebody give me some pointers on how to resolve this issue?
Perhaps somebody could recommend some XAML optimization.
In the .cs file there is no interaction with the contextmenu, just adding and removing of the rows and some view-refresh (to update the grouping). The events are just for logging.
The ressource part
<Window.Resources>
<local:NegativeColorConverter x:Key="NegativeColorConverter"/>
<local:AllJobs x:Key="jobs"/>
<CollectionViewSource x:Name="cvsAllJobs" x:Key="cvsJobs" Source="{StaticResource jobs}" IsLiveGroupingRequested="True" IsLiveSortingRequested="True" CollectionViewType="ListCollectionView">
<CollectionViewSource.LiveGroupingProperties>
<s:String>omitted</s:String>
</CollectionViewSource.LiveGroupingProperties>
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="omitted"/>
</CollectionViewSource.GroupDescriptions>
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="GroupSort"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
And the grid
<DataGrid
VirtualizingPanel.IsVirtualizingWhenGrouping="True"
x:Name="gridJobs"
CanUserSortColumns="False"
IsReadOnly="True"
CanUserDeleteRows="False"
CanUserAddRows="False"
GridLinesVisibility="Horizontal"
DragEnter="gridJobs_DragEnter"
Drop="gridJobs_Drop"
AllowDrop="True"
AutoGenerateColumns="False"
Margin="10"
SelectedItem ="{Binding SelectedRow, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding Source={StaticResource cvsJobs}}"
HorizontalGridLinesBrush="Transparent"
PreviewKeyDown="gridJobs_PreviewKeyDown"
ContextMenuClosing="gridJobs_ContextMenuClosing"
ContextMenuOpening="gridJobs_ContextMenuOpening"
MouseRightButtonDown="gridJobs_MouseRightButtonDown"
>
<DataGrid.Resources>
<tools:BindingProxy x:Key="proxy" Data="{Binding}" />
<ContextMenu StaysOpen="True" x:Key="Jobs" ItemsSource="{Binding MenuItems}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="IsEnabled" Value="{Binding Enabled}" />
</Style>
</ContextMenu.ItemContainerStyle>
<ContextMenu.ItemTemplate>
<HierarchicalDataTemplate DataType="MenuItemViewModel" ItemsSource="{Binding MenuItems}">
<TextBlock Text="{Binding Header}"/>
</HierarchicalDataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</DataGrid.Resources>
Columns omitted
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontFamily" Value="Calibri"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<!--<Setter Property="Background" Value="Black"/>-->
<Setter Property="Background" Value="{Binding BrushState, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource NegativeColorConverter}}"/>
<Setter Property="Foreground" Value="{Binding BrushState, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" >
<Setter Property="ContextMenu" Value="{StaticResource Jobs}" />
<Setter Property="Foreground" Value="{Binding BrushState, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="Margin" Value="10,0,0,0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Height" Value="20"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<DockPanel Background="Gray" Height="1">
</DockPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
Add to the ContextMenu tag an attribute x:Shared="false", this will create an own ContextMenu for each row. So it should work I think.
<ContextMenu StaysOpen="True" x:Key="Jobs" ItemsSource="{Binding MenuItems}" x:Shared="false">

Tree View Item Selected and Mouse button down event not firing

I have created view models for the tree view. Also created their bindings. I created style trigger so that whenever a tree view item is selected, its background is changed. But the background does not change.I handled the item selected and left mouse down events of tree view item to see if the item is selected or not. But both the events do not fire. Below is the XAML.
<TreeView Grid.Row="0" x:Name="TreeViewLocalSystem" BorderBrush="Transparent" Panel.ZIndex="0">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource TextBoxBackgroundColor}"></Setter>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Background" Value="Transparent"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}" DataType="{x:Type local:LocalTreeViewItemModel}">
<TreeViewItem Header="{Binding Path=Text}" Selected="TreeViewItem_Selected" HorizontalAlignment="Left" FontSize="{StaticResource MediumFontSize}" MouseLeftButtonDown="TreeViewItem_MouseLeftButtonDown" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
What is it that I am doing wrong?
Edit: Another thing that I noticed is that MouseDown event is fired when I do right click but does not fire on left mouse button click.
You could handle the PreviewMouseLeftButtonDown event for the TreeViewItem:
<TreeView Grid.Row="0" x:Name="TreeViewLocalSystem" BorderBrush="Transparent" Panel.ZIndex="0">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="TreeViewLocalSystem_PreviewMouseLeftButtonDown" />
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource TextBoxBackgroundColor}"></Setter>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Background" Value="Transparent"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Children}" DataType="{x:Type local:LocalTreeViewItemModel}">
<TextBlock Text="{Binding Path=Text}" HorizontalAlignment="Left" FontSize="{StaticResource MediumFontSize}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
private void TreeViewLocalSystem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//...
}

Why binding MenuItems to a ContextMenu doesn't display anything?

I'm beginner in MVVM and I've been trying to display MenuItems in a ContextMenu, but something seems to be wrong. I've already made a working Menu which has Itemssource bound to a collection in the viewmodel, but it doesn't work in case of the ContextMenu.
Could you guys take a look and say if I'm missing something?
Here's the Menu, which works well:
<Menu DockPanel.Dock="right" ItemsSource="{Binding Path=modes}" Background="#FF303030" Foreground="White" Height="21">
<Menu.Resources>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Background" Value="#FF303030"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Height" Value="21" />
<Setter Property="Visibility" Value="{Binding visibility}" />
<Setter Property="Header" Value="{Binding header}" />
<Setter Property="ItemsSource" Value="{Binding children}"/>
<Setter Property="Command" Value="{Binding action}"/>
<Setter Property="CommandParameter" Value="{Binding attachedData}"/>
</Style>
</Menu.Resources>
</Menu>
And here's the XAML of the ContextMenu, which, for some reason, doesn't display any MenuItems:
<Grid x:Name="btnMode" PreviewMouseDown="OnBtnModeMouseDown" Width="19" Height="19" Margin="0,0" DockPanel.Dock="Right">
<Canvas>
<Path Data="M0,0 L19,0 L19,19 L0,19" Margin="0,0" Fill="#FF303030"/>
<Ellipse Height="12" Margin="4,3,0,0" Width="12" Fill="#FFFDFDFD"/>
<Path Data="M1.5,1L18.5,1 L10,9.5" Margin="0,0,0,8.875" Fill="#FF303030"/>
</Canvas>
<Grid.ContextMenu>
<ContextMenu ItemsSource="{Binding Path=modes}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Background" Value="#FF303030"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Height" Value="21" />
<Setter Property="Visibility" Value="{Binding visibility}" />
<Setter Property="Header" Value="{Binding header}" />
<Setter Property="ItemsSource" Value="{Binding children}"/>
<Setter Property="Command" Value="{Binding action}"/>
<Setter Property="CommandParameter" Value="{Binding attachedData}"/>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Grid.ContextMenu>
</Grid>
I also have a ContextMenu that has hard-coded menu items:
<Grid x:Name="btnMenu" PreviewMouseDown="OnBtnMenuMouseDown" Width="19" Height="19" Margin="0,1" DockPanel.Dock="Right">
<Canvas>
<Path Data="M0,0 L19,0 L19,19 L0,19" Margin="0,0" Fill="#FF303030"/>
<Path Data="M0,0L7,0 L3.5,7" Margin="6,7" Fill="White"/>
</Canvas>
<Grid.ContextMenu >
<ContextMenu IsVisibleChanged="OnBtnMenuPopup">
<MenuItem Name="menuFloatingWindow" Header="Floating window" Click="OnDockingMenu"></MenuItem>
<MenuItem Name="menuDockedWindow" Header="Docked window" Click="OnDockingMenu"></MenuItem>
<MenuItem Name="menuTabbedDocument" Header="Tabbed document" Click="OnDockingMenu"></MenuItem>
<MenuItem Name="menuAutoHide" Header="Auto hide" Click="OnDockingMenu"></MenuItem>
<MenuItem Name="menuClose" Header="Close" Click="OnDockingMenu"></MenuItem>
</ContextMenu>
</Grid.ContextMenu>
</Grid>
The collection of MenuItems is an ObservableCollection, defined as follows:
_menus = new ObservableCollection<MenuItem>()
{
new MenuItem(
"File", // string header
Visibility.Visible, // Visibility visibility
null, // ICommand action
null, // object attachedData (CommandParameters)
new ObservableCollection<MenuItem>() // children
{
new MenuItem(
"Exit",
Visibility.Visible,
MainWindow.exitCommand,
null,
null
)
}
),
..., // more nested MenuItems here
};
Both the working Menu and the ContextMenu have the same ObservableCollection as an ItemSource.
Here's an image showing how the controls look in the application:
Did I mess something up in XAML?
P.S.
I tried debugging the XAML at runtime using this: http://www.wpftutorial.net/DebugDataBinding.html but I couldn't see any helpful information when the breakpoint occured.

Change the colour of the particular element in Treeview WPF

I have a Treeview in my WPF application. On the fly, in run time, If the element of the Tree meets certain condition, It should change its Font color from Black To Red.!
XAML
<TreeView Grid.Column="0" Grid.Row="0" HorizontalAlignment="Stretch" Name="treeView1"
VerticalAlignment="Stretch"
SelectedItemChanged="treeView1_SelectedItemChanged" HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Top" BorderThickness="0,0,0,1" BorderBrush="LightGray">
<TreeViewItem Header="Head Tree" ItemsSource="{Binding MainComps}">
<TreeViewItem.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="Foreground" Value="RED" />
</DataTrigger>
</Style.Triggers>
</Style>
</TreeViewItem.ItemContainerStyle>
<TreeViewItem.Resources>
<HierarchicalDataTemplate DataType="{x:Type TextBlock}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Head Tree" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MainCompViewModel}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Maincompname}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:FeatureViewModel}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FeatureName}" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:CompViewModel}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Component}" />
</StackPanel>
</DataTemplate>
</TreeViewItem.Resources>
</TreeViewItem>
</TreeView>
Code behind
private void treeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if(selected Item meets certain condition)
{
//Change color of tree node
}
}
How can I change the color of particular Node and leave it in the same color SO that when expanded again It should be in RED.
Any help would be appreciated.
You could create a boolean property in the model which is true when the elements meets the condition. Then you bind the Foreground like so:
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=BoolProp}" Value="False">
<Setter Property="Foreground" Value="Blue"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=BoolProp}" Value="True">
<Setter Property="Foreground" Value="Red"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
or with converter:
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Foreground" Value="{Binding Path=BoolProp, Converter={StaticResource ResourceKey=TheKey}}"/>
</Style>
</TreeView.ItemContainerStyle>
Just change the Foreground:
TreeViewItem ti = (TreeViewItem)treeView1.SelectedItem;
ti.Foreground = Brushes.Red;
That is embedded into the template. You can only change the color by copying the default Aero-Style for the control and changing the hard-coded value.
Or by drilling down the visual tree on-load to change it that way.
To get the default style & tenmplate go through this MSDN
Can also check step wise EXAMPLE from here.

UserControl databinding with a treeview

I have a UserControl which contains a TreeView and a TextBlock:
<TreeView ItemsSource="{Binding FirstGeneration}" AllowDrop="True" Drop="TreeView_Drop" Width="300">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Normal" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal" >
<Image Source="{Binding Path=Image}" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<TextBlock Height="23" Name="textBlock1" Text="{Binding= ???}" Width="187" />
When I select an item of the treeview, I want do show some informations contained in the item (eg : the name of the selected item).
My problem is that I don't know how doing this binding, because when I select an item, the setter IsSelected of the item class is called.
Have you a best practice for doing that ?
Have a look at this in MSDN. And also the BindableSelectedItemBehaviour here.

Categories