wpf 用户控件模板
在我的 MVVM 应用程序中,我有一个代表数据库中记录的树视图。我的视图和视图模型在资源字典中链接,如下所示
<DataTemplate DataType="{x:Type vm:TrialSiteViewModel}">
<vw:TrialSiteView />
</DataTemplate>
我想在用户将鼠标悬停在使用工具提示的图标上时显示视图的预览。我在树视图中的 HierarchicalDataTemplate 是这样的
<HierarchicalDataTemplate DataType="{x:Type vm:TrialSiteViewModel}"
ItemsSource="{Binding Path=Children}">
...
<Button Style="{StaticResource previewButtonStyle}">
<Button.ToolTip>
<ToolTip Style="{x:Null}">
<ToolTip.ContentTemplate>
<DataTemplate>
<localtools:ObjectPreview
PreviewObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}, Path=DataContext}"
/>
</DataTemplate>
</ToolTip.ContentTemplate>
</ToolTip>
</Button.ToolTip>
</Button>
</StackPanel>
</HierarchicalDataTemplate>
这正确地选择了 TrialSiteViewModel,它是 Treeviewitem 的 DataContext。
ObjectPreview 使用视图框和内容控件来显示记录的视图
<Viewbox Grid.Row="1" Name="treeviewViewBox"
Stretch="Uniform"
IsEnabled="False">
<ContentControl Name="treeViewItemViewModel"
Content="{Binding PreviewObject}">
</ContentControl>
</Viewbox>
,后面的代码包含依赖属性
public partial class ObjectPreview : UserControl
{
public ObjectPreview()
{
InitializeComponent();
}
public static readonly DependencyProperty _previewObjectProperty =
DependencyProperty.Register("PreviewObject", typeof(TreeViewItemViewModel), typeof(ObjectPreview));
public TreeViewItemViewModel PreviewObject
{
get { return (TreeViewItemViewModel)GetValue(_previewObjectProperty); }
set { SetValue(_previewObjectProperty, value); }
}
}
我遇到的问题是用于显示对象的模板与树视图中使用的模板相同。这仅显示一个图标和一个对象摘要(即主键和一个或两个关键字段),而不是视图 TrialSiteView 中定义的整个模板。如果我修改代码以在 TrialSiteViewModel 上使用按钮命令并将其注入 ObjectPreview 中,我可以在后面的代码中设置内容控件并使用 TrialSiteView。
我猜测 Template 是从 TreeViewItem 中推断出来的。谁能告诉我如何确保工具提示使用 TrialSiteView?
更新
好的,所以我已经解决了这个问题,但不得不诉诸代码隐藏并删除用户控件并将视图直接放在工具提示中。关键是从资源中获取数据模板。我之前曾尝试通过为数据模板分配一个键来做到这一点,但要么我的代码有缺陷,要么它不起作用。无论如何,这可以工作,但不是首选的 Xaml 解决方案。
private void PreviewObject_MouseEnter(object sender, MouseEventArgs e)
{
Image image = (Image)sender;
var key = new System.Windows.DataTemplateKey(image.DataContext.GetType());
var datatemplate = (DataTemplate)this.FindResource(key);
ToolTip tooltip = new ToolTip();
tooltip.Style = VisualUtils.GetResource<Style>("ControlTemplates.xaml", "toolTipWithContentStyle");
tooltip.MaxWidth = 460;
ContentControl contentcontrol = new ContentControl();
contentcontrol.ContentTemplate = datatemplate;
contentcontrol.Content = image.DataContext as TreeViewItemViewModel;
Viewbox viewbox = new Viewbox();
viewbox.Stretch = Stretch.Uniform;
viewbox.Child = contentcontrol;
tooltip.Content = viewbox;
image.ToolTip = tooltip;
}
In my MVVM app I have a treeview representing records in a database. My views and viewmodels are linked in a resource dictionary like this
<DataTemplate DataType="{x:Type vm:TrialSiteViewModel}">
<vw:TrialSiteView />
</DataTemplate>
I want to display a preview of the view when a user hovers over an icon using the tooltip. My HierarchicalDataTemplate in the treeview is this
<HierarchicalDataTemplate DataType="{x:Type vm:TrialSiteViewModel}"
ItemsSource="{Binding Path=Children}">
...
<Button Style="{StaticResource previewButtonStyle}">
<Button.ToolTip>
<ToolTip Style="{x:Null}">
<ToolTip.ContentTemplate>
<DataTemplate>
<localtools:ObjectPreview
PreviewObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}, Path=DataContext}"
/>
</DataTemplate>
</ToolTip.ContentTemplate>
</ToolTip>
</Button.ToolTip>
</Button>
</StackPanel>
</HierarchicalDataTemplate>
This correctly picks up the TrialSiteViewModel that is the DataContext for the Treeviewitem.
ObjectPreview uses a viewbox and contentcontrol to display the view of the record
<Viewbox Grid.Row="1" Name="treeviewViewBox"
Stretch="Uniform"
IsEnabled="False">
<ContentControl Name="treeViewItemViewModel"
Content="{Binding PreviewObject}">
</ContentControl>
</Viewbox>
and the code behind contains the dependency property
public partial class ObjectPreview : UserControl
{
public ObjectPreview()
{
InitializeComponent();
}
public static readonly DependencyProperty _previewObjectProperty =
DependencyProperty.Register("PreviewObject", typeof(TreeViewItemViewModel), typeof(ObjectPreview));
public TreeViewItemViewModel PreviewObject
{
get { return (TreeViewItemViewModel)GetValue(_previewObjectProperty); }
set { SetValue(_previewObjectProperty, value); }
}
}
The problem I'm having is that the Template used to display the object is the same as that used in the treeview. This simply shows an icon and an object summary (ie. Primary Key and one or two key fields) rather than the entire template as defined in the view TrialSiteView. If I amend the code to use a button Command on the TrialSiteViewModel and inject it into ObjectPreview I can set the contentcontrol in the code behind and the TrialSiteView is used.
I'm guessing that somehow the Template is inferred from the TreeViewItem. Can anyone tell me how I can ensure the tooltip uses the TrialSiteView?
UPDATE
Ok, so I've fixed this but had to resort to code behind and removed the usercontrol and put the view directly in the tooltip. The key bit is getting the datatemplate from the resources. I'd tried to do this previously by assigning a key to the datatemplate, but either my code was flawed or it did not work. Anyhow, this works but is not the preferred Xaml solution.
private void PreviewObject_MouseEnter(object sender, MouseEventArgs e)
{
Image image = (Image)sender;
var key = new System.Windows.DataTemplateKey(image.DataContext.GetType());
var datatemplate = (DataTemplate)this.FindResource(key);
ToolTip tooltip = new ToolTip();
tooltip.Style = VisualUtils.GetResource<Style>("ControlTemplates.xaml", "toolTipWithContentStyle");
tooltip.MaxWidth = 460;
ContentControl contentcontrol = new ContentControl();
contentcontrol.ContentTemplate = datatemplate;
contentcontrol.Content = image.DataContext as TreeViewItemViewModel;
Viewbox viewbox = new Viewbox();
viewbox.Stretch = Stretch.Uniform;
viewbox.Child = contentcontrol;
tooltip.Content = viewbox;
image.ToolTip = tooltip;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您需要做的是明确指定要使用的数据模板。为此,只需在预览控件中添加模板属性和
PreviewObject
属性:然后,在
ObjectPreview.xaml
中添加ContentTemplate
绑定到PreviewObjectTemplate
属性的属性:最后,为数据模板提供一个键,并在声明
ObjectPreview
时显式指定对其的引用:...
What you need to do is to specify explicitly what data template to use. In order to do that just add a template property along with the
PreviewObject
property in the preview control:Then, in the
ObjectPreview.xaml
add theContentTemplate
property that is bound to thePreviewObjectTemplate
property:And finally, give a key to your data template and specify a reference to it explicitly when you declare
ObjectPreview
:...