2012-10-18 76 views
0

我正在使用MVVM模式实现WPF应用程序。将viewmodel中的变量绑定到另一个视图模型中的另一个变量

该应用程序基本上是一个通讯面板(通讯面板),其上放置了控件(例如拨号盘,对讲线等)。控件小部件也使用MVVM模式实现,因为这使我们可以轻松测试它们。

我有这样的“拨号盘”控制小部件,它暴露了它的视图模型一个DialedNumber公共领域:

public string DialedNumber 
    { 
     get { return _dialPadModel.DialedNumber; } 
     set 
     { 
      _dialPadModel.DialedNumber = value; 
      RaisePropertyChanged("DialedNumber"); 
     } 
    } 

的“拨号盘”控制部件也可以通过在公共领域公开其视图模型观点:

public DialPadViewModel DialPadViewModel 
    { 
     get { return DataContext as DialPadViewModel; } 
    } 

而且它也暴露出它通过其观点,这只是写入/读取来自公共领域的视图模型:

public string DialedNumber 
    { 
     get 
     { 
      return DialPadViewModel.DialedNumber; 
     } 
     set 
     { 
      DialPadViewModel.DialedNumber = value; 
     } 
    } 

拨号盘被放置在一个通讯科面板(也使用MVVM实现),该公司在其视图模型DialedPABXNumber公共领域:

public string DialedPABXNumber 
    { 
     get { return _dialedPABXNumber; } 
     set 
     { 
      _dialedPABXNumber = value; 
      OnPropertyChanged("DialedPABXNumber"); 
     } 
    } 

现在,我希望能够给DialedNumber字段从机按键链接到comms面板中的DialedPABXNumber字段。但是,为了达到这个目的,我正在努力寻找正确的XAML语法。我的做法是这样的:

<PanelControls:DialPad x:Name="MyDialPad2" DialPadViewModel.DialedNumber="{Binding Path=CommsPanelViewModel.DialedPABXNumber, Mode=OneWayToSource}"/> 

通过这样做,我得到一个运行时异常加载通讯科面板XAML时。更具体地讲:

无法设置未知成员 '{http://schemas.microsoft.com/winfx/2006/xaml/presentation}DialPadModel.DialedNumber'。

如何在XAML中指定我想要访问DialPadViewModel.DialedNumber?

编辑:添加有关组件如何配合在一起的背景信息。应用程序的主窗口有两个子窗口:左侧的控制面板和适当的通讯面板,该面板是动态加载的。

<Window x:Class="Comms.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:Views="clr-namespace:Comms.View" 
    xmlns:ViewModel="clr-namespace:Comms.ViewModel" 
    Title="Comms" Height="350" Width="525" Closing="WindowClosing"> 
<Window.Resources> 
    <DataTemplate x:Name="CommsControlPanelViewModel" DataType="{x:Type ViewModel:CommsControlPanelViewModel}"> 
     <Views:CommsControlPanelView x:Name="CommsControlPanelView"/> 
    </DataTemplate> 
    <DataTemplate x:Name="CommsPanelViewModel" DataType="{x:Type ViewModel:CommsPanelViewModel}"> 
     <Views:CommsPanelView x:Name="CommsPanelView"/> 
    </DataTemplate> 
</Window.Resources> 

<StackPanel x:Name="Layout" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Orientation="Horizontal"> 
    <ContentControl Content="{Binding CommsControlPanelView}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" /> 
    <ContentControl Content="{Binding CommsPanelView}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" /> 
</StackPanel> 

的通讯科面板是动态加载。下面是该面板的XAML文件:

<Border x:Name="CommsPanelBorder" 
    Style="{DynamicResource BorderTemplate}" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:PanelControls="clr-namespace:CommsPanelControlsLib.View;assembly=CommsPanelControlsLib" 
    VerticalAlignment="Top"> 
<StackPanel> 
    <!-- PABX Dial Pad --> 
    <StackPanel Orientation="Horizontal"> 
    <PanelControls:DialPad x:Name="MyDialPad2" DialPadViewModel.DialedNumber="{Binding Path=CommsPanelViewModel.DialedPABXNumber, Mode=OneWayToSource}"/> 
    </StackPanel> 
</StackPanel> 

+0

DialedNumber是一个依赖对象吗? – Blachshma

+0

看来你试图直接在你的控件上访问你的ViewModel属性之一“DialPadModel.DialedNumber”,这是不对的。您将需要PanelControls:DialPad上的依赖项属性。在你的文章中不太清楚什么是model/viewModel/view(我可能对widget有不同的语义))。请澄清什么是Model/ViewModel/View :) – Sisyphe

+0

@Blachshma不,它只是视图模型中的一个公共访问器。请注意,我忘记说我在视图的代码隐藏文件中也有一个DialedNumber公共字段,但它只是从视图模型的DialedNumber字段读取/写入。让我编辑我的原始帖子,以便清楚说明。 – Nacho1984

回答

0

经过与Blachshma的长时间聊天(感谢Blachshma!),我修改了DialPad代码,删除了它的模型,并将viewmodel中的代码移动到其后面的代码中。

结合我在面板的XAML文件中使用如下:

<PanelControls:DialPad x:Name="MyDialPad2" DialedNumber="{Binding Path=CommsPanelViewModel.DialedPABXNumber, Mode=OneWayToSource, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"/> 

我可以证实,点击拨号键盘的按键有效触发CommsPanelViewModel内的DialedPABXNumber场中的变化,这是我想要的。但是,为了做到这一点,我在DialPad的代码中做了一些大的修改,现在我无法对它进行单元测试。我会将问题标记为已回答,并且我将开放一个新问题以解决这个新问题。

谢谢大家的意见!

0

绑定到一个属性,这个属性是一个DependencyProperty。你可以做一个假人,物业在你浏览一个经过PropertyChangedCallback操纵您的视图模型:

public static DependencyProperty TestProperty = DependencyProperty.Register("Test", typeof(string), typeof(View), new PropertyMetadata("default", new PropertyChangedCallback(TestPropertyChanged))); 
public string Test 
{ 
    get { return GetValue(TestProperty).ToString(); } 
    set { SetValue(TestProperty, value); } 
} 
public static void TestPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
{ 
    ViewModel vm= ((View)obj).DataContext; 
    if (vm.Test != e.NewValue.ToString()) 
    { 
     vm.Test = e.NewValue.ToString(); 
    } 
} 

现在可以绑定到这个属性在您的视图。

但我认为这违反了MVVM模式,不是吗?

+0

是的,这是我根据Blachshma的建议采取的方法。说实话,我不确定它是否违反了MVVM模式。 – Nacho1984

1

我有点困惑你想要做什么,但它听起来像你想在另一个对象

首先从一个对象的属性绑定到一个属性,有两个属性类型:常规属性和依赖属性。如果要使用绑定来设置属性,则它必须是DependencyProperty,因此DialPadViewModel.DialedNumber必须是依赖项属性(如果值将由绑定提供)。

其次,您的实际绑定尝试引用CommsPanelViewModel.DialedPABXNumber。这实际上会绑定到MyDialPad2.DataContext.CommsPanelViewModel.DialedPABXNumber,我认为如果我正确理解您的代码,它不是一个有效的属性。

我想你要做的是找到CommsPanelViewModel这是DataContext为CommsPanelView,并绑定到它的DialedPABXNumber属性。

要做到这一点,首先需要更改绑定的源通过任一RelativeSourceElementName结合找到你CommsPanelView,你需要设置PathDataContext.DialedPABXNumber,因为DataContextCommsPanelViewCommsPanelViewModel,和该视图模型的财产DialedPABXNumber

<PanelControls:DialPad x:Name="MyDialPad2" DialPadViewModel.DialedNumber="{Binding ElementName=CommsPanelView, Path=DataContext.DialedPABXNumber, Mode=OneWayToSource}"/> 

这么说,我还不能肯定,你就可以找到CommsPanelView与使用当前的XAML布局,由于涉及到的模板结合。尝试一下,但如果不是这样的话,你仍然有几个选择可供你选择。

你可以尝试保存你在未使用的依赖项属性所需要的性能,如Tag财产,那么你可以使用一个RelativeSourceElementName财产找到ContentControl中并绑定到其Tag财产

<ContentControl Content="{Binding CommsControlPanelView}" Tag="{Binding CommsPanelView.DialedPABXNumber}" /> 

你也可以使用MVVM Light的Messenger或Prism的EventAggregator等消息系统来传递价值。 (我有这些的小结中an article on my blog

或者你可以在视图模型层连接的两个属性,所以CommsControlPanelViewModel包含存储CommsViewModel.DialedPABXNumber一个属性,并从视图模型层本身需要时该属性得到更新。

相关问题