0

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

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

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

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

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

6 回答 6

4

为什么不以简单的方式做 mvvm?(首先是视图模型)。你说你有一个主页——这意味着你也有一个主页视图模型。您的 mainpageviewmodel 至少处理保存命令。现在你想在你的主页上显示 MyMetaData 和 MyData。所以最简单的方法是在主视图模型中创建一个 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 个内容演示器。

//资源

    <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 上拥有所需的所有信息。

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

编辑:我没有silverlight,所以只是一个建议:也许雷切尔可以给你一个更好的答案。

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

如果 silverlight 无法处理数据类型的数据模板,您可以直接将用户控件放在那里。

<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>
于 2012-07-11T12:54:26.277 回答
4

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

MainViewModel应该包含MyMetaDataMyData属性(绑定到它们各自的UserControls),并且这些对象中的每一个都应该包含UserControl. 例如,如果你UserControl有一个TextBoxfor Name,那么你的数据对象应该有一个绑定到Name的属性。TextBox

如果 Save 按钮位于其中之一,UserControls则相应的 ViewModel 应该有一个在单击SaveCommand时执行的Button。所需的所有数据Save也都位于该 ViewModel 中,因此您可以开始了。

如果您MainViewModel负责保存数据,那么它应该能够连接到您的子 ViewModelSaveCommand并附加它自己的方法,例如

this.MyData.SaveCommand = this.SaveCommand();

保存所需的所有数据都可以在this.MyData

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

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

于 2012-07-11T13:08:43.453 回答
1

您应该使用双向绑定来自动更新控制器中的值。看看这篇文章

这是一个例子:

<TextBox Text="{Binding MyMetaData, Mode=TwoWay }" />
<TextBox Text="{Binding MyData, Mode=TwoWay }" />
于 2012-07-11T11:46:07.750 回答
1

我会给你一个小例子,你可以如何使用 MVVM Light Messenger 进行 ViewModel 到 ViewModel 的通信。假设您有一个 MyDataCollection 类:

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

在您的 MainViewModel 上,您有一个由 View 的 SaveButton 绑定的 RelayCommand(来自 MVVM light toolkit)。执行 Connad 时,您必须发送带有回调操作的 Message 以从订阅者请求数据。回调将 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});
            }
        }
    }

}
于 2012-07-11T12:16:40.607 回答
0

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

我如何使用它来设置 UI 语言 ViewModel A 的 Messenger 示例,我在此处使用“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);
于 2012-07-11T12:17:19.710 回答
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();
}
于 2012-07-12T14:09:09.223 回答