Reputation: 11712
I have data template defined in a separate file (Styles.xaml). Page has an instance of ViewModel (I'm using MVVM pattern). My view model contains command which I'm trying to bind to from withing the data template.
How can I access it?
ElementName
and RelativeSource
are not resolved by my binding.
Page Xaml:
xmlns:partial="clr-namespace:PhoneApp7.Partial"
...
<phone:PhoneApplicationPage.DataContext>
<viewModel:DynamicViewModel />
</phone:PhoneApplicationPage.DataContext>
...
<ItemsControl x:Name="ItemsControl" ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<partial:DoItItemTemplate />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
View Model:
public class DynamicViewModel
{
public ObservableCollection<string> Items
{
get
{
return new ObservableCollection<string>
{
"item 1",
"item 2",
"item 2",
};
}
}
public RelayCommand<string> DoIt { get; set; }
public DynamicViewModel()
{
DoIt = new RelayCommand<string>(OnDoIt);
}
private void OnDoIt(string args)
{
MessageBox.Show(string.Format("Yay! {0}", args));
}
}
Item User Control Xaml
<UserControl x:Class="PhoneApp7.Partial.DoItItemTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button Content="{Binding}" Command="{Binding DataContext.DoIt, ElementName=ItemsControl}" CommandParameter="{Binding}"></Button>
</UserControl>
You can find complete sample by the following link: https://dl.dropboxusercontent.com/u/83972129/binding_issue.zip
Upvotes: 0
Views: 960
Reputation: 463
you can use class helper if u need; it will be useful specially if you need to this command in many controls or datatemplates.
Upvotes: 0
Reputation: 6570
The cleanest solution to this problem (IMHO) is to give the UserControl a Command dependency property, and have the Command property of the Button bind to that.
From the MainPage, you can then bind the new Command property of the UserControl to the desired command, by binding to DataContext.DoIt, with ElementName=ItemsControl.
This will also offer some extra flexibility to bind to other commands should the situation demand it, and not hardcode the command to bind to in the template itself.
The user control:
public partial class DoItItemTemplate : UserControl
{
// ...
private static void CommandChangedCallback(...)
{
DoItItemTemplate owner = (DoItItemTemplate)d;
owner.CommandChanged((ICommand)e.OldValue, (ICommand)e.NewValue);
}
private void CommandChanged(ICommand oldValue, ICommand newValue)
{
}
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(...)
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
// ...
}
<UserControl x:Class="PhoneApp7.Partial.DoItItemTemplate"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="root">
<Button Content="{Binding}"
Command="{Binding Path=Command, ElementName=root}"
CommandParameter="{Binding}"></Button>
</UserControl>
And in the main page:
<ItemsControl x:Name="ItemsControl" ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<partial:DoItItemTemplate Command="{Binding DataContext.DoIt, ElementName=ItemsControl}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Upvotes: 1