wpf 用户控件模板

发布于 2024-11-05 21:09:02 字数 3186 浏览 2 评论 0原文

在我的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

海的爱人是光 2024-11-12 21:09:02

您需要做的是明确指定要使用的数据模板。为此,只需在预览控件中添加模板属性和 PreviewObject 属性:

public static readonly DependencyProperty _previewObjectTemplateProperty =
    DependencyProperty.Register("PreviewObjectTemplate", typeof(DataTemplate), typeof(ObjectPreview));

  public DataTemplate PreviewObjectTemplate
  {
   get { return (DataTemplate)GetValue(_previewObjectTemplateProperty); }
   set { SetValue(_previewObjectTemplateProperty, value); }
  }

然后,在 ObjectPreview.xaml 中添加 ContentTemplate 绑定到 PreviewObjectTemplate 属性的属性:

<Viewbox Grid.Row="1" Name="treeviewViewBox" 
         Stretch="Uniform"
         IsEnabled="False">    
    <ContentControl Name="treeViewItemViewModel"
                    Content="{Binding PreviewObject}"
                    ContentTemplate="{Binding PreviewObjectTemplate}" >
    </ContentControl>
</Viewbox>

最后,为数据模板提供一个键,并在声明 ObjectPreview 时显式指定对其的引用:

<DataTemplate x:Key="FullViewTemplate" DataType="{x:Type vm:TrialSiteViewModel}">
   <vw:TrialSiteView />
</DataTemplate>

...

<ToolTip Style="{x:Null}">
 <ToolTip.ContentTemplate>
  <DataTemplate>          
   <localtools:ObjectPreview 
    PreviewObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}, Path=DataContext}"
    PreviewObjectTemplate="{StaticResource FullViewTemplate}"
   />          
  </DataTemplate>
 </ToolTip.ContentTemplate>

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:

public static readonly DependencyProperty _previewObjectTemplateProperty =
    DependencyProperty.Register("PreviewObjectTemplate", typeof(DataTemplate), typeof(ObjectPreview));

  public DataTemplate PreviewObjectTemplate
  {
   get { return (DataTemplate)GetValue(_previewObjectTemplateProperty); }
   set { SetValue(_previewObjectTemplateProperty, value); }
  }

Then, in the ObjectPreview.xaml add the ContentTemplate property that is bound to the PreviewObjectTemplate property:

<Viewbox Grid.Row="1" Name="treeviewViewBox" 
         Stretch="Uniform"
         IsEnabled="False">    
    <ContentControl Name="treeViewItemViewModel"
                    Content="{Binding PreviewObject}"
                    ContentTemplate="{Binding PreviewObjectTemplate}" >
    </ContentControl>
</Viewbox>

And finally, give a key to your data template and specify a reference to it explicitly when you declare ObjectPreview:

<DataTemplate x:Key="FullViewTemplate" DataType="{x:Type vm:TrialSiteViewModel}">
   <vw:TrialSiteView />
</DataTemplate>

...

<ToolTip Style="{x:Null}">
 <ToolTip.ContentTemplate>
  <DataTemplate>          
   <localtools:ObjectPreview 
    PreviewObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}, Path=DataContext}"
    PreviewObjectTemplate="{StaticResource FullViewTemplate}"
   />          
  </DataTemplate>
 </ToolTip.ContentTemplate>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文