MVVM Light:如何从usercontrols获取数据?

时间:2012-07-11 11:43:20

标签: c# silverlight xaml mvvm mvvm-light

我有一个包含MyMetaData和MyData的MyDataCollection类。在我的应用程序中,我有两个usercontrolls,向用户显示输入字段。一个用于MyMetaData,另一个用于MyData。两个用户控件都包含在MainPage中。

我的问题是:如何从用户控件获取数据,然后用户点击保存按钮(位于主页上)?

更新 我已将相应的代码更改为blindmeis帖子,但现在未显示MetaDataView:

<UserControl.Resources>
    <DataTemplate x:Key="MetaDataTemplate">
        <view:MetaDataView/>
    </DataTemplate>
</UserControl.Resources>

<Grid>
    <ContentPresenter Content="{Binding MetaDataTemplate}"/>
</Grid>

6 个答案:

答案 0 :(得分:4)

为什么不以简单的方式做mvvm?(viewmodel first)。你说你有一个主页 - 这意味着你还有一个mainpageviewmodel。你的mainpageviewmodel至少处理save命令。现在你想在你的主页上显示MyMetaData和MyData。所以简单的方法是在mainviewmodel中创建一个MyMetaData实例和一个MyData实例。

public class MainPageViewmodel
{
    public ICommand SaveCommand { get; set; }
    public MyDataViewmodel MyData { get; set; }
    public MyMetaDataViewmodel MyMetaData { get; set; }

    public MainPageViewmodel()
    {
        this.MyData = new MyDataViewmodel();
        this.MyMetaData = new MyMetaDataViewmodel();
    }

}

public class MyDataViewmodel
{}

public class MyMetaDataViewmodel
{}

您的主页只需要2个数据表和2个contentpresenter。

//资源

    <DataTemplate DataType="{x:Type Local:MyDataViewmodel}">
        <view:MyDataUserControl/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type Local:MyMetaDataViewmodel}">
        <view:MyMetaDataUserControl/>
    </DataTemplate>

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <ContentPresenter Content="{Binding MyData}" Grid.Column="0"/>
    <ContentPresenter Content="{Binding MyMetaData}" Grid.Column="1"/>
    <Button Content="Save" Command="{Binding SaveCommand}" Grid.Column="2"/>
</Grid>

因为您的mainpageviewmodel都有“子”视图模型,所以您在savecommand上拥有所需的所有信息。

如果您有其他方案,请更新您的问题,也许发布一些代码。

编辑:我没有银光,所以只是一个建议:也许rachel可以给你一个更好的答案。

<Grid>
  <ContentPresenter Content="{Binding MyMetaData}" ContentTemplate="{StaticResource MetaDataTemplate}"/>
</Grid>

如果silverlight无法使用数据类型处理datatemplates,您可以直接将usercontrol放在那里。

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <view:MyDataUserControl DataContext="{Binding MyData}" Grid.Column="0"/>
    <view:MyMetaDataUserControl DataContext="{Binding MyMetaData}" Grid.Column="1"/>
    <Button Content="Save" Command="{Binding SaveCommand}" Grid.Column="2"/>
</Grid>

答案 1 :(得分:4)

由于您将此问题标记为MVVM,因此您的ViewModel应包含SaveCommand和执行实际保存所需的所有数据

您的MainViewModel应包含MyMetaDataMyData属性(绑定到各自的UserControls),并且每个对象都应包含所需数据的属性UserControl。例如,如果您的UserControl TextBoxName,那么您的数据对象应该具有Name绑定的TextBox的属性。 / p>

如果“保存”按钮位于其中一个UserControls中,则相应的ViewModel应该有一个SaveCommand,在单击Button时会执行该SaveMainViewModel所需的所有数据也位于该ViewModel中,因此您可以继续使用。

如果您的SaveCommand负责保存数据,那么它应该可以挂钩到您的子ViewModel的this.MyData.SaveCommand = this.SaveCommand(); 并附加它自己的方法,例如

this.MyData

可以在SaveButton

中找到保存所需的所有数据

如果MainView位于MainViewModel,而不是其中一个UserControls中,则SaveCommand应该是this.MyData的一部分,并且保存所需的所有数据都可以可以在This.MyMetaData或{{1}}找到。

请记住,使用MVVM,您的ViewModel就是您的应用程序。 View只是一个漂亮的界面,允许用户与您的ViewModel进行交互。

答案 2 :(得分:1)

您应该使用双向绑定来自动更新控制器中的值。看看this article

以下是一个例子:

<TextBox Text="{Binding MyMetaData, Mode=TwoWay }" />
<TextBox Text="{Binding MyData, Mode=TwoWay }" />

答案 3 :(得分:1)

我将给你一些示例,如何使用MVVM Light Messenger进行ViewModel-to-ViewModel通信。假设您有一个MyDataCollection类:

public class MyDataCollection
{
    public int MyData;
    public string MyMetaData;
}

在您的MainViewModel上,您有一个由View的SaveButton绑定的RelayCommand(来自MVVM light toolkit)。执行Connad时,您必须发送带有回调操作的消息,以请求来自订阅者的数据。回调将MyDataCollection作为参数:

public class MainViewModel : ViewModelBase 
{
    public RelayCommand SaveCommand { get; private set; }

    //Ctor
    public MainViewModel()
    {
      SaveCommand = new RelayCommand(
                () =>
                Messenger.Default.Send<NotificationMessageAction<MyDataCollection>>(
                    new NotificationMessageAction<MyDataCollection>("SaveData", SaveCallback)));
    }

    private void SaveCallback(MyDataCollection dataCollection)
    {
        // process your dataCollection... 
    }
}

UserControlViewModel具有InputTextBoxes绑定的属性。它只需要注册消息并使用数据属性调用回调:

public class UserControlViewModel : ViewModelBase
{
    //Properties
    public string UserControlMetaData { get; set; }
    public int UserControlData { get; set; }

    //Ctor
    public UserControlViewModel()
    {
        Messenger.Default.Register<NotificationMessageAction<MyDataCollection>>(this, MessageReceived);
    }

    // private Method to handle all kinds of messages.
    private void MessageReceived(MessageBase msg)
    {
        if(msg is NotificationMessageAction<MyDataCollection>)
        {
            var actionMsg = msg as NotificationMessageAction<MyDataCollection>;
            if(actionMsg.Notification == "SaveData")  // Is this the Message, we are looking for?
            {
                // here the MainViewModels callback is called.
                actionMsg.Execute(new MyDataCollection() {MyData = UserControlData, MyMetaData = UserControlMetaData});
            }
        }
    }

}

答案 4 :(得分:0)

您必须使用信使,否则您必须在ViewModelLocator上设置属性

使用它来设置UI语言的Messenger示例 ViewModel A,我在这里使用“SetLanguage”标记注册一个监听器:

Messenger.Default.Register<string>(this, "SetLanguage", false, input =>
{
    SetLanguage(input);
});

ViewModel B,这里我发送带有“SetLanguage”令牌的消息:

Messenger.Default.Send("en-EN", "SetLanguage");

ViewModel A中的ViewModelLocator示例,我通过定位器访问ViewModel B中的数据:

short value = 12;
var myFilteredDataList = ViewModelLocator.ViewModelBStatic.MyDataList.Any(m => m.code == value);

答案 5 :(得分:0)

我现在有两个解决方案:

查看:

<ContentPresenter Content="{Binding MyMetaDataView}" />

视图模型:

public MetaDataViewModel MyMetaDataViewModel { get; set; }
public MetaDataView MyMetaDataView { get; set; }

public MainViewModel()
{
    MyMetaDataViewModel = new MetaDataViewModel();
    MyMetaDataView = new MetaDataView();

    MyMetaDataView.DataContext = MyMetaDataViewModel;
}

或----

查看:

<UserControl.Resources>
    <DataTemplate  x:Key="MetaDataViewTemplate">
        <view:MetaDataView />
    </DataTemplate>
</UserControl.Resources>
...
<ContentPresenter Content="{Binding MyMetaDataViewModel}" ContentTemplate="{StaticResource MetaDataViewTemplate}"/>

视图模型:

public MetaDataViewModel MyMetaDataViewModel { get; set; }

public MainViewModel()
{
    MyMetaDataViewModel = new MetaDataViewModel();
}