私の問題はこの質問で説明されているものと似ています:
DataTemplateのWPF MVVMボタンコントロールバインディング
ここに私の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>
これはListBox
であり、CommandSets
という名前のObservableCollection<string>
にバインドされています(これは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
)のバインディングのみを「認識」しますが、メインウィンドウのバインディングは認識しません。コマンド自体は間違いなく正しいです。なぜなら、ボタンを外側に配置すると、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}}}" />
誰かが喜んでくれますか:
ListBox
内のボタンをフォームのMainViewModel
?のコマンドにバインドするための適切なXAMLを教えてくださいRelativeSource
やStaticResource
など、「通常の」バインディングの代わりに何が必要かを自分で判断します。それは:
{Binding DataContext.FireCommand,
RelativeSource={RelativeSource AncestorType=ListBox}}
途中でDataContext
を実際に変更しない限り、ルートまで移動する必要はありませんが、ListBox
はメインのプロパティにバインドしているようですVM =これで十分です。
私が読むことをお勧めする唯一のものは データバインディングの概要 と Binding
class ドキュメント(そのプロパティを含む)です。
バインディングがどのように構成されるかについての簡単な説明もここにあります:バインディングはsourceとPath
sourceを基準として、デフォルトではsourceは現在のDataContext
です。明示的に設定できるソースは、Source
、ElementName
&RelativeSource
です。これらのいずれかを設定すると、DataContext
がsourceとしてオーバーライドされます。
したがって、RelativeSource
のようなsourceを使用し、そのレベルのDataContext
内の何かにアクセスする場合、DataContext
はPath
に表示される必要があります。
これはほとんどの人とは無関係であると考えられますが、この検索は、Xamarinフォームに関連するため、データテンプレート内のコントロールへのデータバインディングコマンドを検索した結果の3つのうちの1つにすぎません。だから、多分それは、今日の誰かを助けるでしょう。
私のように、BindableLayout内でコマンドをバインドする方法について疑問に思うかもしれません。 Xamarinフォーラムでこれに回答したjesulink2514の功績をたたえます。すべてのコメントのため、おそらくそれは多くの人から見落とされています。これが彼の解決策ですが、私は以下のリンクを含めています:
<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