【问题标题】:Binding to properties of a control, after moving them into a UserControl在将控件的属性移动到 UserControl 之后绑定到控件的属性
【发布时间】:2012-10-15 16:24:40
【问题描述】:

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

例如在我的窗口中,我有一个网格。在 Grid 的一个单元格中,我有 StackPanel,其中包含两个自定义 UserControl:

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

在网格的另一个单元格中,我有另一个自定义用户控件,它绑定到网格中的当前项:

<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>

然后在网格中,我将 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 不存在。

我不知道为什么。

【问题讨论】:

  • 尝试:ElementName=myTickets.tickets 我不确定它是否有效,但值得一试
  • 给出一个不同的错误:“找不到与引用'ElementName = myTickets.ticketGrid'绑定的源” - 这是我所期望的。

标签: wpf xaml binding


【解决方案1】:

尝试:

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

和:

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

好的,所以这不起作用..

执行以下操作:

在你的 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 }" />

【讨论】:

  • 该绑定正在主窗口中查找名为“ticketGrid”的元素,但没有这样的元素 - 它已在 MyTickets 控件中移动。
  • 我尝试在 MyTickets.xaml 中设置 Tag 元素 - 这给了我“找不到与引用 'ElementName=ticketGrid' 绑定的源。”
  • 看起来它正在尝试通过绑定 MyTickets 控件上的 MyProperty 来填充 ticketGrid 上的 YourProperty 属性。而这恰恰相反。
【解决方案2】:

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

  • 创建一个视图模型类,并将它的一个实例设置为控件的 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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多