Prism MVVM WPF 如何将自定义 UserControl 按钮单击命令绑定到 UC 父视图模型

问题描述 投票:0回答:2

我有一个包含按钮、标签和文本框的自定义控件。此用户控件正在另一个具有 ViewModel 的视图中使用。我想将自定义控件中的单击事件处理程序绑定到 viewModel 中的命令。

视图的代码:

    public partial class ViewPage : UserControl
    {
        public ViewPage()
        {
            InitializeComponent();
        }

        private void CustomControl_RestartClick(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("clicked");

        }
    }
}

自定义用户控件的代码:

public partial class CustomControl : UserControl
{

    // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty TitleProperty =
        DependencyProperty.Register("Title", typeof(string), typeof(CustomControl), new PropertyMetadata(String.Empty));



    public string Title
    {
        get { return (string)GetValue(TitleProperty); }
        set { SetValue(TitleProperty, value); }
    }



    public static readonly RoutedEvent RestartClickEvent = EventManager.RegisterRoutedEvent(nameof(RestartClick), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(CustomControl));

    public event RoutedEventHandler RestartClick
    {
        add { AddHandler(RestartClickEvent, value); }
        remove { RemoveHandler(RestartClickEvent, value); }
    }

    public CustomControl()
    {
        InitializeComponent();
    }

    public void OnRestartClick(object sender, RoutedEventArgs e)
    {
        RaiseEvent(new RoutedEventArgs(RestartClickEvent));
    }
}

我在 ViewModel 中有这个命令,我想将其绑定到:

public ICommand RestartCommand { get; private set; }

我希望能够做一些类似的事情

<views:CustomControl Title="PS04-04"  RestartClick="{Binding RestartCommand}" />

c# wpf mvvm user-controls
2个回答
0
投票

您需要一个接受 ICommand 的依赖属性。

public static readonly DependencyProperty FooCommandProperty =
  DependencyProperty.Register(nameof(FooCommand), typeof(ICommand), typeof(CustomControl));
public ICommand FooCommand
{
  get => (ICommand)GetValue(FooCommandProperty);
  set => SetValue(FooCommandProperty, value);
}

然后,在用户控件中的某个位置(可能在事件处理程序中),您需要在发生某些情况时执行该命令。

if(FooCommand != null && FooCommand.CanExecute(fooParameter))
{
  FooCommand.Execute(fooParameter);
}

一旦所有这些都准备就绪,您只需将 ICommand 绑定到该属性即可。


0
投票

从您的解释和代码来看,我认为问题很可能是由于不同布局级别的数据上下文混乱造成的。

<views:ConveyorControl
声明级别,您期望数据上下文中存在
DesignMCP06PageViewModel
的实例。但在运行时,事实上,数据上下文中有一个
MainWindowViewModel
的实例,它不具有
RestartCommand
属性。

在不完全了解您的任务及其执行条件的情况下,我无法给出适合您的解决方案的准确答案。因此,我将建议 WPF 中使用的常用方法之一。如果它不适合您,请更详细地描述您的任务,如果您将解决方案上传到 GitHub 存储库并提供指向它的链接,那就更好了。

创建定位器。
这只是一个容器,其中包含需要在不同布局级别使用的各种数据的属性。大多数情况下,定位器属性是 ViewModel 的单独实例。在最简单的情况下(当属性在应用程序启动时初始化一次,必须在第一次调用定位器之前),不需要在定位器中实现 INotifyPropertyChanged 接口。

    public class Locator
    {
        public MainWindowViewModel MainVM { get; set; } = new();
        public DesignMCP06PageViewModel MCP06_VM { get; set; } = new();
    }

您在应用程序资源中声明定位器的实例。

    <Application.Resources>
        <somens:Locator x:Key="locator"/>

访问定位器属性:

<Window x:Class="-------------.MainWindow"
        ----------------------------------
        DataContext="{Binding MainVM, Source={StaticResource locator}}">
    <Grid>

        <views:ConveyorControl x:Name="binding"
                               Title="PS04-04"
                               RestartCommand="{Binding MCP06_VM.RestartCommand,
                                                        Source={StaticResource locator}}"/>
        
    </Grid>
</Window>

P.S. 答案不相关,因为经过额外澄清并查看 GitHub 上的解决方案后,结果发现使用 Prism 包进行视图切换。本质上,作者的问题归结为如何正确使用Prism。

© www.soinside.com 2019 - 2024. All rights reserved.