MVVM 和控件创建

发布于 2024-10-20 02:56:58 字数 268 浏览 0 评论 0原文

想象一个简单的场景,其中包含一个包含按钮和一些空白空间的 WPF 窗口。单击该按钮将创建一个新的自定义/用户控件并将其随机放置在窗口上的某个位置。

单击这些控件之一会将其从窗口中删除。

现在我有一个 ViewModel ala MVVM,它公开了一个用于“创建新”按钮的 ICommand,但是创建新控件的代码在哪里?我猜每个控件可能都有自己的 ViewModel,它将处理其删除和定位。

可以在窗口上没有代码隐藏并且 ViewModel 对视图没有真正了解的情况下实现吗?

Imagine a simple scenario with a WPF window containing a button and some clear space. Clicking the button creates a new custom/user control and places it somewhere randomly on the window.

Clicking one of these controls will remove it from the window.

So now I have a ViewModel ala MVVM which exposes an ICommand for the "create new" button, but where does the code to create the new control live? Each control will probably have its own ViewModel which will handle its deletion and positioning I guess.

Can it be achieved with no code behind on the window AND no real knowledge of the View by the ViewModel?

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

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

发布评论

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

评论(2

千笙结 2024-10-27 02:56:58

导致创建控件的代码位于“主”ViewModel 中。

实际创建控件的代码是容器。

所以它会像这样:

void AddControlCommandExecuted() {
    var container = // resolve your DI container here

    // Now use the container to resolve your "child" view. For example,
    // if using UnityContainer it could go like this:
    var view = container.Resolve<ChildView>();

    // Of course you can also resolve the ViewModel if your program is
    // "ViewModel-first" instead of "View-first".

    // Does the ChildViewModel need some properties to be set?
    var viewModel = (ChildViewModel)view.DataContext;
    viewModel.StringProperty = "blah";

    // Now get a reference to the region in your View which will host
    // the "child" views.
    var regionManager = container.Resolve<IRegionManager>();
    var region = regionManager.Regions["MyRegionName"];

    // Finally add the view to the region. You can do it manually, you
    // can use the concept of "navigation" if your MVVM framework has one
    // (I 'm using Prism, which does), etc etc.
    region.Add(view);
}

更新:在写答案时,我忘记了并非所有 MVVM 框架都像 Prism 那样具有区域。所以请原谅上面代码的特殊性,因为它并没有真正改变任何东西。您只需要自己构建类似 Region 抽象的东西。让我们看看:

class MyViewModel {
    public event EventHandler<ChildViewModelAddedEventArgs> ChildViewModelAdded;
}

MyView 然后会将事件处理程序附加到该事件,并从 ChildViewModelAddedEventArgs 内部获取 ChildView 实例,以便可以添加它到 ItemsControl ,它是父级,而您的 ViewModel 不会弄乱这些细节。

当然,这意味着您现在需要一些代码隐藏,但除非您使用本身提供此类服务的框架,否则这是没有帮助的。

The code that causes the controls to be created lives inside your "main" ViewModel.

The code that actually creates the controls is the container.

So it would go something like:

void AddControlCommandExecuted() {
    var container = // resolve your DI container here

    // Now use the container to resolve your "child" view. For example,
    // if using UnityContainer it could go like this:
    var view = container.Resolve<ChildView>();

    // Of course you can also resolve the ViewModel if your program is
    // "ViewModel-first" instead of "View-first".

    // Does the ChildViewModel need some properties to be set?
    var viewModel = (ChildViewModel)view.DataContext;
    viewModel.StringProperty = "blah";

    // Now get a reference to the region in your View which will host
    // the "child" views.
    var regionManager = container.Resolve<IRegionManager>();
    var region = regionManager.Regions["MyRegionName"];

    // Finally add the view to the region. You can do it manually, you
    // can use the concept of "navigation" if your MVVM framework has one
    // (I 'm using Prism, which does), etc etc.
    region.Add(view);
}

Update: When writing the answer, I forgot that not all MVVM frameworks have Regions as Prism does. So excuse the specificity of the code above, as it doesn't really change anything. You simply need to build something like the Region abstraction yourself. Let's see:

class MyViewModel {
    public event EventHandler<ChildViewModelAddedEventArgs> ChildViewModelAdded;
}

MyView would then attach an event handler to this event, and pick up the ChildView instance from inside ChildViewModelAddedEventArgs so that it can be added to an ItemsControl it is the parent of without your ViewModel messing with such details.

Of course this means that you now need some code-behind, but this cannot be helped unless you are using a framework that provides such services itself.

用心笑 2024-10-27 02:56:58

这应该可以通过在 ItemsControl 上进行一些非常仔细的数据绑定来实现,不确定如何实现布局,但是您将有一个包含子视图模型集合的父视图模型,然后由 ItemsControl 执行布局。当父 ViewModel 创建子 ViewModel 时,它应该注入 RelayCommand 作为 lambda 表达式,以从父集合中删除并清理子 ViewModel。

This SHOULD be doable with some very careful databinding on an ItemsControl, not sure how you would achieve the layout, but you will have a parent view model containing a collection of child view models, layout would then be preformed by the ItemsControl. When the parent ViewModel created the child ViewModel, it should inject a RelayCommand as a lambda expression to remove and cleanup the child ViewModel from the parents collection.

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