WPF上下文菜单不绑定到正确的数据绑定项目 [英] WPF Context menu doesn't bind to right databound item

查看:215
本文介绍了WPF上下文菜单不绑定到正确的数据绑定项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当在标签页上的用户控件上的上下文菜单中绑定命令时,我有问题。
第一次使用菜单(右键单击选项卡)它的效果很好,但是如果我切换选项卡,命令将使用第一次使用的数据绑定实例。

I have a problem when binding a command in a context menu on a usercontrol that is on a tab page. The first time I use the menu (right-click on the tab) it works great, but if I switch tab the command will use the databound instance that was used the first time.

如果我把一个按钮绑定到usercontrol中的命令,它按预期工作...

If I put a button that is bound to the command in the usercontrol it works as expected...

有人可以告诉我什么'做错了?

Can someone please tell me what I'm doing wrong??

这是一个暴露出问题的测试项目:

This is a test project that exposes the problem:

App.xaml。 cs:

App.xaml.cs:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        CompanyViewModel model = new CompanyViewModel();
        Window1 window = new Window1();
        window.DataContext = model;
        window.Show();
    }
}

Window1.xaml:

Window1.xaml:

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vw="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300">

  <Window.Resources>
    <DataTemplate x:Key="HeaderTemplate">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Path=Name}" />
        </StackPanel>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vw:PersonViewModel}">
        <vw:UserControl1/>
    </DataTemplate>

</Window.Resources>
<Grid>
    <TabControl ItemsSource="{Binding Path=Persons}" 
                ItemTemplate="{StaticResource HeaderTemplate}"
                IsSynchronizedWithCurrentItem="True" />
</Grid>
</Window>

UserControl1.xaml:

UserControl1.xaml:

<UserControl x:Class="WpfApplication1.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    MinWidth="200">
    <UserControl.ContextMenu>
        <ContextMenu >
            <MenuItem Header="Change" Command="{Binding Path=ChangeCommand}"/>
        </ContextMenu>
    </UserControl.ContextMenu>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Label Grid.Column="0">The name:</Label>
        <TextBox Grid.Column="1" Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</UserControl>

CompanyViewModel.cs:

CompanyViewModel.cs:

public class CompanyViewModel
{
    public ObservableCollection<PersonViewModel> Persons { get; set; }
    public CompanyViewModel()
    {
        Persons = new ObservableCollection<PersonViewModel>();
        Persons.Add(new PersonViewModel(new Person { Name = "Kalle" }));
        Persons.Add(new PersonViewModel(new Person { Name = "Nisse" }));
        Persons.Add(new PersonViewModel(new Person { Name = "Jocke" }));
    }
}

PersonViewModel.cs:

PersonViewModel.cs:

public class PersonViewModel : INotifyPropertyChanged
{
    Person _person;
    TestCommand _testCommand;

    public PersonViewModel(Person person)
    {
        _person = person;
        _testCommand = new TestCommand(this);
    }
    public ICommand ChangeCommand 
    {
        get
        {
            return _testCommand;
        }
    }
    public string Name 
    {
        get
        {
            return _person.Name;
        }
        set
        {
            if (value == _person.Name)
                return;
            _person.Name = value;
            OnPropertyChanged("Name");
        }
    }
    void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

TestCommand.cs:

TestCommand.cs:

public class TestCommand : ICommand
{
    PersonViewModel _person;
    public event EventHandler CanExecuteChanged;

    public TestCommand(PersonViewModel person)
    {
        _person = person;
    }
    public bool CanExecute(object parameter)
    {
        return true;
    }
    public void Execute(object parameter)
    {
        _person.Name = "Changed by command";
    }
}

Person.cs:

Person.cs:

public class Person
{
    public string Name { get; set; }
}


推荐答案

这里是上下文菜单不是视觉树的一部分。

因此,他们不会继承与他们所属的控件相同的来源捆绑。处理这个的方法是绑定到ContextMenu本身的放置目标。

Therefore they don't inherit the same source as the control they belong to for binding. The way to deal with this is to bind to the placement target of the ContextMenu itself.

<MenuItem Header="Change" Command="{Binding 
    Path=PlacementTarget.ChangeCommand, 
    RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"
/>

这篇关于WPF上下文菜单不绑定到正确的数据绑定项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆