我很难理解我做错了什么。基本上我正在努力实现一个"取消"表格上的功能。
我有一个Model,它实现了工具包的ObservableObject并映射到EF实体类。当我调用CancelChanges()方法时,它基本上使用StoreWins执行context.Refresh()。
现在我有一个具有以下属性的ViewModel:
/// <summary>
/// The <see cref="CurrentDairyProduct" /> property's name.
/// </summary>
public const string CurrentDairyProductPropertyName = "CurrentDairyProduct";
private DairyProduct _currentDairyProduct = null;
/// <summary>
/// Sets and gets the CurrentDairyProduct property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public DairyProduct CurrentDairyProduct
{
get
{
return _currentDairyProduct;
}
set
{
RaisePropertyChanging(CurrentDairyProductPropertyName);
_currentDairyProduct = value;
RaisePropertyChanged(CurrentDairyProductPropertyName);
}
}
使用此表单的视图
<Grid HorizontalAlignment="Left" Margin="27,14,0,0" Name="grid1" VerticalAlignment="Top" DataContext="{Binding Path=CurrentDairyProduct, Mode=OneWay, NotifyOnSourceUpdated=True}">
<Grid.Resources>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Content="DAIRY PRODUCT CODE:" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="0" Height="23" HorizontalAlignment="Left" Margin="3" Text="{Binding Path=DairyProductCode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" VerticalAlignment="Center" Width="120" />
<Label Content="DAIRY PRODUCT NAME EN:" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Text="{Binding Path=DairyProductNameEn, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" VerticalAlignment="Center" Width="120" />
<Label Content="DAIRY PRODUCT NAME FR:" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="3" Text="{Binding Path=DairyProductNameFr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" VerticalAlignment="Center" Width="120" />
</Grid>
<Button Content="Save" Height="29" HorizontalAlignment="Left" Margin="342,332,0,0" Name="button1"
VerticalAlignment="Top" Width="87" Command="{Binding Path=SaveCommand}" />
<Button Content="Cancel" Height="29" HorizontalAlignment="Left" Margin="442,332,0,0" Name="button2"
VerticalAlignment="Top" Width="87" Command="{Binding Path=CancelCommand}" />
当我调用以下语句从数据库中获取数据时,一切正常
CurrentDairyProduct = _dairyProductRepository.GetObservableObjectById(_currentDairyProductId);
使用我的模型中的所有数据更新视图。
我可以对视图进行更改,然后将其转移到我的模型而不会出现问题
现在是CancelCommand
protected override void CancelChanges()
{
CurrentDairyProduct = _dairyProductRepository.CancelChanges(_currentDairyProduct);
}
理论上应该调用CurrentDairyProduct的setter,后者又调用RaisePropertyChanged。这就像我可以调试它一样。不幸的是,View根本没有更新。
出于好奇,我将CancelCommand代码更改为以下内容:
protected override void CancelChanges()
{
//CurrentDairyProduct = _dairyProductRepository.CancelChanges(_currentDairyProduct);
DairyProduct temp = _dairyProductRepository.CancelChanges(_currentDairyProduct);
CurrentDairyProduct = null;
CurrentDairyProduct = temp;
}
使用此代码,View会更新...
我的问题是,如果实际的DataContext停留在同一个对象上但它的属性发生了变化,我应该怎么做才能更新View。有没有办法在不使用这个临时变量的情况下强制更新?
提前致谢。
答案 0 :(得分:1)
似乎您正在尝试使用自己的支持字段更新CurrentDairyProduct。我猜你将_currentDairyProduct传递给你的存储库方法并直接操作它,然后返回它。通过这样做,您不会触发INPC,因此不会发生视图更新。当您尝试将其分配回CurrentDairyProduct时,该值现在是相同的,因此INPC也不会触发。当您将其设置为null并重新分配CurrentDairyProduct时,会检测到更改,因此会触发INPC。
解决此问题的一种方法是在存储库的CancelChanges方法中创建一个新实例DairyProduct,然后返回该实例而不是操纵_currentDairyProduct。 然后,CurrentDairyProduct将检测到一个新值并触发INPC。
更好的选择可能是传递CurrentDairyProduct而不是_currentDairyProduct。对CurrentDairyProduct的更改将触发INPC。
我相信如果你将变量设为私有,那么就没有业务在其范围之外被操纵。我的意思是,这就是为什么你有公共版本的权利?