好的,我一直在UWP上练习MVVM模式,现在我已经创建了一个对象Customer EditableCustomer,这是我的视图和我的VM模型之间的帮助属性。 如果我的四个属性FirstName,LastName,Email和Phone不为空或者空,我的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>
正如您在我的文本框中看到的那样,text属性绑定到我的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属性的setter,但我已经能够用它来做到这一点。 我在这里失踪了什么?
我看到了我的代码,我认为每当每个字段都有文本时都应该提高它,直到它的所有文本框都有文字后才会变为真。
但没有任何反应。
只是为了理解这是我的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);
}
}
我希望有人可以让我高兴,同时我会继续深入研究这个问题。
答案 0 :(得分:1)
看起来SaveCommand.RaiseCanExecuteChanged();
仅在您设置EditableCustomer
时被调用,但是当您修改该对象内的值(即名称,电子邮件等)时,没有任何内容通知UI {{ 1}}可以执行。
如果你打算拆分这样的视图模型,你有一个管理输入的封装类,那么它需要通知父视图模型的变化。您的SaveCommand
不知道属性何时发生变化,因此无法AddEditCustomerViewModel
。
<强>更新强>
在您的情况下,我建议让视图模型路由所有可以由UI表单修改的属性。例如:
RaiseCanExecuteChanged()
并且您的XAML应该直接绑定到视图模型,而不是模型:
public class AddEditCustomerViewModel : BindableBase
{
public string FirstName
{
get { return _editableCustomer.FirstName; }
set
{
_editableCustomer.FirstName = value;
OnPropertyChanged(nameof(FirstName));
if (!HasEmptyFields())
{
SaveCommand.RaiseCanExecuteChanged();
}
}
}
}