My WPF uses the MVVM approach. I'm trying to bind 2 controls within my list control
<ListBox ItemsSource="{Binding ParentDuplicate}" SelectedItem="{Binding SelectedParent, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<ContentControl Content="{Binding}" />
<Button Content="Delete me now"
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType=Window}, Path=DeleteCommand}"
CommandParameter="{Binding FilePath}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The problem I'm having, is the DeleteCommand is not binding (the Ouput window informs me as well)
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Data.Binding', AncestorLevel='1''. BindingExpression:Path=DeleteCommand; DataItem=null; target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')
If I move this button to outside the ListBox, then the binding works and the event fires so I know the issue must be with the ListBox (I'm guessing the problem is the ItemsSource prevents the binding to anything but the ItemsSource bound property (in this case, ParentDuplicate))
So, within the Button control, there are 2 properties being bound, DeleteCommand and FilePath
Both of these properties live within my single ViewModel. FilePath is a child of ParentDuplicate and this binds as desired. The issue is only with the DeleteCommand. What am I doing wrong?
Edit
When I use the Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType=Window}, Path=DeleteCommand} it is looking in my MainWindow code behind, not at the ViewModel. How do I make it use the ViewModel?
I tried
Command="{Binding RelativeSource={RelativeSource AncestorType=xmlnsViewModel:MainWindowViewModel}, Path=DeleteCommand}"
but the above also results in the same binding errors
The ancestor search finds the control, not the DataContext, so you'll need to tell your binding where to find the DeleteCommand property. If your ViewModel is the DataContext of the MainWindow then you can just use:
<Button Content="Delete me now"
Command="{Binding RelativeSource={RelativeSource
Mode=FindAncestor, AncestorLevel=1, AncestorType=Window},
Path=DataContext.DeleteCommand}"
CommandParameter="{Binding FilePath}" />
Related
I have an ItemsControl whose for the ItemTemplate DataTemplate contains a Button. I want the Command on the button to bind to a Command on the DataContext of the ItemsControl, not the ItemTemplate. I think the solution has to do with using RelativeSource, but my attempts so far have failed:
<ItemsControl ItemsSource="{Binding Games}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding Path=GameSelectedCommand, Source={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"
CommandParameter="{Binding}"
Style="{StaticResource MenuButtonStyle}"
Content="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
How can I get the Button to bind to the GameSelectedCommand of the ItemsControl's DataContext object?
You're setting the source of the binding to the ItemsControl itself. Therefore, you'll need to dereference the DataContext of the ItemsControl:
Command="{Binding DataContext.GameSelectedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"
How would you have known this? Take a look at your debug output window when running the app. You'll see a message along the lines of "Cannot resolve property 'GameSelectedCommand' on type 'ItemsControl'".
I have a DataGrid which contains Transactions. I have an InterestOrDividend column where I can select a value using a ComboBox. This works fine.
A new feature would be to enter a value and add it to the list of possibilities. I set IsEditable to true and added Interaction.Triggers from http://schemas.microsoft.com/expression/2010/interactivity
Problem 1:
It seems InterestOrDividendSelectionChangedCommand not only fires when the selection is changed but also when I scroll the DataGrid and such rows come into view which has a not null value in the InterestOrDividend column. Moreover, when a new value is entered (which is not in the list), the event does not fire.
Problem 2:
I want to bind the Text property of the ComboBox to get the newly added value. It seems the event fire before the Text property changes, so I get the old value.
<DataGridTemplateColumn Header="{x:Static r:Resource.InterestOrDividend}"
CellTemplate="{StaticResource InterestOrDividendEditingTemplate}"
CellEditingTemplate="{StaticResource InterestOrDividendEditingTemplate}" />
<DataTemplate x:Key="InterestOrDividendEditingTemplate">
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}, Path=DataContext.AppData.AlienTypeObjects}"
SelectedItem="{Binding InterestOrDividend}"
DisplayMemberPath="FullName"
IsEditable="True"
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}},
Path=DataContext.InterestOrDividendSelectionChangedCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ComboBox}}, Path=Text}"
/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</DataTemplate>
This is my solution. Instead of using the EventTrigger I catch the new element in the setter of NewInterestOrDividend. It is important that the UpdateSourceTrigger is LostFocus. When InterestOrDividend is null and you change the focus then value in NewInterestOrDividend contains the new value.
<DataTemplate x:Key="InterestOrDividendEditingTemplate">
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}, Path=DataContext.AppData.AlienTypeObjects}"
DisplayMemberPath="FullName" Style="{StaticResource ComboBoxError}"
IsEditable="True"
SelectedItem="{Binding InterestOrDividend, UpdateSourceTrigger=LostFocus}"
Text="{Binding NewInterestOrDividend, UpdateSourceTrigger=LostFocus}">
</ComboBox>
</DataTemplate>
I build some WPF application that as MainView, inside this MainView I have a button that opens a setting window and a Model that I want to be able to show or hide from this settings view. (the show/hide button was originally on the MainView itself) the problem is that I do not know how to use the CommandParameter in the SettingsView to bind to an element In the MainViw.
the element in the MainView:
<Dev:DevUnitView x:Name="DevData" DataContext="{Binding MainModel.DevUnit}" Visibility="Visible" Margin="994,656,74,-83"/>
the button in the SettingsView:
<Button Content="Show/Hide debug values" Command="{Binding Settings.DevVisibilityCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Dev:DevUnitView}}, Path=DataContext}" Margin="156,22,180,349"/>
I also tried to Bind to the MainView but I do not know how to find the element I need from there:
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type mainWindow:MainView}}, Path=DevUnit}"
in this case, it cannot resolve the "DevUnit" in the data context, I also tried by name and other variation of this without success.
the old button that worked in the MainView:
<Button Content="DEV" Command="{Binding Settings.DevVisibilityCommand}" CommandParameter="{Binding ElementName=DevData}" Margin="406,359,810,259"/>
now no matter how I try to bind it I getting Null UserControl.
So I am trying to pass the SelectedItem as a parameter so that I can make use of the data that is bound to it.
Essentially I want to open a MessageBox and display the Name property of the User that is bound that item.
This is my xaml
<ItemsControl ItemsSource="{Binding CardViewModel.Users}"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.UseDefaultEffectDataTemplate="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:UserCard>
<controls:UserCard.ContextMenu>
<!-- Bind the DataContext of the CM to the DataContext that's bound to the RootObject-->
<ContextMenu DataContext="{Binding DataContext, Source={local:RootObject}}">
<MenuItem Header="Edit"
Command="{Binding CardViewModel.EditUser}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}},
Path=PlacementTarget.SelectedItem}"/>
</ContextMenu>
</controls:UserCard.ContextMenu>
</controls:UserCard>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The command works fine everything is bound just fine besides that when I click the MenuItem and it fires the command, I put a breakpoint where the action is and it shows the parameter as null I am suspecting that it's me who is binding it wrong.
public void DisplayEditUser(object user)
{
if (user != null)
{
MessageBox.Show("Not null");
}
}
The problem is that ContextMenu.PlacementTarget wasn't the ItemsControl but the UserCard, so binding source resolving will absolutely fail. To solve it, you need to bind ItemsControl.SelectedItem to one property of UserCard such as Tag as a relay.
<controls:UserCard Tag="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType=ListBox}}">
CommandParameter="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
I have a List of UserControl elements in a WP8 application page.
I'm trying to enable the UserControl itself to have different visual effect when it is in a selected state in the list.
I have created a DependencyProperty (IsHighlighted) in the UserControl, and I am now stuck trying to pass the ListBoxItem's IsSelected property into the UserControl.
<ListBox ItemsSource="{Binding MyItems}" SelectedItem="{Binding MySelectedItem, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate >
<userControls:MyControl IsHighlighted="{Binding Path=IsSelected ???}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
It could have been easy if the following was enabled in WP8:
{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}}, Path=IsSelected}
But it's not enabled..
Tried many variations, and I am out of ideas. Anyone?
EDIT:
The following error appears on the console:
System.Windows.Data Error: BindingExpression path error: 'IsSelected' property not found on 'System.Windows.Controls.ContentPresenter' 'System.Windows.Controls.ContentPresenter' (HashCode=6915811). BindingExpression: Path='IsSelected' DataItem='System.Windows.Controls.ContentPresenter' (HashCode=6915811); target element is 'WP8.UserControls.MyViewControl' (Name='userControlObj'); target property is 'IsHighlighted' (type 'System.Boolean')
Super old thread, but in case someone else comes looking like I did.....
I had joy with:
"{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}