设计从外部控件获取其 DataContext 的 WPF UserControl:如何在设计器中拥有一些示例数据但在运行时使用继承的 DC?

发布于 2024-07-24 17:54:00 字数 2102 浏览 5 评论 0原文

我正在设计一个 WPF 用户控件,其中包含其他用户控件(想象一个 WidgetContainer,包含不同的 Widget) - 使用 MV-VM 架构。 在开发过程中,我在窗口中有 WidgetContainerView,窗口(View)生成 WidgetContainerViewModel 作为其资源,并且在 WidgetContainerViewModel 的无参数构造函数中,我用一些示例小部件(WidgetViewModels)填充其公开的集合。

WidgetContainer控件继承了window的DataContext,内部有一个ListView,它将Widgets绑定到WidgetView控件(位于ListView.ItemTemplate内部)。

现在,这在我的 WindowView 中工作正常,正如我看到的示例小部件一样,但是一旦我编辑 WidgetContainerView 或 WidgetView,就没有内容 - 在设计时,控件是独立的,并且它们不继承任何 DataContext,所以我不'看不到内容,并且在设计它们时遇到麻烦(ListView 是空的,Widget 的字段也是如此......)。

我尝试将示例小部件添加到 WidgetView:

public partial class WidgetView : UserControl
{
    public WidgetView()
    {
        InitializeComponent();
        if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
        {
            //btw, MessageBox.Show(...) here sometimes crashes my Visual Studio (2008), but I have seen the message - this code gets executed at design time, but with some lag - I saw the message on reload of designer, but at that time, I have already commented it - wtf?
            this.DataContext = new WidgetViewModel(); //creates sample widget
        }
    }
}

但这不起作用 - 我仍然在设计器中看不到任何内容。

我还想创建一个 WidgetViewModel 作为 WidgetView 中的资源,如下所示:

<UserControl x:Class="MVVMTestWidgetsControl.View.WidgetView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="WidgetViewModel" //this doesn't work!
    Height="Auto" Width="Auto">
    <UserControl.Resources>
        <ResourceDictionary>
            <ViewModel:WidgetViewModel x:Key="WidgetViewModel" />
        </ResourceDictionary>
    </UserControl.Resources>

    <TextBlock Text="{Binding Path=Title}"></TextBlock>

</UserControl>

但我不知道如何将 WidgetViewModel 分配为整个小部件的 DataContext - 我无法将 DataContext 属性添加到 UserControl,因为 WidgetViewModel 是稍后定义的在代码中。 有什么想法如何做到这一点? 我可以通过这种方式使用示例数据,然后在代码中覆盖它,以便它在运行时具有正确的内容...

开发用户控件时,您的最佳实践是什么? 谢谢,设计空控件并不有趣:))。

I am designing a WPF user control which contains other user controls (imagine a WidgetContainer, containing different Widgets) - using M-V-VM architecture.
During development, I have WidgetContainerView in a window, window (View) spawns a WidgetContainerViewModel as its resource, and in a parameterless constructor of WidgetContainerViewModel, I fill its exposed collection with some sample widgets (WidgetViewModels).

WidgetContainer control inherits the DataContext from window, and inside, there is a ListView, that binds Widgets to WidgetView control (which is inside ListView.ItemTemplate).

Now this works OK in my WindowView, as I see my sample widgets, but once I edit the WidgetContainerView or WidgetView, there is no content - at design time, controls are standalone, and they don't inherit any DataContext, so I don't see a content, and have troubles designing them (a ListView is empty, Widget's fields as well...).

I tried adding a sample widget to the WidgetView:

public partial class WidgetView : UserControl
{
    public WidgetView()
    {
        InitializeComponent();
        if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
        {
            //btw, MessageBox.Show(...) here sometimes crashes my Visual Studio (2008), but I have seen the message - this code gets executed at design time, but with some lag - I saw the message on reload of designer, but at that time, I have already commented it - wtf?
            this.DataContext = new WidgetViewModel(); //creates sample widget
        }
    }
}

but that didn't work - I still don't see anything in designer.

I also wanted to create a WidgetViewModel as a resource in WidgetView, like this:

<UserControl x:Class="MVVMTestWidgetsControl.View.WidgetView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="WidgetViewModel" //this doesn't work!
    Height="Auto" Width="Auto">
    <UserControl.Resources>
        <ResourceDictionary>
            <ViewModel:WidgetViewModel x:Key="WidgetViewModel" />
        </ResourceDictionary>
    </UserControl.Resources>

    <TextBlock Text="{Binding Path=Title}"></TextBlock>

</UserControl>

but I don't know how to assign a WidgetViewModel as a DataContext of a whole widget - I can't add DataContext attribute to UserControl, because WidgetViewModel is defined later in the code. Any ideas how to do this? I could use a sample data this way, and just override it in code so that it has the right content at runtime...

What are your best practices when developing user controls? Thank you, designing empty control is no fun :)).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(2

紅太極 2024-07-31 17:54:00

在第二个代码片段中,您应该能够将 DataContext 作为 DynamicResource 引用:

DataContext="{DynamicResource WidgetViewModel}"

但是大多数自定义用户控件都有某种顶级布局容器,并且您可以将该容器上的 DataContext 设置为 StaticResource。

但是,就您的情况而言,您可能需要考虑完全删除代码的 VM 部分,因为您正在编写自定义 UserControl。 您应该问自己,您从完全独立的 ViewModel 中获得了哪些好处,而没有为一个视图(即自定义 UserControl)设计的真正支持模型。 也许您可以定义一些 DependencyProperties 并使用它们?

In your second snippet, you should be able to refer to your DataContext as a DynamicResource:

DataContext="{DynamicResource WidgetViewModel}"

But most custom user controls have some sort of top level layout container, and you can set the DataContext on that container as a StaticResource.

In your case, however, you may want to consider dropping the VM portion of your code altogether since you're writing a custom UserControl. You should ask yourself what benefits are you gaining from a completely self-contained ViewModel with no real backing Model designed for just one View (i.e. the custom UserControl). Perhaps you could just define some DependencyProperties and use those?

ゞ记忆︶ㄣ 2024-07-31 17:54:00

我想出了几个解决方案: 添加 DC 作为资源(它将使用无参数构造函数自动实例化),并在 View 的代码隐藏中执行以下操作:

    public PanelView()
    {
        InitializeComponent();

        if (!DesignerProperties.GetIsInDesignMode(new DependencyObject())) //DeleteAtRelease:
        {
            //we are in runtime, reset DC to have it inherited
            this.DataContextHolder.DataContext = DependencyProperty.UnsetValue;
        }

    }

更好的方法是仅在设计时分配 DC,但 VS 不喜欢它 - 它只是有时起作用,并且非常不确定,甚至有一次它崩溃了。

设计时间的其他检查是:

        if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
        {
            this.DataContext = new WidgetViewModel();
        }

I came up with several solutions: Add DC as resource (it will get automatically instantiated with parameterless constructor), and do the following in View's codebehind:

    public PanelView()
    {
        InitializeComponent();

        if (!DesignerProperties.GetIsInDesignMode(new DependencyObject())) //DeleteAtRelease:
        {
            //we are in runtime, reset DC to have it inherited
            this.DataContextHolder.DataContext = DependencyProperty.UnsetValue;
        }

    }

Better way would be to only assign DC if we are at designtime, but VS didn't like it - it worked only sometimes, and quite nondeterministically, and once it even crashed.

Other check for design time is:

        if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
        {
            this.DataContext = new WidgetViewModel();
        }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文