我有一个包含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>
答案 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
应包含MyMetaData
和MyData
属性(绑定到各自的UserControls
),并且每个对象都应包含所需数据的属性UserControl
。例如,如果您的UserControl
TextBox
为Name
,那么您的数据对象应该具有Name
绑定的TextBox
的属性。 / p>
如果“保存”按钮位于其中一个UserControls
中,则相应的ViewModel应该有一个SaveCommand
,在单击Button
时会执行该Save
。 MainViewModel
所需的所有数据也位于该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();
}