2

私は次のxamlを持っています。

    <DataTemplate DataType="{x:Type NameSpace:Node}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Item.Value}"/>
            <ContentControl Content="{Binding Item}"/>
        </StackPanel>
    </DataTemplate>

    <DataTemplate DataType="{x:Type NameSpace:Item}">
        <TextBlock Text="{Binding Value}" />
    </DataTemplate>

Nodeテンプレートを使用してNodeオブジェクトを表示すると、2つのTextBlockが表示され、どちらも同じ値を表示します。ここまでは順調ですね。アイテムが変更されると、問題が発生します。NodeクラスがINotifyPropertyChangedイベントを発生させると、Node DataTemplateのTextBlockは期待どおりに更新されますが、ItemDataTemplateのTextBlockは更新されません。

NodeクラスがIPropertyChangedイベントを発生させたときに、Item DataTemplateにそのバインディングを更新させるにはどうすればよいですか?

更新 上記は、次の単純なシナリオで機能することがわかりました。

Xaml

        <DataTemplate DataType="{x:Type DataTemplateExample:Node}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Item.Value}"/>
                <ContentControl Content="{Binding Item}"/>
            </StackPanel>
        </DataTemplate>

        <DataTemplate DataType="{x:Type DataTemplateExample:Item}">
            <TextBlock Text="{Binding Value}" />
        </DataTemplate>
    </Window.Resources>

    <Grid>
        <StackPanel Orientation="Vertical">
            <ContentControl Content="{Binding MyNode}"/>
            <Button Command="{Binding ChangeMyNodeItem}">Change Item</Button>
        </StackPanel>
    </Grid>
</Window>

c#

public class MainViewModel
{
    private readonly Node myNode;
    private readonly DelegateCommand changeMyNodeItemCmd;

    public MainViewModel()
    {
        myNode = new Node {Item = new Item("a")};
        changeMyNodeItemCmd = new DelegateCommand(()=>
            myNode.Item = new Item("b"));
    }

    public Node MyNode { get { return myNode; } }

    public ICommand ChangeMyNodeItem
    {
        get { return changeMyNodeItemCmd; }
    }
}

public class Node : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private Item item;
    public Item Item
    {
        set
        {
            item = value;
            if (PropertyChanged != null)
                PropertyChanged(this,new PropertyChangedEventArgs("Item"));
        }
        get { return item; }
    }
}

public class Item
{
    private readonly string value;

    public Item(string value)
    {
        this.value = value;
    }

    public string Value
    {
        get { return value; }
    }
}

私の実際のシナリオでは、プロキシを使用していましたが、これがWPFを混乱させていたものだと思います。アイテムは実際には変更されていませんでした-再マップされていました。

最終的には、ShadeOfGrayが提案したものと同様のソリューションを使用して問題を解決しました。ただし、プロキシを使用していない限り、これは必要ないことを指摘しておく必要があります。

4

1 に答える 1

3

あなたが投稿したことから、間違ったクラスで NotifyPropertyChanged を起動していると思います。そのようなものは、シナリオで適切に機能するはずです。

コメントに従って更新されました:

public class Node : INotifyPropertyChanged
{
    private Item item;

    public event PropertyChangedEventHandler PropertyChanged;

    public Item Item
    {
        get
        {
            return item;
        }

        set
        {
            item = value;

            this.NotifyPropertyChanged("Item");

            if (item != null)
            {
                item.ForcePropertyChanged("Value");
            }
        }
    }

    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public class Item : INotifyPropertyChanged
{
    private string itemValue;

    public Item()
    {
        this.Value = string.Empty;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public string Value
    {
        get
        {
            return itemValue;
        }

        set
        {
            itemValue = value;

            NotifyPropertyChanged("Value");
        }
    }

    public void ForcePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
于 2012-12-05T08:42:10.117 に答える