2

私はMVVMに非常に慣れていないので、最初のPOCを実行します。しかし、私は2日間、1つの問題を解決するために頭を悩ませてきました。あなたたちに説明することを考えれば、問題をすぐに解決するのに役立つかもしれません。今、私の問題を簡単に説明しましょう。MainViewModelにバインドされたメインビューを持つWPFMVVMアプリケーションがあります。私はここにTextblockを持っており、素晴らしい動作をしている画面をロードしながら、ビューモデルからいくつかのコンテンツをバインドします。また、ChildUserControlをChildViewModelにバインドしています。ここで、ユーザーコントロールレベルで行われているアクションで、ユーザーコントロールからメインウィンドウのテキストブロックにさまざまなコンテンツをバインドする必要があります。どのようにそれは可能ですか?

これが私が持っているサンプルコードです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

2 に答える 2

6

これを実現する簡単な方法は、IoC を使用することです。子ビュー モデルを作成するときは、メイン ビュー モデルの参照を子ビューモデルに渡し、それを読み取り専用のプライベート変数として保持します。これで、すべての主要な VM パブリックにアクセスできます。

別の解決策は、おそらく Mediator パターンを使用することです。

シンプルなアプリをノックアップして、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>

更新ステータスをクリックする前の画像

前

updatestatus をクリックした後の画像

ここに画像の説明を入力

于 2013-03-14T19:50:21.823 に答える
0

ここであなたのニーズを誤解しているかもしれませんが、MainWindow に TextBlock があり、ChildWindow で発生したデータに応じて更新する必要があるようです。それがあなたがやろうとしていることだと仮定すると、それを行うにはいくつかの異なる方法があると思います. 特に、添付イベントを使用できます。

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

技術的な説明は少し長いので、MSDN に任せますが、簡単に説明すると、子ウィンドウから発生し、MainWindow によって処理される単なるイベントであるということです。ここでのボーナスは、ChildWindowViewModel を DataContext として渡すことです。

于 2013-03-14T19:56:13.110 に答える