【问题标题】:How to debug INPC property setter not triggered?如何调试未触发的 INPC 属性设置器?
【发布时间】:2016-04-30 21:25:40
【问题描述】:

概述: 我已经使用 INPC 设置了一个属性,该属性在 MainViewModel 后面的视图代码中调用页面导航。此属性绑定到绑定视图中列表视图的 SelectedItem 属性。

INPC 实现继承自 ViewModelBase 类,实现如下,https://gist.github.com/BrianJVarley/4a0890b678e037296aba

问题:

当我从列表视图中选择一个项目时,SelectedCouncilItem setter 属性不会触发。此属性绑定到列表视图的 SelectedItem 属性。

调试步骤:

  • 已检查列表视图属性中 SelectedItem 的绑定名称,与 MainViewModel 中的属性名称相同。
  • 运行解决方案并检查输出窗口中是否存在任何绑定错误,但没有。
  • 在 SelectedCouncilItem 上放置了一个断点,当我从列表视图中选择时它不会被触发。
  • 检查了视图的数据上下文设置,验证该视图已设置为 MainViewModel 的数据上下文。

问题:

有谁知道我可以采取哪些其他步骤来调试问题,或者问题可能是什么?

代码:

MainPage -(列表视图)

    <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;
        }


    }
}

【问题讨论】:

    标签: c# properties windows-phone-8.1 inotifypropertychanged


    【解决方案1】:

    控件有问题。请尝试使用自定义 LongListSelector

    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>
    

    【讨论】:

    • 我尝试先添加上面的类,hastebin.com/ahudowakop.cs ctor 名称有误,所以改了。我在课堂上遇到的唯一错误是在 SetSelectedItem 上,说明它不在 LongListSelector 中。有什么想法吗?另外,实现这个扩展列表选择器如何解决问题中的问题?
    • 使用 SelectedItem="{Binding SelectedCouncilItem}"。无需调用 SetSelectedItem
    • 所以我需要从上面的类中删除这个方法?私有无效 SetSelectedItem(DependencyPropertyChangedEventArgs e) { base.SelectedItem = e.NewValue; }
    • 没有。永远不要从中删除任何东西。构建您的代码并粘贴我确切的调试错误
    • 已编辑答案。请更改它并让我知道。
    猜你喜欢
    • 1970-01-01
    • 2013-04-09
    • 2013-08-30
    • 1970-01-01
    • 2022-01-03
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 2011-03-10
    相关资源
    最近更新 更多