Связывание элемента управления WPF MVVM в шаблоне данных

Я видел другие вопросы, которые касаются этого, но никогда не было явного кода, описывающего исправление. Я не могу получить кнопку внутри моего ItemTemplate для привязки к ЛЮБОЙ команде. Очень расстраивает. Я полный новичок MVVM, кстати.

Вот мой Window XAML.

<Window x:Class="RET.CMS.Printing.App.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:RET.CMS.Printing.App.ViewModel"
    Height="350" Width="525"
    WindowStartupLocation="CenterScreen"
    Title="{Binding Path=DisplayName}"
    >
<Window.Resources>
    <ResourceDictionary Source="MainWindowResources.xaml" />
</Window.Resources>
<Window.DataContext>
    <local:MainWindowViewModel />
</Window.DataContext>

<DockPanel Margin="10">
    <Grid Margin="10" DockPanel.Dock="Top">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
        <Image Grid.Column="0" MaxHeight="75" MinHeight="25" HorizontalAlignment="Left"
                   Source="/RET.CMS.Printing.App;component/Resources/BarkleyREI%20%283%29.png" />
        <TextBlock Grid.Column="1" HorizontalAlignment="Right" 
                    Height="30" VerticalAlignment="Top"
                    Style="{StaticResource TBHyperlinkStyle}"
                    >
            Help
        </TextBlock>
    </Grid>

    <Border Padding="10" DockPanel.Dock="Left">
        <DockPanel>
            <Label Style="{StaticResource H1Style}" DockPanel.Dock="Top">YOUR PRINTERS</Label>
            <StackPanel Margin="10" DockPanel.Dock="Top">
                <Button Style="{StaticResource RegularButton}" HorizontalAlignment="Left" Command="{Binding RefreshPrintersCommand}">Refresh List</Button>
            </StackPanel>
                <ListBox ItemsSource="{Binding Printers}" DockPanel.Dock="Left">
                <ListBox.ItemContainerStyle>
                    <Style TargetType="ListBoxItem">
                        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                    </Style>
                </ListBox.ItemContainerStyle>
                    <ListBox.ItemTemplate>
                <DataTemplate>
                        <Border Padding="5">
                            <StackPanel>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="75" />
                                </Grid.ColumnDefinitions>
                                <Grid>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="*" />
                                        <RowDefinition Height="*" />
                                    </Grid.RowDefinitions>
                                    <Grid Grid.Row="0">
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="*" />
                                            <ColumnDefinition Width="*" />
                                            <ColumnDefinition Width="50" />
                                        </Grid.ColumnDefinitions>
                                            <TextBlock Style="{StaticResource TBHyperlinkStyle}" Text="{Binding Printer.Name}" Grid.Column="0" Margin="2" />
                                            <TextBlock Text="{Binding Printer.Status}" Grid.Column="1" Margin="2"/>
                                        <Image Grid.Column="2" Margin="2"  />
                                    </Grid>
                                    <TextBlock Text="{Binding Printer.Debug}" Grid.Row="1"/>
                                </Grid>
                            <Button Grid.Column="1" Content="Pause"
                                    Command="{Binding Path=PausePrinterCommand}"
                                    ></Button>
                        </Grid>

                        </StackPanel>
                        </Border>
                    </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        </DockPanel>
    </Border>

</DockPanel>

И вот моя ViewModel для этого:

 public class MainWindowViewModel:ViewModelBase
{
    #region Fields
    private ObservableCollection<PrinterViewModel> _Printers = new ObservableCollection<PrinterViewModel>();
    #endregion Fields

    #region Properties
    public ObservableCollection<PrinterViewModel> Printers
    {
        get
        {
            if(_Printers==null)
                LoadPrinters();
            return _Printers;
        }
    }
    #endregion Properties

    #region Constructor
    public MainWindowViewModel()
    {
        base.DisplayName = Resources.MainWindowViewModel_DisplayName;

        //bind commands
        RefreshPrintersCommand = new RelayCommand(param =>this.LoadPrinters());
        PausePrinterCommand = new RelayCommand( param => this.PausePrinter(param));
    }
    #endregion Constructor
    #region Private Members

    private void LoadPrinters()
    {
        PrintersRepository pr = new PrintersRepository(Config.SettingsLoader.GetPrintServers());
        _Printers.Clear();
        pr.GetPrinters().ForEach(i =>
            _Printers.Add(new PrinterViewModel(i)));
        OnPropertyChanged("Printers");
    }
    private void PausePrinter(object printerFullName)
    {
        var p = _Printers.Where(i => i.Printer.FullName == printerFullName as string);
    }
    #endregion Private Members

    #region Commands
    public ICommand RefreshPrintersCommand
    {
        get;
        private set;
    }
    public ICommand PausePrinterCommand
    {
        get;
        private set;
    }

    #endregion Commands
}

Вот моя PrinterViewModel:

 public class PrinterViewModel:ViewModelBase
{
    private Printer _Printer;

    private RelayCommand _PauseCommand;
    public PrinterViewModel(Printer p)
    {
        _Printer = p;

    }
    public Printer Printer { get { return _Printer; } }

    public RelayCommand PauseCommand
    {
        get
        {
            if (_PauseCommand == null)
                _PauseCommand = new RelayCommand(param=>_Printer.Pause());
            return _PauseCommand;
        }
    }

}

Пожалуйста помоги! Почему я не могу получить это?

 Micah22 сент. 2010 г., 21:44
Будет ... очень ценю, что ты указал мне на это. Будучи новичком в этом, приятно знать, какие хитрости используют более опытные разработчики WPF.
 Micah22 сент. 2010 г., 21:24
Кнопка, которую я пытаюсь связать, это кнопка с PausePrinterCommand в DataTemplate ... должен был упомянуть, что
 Will22 сент. 2010 г., 21:29
Похоже, это должно работать. Вам нужно научиться лучше отлаживать проблемы связывания. Перейдите в меню «Отладка», нажмите «Параметры и настройки», затем выберите «Окно вывода» слева и в разделе «Параметры трассировки WPF» переключите «Свойства зависимости» на «Все». Теперь отладьте ваше приложение. Следите за окном вывода на наличие ошибок привязки. Обратите внимание, сAll установить вы получите несколько ложных срабатываний. Но следите за ошибками, которые происходят с опозданием. Вы должны получить некоторую информацию о том, что именно происходит.

Ответы на вопрос(3)

использовать привязку элемента

<Window x:Class="RET.CMS.Printing.App.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:RET.CMS.Printing.App.ViewModel"
    Height="350" Width="525"
    x:Name="rootWindow"
    WindowStartupLocation="CenterScreen"
    Title="{Binding Path=DisplayName}" >
       .
       .
       .
  <Button Grid.Column="1" Content="Pause" Command="{Binding ElementName=rootWindow, Path=DataContext.PausePrinterCommand}"></Button>
 Dave Friedel26 дек. 2014 г., 19:22
Привязка элемента была ключевой для меня, но в случае со списком я должен был ссылаться на список, а не на корень страницы, чтобы он работал. Но спасибо, это был единственный метод, который помог мне.
Решение Вопроса

поскольку ее текст данных представляет собой PrinterViewModel, а не MainWindowViewModel. Если вы посмотрите на выходные данные отладки, VS ясно скажет вам об этом.

 Micah22 сент. 2010 г., 21:43
Клянусь, я сделал это, и это не сработало - но теперь это работает. Спасибо

DataContext для кнопки внутри вашего ItemTemplate является объект PrinterViewModel (который имеетPauseCommand). Тем не менее, вы пытаетесь связатьPausePrinterCommand к нему, который является свойством MainWindowViewModel.

Чтобы выполнить эту работу (то есть выполнить MainViewModel.PausePrinterCommand с помощью Button в вашем ItemTemplate), вам сначала нужно каким-то образом получить MainViewModel.

Один из способов сделать это - использовать RelativeSource для вашей привязки, найти окно и использовать DataContext.PausePrinterCommand в качестве пути привязки. Как это:

<Button Grid.Column="1" Content="Pause"
        Command="{Binding RelativeSource={RelativeSource Window},
                  Path=DataContext.PausePrinterCommand}" />
 Dan J22 сент. 2010 г., 21:30
+1 За то, что я набрал это быстрее и тщательнее, чем мог. :)
 Will22 сент. 2010 г., 21:38
Хороший улов.ItemsSource={Binding Printers} виновник

Ваш ответ на вопрос