<UserControl x:Class="ControlsLibrary.RecordingListControl"
...
x:Name="parent"
d:DesignHeight="300" d:DesignWidth="300">
<Grid >
<StackPanel Name="LayoutRoot">
<ListBox ItemsSource="{Binding ElementName=parent,Path=Recordings}" Height="100" Margin="5" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=FullDirectoryName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Grid>
在代码后台(如果有避免代码后台的方法,请告诉我)...
public partial class RecordingListControl : UserControl
{
private RecordingListViewModel vm = new RecordingListViewModel();
public RecordingListControl()
{
InitializeComponent();
// I have tried the next two lines at various times....
// LayoutRoot.DataContext = vm;
//DataContext = vm;
}
public static FrameworkPropertyMetadata md = new FrameworkPropertyMetadata(new PropertyChangedCallback(OnPatientId));
// Dependency property for PatientId
public static readonly DependencyProperty PatientIdProperty =
DependencyProperty.Register("PatientId", typeof(string), typeof(RecordingListControl), md);
public string PatientId
{
get { return (string)GetValue(PatientIdProperty); }
set { SetValue(PatientIdProperty, value);
//vm.SetPatientId(value);
}
}
// this appear to allow us to see if the dependency property is called.
private static void OnPatientId(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
RecordingListControl ctrl = (RecordingListControl)d;
string temp = ctrl.PatientId;
}
在我的ViewModel中,我有以下内容:
public class RecordingListViewModel : ViewModelBase
{
private ObservableCollection<RecordingInfo> _recordings = null;// = new ObservableCollection<string>();
public RecordingListViewModel()
{
}
public ObservableCollection<RecordingInfo> Recordings
{
get
{
return _recordings;
}
}
public void SetPatientId(string patientId)
{
// bunch of stuff to fill in _recordings....
OnPropertyChanged("Recordings");
}
}
然后我将这个控件放在我的主窗口中,像这样:
<Grid>
<ctrlLib:RecordingListControl PatientId="{Binding PatientIdMain}" SessionId="{Binding SessionIdMain}" />
<Label Content="{Binding PatientIdMain}" /> // just to show binding is working for non-controls
</Grid>
当我运行所有内容时,我收到的错误信息是:
System.Windows.Data Error: 40 : BindingExpression path error: 'Recordings' property not found on 'object' ''RecordingListControl' (Name='parent')'. BindingExpression:Path=Recordings; DataItem='RecordingListControl' (Name='parent'); target element is 'ListBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
很明显我有某种绑定问题。这比我之前遇到的问题要深入得多。至少我正在访问控件代码后台中的OnPatientId:
在此之前,我在用户控件中没有ElementName,并且正在使用DataContext,但是出现了绑定错误,指示PatientIdMain被视为用户控件的成员。
有人能给我指出一个在MVVM应用程序中使用MVVM设计的用户控件示例吗?我认为这是一个相当常见的模式。
如果需要更多细节,请告诉我。
非常感谢, Dave 编辑1 我尝试了har07的想法(请参见其中一个答案)。我得到了:如果我尝试:
ItemsSource="{Binding ElementName=parent,Path=DataContext.Recordings}"
我明白了
System.Windows.Data Error: 40 : BindingExpression path error: 'Recordings' property not found on 'object' ''MainViewModel' (HashCode=59109011)'. BindingExpression:Path=DataContext.Recordings; DataItem='RecordingListControl' (Name='parent'); target element is 'ListBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
如果我尝试:
ItemsSource="{Binding Recordings}"
我明白了
System.Windows.Data Error: 40 : BindingExpression path error: 'Recordings' property not found on 'object' ''MainViewModel' (HashCode=59109011)'. BindingExpression:Path=Recordings; DataItem='MainViewModel' (HashCode=59109011); target element is 'ListBox' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
我认为他的第一个想法(也许是第二个)非常接近,但请记住,Recordings在ViewModel中定义,而不是视图中。我需要以某种方式告诉XAML使用viewModel作为源。这就是设置DataContext所做的事情,但正如我在主要部分中所说的那样,这会在其他地方创建问题(您会得到与从MainWindown到控件属性的绑定相关的绑定错误)。
编辑2.如果我尝试har07的第一个建议:
ItemsSource="{Binding ElementName=parent,Path=DataContext.Recordings}"
并在控件的代码后台添加以下代码:
RecordingListViewModel vm = new RecordingListViewModel();
DataContext = vm;
I get:
System.Windows.Data Error: 40 : BindingExpression path error: 'PatientIdMain' property not found on 'object' ''RecordingListViewModel' (HashCode=33515363)'. BindingExpression:Path=PatientIdMain; DataItem='RecordingListViewModel' (HashCode=33515363); target element is 'RecordingListControl' (Name='parent'); target property is 'PatientId' (type 'String')
换句话说,控件看起来没问题,但是依赖属性与主窗口的绑定似乎出了问题。编译器假设PatientIdMain是RecordingListViewModel的一部分。
一些帖子表明我不能为此设置DataContext。这将会破坏与主窗口的绑定。例如,请参见: Binding to a dependency property of a user control WPF/XAML 并查看Marc的答案。