将控件移动到UserControl后绑定到控件的属性

时间:2012-10-15 16:24:40

标签: wpf xaml binding

我有一个带有许多控件的窗口,它们必须引用彼此的viewModels。我想将一组相关控件移动到自定义UserControl中,当我这样做时,我遇到了从窗口中其他控件绑定到现在嵌入控件的问题。

E.g。在我的窗口中,我有一个网格。在Grid的一个单元格中,我有StackPanel包含两个自定义UserControls:

<StackPanel>
    <KtWpf:TicketGridControl x:Name="ticketGrid" />
    <KtWpf:TicketViewControl x:Name="ticketView" />
</StackPanel>

在Grid的另一个单元格中,我有另一个自定义UserControl,它绑定到网格中的当前项目:

<local:AddressView x:Name="addressView"
    currentItem="{Binding ElementName=ticketGrid,Path=viewModel.tickets.CurrentItem}" />

这种绑定工作正常。

但我想要的是将ticketGrid和ticketView移动到新的自定义UserControl中。这很容易做到:

<UserControl
        x:Class="KorEnterprise.EnterpriseMobile.MyTickets"
        ...
        >
    <StackPanel>
        <KtWpf:TicketGridControl x:Name="ticketGrid" />
        <KtWpf:TicketViewControl x:Name="ticketViewControl" />
    </StackPanel>
</UserControl>

然后在Grid中,我将StackPanel替换为:

<local:MyTickets x:Name="myTickets" />

然后我希望addressView的绑定更改为:

<local:AddressView x:Name="addressView"
    currentItem="{Binding ElementName=myTickets,Path=ticketGrid.viewModel.tickets.CurrentItem}" />

但这不起作用。我在运行时遇到BindingExpression错误:

System.Windows.Data Error: 40 : 
BindingExpression path error: 'ticketGrid' property not found on 'object' ''MyTickets' (Name='myTickets')'. 
BindingExpression:Path=ticketGrid.viewModel.tickets.CurrentItem; 
DataItem='MyTickets' (Name='myTickets'); 
target element is 'AddressView' (Name='addressView'); 
target property is 'currentItem' (type 'TicketVM')

我不明白为什么。我在编译时没有错误 - 我在代码中没有错误。

例如,这不会引发异常:

public MainWindow()
{
    ...
    this.applicationExiting += new ApplicationExitingEventHandler(this.myTickets.ticketGrid.applicationExitingEventHandler);
    ...
}

当我在调试器中浏览时,this.myTickets存在,并且this.myTickets.ticketGrid存在,并且事件处理程序连接正常。

但是当XAML开始执行其无声魔法时,挂钩绑定,由于某种原因,this.myTickets.ticketGrid不存在。

我无法理解为什么。

2 个答案:

答案 0 :(得分:0)

尝试:

 <local:MyTickets x:Name="myTickets" 
        Tag="{Binding ElementName=ticketGrid,Path=YourProperty}" /> 

  <local:AddressView currentItem="{Binding ElementName=myTickets,Path=Tag}" />

o'k所以这不起作用..

执行以下操作:

在UserControl上创建DependencyProperty:

  public Class MyTickets: UserControl 
  {
       public object MyProperty
       {
           get { return (object)GetValue(MyPropertyProperty); }
           set { SetValue(MyPropertyroperty, value); }
       }

       public static readonly DependencyProperty MyPropertyProperty=
        DependencyProperty.Register("MyProperty", typeof(object), typeof(MyTickets), new UIPropertyMetadata(null));

  }

XAML:

 <UserControl
    x:Class="KorEnterprise.EnterpriseMobile.MyTickets"
    ...
    >
          <StackPanel>
              <KtWpf:TicketGridControl x:Name="ticketGrid" 
                                YourProperty={Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl} , 
                                Path=MyProperty />
              <KtWpf:TicketViewControl x:Name="ticketViewControl" />
          </StackPanel>

和:

 <local:AddressView currentItem="{Binding ElementName=myTickets,Path=MyProperty }" />

答案 1 :(得分:0)

我不确定这是最好的方法,但确实有效。它只涉及比我想要的更多的管道。

  • 创建一个视图模型类,并将其实例设置为控件的DataContext。
  • 在视图模型上创建故障单集合属性
  • 在构建用户控件时,将视图模型的故障单集合设置为ticketGrid的故障单集合
  • 将AddressView控件的currentItem属性绑定到视图模型的故障集合
  • 最重要的是 - 在更改视图模型的故障单集合时提升PropertyChanged。

这很有效,但我很想找到更简单的东西:

public partial class MyTickets : KorUserControl
{
    public MyTickets()
    {
        InitializeComponent();

        this.DataContext = new MyTicketsVM();
        this.viewModel.tickets = this.ticketGrid.viewModel.tickets;
    }

    public MyTicketsVM viewModel
    {
        get { return this.DataContext as MyTicketsVM; }
    }
}

public class MyTicketsVM : MyViewModelBase
{
    private QueryableCollectionView _tickets;
    public QueryableCollectionView tickets
    {
        get { return this._tickets; }
        internal set
        {
            this._tickets = value;
            notifyPropertyChanged("tickets");
        }
    }
}

<local:AddressView
    x:Name="addressView"
    currentItem="{Binding ElementName=myTickets,Path=viewModel.tickets.CurrentItem}"
    />

(注意:MyViewModelBase实现了INotifyPropertyChanged)