Привязка к ICommand изнутри DataTemplate

#silverlight #xaml #data-binding #silverlight-4.0 #datatemplate

#Silverlight #xaml #Привязка к данным #Silverlight-4.0 #DataTemplate

Вопрос:

У меня есть пользовательский элемент управления, который имеет свойство зависимости ICommand. Я хотел бы привязаться к этому свойству изнутри DataTemplate. Чтобы было понятнее, вот мой код:

Класс DataForm:

 public class DataForm : Form
{
    #region Properties

    public ICommand HideForm
    {
        get { return (ICommand)GetValue(HideFormProperty); }
        set { SetValue(HideFormProperty, value); }
    }

    public static readonly DependencyProperty HideFormProperty =
        DependencyProperty.Register("HideForm", typeof(ICommand), typeof(DataForm), new PropertyMetadata(null));


    #endregion

    #region Ctors
    public DataForm(Guid formId, String title)
        : base(formId, title)
    {
        this.Template = Application.Current.Resources["DataFormDefaultTemplate"] as ControlTemplate;
    }
    public DataForm()
        : this(Guid.NewGuid(), "bla")
    {
    }
    #endregion

    #region Methods
    public override void OnApplyTemplate()
    {
        if (HeaderTemplate == null)
        {
            HeaderTemplate = Application.Current.Resources["DefaultFormHeaderTemplate"] as DataTemplate;
        }
        base.OnApplyTemplate();
    }
    #endregion
}
  

ControlTemplate формы данных:

 <ControlTemplate x:Name="DataFormDefaultTemplate" TargetType="my:DataForm">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <ContentPresenter Grid.Row="0" ContentTemplate="{TemplateBinding HeaderTemplate}"></ContentPresenter>
        <ContentPresenter Grid.Row="1" ContentTemplate="{TemplateBinding BodyTemplate}"></ContentPresenter>
        <ContentPresenter Grid.Row="2" ContentTemplate="{TemplateBinding FooterTemplate}"></ContentPresenter>
    </Grid>
</ControlTemplate>
  

DataTemplate, с которого я хочу привязаться к команде HideForm:

 <DataTemplate x:Name="DefaultFormHeaderTemplate">
    <Grid HorizontalAlignment="Stretch">
        <my:TextField FieldViewStyle="{StaticResource formLabelStyle}" Value="Form Title" Mode="View"></my:TextField>
        <my:ImageButtonField ImagePath="../Images/Popup_Close.png" 
                         CommandToExecute="{Binding HideForm}" 
                             HorizontalAlignment="Right" Width="8" Height="8"></my:ImageButtonField>
    </Grid>
</DataTemplate>
  

Примечание: CommandToExecute правильно работает с ImageButtonField. Я уже протестировал это.

Код для создания экземпляра формы данных:

     DataForm form = new DataForm();
    form.BodyTemplate = Application.Current.Resources["DataFormBodyTemplate"] as DataTemplate;
    form.FooterTemplate = Application.Current.Resources["DataFormFooterTemplate"] as DataTemplate;

    form.HideForm = new DelegateCommand(CloseIt);
  

Как мне заставить это работать? В принципе, идеальным сценарием является возможность привязки к этой команде (и другим свойствам) в шаблоне данных из ViewModel без необходимости добавлять это свойство ( HideForm в данном случае) к DataForm классу. Разве DataContext не должен наследоваться и — теоретически — то, что я говорю, должно работать?

Комментарии:

1. Ни у кого, кроме вас, нет ваших Form , TextField ни ImageButtonField классов, поэтому никто, кроме вас, не может запустить этот код, чтобы выяснить, в чем проблема. В частности, как a Form использует a HeaderTemplate ? Попробуйте вместо этого предоставить SSCCE .

2. @Luke Woodward: Это будет сложно, потому что в цепочке наследования есть несколько классов, но я уверен, что проблема связана с DataTemplate. Я хочу знать, возможно ли то, чего я пытаюсь достичь, или это ограничение Silverlight 4…

Ответ №1:

Я использую EventToCommand в MVVM Light, см. Пример кода ниже.

 <UserControl.Resources>
    <ContentControl x:Key="ViewModel" Content="{Binding}" />
</UserControl.Resources>

.. Your code here ..

<my:ImageButtonField ImagePath="../Images/Popup_Close.png" 
                     CommandToExecute="{Binding HideForm}" 
                     HorizontalAlignment="Right" Width="8" Height="8">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseLeftButtonUp">
            <Command:EventToCommand Command="{Binding Content.YourCommand, Source={StaticResource ViewModel}}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</my:ImageButtonField>
  

Вы можете прочитать больше о EventToCommand <- здесь .

Ответ №2:

Оказалось, что нет способа сделать это с помощью a DataTemplate , если вы не используете прокси-сервер привязки. Другой способ — использовать ControlTemplate вместо a и привязывать к Template свойству a ContentControl вместо использования a ContentPresenter