2

値コンバーターを使用して、そのテキストボックスのデータコンテキスト内のプロパティの 1 つに isChecked プロパティをバインドしようとしているテキストボックスにコンテキストメニューがあります。

私が抱えている問題は、この投稿と非常に似ていると思います... WPF MenuItem.Command binding to ElementName results to System.Windows.Data Error: 4 : Cannot find source for binding with reference

そこでは、Aran Mulholland が 3 つの異なる解決策を提案しています。私が動かそうとしているもので、実際に動く例をまだ見ていないのは #2 です。これは最もMVVMに適したアプローチであり、そのためには最もエレガントだと思います...繰り返しになりますが、私はこれにかなり慣れていません。

ここに私のxamlがあります

<DataTemplate x:Key="SFTemplateWithContextMenu">
        <TextBlock x:Name="Field" Text="{Binding Path=FieldName}" >
         <TextBlock.ContextMenu>
              <!--<ContextMenu PlacementTarget="{Binding ElementName=Field}" > -->
                    <ContextMenu DataContext="{Binding RelativeSource={RelativeSource Mode=Self}, Path=PlacementTarget.DataContext}">
                    <MenuItem  Header="Rename..." />
                    <MenuItem Header="Field Type">
                        <MenuItem.Resources>
                            <Configurator:EnumToBooleanConverter x:Key="EnumToBooleanConverter" />
                        </MenuItem.Resources>
                    <!--<MenuItem  Header="String" IsCheckable="True" IsChecked="{Binding Path=PlacementTarget.DataContext.FieldType, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static Configurator:TypeDesc.String}, PresentationTraceSources.TraceLevel=High}"/>-->
                        <MenuItem  Header="String" IsCheckable="True" IsChecked="{Binding Path=FieldType, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static Configurator:TypeDesc.String}, PresentationTraceSources.TraceLevel=High}"/>
                    </MenuItem>
                </ContextMenu>
            </TextBlock.ContextMenu>
        </TextBlock>
    </DataTemplate>

DataTemplate を使用して、次の ListBox にデータを入力しています...

<ListBox DnD:DragDropHelper.IsDragSource="True"   Name="sourceFieldsLB" Height="238" HorizontalAlignment="Left" Margin="20,286,0,0" VerticalAlignment="Top" Width="150" ItemTemplate="{StaticResource SFTemplateWithContextMenu}"  ItemsSource="{Binding Selection.SourceFields, Mode=TwoWay}" AllowDrop="True" >

私は Snoop をダウンロードして内部を調べ、何が起こっているのかを確認しました。さまざまな程度の失敗で、いくつかの異なる方法を試しました。

コメントアウトされた部分は、私が目標を達成しようとしていた以前の方法です。問題は、エラーが発生したことです...「参照 'elementname=Field' でバインドするソースが見つかりません」しかし、TextBlock は Snoop を使用してその名前が Field であることを示しています。

私がやっている現在の方法では、テキストブロックにローカルの名前スコープがあり、その名前がフィールドであることがわかります。これは、私が期待し、望んでいるものです。ContextMenu 値は、2 つの項目を持つ ContextMenu があることを示しています...これは正しいです。そこで、ContextMenu をクリックして、どのように見えるかを確認し、ContextMenu に DataContext がないことを確認します。

これに関するヘルプと指示は素晴らしいでしょう。ここで何が欠けているのか正確にはわかりません。私は周りを見回しましたが、誰かがこの作業に近づいているように見えるときはいつでも、彼らは何らかの「回避策」またはそれを行うための他の方法を見つけたと述べていますが、決して機能しません. これは機能する必要があります...私はこれに慣れていないため、欠けている部分を見ることができません。

真のMVVMの方法で実行できることはわかっています...そうですか?

4

1 に答える 1

3

ブライス、主な問題は、ContextMenus が標準のビジュアル ツリーの一部ではなく、唯一の実際の接続が PlacementTarget プロパティを介していることです。したがって、通常はできるだけ早く接続することをお勧めします。そう...

ViewModel が与えられた場合

public class ViewModel
{
    public string Field { get; set; }
    public string FieldType { get; set; }
}

そしてメインウィンドウ

<Window x:Class="ContextMenuSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock Text="{Binding Field}">
            <TextBlock.ContextMenu>
                <ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext}">
                    <MenuItem Header="{Binding FieldType}" />
                </ContextMenu>
            </TextBlock.ContextMenu>
        </TextBlock>
    </Grid>
</Window>

そして app.xaml.cs

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;

namespace ContextMenuSample
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            var shell = new MainWindow();
            shell.DataContext = new ViewModel { Field = "FirstName", FieldType = "String" };
            shell.Show();
        }
    }
}

ContextMenu の DataContext が次の行で正しく接続されていることがわかります。

<ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext}">

基礎となる VieWModel と対話する適切に動作する ContextMenu を取得する必要があります。

于 2012-05-23T10:28:43.873 に答える