繁体   English   中英

为什么我的SaveCommand Button无法在UWP中工作? 我使用MVVM模式

[英]My SaveCommand Button isnt working in UWP why?? I use MVVM Pattern

好的,我一直在UWP上使用MVVM Pattern进行练习,现在我创建了一个对象Customer EditableCustomer,这是我的视图和VM上的模型之间的辅助属性。 如果我的四个属性FirstName,LastName,Email和Phone arent为空或为空,则应该启用我的savecommand按钮。

但是我无法在EditableCustomer上引发属性更改,因此我可以引发SaveCommand.RaiseCanExecuteChanged()。

这是我的观点代码:

<UserControl
x:Class="MVVMHeirarchiesDemo.Views.AddEditCustomerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MVVMHeirarchiesDemo.Views"
xmlns:viewmodel="using:MVVMHeirarchiesDemo.ViewModel"
xmlns:conv="using:MVVMHeirarchiesDemo.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">

<UserControl.DataContext>
    <viewmodel:AddEditCustomerViewModel/>
</UserControl.DataContext>

<UserControl.Resources>
    <conv:ValidationMessageConverter x:Key="ValidationMessageConverter"/>
</UserControl.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <Grid x:Name="grid1"
          HorizontalAlignment="Left"
          Margin="10,10,0,0"
          VerticalAlignment="Top">

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <TextBlock Text="First Name:"
                   Grid.Column="0"
                   Grid.Row="0"
                   HorizontalAlignment="Left"
                   VerticalAlignment="Center"
                   Margin="3"/>
        <StackPanel Orientation="Vertical"
                    Grid.Column="1"
                    Grid.Row="0">

            <TextBox x:Name="firstNameTextBox"
                     Text="{Binding EditableCustomer.FirstName, Mode=TwoWay}"
                     HorizontalAlignment="Left"
                     VerticalAlignment="Center"
                     Margin="3"
                     Height="23"
                     Width="120"/>
            <TextBlock x:Name="firstNameErrorMessage"
                       Text="{Binding EditableCustomer.ValidationMessages[FirstName], Converter={StaticResource ValidationMessageConverter}}"
                       Width="{Binding Width, ElementName=firstNameTextBox, Mode=OneWay}"
                       TextWrapping="Wrap"/>
        </StackPanel>

        <TextBlock Text="Last Name:"
                   Grid.Column="0"
                   Grid.Row="1"
                   HorizontalAlignment="Left"
                   VerticalAlignment="Center"
                   Margin="3"/>

        <StackPanel Orientation="Vertical"
                    Grid.Column="1"
                    Grid.Row="1">

            <TextBox x:Name="lastNameTextBox"
                     Text="{Binding EditableCustomer.LastName, Mode=TwoWay}"
                     HorizontalAlignment="Left"
                     VerticalAlignment="Center"
                     Width="{Binding Width, ElementName=firstNameTextBox, Mode=OneWay}"
                     Height="{Binding Height, ElementName=firstNameTextBox, Mode=OneWay}"
                     Margin="3"/>
            <TextBlock x:Name="lastNameErrorMessage"
                       Text="{Binding EditableCustomer.ValidationMessages[LastName], Converter={StaticResource ValidationMessageConverter}}"
                       Width="{Binding Width, ElementName=firstNameTextBox, Mode=OneWay}"
                       TextWrapping="Wrap"/>
        </StackPanel>

        <TextBlock Text="Email:"
                   Grid.Column="0"
                   Grid.Row="2"
                   HorizontalAlignment="Left"
                   VerticalAlignment="Center"
                   Margin="3"/>
        <StackPanel Orientation="Vertical"
                    Grid.Column="1"
                    Grid.Row="2">

            <TextBox x:Name="emailTextBox"
                     Text="{Binding EditableCustomer.Email, Mode=TwoWay}"
                     HorizontalAlignment="Left"
                     VerticalAlignment="Center"
                     Width="{Binding Width, ElementName=firstNameTextBox, Mode=OneWay}"
                     Height="{Binding Height, ElementName=firstNameTextBox, Mode=OneWay}"
                     Margin="3"/>
            <TextBlock x:Name="emailErrorMessage"
                       Text="{Binding EditableCustomer.ValidationMessages[Email], Converter={StaticResource ValidationMessageConverter}}"
                       Width="{Binding Width, ElementName=firstNameTextBox, Mode=OneWay}"
                       TextWrapping="Wrap"/>
        </StackPanel>

        <TextBlock Text="Phone:"
                   Grid.Column="0"
                   Grid.Row="3"
                   HorizontalAlignment="Left"
                   VerticalAlignment="Center"
                   Margin="3"/>

        <StackPanel Orientation="Vertical"
                    Grid.Column="1"
                    Grid.Row="3">

            <TextBox x:Name="phoneTextBox"
                     Text="{Binding EditableCustomer.Phone, Mode=TwoWay}"
                     HorizontalAlignment="Left"
                     VerticalAlignment="Center"
                     Width="{Binding Width, ElementName=firstNameTextBox, Mode=OneWay}"
                     Height="{Binding Height, ElementName=firstNameTextBox, Mode=OneWay}"
                     Margin="3"/>
            <TextBlock x:Name="phoneErrorMessage"
                       Text="{Binding EditableCustomer.ValidationMessages[Phone], Converter={StaticResource ValidationMessageConverter}}"
                       Width="{Binding Width, ElementName=firstNameTextBox, Mode=OneWay}"
                       TextWrapping="Wrap"/>
        </StackPanel>
    </Grid>

    <Grid Grid.Row="1">
        <StackPanel Orientation="Horizontal">
            <Button x:Name="saveCommandButton"
                Content="Save"
                Command="{Binding SaveCommand}"
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Margin="25,5,0,0"
                Width="75"/>

            <Button x:Name="addCommandButton"
                Content="Add"
                Command="{Binding SaveCommand}"
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Margin="25,5,0,0"
                Width="{Binding Width, ElementName=saveCommandButton, Mode=OneWay}"/>

            <Button x:Name="cancelCommandButton"
                    Content="Cancel"
                    Command="{Binding CancelCommand}"
                    HorizontalAlignment="Left"
                    VerticalAlignment="Center"
                    Margin="25,5,0,0"
                    Width="{Binding Width, ElementName=saveCommandButton, Mode=OneWay}"/>
        </StackPanel>
    </Grid>
</Grid>

如您在我的文本框中看到的,文本属性绑定到我的EditableCustomer。(propertyName)

我的ViewModel是这样的:

public class AddEditCustomerViewModel : BindableBase
{
    public AddEditCustomerViewModel()
    {
        CancelCommand = new MyCommand(OnCancel);
        SaveCommand = new MyCommand(OnSave, CanSave);
        EditableCustomer = new Customer();
    }

    private Customer _editableCustomer;

    public Customer EditableCustomer
    {
        get
        {
            return _editableCustomer;
        }
        set
        {
            SetProperty(ref _editableCustomer, value);
            SaveCommand.RaiseCanExecuteChanged();
        }
    }

    public MyCommand CancelCommand { get; private set; }
    public MyCommand SaveCommand { get; private set; }

    public event Action Done = delegate { };

    private void OnCancel()
    {
        Done();
    }

    private void OnSave()
    {
        Done();
    }

    private bool CanSave()
    {
        if (HasEmptyFields())
            return false;
        return true;
    }

    private bool HasEmptyFields()
    {
        return string.IsNullOrEmpty(EditableCustomer.FirstName) || string.IsNullOrEmpty(EditableCustomer.LastName)
                        || string.IsNullOrEmpty(EditableCustomer.Phone) || string.IsNullOrEmpty(EditableCustomer.Email);
    }
}

我需要做的就是能够为我的EditableCustomer属性触发设置器,但是我已经能够做到这一点。 我在这里想念什么?

我看到了我的代码,我认为每当每个字段都包含文本时就应该提高它,直到我所有的文本框上都带有文本时才变为真。

但是什么也没发生。

只是为了了解这是我的BindableBase是我应用INotifyPropertyChanged的类。

public class BindableBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void SetProperty<T>(ref T member, T val, [CallerMemberName]string propertyName = null)
    {
        if (object.Equals(member, val))
            return;

        member = val;
        OnPropertyChanged(propertyName);
    }
}

我希望有人能启发我,与此同时,我将继续努力研究这个问题。

看起来像SaveCommand.RaiseCanExecuteChanged(); 仅在设置EditableCustomer时调用,但是在修改该对象内的值(即名称,电子邮件等)时,没有任何事情通知UI可以执行SaveCommand

如果要像这样分解视图模型,在该模型中有一个封装类来管理输入,则需要将更改通知给父视图模型。 您的AddEditCustomerViewModel不知道属性何时更改,因此无法相应地RaiseCanExecuteChanged()


更新资料

在您的情况下,我建议让视图模型路由UI表单可以修改的所有属性。 例如:

public class AddEditCustomerViewModel : BindableBase
{
    public string FirstName
    {
        get { return _editableCustomer.FirstName; }
        set
        {
            _editableCustomer.FirstName = value;
            OnPropertyChanged(nameof(FirstName));

            if (!HasEmptyFields())
            {
                SaveCommand.RaiseCanExecuteChanged();
            }
        }
    }
}

并且您的XAML应该直接绑定到视图模型,而不是模型:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM