简体   繁体   English

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

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

I have a main View called MainContentView.xaml in wich I have set the DataContext to a ViewModel called MainContentViewModel.cs . 我有一个名为MainContentView.xaml的主视图,我已经将DataContext设置为一个名为MainContentViewModel.cs的ViewModel。 Here I can update the values that appear in the UI, just as a normal MVVM would work. 在这里,我可以更新UI中显示的值,就像正常的MVVM可以工作一样。
It looks like this: 看起来像这样:

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

And my MainContentViewModel.cs looks like this: 我的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)); }
    }
}

Now I want to set some properties in the MyCustomUserControl.xaml through it's own MyCustomUserControlViewModel.cs . 现在,我想设置的某些属性MyCustomUserControl.xaml通过它自己的MyCustomUserControlViewModel.cs
My MyCustomUserControl.xaml looks like this: 我的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>

And my MyCustomUserControlViewModel.cs looks like this: 我的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)); }
    }
}

Now I want to, from the MainContentViewModel.cs , update the MyCustomLabel property on the MyUserCustomUserControl.xaml , and I suppose I have to do it through the MyCustomUserControlViewModel.cs so I can keep the MVVM pattern. 现在,我想从MainContentViewModel.cs更新MyUserCustomUserControl.xaml上的MyCustomLabel属性,并且我想必须通过MyCustomUserControlViewModel.cs以便保持MVVM模式。

I've tried something like this: In the MainContentViewModel.cs 我已经尝试过这样的事情:在MainContentViewModel.cs

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

And in MyCustomUserControlViewModel.cs 并在MyCustomUserControlViewModel.cs

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

But this does not work. 但这是行不通的。 I'm guessing it's because I'm instantiating another MyCustomUserControlViewModel.cs object. 我猜是因为要实例化另一个MyCustomUserControlViewModel.cs对象。

So, how can I do this? 那么,我该怎么做呢?


UPDATED AND WORKING (Thank you Sheridan) 更新和工作 (谢谢谢里登)
I picked up one of Sheridan's solutions and ended up with this working solution. 我选择了Sheridan的一种解决方案,最后得到了这个可行的解决方案。 In my MainContentView.xaml : 在我的MainContentView.xaml

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

In my MainContentViewModel.cs : 在我的MainContentViewModel.cs

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

And then I can do this: 然后我可以这样做:

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

If your parent view model had access to the actual child view model instance that is used (which it probably doesn't because of the way that you instantiate your child view model), then you could have simply done this: 如果您的父视图模型可以访问使用的实际子视图模型实例(这可能不是由于实例化子视图模型的方式),那么您可以简单地做到这一点:

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

1. 1。

One solution would be to remove the child view model from the child view to the parent view model and then to display the child view using a ContentControl and a DataTemplate : 一种解决方案是将子视图模型从子视图移除到父视图模型,然后使用ContentControlDataTemplate显示子视图:

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

...

In MainContentViewModel: 在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>

Doing this would enable you to call the property simply, as shown in my first example. 这样做将使您能够简单地调用该属性,如我的第一个示例所示。

2. 2。

One alternative would be to move the property to the parent view model and bind to it directly from the child UserControl : 一种替代方法是将属性移到父视图模型,并直接从子UserControl绑定到它:

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

UPDATE >>> 更新>>>

3. 3。

Ok, I've just had another idea... you could add another property into the parent view model and data bind to the child view model like this maybe: 好的,我刚刚有了另一个主意...您可以在父视图模型中添加另一个属性,然后将数据绑定到子视图模型,如下所示:

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

This is just a guess, but it might be able to hook onto the child view model like this... then you could do this in the parent view model: 这只是一个猜测,但它可能能够像这样子视图视图上的钩子...然后您可以在父视图模型中执行此操作:

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

4. 4。

Actually... I've just had another idea. 其实...我刚有了另一个主意。 You could do bind from a property in your parent view model through to the UserControl if you add a DependencyProperty to it: 如果向其添加DependencyProperty ,则可以从父视图模型中的属性绑定到UserControl

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

You could simply remove the property from the child view model in this case. 在这种情况下,您可以简单地从子视图模型中删除该属性。

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

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