I have a listbox, where a grid with textboxes shows the listboxs currently selecteditems data. (Code below)
The problem is that i want a delete button inside this grid, however the command it uses lies in the Usercontrols DataContext. How do I make the button recieve the command binding inside the UserControls Datacontext?
Following code lies inside a grid where the visual trees root is a UserControl.
<ListBox Name="list" ItemTemplate="{StaticResource listTemplate}" ItemsSource="{Binding listCollection, UpdateSourceTrigger=PropertyChanged}">
</ListBox>
<Grid DataContext="{Binding ElementName=list, Path=SelectedItem}" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Margin="7">Name:</TextBlock>
<TextBox Margin="5" Grid.Column="1" Text="{Binding Path=Name}"></TextBox>
<Button Grid.Row="1" Command="{Binding DeleteSelectedItemCommand}">Delete Selected Item</Button>
</Grid>
You need to change DataContext, provide same Name for UserControl and then
Command="{Binding ElementName=Name, Path=DeleteSelectedItemCommand}"
You mean you want to fire the button's command on your UserControls DataContext IE your vm?
Then you need this binding;
<Button Grid.Row="1" Command="{Binding Path=DeleteSelectedItemCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type YourControl}}}">Delete Selected Item</Button>
Basicly this just traverse up your xaml tree and fetch datacontext from the control called YourControl. You could set UserControl here. The cool thing about this kind of binding is that you may track back the datacontext of any items up the chain :)
This document is still very handy for bindings that are a bit tricky :)
Cheers,
Stian
The trick was to wire up the DataContext using Stians reference.
<Button
DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType {x:Type UserControl}}, Path=DataContext}"
Command="{Binding Path=DeleteSelectedItemCommand}">
</Button>
Related
I'm using hardcodet's WPF NotifyIcon in my app, which is being implemented using MVVM Light. I'm trying to create a custom TrayPopup for the icon. In this popup I have an ItemsControl, whose ItemsSource is a list of objects "NumberList" in my ViewModel. For my DataTemplate I'm using a grid which display an property called "Id" of my source object, and a button. The button I'm trying to tie back to a RelayCommand in my ViewModel. I've done similar things with ItemsControls in the past by Binding using a RelativeSource to get the DataContext of the Window Ancestor. I tried a similar approach this time, but when I run the app, open the TrayPopup, and click the button nothing happens. My command is not fired in my ViewModel.
As a test I tried adding another button to my TrayPopup and binding its command to the same one in my ViewModel. That binding works fine, so it's not the command as far as I can tell.
Like I said, I've used this technique almost exactly in the past, just never before in a NotifyIcon. I've tried specifying the ElementName in the button Binding to the name of my Window, which didn't work. I've also tried changing the RelativeSource to the parent TaskbarIcon, also without success.
Here is an example implementation of what the NotifyIcon with the same problem:
<tb:TaskbarIcon PopupActivation="LeftOrRightClick">
<tb:TaskbarIcon.TrayPopup>
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="200"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0">
<ItemsControl ItemsSource="{Binding NumberList, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{Binding Id, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button Grid.Column="1" Content="Test" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.TestCommand}"/> <!--This binding doesn't work!-->
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
<Button Grid.Row="1" Content="Test2" Command="{Binding TestCommand}"/> <!--This works-->
</Grid>
</tb:TaskbarIcon.TrayPopup>
</tb:TaskbarIcon>
I'm fairly confident everything in the ViewModel is correct as I have been using a previous version of this app that I wrote a while ago. So far I haven't run in to any problems other than this NotifyIcon. Any ideas?
After banging away at it for a while I found an answer to my problem. The StackPanel in my ItemsPanelTemplate had the DataContext which contained the command I wanted to bind my button to, my main ViewModel. By specifying a name for the StackPanel, I was able to set the ElementName of my button to its name, and then the binding worked. Not sure why this method worked with the StackPanel and not the main Window though.
Anyway, here's the updated code if anyone runs in to this same problem:
<tb:TaskbarIcon PopupActivation="LeftOrRightClick">
<tb:TaskbarIcon.TrayPopup>
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="200"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0">
<ItemsControl ItemsSource="{Binding NumberList, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{Binding Id, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button Grid.Column="1" Content="Test" Command="{Binding ElementName=trayMainStack, Path=DataContext.TestCommand}"/> <!--Updated binding works!-->
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Name="trayMainStack"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
<Button Grid.Row="1" Content="Test2" Command="{Binding TestCommand}"/> <!--This works-->
</Grid>
</tb:TaskbarIcon.TrayPopup>
</tb:TaskbarIcon>
I have a NavigateToAccountsCommand RelayCommand property in the ViewModel. When I bind the same to a button on the page anywhere outside the ListView the command binding is working. However as soon as I move this to a ListView's DataTemplate its not working.
I have tried changing the binding from NavigateToAccountsCommand to DataContext.NavigateToAccountsCommand still not working.
Appreciate your help...
<Page
x:Class="FinancePRO.App.Views.AccountsView"
DataContext="{Binding AccountsViewModel, Source={StaticResource MainViewModelLocator}}"
mc:Ignorable="d">
<Grid>
<!--**This one is working**-->
<Button Command="{Binding NavigateToAccountsCommand}" >
<!--**This one is not working**-->
<ListView ItemsSource="{Binding AllAccounts}" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Stretch">
<TextBlock Text="{Binding AccountName}"/>
<Button Command="{Binding NavigateToAccountsCommand}">
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
When you are inside the DataTemplate of the ListView, your data context is the current item of the ListView's ItemsSource. As there is nothing called "NavigateToAccountsCommand" property within your AllAcounts' each individual element, binding isn't working.
To fix that, you will need to reference something from the outside of DataTemplate; following should work. It changes the binding to reference the root Grid's DataContext which should have the property NavigateToAccountsCommand accessible. To reference the grid, you have to add Name attribute, and then use ElementName binding.
<Grid Name="Root">
<!--**This one is working**-->
<Button Command="{Binding NavigateToAccountsCommand}" >
<!--**This one is not working**-->
<ListView ItemsSource="{Binding AllAccounts}" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Stretch">
<TextBlock Text="{Binding AccountName}"/>
<Button Command"{Binding ElementName=Root, Path=DataContext.NavigateToAccountsCommand}">
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
You can use
<Button x:Name="cmdTabItemCloseButton"
Style="{StaticResource TabItemCloseButtonStyle}"
Grid.Column="1" Margin="15,0,0,0"
Command="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type ListView}},
Path=DataContext.NavigateToAccountsCommand}"
CommandParameter="{Binding}"/>
I had a similar problem (Win RT) which I solved by just using:
<GridView
x:Name="itemGridView"
ItemClick="ItemView_ItemClick"
IsItemClickEnabled="True"/>
and then in the Page class:
private void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
//e is the object being clicked
}
I have a Page and a viewmodel is set as its datacontext. in that page I have a list. which is populating through a property in the viewmodel. List has a user control. and that user control has a button. I want that button to be bind with a command that is in viewmodel. Is there anyway to do that?
<Page DataContext=PageViewModel>
...
<ScrollViewer Grid.Row="3" Margin="20,0" Visibility="{Binding ByVenueSelected, Converter={StaticResource BooleanToVisibilityConverter}}">
<StackPanel>
<ItemsControl ItemsSource="{Binding EventsListByVenue}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<myControls:EventDetails /> <!--in this control i want to bind a command available in PageViewModel-->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
...
</Page>
with help of #FunksMaName, I solved this. I am sure there are more elegant and better approach, but yet this is a quick & easy solution for me:
<Button Style="{StaticResource NoHighlightButtonStyle}" Tag="{Binding link}" CommandParameter="{Binding Path=Tag,RelativeSource={RelativeSource Mode=Self}}" Visibility="{Binding link,Converter={StaticResource DataAvailabilityToVisibilityConverter}}" Command="{Binding Path=Event.LinkCommand,Source={StaticResource Locator}}" >
<TextBlock Margin="0,5" Foreground="SkyBlue" Text="{Binding link}" TextWrapping="Wrap" FontSize="16"/>
</Button>
things to note:
i think xaml searched the command parameter in context of command only, so it was giving me null parameter, while the same binding was working fine for textblock inside Button. So i tricked it to store the value in tag, and used it from there.
Tag="{Binding link}" CommandParameter="{Binding Path=Tag,RelativeSource={RelativeSource Mode=Self}}"
I have a TreeView of items, and a corresponding TreeViewModel. I want to support a property on the TreeViewModel which keeps a track of the currently selected item in the TreeView.
This is the code I have:
<UserControl.DataContext>
<vm:TreeMenuViewModel />
</UserControl.DataContext>
<UserControl.Resources>
<common:HierarchicalDataTemplate x:Key="MenuItemsTemplate"
ItemsSource="{Binding ChildItems}">
<TextBlock Text="{Binding MenuOption}"/>
</common:HierarchicalDataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<toolkit:DockPanel>
<sdk:TreeView
Name="treeView1"
VerticalAlignment="Stretch"
toolkit:DockPanel.Dock="Left"
Background="Transparent"
ItemsSource="{Binding ChildItems}"
ItemTemplate="{StaticResource MenuItemsTemplate}"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<ei:ChangePropertyAction
TargetObject="{Binding}"
PropertyName="SelectedItemId"
Value="{Binding MenuOptionId}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</sdk:TreeView>
</toolkit:DockPanel>
</Grid>
The TreeView binds and displays the data correctly. The trigger is also working and targeting the correct property - when I break on the SelectedItemId property in the TreeViewModel, the property is being hit, but the value supplied is always 0. How can I supply the value of the selected item?
Just remove the whole trigger and add:
ItemsSource="{Binding ChildItems}"
SelectedItem="{Binding SelectedChild}"
And then your ViewModel needs a SelectedChild property. Your VM can react to changes from the setter of that property.
If you want 2-way binding then make it a NotifyChange property.
And I think you want the id: SelectedChild.Id or something like that.
Try using the TreeView SelectedValue and SelectedValuePath properties:-
<Grid x:Name="LayoutRoot" Background="White">
<toolkit:DockPanel>
<sdk:TreeView
Name="treeView1"
VerticalAlignment="Stretch"
toolkit:DockPanel.Dock="Left"
Background="Transparent"
ItemsSource="{Binding ChildItems}"
ItemTemplate="{StaticResource MenuItemsTemplate}"
SelectedValue="{Binding SelectedItemId, Mode=TwoWay}"
SelectedValuePath="MenuOptionId"
/>
</toolkit:DockPanel>
</Grid>
why not use something like this.
(SingleObjectInYourList)Item = treeview.SelectedItem;
I am trying to create a menu bar for my application. I have created a collection in xaml that I will contain menu items that my menu will bind to.
In xaml I have created an array that I use as my static resource for binding.
<coll:ArrayList x:Key="MenuOptionsList">
<model:DashboardMenuBarItem
Icon="the location of an image in my images folder"
DisplayName="The test that will appear under my button"
CommandName="someCommandInMyViewModel"/>
</coll:ArrayList>
I am using a listbox with a data template to show these items as follows.
<ListBox x:Name="lstNavigateTo" MinWidth="400" DockPanel.Dock="Top"
ItemsSource="{Binding Source={StaticResource MenuOptionsList}}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Style="{StaticResource horizontalListTemplate}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="5">
<Button Height="60" Width="60"
Command="{Binding Mode=OneWay, Path=CommandName}">
<Button.Content>
<Image Source="{Binding Path=Icon}" Grid.Row="0" />
</Button.Content>
</Button>
<TextBlock Text="{Binding Path=DisplayName}"
Width="100" TextAlignment="Center" Grid.Row="1" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My problem is that I am using the MVVM design pattern and cannot get the command bindings to work on the button click. Previously I would have managed the button click like this.
Command="{Binding someCommandInMyViewModel}"
That would work fine but when I try to bind a command to a property of an item in my collection the command will not fire.
Does anyone know how I can achieve this.
The CommandName property in your collection is of type String, whereas the Command property on Button is of type ICommand. In what way are you expecting WPF to resolve an ICommand from a String? You'll need to help it: either create a converter and use it in your binding, or change your CommandName property so that it contains an actual ICommand rather than a String.