簡體   English   中英

MVVM Light:如何從用戶控件獲取數據?

[英]MVVM Light: How to get data from usercontrols?

我有一個MyDataCollection類,其中包含MyMetaData和MyData。 在我的應用程序中,我有兩個usercontroll,它們向用戶顯示輸入字段。 一個用於MyMetaData,另一個用於MyData。 這兩個用戶控件都包含在MainPage中。

我的問題是:我應該如何從用戶控件中獲取數據,然后用戶輕按保存按鈕(位於主頁上)?

更新我已經將我的代碼相應地更改為blindmeis發布,但是現在未顯示MetaDataView:

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

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

為什么不以簡單的方式執行mvvm?(首先是viewmodel)。 您說您有一個主頁-這意味着您也有一個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上獲得所有想要的信息。

如果您還有其他情況,請更新您的問題,也許發布一些代碼。

編輯:我沒有任何建議,所以只是一個建議:也許瑞秋可以給你一個更好的答案。

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

如果silverlight無法處理具有數據類型的數據模板,則可以直接將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>

由於您將此問題標記為MVVM ,因此ViewModels應該包含SaveCommand和執行實際保存所需的所有數據

您的MainViewModel應該包含MyMetaDataMyData屬性(它們綁定到各自的UserControls ),並且每個對象都應包含UserControl所需的任何數據的屬性。 例如,如果您的UserControl有一個NameTextBox ,則您的數據對象應具有TextBox綁定到的Name的屬性。

如果“保存”按鈕位於這些UserControls之一中,則相應的ViewModel應該具有一個“ SaveCommand ,該命令在單擊“ Button時將被執行。 Save所需的所有數據也都位於該ViewModel中,因此您可以使用。

如果您的MainViewModel負責保存數據,那么它應該能夠掛接到子ViewModel的SaveCommand並附加其自己的方法,例如

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

保存所需的所有數據都可以在this.MyData找到

如果SaveButton位於MainView ,而不位於UserControl之一中,則SaveCommand應該是MainViewModel一部分,並且保存所需的所有數據都可以在this.MyDataThis.MyMetaData找到。

記住,使用MVVM,您的ViewModels是您的應用程序。 視圖只是一個漂亮的界面,允許用戶與您的ViewModels進行交互。

您應該使用雙向綁定來自動更新控制器中的值。 看一下這篇文章

這是一個例子:

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

我將為您提供一些示例,說明如何使用MVVM Light Messenger進行ViewModel到ViewModel的通信。 假設您有一個MyDataCollection類:

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

在MainViewModel上,您有一個RelayCommand(來自MVVM light工具箱),由View的SaveButton綁定。 執行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});
            }
        }
    }

}

您將必須使用Messenger或必須在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);

我現在有兩種解決方案:

視圖:

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

ViewModel:

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}"/>

ViewModel:

public MetaDataViewModel MyMetaDataViewModel { get; set; }

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM