21

私はこれに約1時間取り組んでおり、関連するすべてのSOの質問を調べました。

私の問題は非常に単純です:

私はHomePageVieModelを持っています:

HomePageVieModel
+IList<NewsItem> AllNewsItems
+ICommand OpenNews

私のマークアップ:

<Window DataContext="{Binding HomePageViewModel../>
<ListBox ItemsSource="{Binding Path=AllNewsItems}">
 <ListBox.ItemTemplate>
   <DataTemplate>
       <StackPanel>
        <TextBlock>
           <Hyperlink Command="{Binding Path=OpenNews}">
               <TextBlock Text="{Binding Path=NewsContent}" />
           </Hyperlink>
        </TextBlock>
      </StackPanel>
    </DataTemplate>
</ListBox.ItemTemplate>

リストはすべての項目で問題なく表示されますが、私の人生では、コマンドに対して何をしようとしても機能しません。

<Hyperlink Command="{Binding Path=OpenNewsItem, RelativeSource={RelativeSource AncestorType=vm:HomePageViewModel, AncestorLevel=1}}">
<Hyperlink Command="{Binding Path=OpenNewsItem, RelativeSource={RelativeSource AncestorType=vm:HomePageViewModel,**Mode=FindAncestor}**}">
<Hyperlink Command="{Binding Path=OpenNewsItem, RelativeSource={RelativeSource AncestorType=vm:HomePageViewModel,**Mode=TemplatedParent}**}">

私はいつも得る:

System.Windows.Dataエラー:4:参照とのバインドのソースが見つかりません....。

更新 ViewModelをこのように設定していますか?これが重要だとは思わなかった:

 <Window.DataContext>
        <Binding Path="HomePage" Source="{StaticResource Locator}"/>
    </Window.DataContext>

魔法を実行するMVVMLightツールキットのViewModelLocatorクラスを使用します。

4

7 に答える 7

31

例は少し異なりますが、バインドで (ElementName を使用して) 親コンテナーを参照することで、Path 構文を使用してその DataContext とその後続のプロパティを取得できることがわかりました。以下に示すように:

<ItemsControl x:Name="lstDevices" ItemsSource="{Binding DeviceMappings}">
 <ItemsControl.ItemTemplate>
  <DataTemplate>
   <Grid>
    <ComboBox Text="{Binding Device}" ItemsSource="{Binding ElementName=lstDevices, Path=DataContext.AvailableDevices}" />
    ...
   </Grid>
  </DataTemplate>
 </ItemsControl.ItemTemplate>
</ItemsControl>
于 2012-11-13T04:57:00.880 に答える
14

ここであなたに対して働く2つの問題があります。

DataContextDataTemplate、テンプレートが表示しているアイテムに設定されます。つまり、ソースを設定せずにバインディングを使用することはできません。

DataTemplateもう 1 つの問題は、テンプレートは項目が技術的に論理ツリーの一部ではないことを意味するため、ノードを超えて祖先を検索できないことです。

これを解決するには、バインディングを論理ツリーの外側に到達させる必要があります。ここで定義された DataContextSpy を使用できます。

<ListBox ItemsSource="{Binding Path=AllNewsItems}">
    <ListBox.Resources>
        <l:DataContextSpy x:Key="dataContextSpy" />
    </ListBox.Resources>

    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock>
                   <Hyperlink Command="{Binding Source={StaticResource dataContextSpy}, Path=DataContext.OpenNews}" CommandParameter="{Binding}">
                       <TextBlock Text="{Binding Path=NewsContent}" />
                   </Hyperlink>
               </TextBlock>
           </StackPanel>
       </DataTemplate>
   </ListBox.ItemTemplate>
</ListBox>
于 2011-02-21T08:20:01.533 に答える
8

このようなことを試してください

<Button Command="{Binding DataContext.YourCommand,RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"

そのリストボックスのビューモデルとは異なるデータコンテキストを設定しているため、リストボックス内でコマンドバインディングを見つけることができません

于 2011-04-29T09:07:27.783 に答える
8

ICommand をトリガーするために、HyperLink に適切な DataContext を与えようとしているようです。単純な要素名バインディングでこれを解決できると思います。

<Window x:Name="window" DataContext="{Binding HomePageViewModel../>
 <ListBox ItemsSource="{Binding Path=AllNewsItems}">
 <ListBox.ItemTemplate>
  <DataTemplate>
   <StackPanel>
    <TextBlock>
       <Hyperlink DataContext="{Binding DataContext ,ElementName=window}" Command="{Binding Path=OpenNews}">
           <TextBlock Text="{Binding Path=NewsContent}" />
       </Hyperlink>
    </TextBlock>
  </StackPanel>
</DataTemplate>

AncestorType は、ViewModel 型ではなく Visual-Type のみをチェックします。

于 2011-02-21T08:01:56.540 に答える
2

まあ、それは少し遅いです、私は知っています。しかし、私は最近同じ問題に直面したばかりです。アーキテクチャ上の理由から、dataContextSpy の代わりに静的ビューモデル ロケーターを使用することにしました。

<UserControl x:Class="MyView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:locator="clr-namespace: MyNamespace"
             DataContext="{Binding Source={x:Static locator:ViewModelLocator.MyViewModel}}" >
    <ListBox ItemsSource="{Binding Path=AllNewsItems}">        

        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock>
                        <Hyperlink Command="{Binding Source={x:Static locator:ViewModelLocator.MyViewModel}, 
                                                     Path=OpenNews}" 
                                   CommandParameter="{Binding}">
                            <TextBlock Text="{Binding Path=NewsContent}" />
                        </Hyperlink>
                    </TextBlock>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</UserControl>

静的ビューモデル ロケーターは、ビュー モデルをインスタンス化します。

namespace MyNamespace
{
    public static class ViewModelLocator
    {
        private static MyViewModelType myViewModel = new MyViewModelType();
        public static MyViewModelType MyViewModel 
        {
            get
            {
                return myViewModel ;
            }
        }
    }
}

この回避策を使用することは、データ テンプレートからビューモデル内のコマンドにバインドする別の方法です。

于 2012-12-14T11:47:58.567 に答える
1

@Darren からの回答はほとんどの場合うまく機能し、可能であれば推奨される方法です。ただし、次の (ニッチな) 条件がすべて発生する実用的なソリューションではありません。

  • DataGridTemplateColumnを使用したDataGrid
  • .NET 4
  • WindowsXP

...そしておそらく他の状況でも。理論的には、Windows のすべてのバージョンで失敗するはずです。しかし、私の経験では、ElementNameアプローチはWindows 7以上のDataGridで機能しますが、XPでは機能しません。

次の架空の例では、UserControl.DataContext (ViewModel) のShowThingCommandというICommandにバインドしようとしています。

<UserControl x:Name="ThisUserControl" DataContext="whatever...">
    <DataGrid ItemsSource="{Binding Path=ListOfThings}">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Thing">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Button
                            Command="{Binding ElementName=ThisUserControl, Path=ShowThingCommand}"
                            CommandParameter="{Binding Path=ThingId}"
                            Content="{Binding Path=ThingId}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</UserControl>

DataTemplateがメイン コントロールと同じ VisualTree にないため、 ElementName でコントロールを参照することはできませ

これを解決するには、あまり知られていない .NET 4 以降の{x:Reference}を使用できます。上記の例を次のように変更します。

<UserControl x:Name="ThisUserControl" DataContext="whatever...">
    <DataGrid ItemsSource="{Binding Path=ListOfThings}">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Thing">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Button
                            Command="{Binding Source={x:Reference ThisUserControl}, Path=ShowThingCommand}"
                            CommandParameter="{Binding Path=ThingId}"
                            Content="{Binding Path=ThingId}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</UserControl>

参考までに、次のスタックオーバーフローの投稿を参照してください。

質問19244111

質問 5834336

...そして、この状況でElementNameが機能しない理由の説明については、.NET 4 より前の回避策を含むこのブログ投稿を参照してください。

于 2016-02-29T21:27:26.043 に答える