繁体   English   中英

使用ViewModel(MVVM)在当前视图的子UserControl中设置属性

[英]Set properties in child UserControl of a current View with ViewModel (MVVM)

我有一个名为MainContentView.xaml的主视图,我已经将DataContext设置为一个名为MainContentViewModel.cs的ViewModel。 在这里,我可以更新UI中显示的值,就像正常的MVVM可以工作一样。
看起来像这样:

<UserControl x:Class="namespace:MyProject.View.Home.MainContentView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:UserTools="clr-namespace:MyProject.View.Tools"
             xmlns:ViewModel="clr-namespace:MyProject.ViewModel.Home"
             mc:Ignorable="d" >
    <UserControl.DataContext>
        <ViewModel:MainContentViewModel />
    </UserControl.DataContext>

    <Grid x:Name="mainGrid">
        <!-- Normal objects -->
        <StackPanel>
            <Label Text="Im a label" />
            <TextBox />
        </StackPanel>
        <!-- My Custom Object -->
        <UserTools:MyCustomUserControl x:Name="myUserControl" />
    </Grid>
</UserControl>

我的MainContentViewModel.cs看起来像这样:

public class MainContentViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    private string myLabel = "";
    public string MyLabel {
        get { return this.myLabel; }
        set {
            this.myLabel = value;
            OnPropertyChangedEvent("MyLabel");
        }
    }

    public MainContentViewModel() {
        MyLabel = string.Format("my label text");
    }

    protected virtual void OnPropertyChangedEvent(string _propertyName) {
        var _handler = this.PropertyChanged;
        if(_handler != null) { _handler(this, new PropertyChangedEventArgs(_propertyName)); }
    }
}

现在,我想设置的某些属性MyCustomUserControl.xaml通过它自己的MyCustomUserControlViewModel.cs
我的MyCustomUserControl.xaml如下所示:

<UserControl x:Class="MyProject.View.Tools.MyCustomUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:ViewModel="clr-namespace:MyProject.ViewModel.Tools"
             mc:Ignorable="d" >
    <UserControl.DataContext>
        <ViewModel:MyCustomUserControlViewModel />
    </UserControl.DataContext>
    <Grid x:Name="mainGrid">
        <Label Content="{Binding myCustomLabel}" />
    </Grid>
</UserControl>

我的MyCustomUserControlViewModel.cs看起来像这样:

public class MyCustomUserControlViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    private string myCustomLabel = "";
    public string MyCustomLabel {
        get { return this.myCustomLabel; }
        set {
            this.myCustomLabel = value;
            OnPropertyChangedEvent("MyCustomLabel");
        }
    }

    public MyCustomUserControlViewModel() {
        MyCustomLabel = string.Format("my custom label text");
    }

    protected virtual void OnPropertyChangedEvent(string _propertyName) {
        var _handler = this.PropertyChanged;
        if(_handler != null) { _handler(this, new PropertyChangedEventArgs(_propertyName)); }
    }
}

现在,我想从MainContentViewModel.cs更新MyUserCustomUserControl.xaml上的MyCustomLabel属性,并且我想必须通过MyCustomUserControlViewModel.cs以便保持MVVM模式。

我已经尝试过这样的事情:在MainContentViewModel.cs

private MyCustomUserControlViewModel _viewModel = new MyCustomUserControlViewModel ();
(...)
public MainContentViewModel() {
    (...)
    _viewModel.SetMyCustomLabel("my new custom label text");
}

并在MyCustomUserControlViewModel.cs

public void SetMyCustomLabel(string _text) {
    MyCustomLabel = _text;
}

但这是行不通的。 我猜是因为要实例化另一个MyCustomUserControlViewModel.cs对象。

那么,我该怎么做呢?


更新和工作 (谢谢谢里登)
我选择了Sheridan的一种解决方案,最后得到了这个可行的解决方案。 在我的MainContentView.xaml

(...)
<UserTools:MyCustomUserControl DataContext="{Binding ChildViewModel, Mode=OneWay}" />

在我的MainContentViewModel.cs

private MyCustomUserControlViewModel childViewModel = new MyCustomUserControlViewModel();
public MyCustomUserControlViewModel ChildViewModel {
    get { return childViewModel; }
    private set { childViewModel = value; OnPropertyChangedEvent("ChildViewModel"); }
}

然后我可以这样做:

public MainContentViewModel() {
    (...)
    ChildViewModel.SetMyCustomLabel("my new custom label text");
}

如果您的父视图模型可以访问使用的实际子视图模型实例(这可能不是由于实例化子视图模型的方式),那么您可以简单地做到这一点:

public MainContentViewModel() {
    (...)
    _viewModel.CustomLabel  = "my new custom label text";
}

1。

一种解决方案是将子视图模型从子视图移除到父视图模型,然后使用ContentControlDataTemplate显示子视图:

<DataTemplate DataType="{x:Type ViewModels:MyCustomUserControlViewModel}">
    <Views:MyCustomUserControlView />
</DataTemplate>

...

在MainContentViewModel中:

public MyCustomUserControlViewModel ChildViewModel
{
    get { return childViewModel; }
    private set { childViewModel = value; NotifyPropertyChanged("ChildViewModel"); }
}

...

<Grid x:Name="mainGrid">
    <!-- Normal objects -->
    <StackPanel>
        <Label Text="Im a label" />
        <TextBox />
    </StackPanel>
    <!-- My Custom Object -->
    <ContentControl x:Name="myUserControl" Content="{Binding ChildViewModel}" />
</Grid>

这样做将使您能够简单地调用该属性,如我的第一个示例所示。

2。

一种替代方法是将属性移到父视图模型,并直接从子UserControl绑定到它:

<Grid x:Name="mainGrid">
    <Label Content="{Binding DataContext.myCustomLabel, RelativeSource={RelativeSource 
        AncestorType={x:Type Views:MainContentView}}}" />
</Grid>

更新>>>

3。

好的,我刚刚有了另一个主意...您可以在父视图模型中添加另一个属性,然后将数据绑定到子视图模型,如下所示:

<UserTools:MyCustomUserControl DataContext="{Binding ChildViewModel, 
Mode=OneWayToSource}" x:Name="myUserControl" />

这只是一个猜测,但它可能能够像这样子视图视图上的钩子...然后您可以在父视图模型中执行此操作:

if (ChildViewModel != null) ChildViewModel.CustomLabel = "my new custom label text";

4。

其实...我刚有了另一个主意。 如果向其添加DependencyProperty ,则可以从父视图模型中的属性绑定到UserControl

<UserTools:MyCustomUserControl CustomLabel="{Binding CustomLabelInParentViewModel}" 
x:Name="myUserControl" />

在这种情况下,您可以简单地从子视图模型中删除该属性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM