簡體   English   中英

mvvm Windows Phone 8混亂以及更改文本時如何捕獲

[英]mvvm windows phone 8 confusion and how to capture when text is changed

我正在嘗試使用mvvm模式編寫Windows Phone 8應用程序,但我正在為此苦苦掙扎。

我有一個頁面,其中包含綁定到我的PersonViewModel的人員列表。 那部分工作正常。 然后,我在應用程序欄中有2個按鈕,即添加或編輯。 當我要編輯人物時,我從列表中選擇人物,然后在ViewModel中設置CurrentPerson。 依次在我的MainViewModel中設置一個屬性,該屬性用於存儲當前選定的人,即

App.MainViewModel.CurrentPerson = this.CurrentPerson;

當我想添加一個新的人時,我使用相同的主體,但是我創建了一個新的人模型。

App.MainViewModel.CurrentPerson = new PersonModel();

然后,我重定向到一個頁面,該頁面包含用於處理人的字段(無論是添加還是編輯該人),並將其綁定到名為PersonEntryViewModel的ViewModel

在解釋問題之前,我想讓您知道我要實現的目標。 我希望我的應用程序欄中的“保存”按鈕在滿足一定數量的條件后即被啟用,即名稱已填寫並且具有x個字符,等等。

我可以看到我的問題是什么,但我不知道如何解決。

這是我的PersonEntryViewModel的簡化版本:

public class PersonEntryViewModel : BaseViewModel
{
    private PersonModel _currentPerson;
    private bool _isNewPerson;
    private ICommand _savePersonCommand;
    private ICommand _cancelCommand;
    private ICommand _titleTextChanged;

    private bool _enableSaveButton;

    public PersonEntryViewModel()
    {
        this.CurrentPerson = App.MainViewModel.CurrentPerson ?? new PersonModel();
    }

    public ICommand SavePersonCommand
    {
        get
        {
            return this._savePersonCommand ?? (this._savePersonCommand = new DelegateCommand(SavePersonAction));
        }
    }

    public ICommand CancelCommand
    {
        get
        {
            return this._cancelCommand ?? (this._cancelCommand = new DelegateCommand(CancelAction));
        }
    }

    public ICommand NameTextChanged
    {
        get
        {
            return this._nameTextChanged ?? (this._nameTextChanged = new DelegateCommand(NameTextChangedAction));
        }
    }

    private void NameTextChangedAction(object actionParameters)
    {
        if (!string.IsNullOrEmpty(this._currentPerson.Name) && _currentPerson.Name.Length > 2)
        {
            EnableSaveButton = true;
        }            
    }

    private void CancelAction(object actionParameters)
    {
        Console.WriteLine("Cancel");
        INavigationService navigationService = this.GetService<INavigationService>();
        if (navigationService == null)
            return;
        navigationService.GoBack();
        navigationService = null;
    }

    private void SavePersonAction(object actionParameters)
    {
        Console.WriteLine("Saving");
    }

    public PersonModel CurrentPerson
    {
        get { return this._currentPerson; }
        set
        {
            if (this._currentPerson != value)
                this.SetProperty(ref this._currentPerson, value);
        }
    }

    public string PageTitle
    {
        get { return this._pageTitle; }
        set { if (this._pageTitle != value) this.SetProperty(ref this._pageTitle, value); }
    }

    public bool IsNewPerson
    {
        get { return this._isNewPerson; }
        set
        {
            if (this._isNewPerson != value)
            {
                this.SetProperty(ref this._isNewPerson, value);
                if (this._isNewPerson)
                    this.PageTitle = AppResources.PersonEntryPageNewTitle;
                else
                    this.PageTitle = AppResources.PersonEntryPageEditTitle;
            }
        }
    }

    public bool EnableSaveButton
    {
        get { return this._enableSaveButton; }
        set { if (this._enableSaveButton != value) this.SetProperty(ref this._enableSaveButton, value); }
    }
}

這是我的XAML的一部分:

<Grid x:Name="LayoutRoot" Background="Transparent" DataContext="{StaticResource PersonEntryViewModel}" >

    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" DataContext="{Binding CurrentPerson, Mode=TwoWay}">
        <Grid Margin="0,0,0,5">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Border BorderBrush="{StaticResource PhoneAccentBrush}"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            BorderThickness="5"
                            Background="Transparent"
                            CornerRadius="5">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <TextBlock Text="Name:" 
                                       Grid.Row="0"
                                       Margin="12,0,0,0"/>
                    <TextBox Text="{Binding Name, Mode=TwoWay}" 
                                     Grid.Row="1">
                        <!--<i:Interaction.Triggers>
                            <i:EventTrigger EventName="TextChanged">
                                <i:InvokeCommandAction Command="{Binding NameTextChanged, Mode=OneWay}" CommandParameter="{Binding}" />
                            </i:EventTrigger>
                        </i:Interaction.Triggers>-->
                    </TextBox>
                    <TextBlock Text="Address:" 
                                       Grid.Row="2"
                                       Margin="12,0,0,0"/>
                    <TextBox Text="{Binding Address, Mode=TwoWay}" 
                             AcceptsReturn="True" 
                             Height="200" 
                             VerticalScrollBarVisibility="Visible" 
                             TextWrapping="Wrap" 
                             Grid.Row="3"/>

如您所見,我的layoutRoot網格綁定到了我的ViewModel,即PersonEntryViewModel,而包含編輯所需文本框的網格內容面板被綁定到了CurrentPerson。

那是正確的方法嗎? 我需要將控件綁定到CurrentPerson屬性,如果正在編輯此人,它將包含數據;如果正在添加新人,它將包含一個新的空PersonModel。

就目前而言,這部分正在發揮作用。 當我在字段中鍵入一些文本並單擊下一個文本時,它將調用setCurrentPerson相關屬性,而該屬性又將調用PersonModel。 單擊保存按鈕,然后檢查CurrentPerson,我可以看到它已設置了所有各種屬性。

如您在我的PersonEntryViewModel中看到的,我還有其他必需的屬性。 例如,EnableSaveButton,從技術上應該基於CurrentPerson對象對各種屬性的驗證將其設置為true或false,但是我需要在用戶在各個文本框中鍵入文本時進行檢查,這就是我在有問題。

如果啟用以下代碼:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="TextChanged">
        <i:InvokeCommandAction Command="{Binding NameTextChanged, Mode=OneWay}" CommandParameter="{Binding}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

在我真正需要它的PersonEntryViewModel中並沒有觸發它,因為這是我要設置EnableSaveButton屬性的地方,但是我想這是有意義的,因為此代碼綁定到Name文本框,而后者又綁定到CurrentPerson屬性,是我的PersonModel。

如果我將代碼從PersonEntryViewModel移到PersonViewModel

private ICommand _personTextChanged;

public ICommand PersonTextChanged
{
   get
   {
       return this._personTextChanged ?? (this._personTextChanged = new DelegateCommand(PersonTextChangedAction));
   }
}

private void PersonTextChangedAction(object actionParameters)
{
    if (!string.IsNullOrEmpty(this._name) && this._name.Length > 2)
    {
        //EnableSaveButton = true;
        Console.WriteLine("");
    }
}

它會被相應地觸發,但是然后我如何將這些信息返回到我的PersonEntryViewModel,該信息綁定到我的2個按鈕(即保存和取消)所在的視圖,並且假設設置時,EnableSaveButton屬性負責相應地啟用保存按鈕名稱有效,例如set和minlen是匹配的。

是否正確設計了PersonEntryViewModel並使用CurrentPerson屬性(正在編輯或添加的當前人員)正確設計了該如何處理?

我希望以上所述是有道理的,但是如果我對某些內容不清楚,請告訴我,我會盡力澄清。

謝謝。

PS:我發表了另一篇有關如何檢測文本更改的文章,但我發現了,但這顯然不是問題所在。 這個問題似乎與設計有關。

您的設計對我來說還不清楚。

如果您想使用當前的設計本身,我建議您做以下事情。

刪除為xaml中的網格分配DataContext的方法。

在后面的代碼中添加:

var dataContext = new PersonEntryViewModel();
this.ContentPanel.DataContext = dataContext.CurrentPerson;
// After creating App bar
this.appBar.DataContext = dataContext;
//Your xaml code will look something like this:
<AppBar x:Name="appBar">
    <Button x:Name="saveBtn" IsEnabled={Binding EnableSaveButton} />
<AppBar />

暫無
暫無

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

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