29

私の問題は、この質問で説明されている問題と似ています:
WPF MVVM Button Control Binding in 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>

これは、名前付き(ViewModel 内にある) にListBoxバインドされた単なるです。 このバインドは機能します (コレクション内の各アイテムのボタンが表示されます)。ObservableCollection<string>CommandSets

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");
    }
}

このボタンのバインドは機能しません。上記でリンクした質問
から私が理解したことから、バインディングが機能しない理由は次のとおりです。(間違っている場合は修正してください)

  • ボタンは の内部にあるため、 (この場合は )ListBoxのバインディングのみを「認識」し、メイン ウィンドウのバインディングは認識しません。ListBoxObservableCollection
  • メイン ウィンドウのメイン 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}}}" />

誰かお願いします:

  1. ListBox内のボタンをフォームのコマンドにバインドする適切な XAML を教えてくださいMainViewModel
  2. WPF/MVVM の初心者が理解できる方法でこの高度なバインディングが説明されているリンクを教えてください。
    私は難解な XAML の呪文をコピーして貼り付けているだけのように感じています。これまでのところ、どのような場合に必要になるかを自分でどのように理解するかについての手がかりがありません (そして適切なドキュメントが見つかりません)。RelativeSourceまたはStaticResource、「通常の」バインディングの代わりに何でも。
4

2 に答える 2

75

これは:

{Binding DataContext.FireCommand,
         RelativeSource={RelativeSource AncestorType=ListBox}}

DataContext途中でを実際に変更しない限り、ルートまで歩く必要はありませんがListBox、 はメイン VM のプロパティにバインドされているように見えるので、これで十分です。

私が読むことをお勧めする唯一のものは、Data Binding OverviewBindingクラスのドキュメント (そのプロパティを含む) です。


また、バインディングがどのように構築されるかについての簡単な説明次のとおりです。明示的に設定できるソースは、 、&です。これらのいずれかを設定すると、 as sourceがオーバーライドされます。PathDataContextSourceElementNameRelativeSourceDataContext

したがって、次のようなソースを使用して、そのレベルの にあるRelativeSourceものにアクセスしたい場合は、 に表示する必要があります。DataContextDataContextPath

于 2012-09-10T23:00:42.253 に答える