MVVM 主窗口控件从子用户控件绑定 [英] MVVM Main window control bind from child user control

查看:23
本文介绍了MVVM 主窗口控件从子用户控件绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对 MVVM 非常陌生,现在正在完成我的第一个 POC.但是,我一直在努力解决一个问题 2 天.向你们解释的想法可能会帮助并迅速解决问题.现在让我简单介绍一下我的问题.我有 WPF MVVM 应用程序,主视图绑定到 MainViewModel.我在此处使用 Textblock 来绑定视图模型中的一些内容,同时加载工作正常的屏幕.我也将 ChildUserControl 绑定到 ChildViewModel.现在,我需要将不同的内容绑定到主窗口中的 Textblock,从用户控件开始,在用户控件级别发生的某些操作上.怎么可能?

I’m very new to MVVM and getting my first POC done now. However, I have been hitting my head to get one issue resolved for 2 days. Thought of explaining to you guys may help and resolve the issue so quickly. Let me brief my issue now. I have WPF MVVM application with a main View bound to MainViewModel. I have Textblock here to bind some content from the viewmodel while loading the screen which is working awesome. I also have ChildUserControl bound to ChildViewModel. Now, I need to bind different content to the Textblock in the main window from user control up on some action which is taking place in user control level. How it is possible ?

这是我的示例代码主窗口.Xaml

here is the sample code I have MainWindow.Xaml

<Window.Resources>
    <viewModel:MainViewModel x:Key="mainWindowViewModel"/></Window.Resources>

<TextBlock Name="txtStatus" Text="{Binding StatusMessage, Mode=OneWay }"/>

ChildUserControl.xaml

ChildUserControl.xaml

<UserControl.Resources>
    <viewModel:ChildModelView x:Key="ChildModelView"/> </UserControl.Resources>

public class ChildModelView : BaseViewModel
{
// Some child level logic..
// then need to update the txtStatus text block from parent
}

非常感谢您的帮助..!

Your helps are much appreciated..!

推荐答案

实现这一目标的一种简单方法是使用 IoC.创建子视图模型时,将主视图模型的引用传递给子视图模型,并将其作为私有只读变量保存.您现在可以访问所有主要的 VM 公共信息.

An easy way to achieve this would be to use IoC. When you create your child view model, pass a reference of your main view model to your child viewmodel , and hold it as a private read only variable. You now access all of your main VM publics .

另一种解决方案可能是使用中介者模式.

An alternative solution would ppossibly be to use the Mediator pattern.

开发了一个简单的 App 来演示 IoC 解决方案.

Knocked up a simple App to demonstrate IoC solution.

App.xaml.cs

App.xaml.cs

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        var window = new MainWindow() {DataContext = new MainWindowViewModel() };
        window.Show();
    }
}

MainWindowViewModel.cs

MainWindowViewModel.cs

public class MainWindowViewModel : ViewModelBase
{
    private string _statusMessage;

    public string StatusMessage
    {
        get { return _statusMessage; }
        set { _statusMessage = value; this.OnPropertyChanged("StatusMessage"); }
    }

    public ICommand OpenChildCommand { get; private set; }

    public MainWindowViewModel()
    {
        this.StatusMessage = "No status";
        this.OpenChildCommand = new DelegateCommand((o) => this.OpenChild());
    }

    private void OpenChild()
    {
        var window = new ChildWindow {DataContext = new ChildWindowViewModel(this)};
        window.Show();
    }
}

ChildWindowViewModel.cs

ChildWindowViewModel.cs

public class ChildWindowViewModel : ViewModelBase
{
    private readonly MainWindowViewModel _mainvm;

    public ChildWindowViewModel(MainWindowViewModel mainvm)
    {
        _mainvm = mainvm;
        this.UpdateStatusCommand = new DelegateCommand((o) => this.UpdateStatus());
    }

    public ICommand UpdateStatusCommand { get; private set; }

    private void UpdateStatus()
    {
        this._mainvm.StatusMessage = "New Status";
    }
}

ViewModelBase.cs

ViewModelBase.cs

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }
}

委托命令.cs

public class DelegateCommand : ICommand
{
    /// <summary>
    /// Action to be performed when this command is executed
    /// </summary>
    private Action<object> executionAction;

    /// <summary>
    /// Predicate to determine if the command is valid for execution
    /// </summary>
    private Predicate<object> canExecutePredicate;

    /// <summary>
    /// Initializes a new instance of the DelegateCommand class.
    /// The command will always be valid for execution.
    /// </summary>
    /// <param name="execute">The delegate to call on execution</param>
    public DelegateCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Initializes a new instance of the DelegateCommand class.
    /// </summary>
    /// <param name="execute">The delegate to call on execution</param>
    /// <param name="canExecute">The predicate to determine if command is valid for execution</param>
    public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
        {
            throw new ArgumentNullException("execute");
        }

        this.executionAction = execute;
        this.canExecutePredicate = canExecute;
    }

    /// <summary>
    /// Raised when CanExecute is changed
    /// </summary>
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    /// <summary>
    /// Executes the delegate backing this DelegateCommand
    /// </summary>
    /// <param name="parameter">parameter to pass to predicate</param>
    /// <returns>True if command is valid for execution</returns>
    public bool CanExecute(object parameter)
    {
        return this.canExecutePredicate == null ? true : this.canExecutePredicate(parameter);
    }

    /// <summary>
    /// Executes the delegate backing this DelegateCommand
    /// </summary>
    /// <param name="parameter">parameter to pass to delegate</param>
    /// <exception cref="InvalidOperationException">Thrown if CanExecute returns false</exception>
    public void Execute(object parameter)
    {
        if (!this.CanExecute(parameter))
        {
            throw new InvalidOperationException("The command is not valid for execution, check the CanExecute method before attempting to execute.");
        }
        this.executionAction(parameter);
    }
}

主窗口.xaml

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<StackPanel>
    <TextBlock Text="{Binding StatusMessage, Mode=OneWay}" />
    <Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="Open Child Window" 
            Command="{Binding Path=OpenChildCommand}"/>
</StackPanel>

ChildWindow.xaml

ChildWindow.xaml

<Window x:Class="WpfApplication2.ChildWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="ChildWindow" Height="300" Width="300">
<Grid>
    <Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="UpdateStatus"
            Command="{Binding Path=UpdateStatusCommand}" />
</Grid>

点击更新状态前的图片

点击updatestatus后的图片

Image after clicking on updatestatus

这篇关于MVVM 主窗口控件从子用户控件绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆