如果我使用類型轉換器將RadioButton綁定到視圖模型屬性,則每次創建視圖時,都會調用前一個ViewModel的setter,甚至儘管視圖已卸載並且不應再存在。這裏是最小代碼重現該問題:在創建新視圖時在未加載視圖/視圖模型上綁定火災
1)定義枚舉類型:
enum EnumType {
Value1,
Value2,
}
2)定義一個convereter:
public class EnumTypeToBooleanConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, string language) {
return true;
}
public object ConvertBack(object value, Type targetType, object parameter, string language) {
return EnumType.Value1;
}
}
3)定義視圖模型:
class ViewModel : INotifyPropertyChanged {
private EnumType value;
public ViewModel() {
Debug.WriteLine(string.Format("ViewModel ({0})::ctor", this.GetHashCode()));
}
public EnumType Value {
get {
Debug.WriteLine(string.Format("ViewModel ({0})::Value::get", this.GetHashCode()));
return this.value;
}
set {
Debug.WriteLine(string.Format("ViewModel ({0})::Value::set", this.GetHashCode()));
if (this.value != value) {
this.value = value;
this.OnPropertyChanged();
}
}
}
private void OnPropertyChanged([CallerMemberName] string name = null) {
if (this.PropertyChanged != null) {
var ea = new PropertyChangedEventArgs(name);
this.PropertyChanged(this, ea);
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
4)定義一個用戶控件(View.xaml)
<UserControl
x:Class="BindingIssue.View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BindingIssue"
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"
x:Name="root">
<UserControl.DataContext>
<local:ViewModel x:Name="ViewModel"/>
</UserControl.DataContext>
<Grid>
<ScrollViewer>
<StackPanel>
<RadioButton x:Name="rdo1"
Content="Value1"
IsChecked="{Binding Path=Value, Converter={StaticResource EnumTypeToBooleanConverter}, ConverterParameter=Value1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button x:Name="btnClose"
Click="btnClose_Click"
Content="Close"/>
</StackPanel>
</ScrollViewer>
</Grid>
5)添加代碼觀的背後:
public View() {
Debug.WriteLine(string.Format("View ({0})::ctor", this.GetHashCode()));
this.InitializeComponent();
this.Loaded += OnLoaded;
this.Unloaded += OnUnloaded;
}
private void btnClose_Click(object sender, RoutedEventArgs e) {
if (this.Parent is Popup) {
Debug.WriteLine("Closing the popup...");
((Popup)this.Parent).IsOpen = false;
}
}
private void OnLoaded(object sender, RoutedEventArgs e) {
Debug.WriteLine(string.Format("View ({0})::Loaded", this.GetHashCode()));
}
private void OnUnloaded(object sender, RoutedEventArgs e) {
Debug.WriteLine(string.Format("View ({0})::Unloaded", this.GetHashCode()));
}
6)的MainPage(XAML)
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
x:Name="Grid">
<Button x:Name="btnNewView"
Click="btnNewView_Click"
Content="New View"
Margin="4"/>
</Grid>
7)的事件處理程序添加到的MainPage
private void btnNewView_Click(object sender, RoutedEventArgs e) {
Debug.WriteLine("Opening a new popup...");
View view = new View();
view.HorizontalAlignment = HorizontalAlignment.Center;
view.VerticalAlignment = VerticalAlignment.Center;
Popup popup = new Popup();
popup.Child = view;
popup.HorizontalOffset = 300;
popup.VerticalOffset = 300;
popup.IsOpen = true;
}
打開d關閉彈出式菜單多次結果如下輸出(請跟蹤的散列碼):
打開一個新的彈出...
視圖(46418718):: ctor的
視圖模型(59312528) ::男星
視圖模型(59312528)::值::獲得
視圖(46418718)::加載
關閉彈出窗口...
視圖(46418718)::卸載
打開一個新的彈出...
視圖(58892413):: ctor的
視圖模型(61646925) ::男星
視圖模型(61646925)::值::獲得
視圖模型(59312528)::值::設爲
視圖(58892413)::加載
關閉彈出...
視圖(58892413)::卸載
這意味着對於處於無負載視圖模型創建的視圖模型設置器被稱爲是有點怪。對於x:Bind和Binding,這種行爲是相同的。
我想知道是否有關於此行爲的解釋。
明晰更多: 一個全新的一對視圖/視圖模型實例被創建的每個時間,但已在加載新的視圖時,上視圖模型的前一個實例的設置器被調用。視圖的前一個實例已卸載,並且不應該在此時存在。 (認爲這是被每次閉合一個彈出的,並且沒有事件的引用舊視圖/視圖模型。)
謝謝您的答覆,但我認爲你錯過了問題的全部意義:爲什麼制定者正在呼籲「老」視圖模型視圖時的一個新實例(和新的視圖模型)被加載?請注意,我不重新載入舊視圖,每次創建一個「新」視圖和視圖模型,舊視圖在這一點上應該超出範圍(或GC'ed)。而且我沒有說當視圖被卸載時調用者被調用。我說setter正在被調用的未加載視圖/視圖模型。那個觀點模型在這一點上應該已經死了。 –
你是對的滾動查看器的東西,它發生沒有滾動查看器以及。我更新了這個問題,但問題的主要觀點仍未得到答覆。 –