如何调试INPC属性setter没有触发?
How to debug INPC property setter not triggered?
概览:
我已经用 INPC 设置了 属性,它在 MainViewModel
后面的视图代码中调用页面导航。此属性绑定到绑定视图中列表视图的SelectedItem属性。
INPC 实现继承自 ViewModelBase
class 实现如下,https://gist.github.com/BrianJVarley/4a0890b678e037296aba
问题:
当我 select 列表视图中的项目时,属性 SelectedCouncilItem
setter 不会触发。此 属性 绑定到列表视图的 SelectedItem 属性。
调试步骤:
- 已检查列表视图中 SelectedItem 的绑定名称 属性,它与 MainViewModel 中的 属性 名称相同。
- 运行 解决方案并检查输出 window 中的任何绑定错误,其中有 none.
- 在 SelectedCouncilItem 上放置了一个断点,当我从列表视图 select 时它不会被触发。
- 检查了视图的数据上下文设置,确认视图设置为 MainViewModel 的数据上下文。
问题:
有谁知道我可以采取哪些其他步骤来调试问题,或者问题可能是什么?
代码:
主页 -(列表视图)
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<phone:LongListSelector x:Name="MainLongListSelector"
Margin="0,0,-12,0"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedCouncilItem}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<TextBlock Style="{StaticResource PhoneTextExtraLargeStyle}"
Text="{Binding CouncilAcronym}"
TextWrapping="Wrap" />
<TextBlock Margin="12,-6,12,0"
Style="{StaticResource PhoneTextSubtleStyle}"
Text="{Binding CouncilFullName}"
TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
MainViewModel -(摘要)
namespace ParkingTagPicker.ViewModels
{
public class MainViewModel : ViewModelBase
{
//Dependency Injection private instances
private INavigationCallback _navCallBack = null;
public MainViewModel()
{
this.Items = new ObservableCollection<ItemViewModel>();
}
/// <summary>
/// Creates and adds a few ItemViewModel objects into the Items collection.
/// </summary>
public void LoadCouncilNamesData()
{
this.Items.Add(new ItemViewModel() { ID = "6", CouncilAcronym = "WTC", CouncilFullName = "Wicklow Town Council"});
this.Items.Add(new ItemViewModel() { ID = "7", CouncilAcronym = "TS", CouncilFullName = "Tallaght Stadium" });
this.Items.Add(new ItemViewModel() { ID = "8", CouncilAcronym = "GS", CouncilFullName = "Greystones" });
this.IsDataLoaded = true;
}
public ObservableCollection<ItemViewModel> Items { get; private set; }
public bool IsDataLoaded { get; private set; }
private ItemViewModel _selectedCouncilItem;
public ItemViewModel SelectedCouncilItem
{
get
{
return this._selectedCouncilItem;
}
set
{
this.SetProperty(ref this._selectedCouncilItem, value, () => this._selectedCouncilItem);
if (_selectedCouncilItem != null)
{
_navCallBack.NavigateTo(_selectedCouncilItem.ID);
}
}
}
public INavigationCallback NavigationCallback
{
get { return _navCallBack; }
set { _navCallBack = value; }
}
}
}
ViewModelBase -(详细说明 INPC 实现)
namespace ParkingTagPicker.ViewModels
{
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var propertyChanged = this.PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
protected bool SetProperty<T>(ref T backingField, T Value, Expression<Func<T>> propertyExpression)
{
var changed = !EqualityComparer<T>.Default.Equals(backingField, Value);
if (changed)
{
backingField = Value;
this.RaisePropertyChanged(ExtractPropertyName(propertyExpression));
}
return changed;
}
private static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
{
var memberExp = propertyExpression.Body as MemberExpression;
if (memberExp == null)
{
throw new ArgumentException("Expression must be a MemberExpression.", "propertyExpression");
}
return memberExp.Member.Name;
}
}
}
控件有问题。请尝试使用自定义 LongListSeletor
public class ExtendedLongListSelector : Microsoft.Phone.Controls.LongListSelector
{
public ExtendedLongListSelector()
{
SelectionChanged += LongListSelector_SelectionChanged;
}
void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelectedItem = base.SelectedItem;
}
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(LongListSelector),
new PropertyMetadata(null, OnSelectedItemChanged));
private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var selector = (LongListSelector)d;
selector.SelectedItem = e.NewValue;
}
public new object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
}
并在 XAML 中用现有列表替换它。
xmlns:controls="clr-namespace:ProjectName.FolderName"
<controls:ExtendedLongListSelector x:Name="MainLongListSelector"
Margin="0,0,-12,0"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedCouncilItem}">
</controls:ExtendedLongListSelector>
概览:
我已经用 INPC 设置了 属性,它在 MainViewModel
后面的视图代码中调用页面导航。此属性绑定到绑定视图中列表视图的SelectedItem属性。
INPC 实现继承自 ViewModelBase
class 实现如下,https://gist.github.com/BrianJVarley/4a0890b678e037296aba
问题:
当我 select 列表视图中的项目时,属性 SelectedCouncilItem
setter 不会触发。此 属性 绑定到列表视图的 SelectedItem 属性。
调试步骤:
- 已检查列表视图中 SelectedItem 的绑定名称 属性,它与 MainViewModel 中的 属性 名称相同。
- 运行 解决方案并检查输出 window 中的任何绑定错误,其中有 none.
- 在 SelectedCouncilItem 上放置了一个断点,当我从列表视图 select 时它不会被触发。
- 检查了视图的数据上下文设置,确认视图设置为 MainViewModel 的数据上下文。
问题:
有谁知道我可以采取哪些其他步骤来调试问题,或者问题可能是什么?
代码:
主页 -(列表视图)
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<phone:LongListSelector x:Name="MainLongListSelector"
Margin="0,0,-12,0"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedCouncilItem}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<TextBlock Style="{StaticResource PhoneTextExtraLargeStyle}"
Text="{Binding CouncilAcronym}"
TextWrapping="Wrap" />
<TextBlock Margin="12,-6,12,0"
Style="{StaticResource PhoneTextSubtleStyle}"
Text="{Binding CouncilFullName}"
TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
MainViewModel -(摘要)
namespace ParkingTagPicker.ViewModels
{
public class MainViewModel : ViewModelBase
{
//Dependency Injection private instances
private INavigationCallback _navCallBack = null;
public MainViewModel()
{
this.Items = new ObservableCollection<ItemViewModel>();
}
/// <summary>
/// Creates and adds a few ItemViewModel objects into the Items collection.
/// </summary>
public void LoadCouncilNamesData()
{
this.Items.Add(new ItemViewModel() { ID = "6", CouncilAcronym = "WTC", CouncilFullName = "Wicklow Town Council"});
this.Items.Add(new ItemViewModel() { ID = "7", CouncilAcronym = "TS", CouncilFullName = "Tallaght Stadium" });
this.Items.Add(new ItemViewModel() { ID = "8", CouncilAcronym = "GS", CouncilFullName = "Greystones" });
this.IsDataLoaded = true;
}
public ObservableCollection<ItemViewModel> Items { get; private set; }
public bool IsDataLoaded { get; private set; }
private ItemViewModel _selectedCouncilItem;
public ItemViewModel SelectedCouncilItem
{
get
{
return this._selectedCouncilItem;
}
set
{
this.SetProperty(ref this._selectedCouncilItem, value, () => this._selectedCouncilItem);
if (_selectedCouncilItem != null)
{
_navCallBack.NavigateTo(_selectedCouncilItem.ID);
}
}
}
public INavigationCallback NavigationCallback
{
get { return _navCallBack; }
set { _navCallBack = value; }
}
}
}
ViewModelBase -(详细说明 INPC 实现)
namespace ParkingTagPicker.ViewModels
{
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var propertyChanged = this.PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
protected bool SetProperty<T>(ref T backingField, T Value, Expression<Func<T>> propertyExpression)
{
var changed = !EqualityComparer<T>.Default.Equals(backingField, Value);
if (changed)
{
backingField = Value;
this.RaisePropertyChanged(ExtractPropertyName(propertyExpression));
}
return changed;
}
private static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
{
var memberExp = propertyExpression.Body as MemberExpression;
if (memberExp == null)
{
throw new ArgumentException("Expression must be a MemberExpression.", "propertyExpression");
}
return memberExp.Member.Name;
}
}
}
控件有问题。请尝试使用自定义 LongListSeletor
public class ExtendedLongListSelector : Microsoft.Phone.Controls.LongListSelector
{
public ExtendedLongListSelector()
{
SelectionChanged += LongListSelector_SelectionChanged;
}
void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelectedItem = base.SelectedItem;
}
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(LongListSelector),
new PropertyMetadata(null, OnSelectedItemChanged));
private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var selector = (LongListSelector)d;
selector.SelectedItem = e.NewValue;
}
public new object SelectedItem
{
get { return GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
}
并在 XAML 中用现有列表替换它。
xmlns:controls="clr-namespace:ProjectName.FolderName"
<controls:ExtendedLongListSelector x:Name="MainLongListSelector"
Margin="0,0,-12,0"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedCouncilItem}">
</controls:ExtendedLongListSelector>