2013-03-14 42 views
2

我对MVVM非常陌生,并且现在完成了我的第一个POC。但是,我一直在努力解决2天内的问题。认为向你们解释可能会很快帮助并解决问题。现在让我简要介绍我的问题。 我有一个主视图绑定到MainViewModel的WPF MVVM应用程序。我在这里有Textblock来绑定视图模型中的一些内容,同时加载正在工作的屏幕。 我也有ChildUserControl绑定到ChildViewModel。现在,我需要将不同的内容绑定到主窗口中的Textblock,从用户控制用户控制级别发生的某些操作。怎么可能?MVVM主窗口控件绑定从子用户控件

这里是示例代码我 MainWindow.Xaml

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

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

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 
} 

你的帮助是非常感谢..!

回答

4

实现此目的的简单方法是使用IoC。当您创建子视图模型时,将主视图模型的引用传递给您的子视图模型,并将其保存为私有只读变量。您现在访问所有主要VM公众。

另一种解决方案可能是使用介体模式。

敲了一个简单的应用程序来演示IoC解决方案。

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

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

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

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); 
     } 
    } 
} 

DelegateCommand.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); 
    } 
} 

MainWindow.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

<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> 

点击更新状态

Before

图片点击updatestatus

enter image description here

+0

我在启动ChildVM时传递了主视图模型,并将MainVM属性设置了一些值。但它确实也反映了整个页面......不知道为什么。 – user2066540 2013-03-14 21:03:23

+0

您是否在mainvm上实现INPC并在mainvm属性上调用propertychanged? – failedprogramming 2013-03-14 21:07:47

+0

这是我即将在我的MainMV公共字符串中执行的状态消息 { get {return statusMsg; } set { statusMsg = value; OnPropertyChanged(“StatusMessage”); } } 然后,当初始化子vm im做ChildVM(mainVM vm){_main = vm; _main.StatusMessage =“新状态”;这是正确的方式吗? – user2066540 2013-03-14 21:13:16

0

我可能会误解你的需要,他前后图片但是它听起来像是在MainWindow中有一个TextBlock,它需要更新以响应由ChildWindow提供的数据中出现的内容。假设这就是你想要做的,那么我认为有几种不同的方法可以做到这一点。特别是,您可以使用附加事件。

http://msdn.microsoft.com/en-us/library/bb613550.aspx

的技术解释是有点长,所以我要把它留给MSDN要做到这一点,但短期的解释很简单,它只是将你的子窗口被提出和处理的事件通过你的MainWindow。这里的好处是,它将作为DataContext传入你的ChildWindowViewModel。