What's wrong with this binding? - wpf

I'm trying to assign DataContext to a MenuItem, which is part of ListBox.
<Style x:Key="ContextMenuStyle" TargetType="telerik:RadMenuItem">
<Setter Property="DataContext" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=telerik:RadListBox}, Path=DataContext}" />
</Style>
<DataTemplate x:Key="TemplateSelector">
<ContentPresenter Content="{Binding}" Name="contentPresenter">
<telerik:RadContextMenu.ContextMenu>
<telerik:RadContextMenu>
<telerik:RadMenuItem Header="Connect" Click="RadMenuItem_Click" Style="{StaticResource ResourceKey=ContextMenuStyle}" />
<telerik:RadMenuItem Header="Disconnect" />
<telerik:RadMenuItem Header="Delete Database" />
</telerik:RadContextMenu>
</telerik:RadContextMenu.ContextMenu>
</ContentPresenter>
</DataTemplate>
<Grid>
<telerik:RadListBox x:Name="lsbDevices" ItemsSource="{Binding Path=Devices}" ItemTemplate="{StaticResource TemplateSelector}"
SelectedItem="{Binding SelectedDevice, Mode=TwoWay}" Grid.Row="0" />
</Grid>
Here's what I do. RadListBox's DataContext is set to my ViewModel. I want to assign this ViewModel to every RadMenuItem's DataContext through ContextMenuStyle, but it's not working. RadListBox's DataContext is properly set to my modelview, but RadMenuItem's datacontext is null. What am I missing?
Thanks

ContextMenus are not part of the same VisualTree as the rest of the UI, so your RelativeSource binding is not finding the ListBox
You can find the UI object the ContextMenu is attached to by using the PlacementTarget property of the ContextMenu
<Style x:Key="ContextMenuStyle" TargetType="telerik:RadMenuItem">
<Setter Property="DataContext" Value="{Binding PlacementTarget.DataContext,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type telerik:RadContextMenu}}}" />
</Style>

Related

WPF - update a dependency property from a DataTrigger

I have a listView and want when an item is selected to update a public value from the DataContext.
I know I can do this through the SelectedItem from listview, I want to do this (if possible) with a data trigger.
Code:
<Window.DataContext>
<local:MainWindowViewModel></local:MainWindowViewModel>
</Window.DataContext>
<Grid>
<ListView ItemsSource="{Binding listsToDisplay}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding listName}"></TextBlock>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" Value="True">
<Setter Property="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindowViewModel}}, Path=listWidth}" Value="1"></Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
I want to do this (if possible) with a data trigger.
This is not possible. You cannot set a value of a view model property in a setter of a style.
A style setter can only set the value of a property that belongs to the element to which the style is applied.
You could bind the selected item of the listView to a property on the viewmodel then do the update in the viewmodel when that value changes through the property.
<ListView ItemsSource="{Binding listsToDisplay}" SelectedItem="{Binding SelectedItem}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding listName}"></TextBlock>
</ListView.ItemTemplate>
</ListView>
This also has the advantage of allowing you to get or set the selected item in the viewModel.

MVVM WPF How to set style on TreeViewItem based on DataType of DataContext from xaml

Even if some treeviewitems cannot be expanded?
so I have a treeview with these resources, but the viewmodel for one item type is hierarchical, while the other item cannot be expanded. I feel as if I should not be creating an IsExpanded property in the viewmodel of the unexpandable item, but I don't know how I would set a style for an item type based on the datatype of the content. If it's not possible to do from xaml, it is probably possible in code behind, but in that case I am probably just better off just adding an IsExpanded Property to the unexpandable item and leaving it as false
<DaedalusGraphViewer:MultiSelectTreeView.Resources>
<Style TargetType="{x:Type DaedalusGraphViewer:MultiSelectTreeViewItem}" BasedOn="{StaticResource NameTreeViewBusItemStyle}" />
<HierarchicalDataTemplate
ItemsSource ="{Binding Path = bits}"
DataType="{x:Type ViewModels:BusViewModel}"
>
<Grid>
<Components:CenteredTextBlock
BorderThickness="{Binding RelativeSource ={RelativeSource AncestorType={x:Type DaedalusGraphViewer:MultiSelectTreeView}}, Path=BorderThickness}"
BorderBrush="{Binding RelativeSource ={RelativeSource AncestorType={x:Type DaedalusGraphViewer:MultiSelectTreeView}}, Path=BorderBrush}"
HorizontalAlignment="Stretch"
Height="{Binding ElementName=graph_viewer, Path=GraphHeight, Mode=OneWay}"
MainText="{Binding Path = Alias}"
/>
</Grid>
</HierarchicalDataTemplate>
<DataTemplate
DataType="{x:Type ViewModels:BitViewModel}"
>
<Grid>
<Components:CenteredTextBlock
BorderThickness="{Binding RelativeSource ={RelativeSource AncestorType={x:Type DaedalusGraphViewer:MultiSelectTreeView}}, Path=BorderThickness}"
BorderBrush="{Binding RelativeSource ={RelativeSource AncestorType={x:Type DaedalusGraphViewer:MultiSelectTreeView}}, Path=BorderBrush}"
HorizontalAlignment="Stretch"
Height="{Binding ElementName=graph_viewer, Path=GraphHeight, Mode=OneWay}"
MainText="{Binding Path = Alias}"
/>
</Grid>
</DataTemplate>
</DaedalusGraphViewer:MultiSelectTreeView.Resources>

Getting parent ListBox selected index as CommandParamater from context menu item

I am trying to pass a listbox's Selected Index property as a command paramater to a context menu item, I have the command binding working (thanks to Will # ElementName Binding from MenuItem in ContextMenu) but I'm have trouble with my command paramater.
<UserControl>
<ListBox ItemsSource="{Binding myItems}">
<ListBox.Resources> <!-- The selected item is the item the mouse is over -->
<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver,RelativeSource={RelativeSource Self}}"
Value="True">
<Setter Property="IsSelected" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Button Content="Edit" Grid.Column="4" Grid.Row="0" Tag="{Binding DataContext, ElementName=ProductBacklog}">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove"
Command="{Binding PlacementTarget.Tag.RemoveStoryClickCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding <!--I NEED TO BIND TO THE LISTBOX-->, Path=SelectedIndex}"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl>
You can set the CommandParameter="{Binding }" to pass the current data item in that row to your Command
Edit
Just noticed your command is in a ContextMenu. ContextMenus are not part of WPF's default Visual Tree, so bindings do not work the same way. To bind to the current item, use the following:
<MenuItem Header="Remove"
Command="{Binding PlacementTarget.Tag.RemoveStoryClickCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding PlacementTarget.DataContext,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ContextMenu}}}" />
This will bind to the DataContext of whatever control the ContextMenu is placed on, so in this case it will be Button.DataContext

wpf - ListBox - bind SelectedItem to an xml attribute?

I have a listbox on a usercontrol which is populated by a xml file.
<Machines xmlns="">
<Machine Name="Prod1" IP="192.168.1.200" isDefault="true" InstanceName="sql08" />
<Machine Name="Prod2" IP="192.168.1.101" />
<Machine Name="Test1" IP="192.168.1.103" />
<Machine Name="Test2" IP="192.168.1.104" />
</Machines>
I would like to bind the Listbox's Selected Item to the Machine which has a isDefault=true attribute.
My current xmldataprovider and ItemTemplate are listed below along with my ListBox markup. I was not sure if I needed to do some xpath binding in the datatemplate, or if I should make an explicit style with a trigger for this task? Or if either of those approaches would even work? One of the things I can't understand is how I can bind to an attribute that only exists on one node of my file.
<XmlDataProvider x:Key="DataList" Source="XML\ListboxSettings.xml" XPath="Machines/Machine"/>
<DataTemplate x:Key="MachineDataTemplate">
<TextBlock Text="{Binding XPath=#Name}" ToolTip="{Binding XPath=#IP}" />
</DataTemplate>
<ListBox Name="MerlinsListbox" Margin="5" Height="{Binding Height, ElementName=border}" Background="#FF252525" FontFamily="Consolas" FontSize="16" Foreground="#FFFBF9F9"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource MerlinDataTemplate}"
IsSynchronizedWithCurrentItem="true"/>
Two possible ways you could handle this are as follows:
1) You could set the ItemContainerStyle and bind the ListBoxItem's IsSelected property to the #isDefault attribute.
<ListBox Name="MerlinsListbox" Margin="5"
Background="#FF252525" FontFamily="Consolas" FontSize="16" Foreground="#FFFBF9F9"
ItemsSource="{Binding Source={StaticResource DataList}}"
ItemTemplate="{StaticResource MachineDataTemplate}"
IsSynchronizedWithCurrentItem="true">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding XPath=#isDefault, Mode=OneTime}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Or 2) add a trigger for the ItemContainerStyle:
<ListBox ...>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding XPath=#isDefault}" Value="true">
<Setter Property="IsSelected" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>

WPF: How to access Element in ListView.ItemTemplate?

I need to access element named "PageHost" for the selected list item in the following XAML code from C# codebehind, how to do so please ?
<ListView.Resources>
<p:PageWidthConverter x:Key="PageWidthConverter" />
</ListView.Resources>
<ListView.ItemTemplate>
<DataTemplate x:Name="PagesViewDataTemplate">
<DataTemplate.Resources>
<Style x:Key="PageHostStyle" TargetType="{x:Type p:PageHost}">
<Setter Property="Width" Value="{Binding Path=ActualWidth,
Converter={StaticResource PageWidthConverter},
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type Grid}}}"
/>
</Style>
</DataTemplate.Resources>
<p:PageHost x:Name="PageHost">
</p:PageHost>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" VerticalAlignment="Top">
<WrapPanel.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="1"></ScaleTransform>
</WrapPanel.LayoutTransform>
</WrapPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListItem>
</ListItem>
</ListView>
I guess the below idea will work, though I am not verified the code. You need to find out the ContentPresenter Associated with the SelectedItem first, then using the DataTemplate we can find out the pageHost
ContentPresenter lstContent = lstViewInstance.ItemContainerGenerator.ContainerFromIndex(lstViewInstance.SelectedIndex) as ContentPresenter;
DataTemplate pageViewDataTemplate= this.FindResource("PagesViewDataTemplate") as DataTemplate;
PageHost pageHost = pageViewDataTemplate.FindName("PageHost", lstContent) as PageHost;

Resources