Кнопка Bind в DataTemplate для команды в форме ViewModel
Моя проблема аналогична описанной в этом вопросе:
WPF MVVM Управление привязкой кнопок в DataTemplate
Вот мой XAML:
<Window x:Class="MissileSharp.Launcher.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MissileSharp Launcher" Height="350" Width="525">
<Grid>
<!-- when I put the button here (outside the list), the binding works -->
<!--<Button Content="test" Command="{Binding Path=FireCommand}" />-->
<ListBox ItemsSource="{Binding CommandSets}">
<ListBox.ItemTemplate>
<DataTemplate>
<!-- I need the button here (inside the list), and here the binding does NOT work -->
<Button Content="{Binding}" Command="{Binding Path=FireCommand}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Это просто a ListBox
, связанный с ObservableCollection<string>
с именем CommandSets
(который находится в ViewModel).
Эта привязка работает (она отображает кнопку для каждого элемента в коллекции).
Теперь я хочу привязать кнопку к команде (FireCommand
), которая также находится в ViewModel.
Здесь соответствующая часть ViewModel:
public class MainWindowViewModel : INotifyPropertyChanged
{
public ICommand FireCommand { get; set; }
public ObservableCollection<string> CommandSets { get; set; }
public MainWindowViewModel()
{
this.FireCommand = new RelayCommand(new Action<object>(this.FireMissile));
}
private void FireMissile(Object obj)
{
System.Windows.MessageBox.Show("fire");
}
}
Связывание этой кнопки НЕ работает.
Из того, что я понял из question, связанного выше, привязка не работает, потому что:
(исправьте меня, если я ошибаюсь)
- Кнопка находится внутри
ListBox
, поэтому она "знает" привязку ListBox
(в этом случае ObservableCollection
), но не привязка главного окна
- Я пытаюсь связать команду в главной ViewModel главного окна (которое кнопка не знает)
Сама команда определенно правильна, потому что, когда я нажимаю кнопку вне ListBox
(см. выше приведенный выше пример XAML), выполняется работа по связыванию и команда.
По-видимому, мне просто нужно указать кнопке привязку к основной ViewModel формы.
Но я не могу понять правильный синтаксис XAML.
Я попробовал несколько подходов, которые я нашел после некоторых поисковых запросов, но никто из них не работал у меня:
<Button Content="{Binding}" Command="{Binding RelativeSource={RelativeSource Window}, Path=DataContext.FireCommand}" />
<Button Content="{Binding}" Command="{Binding Path=FireCommand, Source={StaticResource MainWindow}}" />
<Button Content="{Binding}" Command="{Binding Path=FireCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
Может кто-то угодить:
- дайте мне правильный XAML, чтобы связать кнопку внутри
ListBox
с командой в форме MainViewModel
?
- укажите мне ссылку, где этот расширенный материал привязки объясняется так, как может понять начинающий WPF/MVVM?
Мне кажется, что я просто копирую и вставляю тайные заклинания XAML, и до сих пор у меня нет никакой подсказки (и я не могу найти хорошую документацию), как бы я сам разобрался, в каких случаях мне понадобится RelativeSource
или StaticResource
или что-то другое вместо "нормального" связывания.
Ответы
Ответ 1
Это:
{Binding DataContext.FireCommand,
RelativeSource={RelativeSource AncestorType=ListBox}}
Не нужно доходить до корня, если вы фактически не измените DataContext
на этом пути, но поскольку ListBox
, похоже, привязывается к свойству на главной виртуальной машине, этого должно быть достаточно.
Единственное, что я рекомендую прочитать, это Обзор привязки данных и Binding
класс (включая его свойства).
Также приведено краткое объяснение того, как строятся привязки: привязка состоит из источника и Path
относительно этого источника, по умолчанию источником является текущий DataContext
. Источники, которые могут быть установлены явно: Source
, ElementName
и RelativeSource
. Установка любого из них приведет к переопределению источника DataContext
.
Итак, если вы используете источник типа RelativeSource
и хотите получить доступ к чему-то в DataContext
на этом уровне, DataContext
должен появиться в Path
.
Ответ 2
Большинству это может показаться несвязанным, но этот поиск - только 1 из 3 результатов, которые вы найдете при поиске команд привязки данных к элементам управления внутри шаблона данных - поскольку это относится к формам Xamarin. Так что, может быть, это поможет кому-то сейчас.
Как и я, вы можете задаться вопросом, как связывать команды внутри BindableLayout. Благодарим jesulink2514 за ответы на форумах Xamarin, где многие, возможно, не заметили его из-за всех комментариев. Здесь его решение, но я включаю ссылку ниже:
<ContenPage x:Name="MainPage">
<ListView Grid.Row="1"
ItemsSource="{Binding Customers}"
VerticalOptions="Fill"
x:Name="ListviewCustomer">
<ListView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Property}"/>
<Button Command="{Binding BindingContext.ItemCommand, Source={x:Reference MainPage}}"
CommandParameter="{Binding .}">Click me</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
https://forums.xamarin.com/discussion/comment/217355/#Comment_217355