【发布时间】:2015-11-04 19:38:10
【问题描述】:
我有一个自定义向导控件 WizardControl 派生自 UserControl,它有一个名为 Pages 的依赖属性,我的自定义类集合的数据类型名为 WizardPageCollection。
WizardControl 托管在 Window 中,视图模型名为 MainViewModel,向导页面使用 XAML 实例化。
我正在尝试将页面绑定到子视图模型 Page1VM 和 Page2VM 声明为 MainViewModel 上的属性。
DataContext 到 Page1VM 的第一页绑定工作正常,但是第二页的绑定失败并显示以下错误消息:
System.Windows.Data Error: 3 : Cannot find element that provides DataContext. BindingExpression:Path=Page2VM; DataItem=null; target element is 'MyPage' (Name=''); target property is 'DataContext' (type 'Object')
问。为什么绑定在第一页上工作,但在第二页上失败,有没有办法让这个工作,同时仍然保持在 DataContext 的 MainWindow 的 DataContext XAML 标记中声明的 MainViewModel?我不希望将 ViewModel 用作字典资源,因为这对我们有一些影响,我不会详细说明。
根据评论员的建议,如果我将绑定更改为使用 RelativeSource,如下所示:
<common:MyPage DataContext="{Binding DataContext.Page1VM, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
<common:MyPage DataContext="{Binding DataContext.Page2VM, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
第一个绑定工作正常,但第二个仍然失败,但出现不同的错误消息(如预期的那样):
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''. BindingExpression:Path=DataContext.Page2VM; DataItem=null; target element is 'MyPage' (Name=''); target property is 'DataContext' (type 'Object')
感谢您的宝贵时间!
我的代码清单如下所示:
主窗口 XAML:
<Window.DataContext>
<common:MainViewModel />
</Window.DataContext>
<Grid>
<common:WizardControl>
<common:WizardControl.Pages>
<common:WizardPageCollection>
<common:MyPage DataContext="{Binding Page1VM}" />
<common:MyPage DataContext="{Binding Page2VM}" />
</common:WizardPageCollection>
</common:WizardControl.Pages>
</common:WizardControl>
</Grid>
MainViewModel 和 PageViewModel:
public class MainViewModel
{
public PageViewModel Page1VM
{
get;
set;
}
public PageViewModel Page2VM
{
get;
set;
}
public MainViewModel()
{
this.Page1VM = new PageViewModel("Page 1");
this.Page2VM = new PageViewModel("Page 2");
}
}
public class PageViewModel
{
public string Title { get; set; }
public PageViewModel(string title) { this.Title = title; }
}
WizardControl XAML:
<Grid>
<ContentPresenter Grid.Row="0" x:Name="contentPage"/>
</Grid>
WizardControl 代码隐藏:
public partial class WizardControl : UserControl
{
public WizardControl()
{
InitializeComponent();
}
public WizardPageCollection Pages
{
get { return (WizardPageCollection)GetValue(PagesProperty); }
set { SetValue(PagesProperty, value); }
}
public static readonly DependencyProperty PagesProperty =
DependencyProperty.Register("Pages", typeof(WizardPageCollection), typeof(WizardControl), new PropertyMetadata(new WizardPageCollection(), new PropertyChangedCallback(Pages_Changed)));
static void Pages_Changed(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
WizardPageCollection col = e.NewValue as WizardPageCollection;
WizardControl ctrl = obj as WizardControl;
ctrl.contentPage.Content = col.First();
}
}
public class WizardPageCollection : ObservableCollection<WizardPageBase> { }
public class WizardPageBase : ContentControl { }
我的页面 XAML:
<Grid>
<Label Content="{Binding Title}" />
</Grid>
【问题讨论】:
-
对我来说看起来不错。您是否尝试过使用
RelativeSource绑定来绑定到Window? -
@Mike 是的,我已将 DataContext 绑定更改为使用 RelativeSource(第一个页面绑定工作正常,但第二个页面绑定仍然失败,但错误消息略有不同)。我已经更新了帖子以反映这一点。
-
源文件可以在 GitHub 找到:github.com/dotnetdeveloper53/WizardControlBinding
-
你有在 WizardControl 中切换页面的代码吗?
-
我没有提供此代码,因为我觉得这与绑定问题无关。但是,当我更改向导上的“当前页面”(只需设置
contentPage.Content = newPage)时,该新页面上的DataContext设置为NULL- 这在绑定失败时是有意义的。
标签: wpf xaml contentcontrol contentpresenter