【问题标题】:Why is this attached property not updating?为什么这个附加属性没有更新?
【发布时间】:2016-04-12 21:51:59
【问题描述】:

好的,所以我最初只是将这个作为绑定不起作用的问题发布。但是,一旦我尝试最小化要在 SO 上发布的代码,它就会产生另一个问题。

所以,从本质上讲,Extensions 类旨在连接到ListBox 并制作SelectedItems 的可绑定版本。这个抓取SelectedItems 并将它们放在Selected 附加属性中的功能在我的程序中有效(在我的真实程序中它似乎没有绑定?),但在这个最小化版本中无效。我不知道为什么,代码似乎完成了它需要做的所有事情。

我用来测试的代码:

.xaml.cs

namespace MyNamespace
{
    public partial class MainWindow
    {
        public IList Selected { get; set; }
        public MainWindow()
        {
            InitializeComponent();
            Selected = new List<object>();
            Why.ItemsSource = new[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        }
        private void Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(Selected.Cast<object>().Aggregate("", (s, info) => $"{s}{info}, ").TrimEnd(',', ' '));
            MessageBox.Show(Extensions.GetSelected(Why).Cast<object>().Aggregate("", (s, o) => $"{s}{o}, ").TrimEnd(',', ' '));
        }
    }
    public static class Extensions
    {
        public static readonly DependencyProperty SelectedProperty = DependencyProperty.RegisterAttached(
            "Selected", typeof(IList), typeof(Extensions), new PropertyMetadata(default(IList), HookSelectionChanged));

        private static void HookSelectionChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ListBox lb = sender as ListBox;
            if (lb == null)
                throw new ArgumentException("This property currently only supports DependencyObjects inheriting from Selector.", nameof(sender));
            lb.SelectionChanged += SelectionChanged;
        }

        private static void SelectionChanged(object sender, SelectionChangedEventArgs selectionChangedEventArgs)
            => SetSelected((ListBox)sender, ((ListBox)sender).SelectedItems.Cast<object>().ToList());

        public static void SetSelected(DependencyObject element, IList value) => element.SetValue(SelectedProperty, value);

        public static IList GetSelected(DependencyObject element) => (IList)element.GetValue(SelectedProperty);
    }
}

.xaml

<Window x:Class="MyNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:lcl="clr-namespace:MyNamespace"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="My title." Height="350" Width="425" MaxHeight="350" MaxWidth="425" MinHeight="350" MinWidth="425">
    <StackPanel>
        <ListBox lcl:Extensions.Selected="{Binding Selected}" x:Name="Why" SelectionMode="Extended"/>
        <Button Click="Click" Content="blah"/>
    </StackPanel>
</Window>

任何想法都会很棒!谢谢:)

【问题讨论】:

  • 这可能会有所帮助:spin.atomicobject.com/2013/12/11/wpf-data-binding-debug PresentationTraceSources.TraceLevel 对我来说是每天的救命稻草(哎呀,错过了您的 DataContext 绑定)
  • 不应该是{Binding Selected}{Binding Selected, Mode=TwoWay} 吗?
  • @Quantic 是对的——你也可以用 [FrameworkPropertyMetadata](msdn.microsoft.com/en-us/library/ms557295(v=vs.110).aspx) 代替PropertyMetadata,这样你就可以传入FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,这样就省去了你消费者的麻烦必须记得添加Mode=TwoWay
  • @Quantic 仅使用控件后,我没有意识到并非所有 Bindings 都默认为 TwoWay。使用 + 实现 INotifyPropertyChanged 在我的测试用例和实际程序中修复了它,谢谢!

标签: c# wpf xaml listbox attached-properties


【解决方案1】:

好吧,只是我错过了两件事:

  • 我没有在我的测试中实现INotifyPropertyChanged
  • 我不知道Bindings 并非一直默认为TwoWay

所以所有需要做的就是:

.xaml.cs

namespace MyNamespace
{
    public partial class MainWindow : INotifyPropertyChanged
    {
        private IList _selected;

        public IList Selected
        {
            get { return _selected; }
            set
            {
                if (Equals(value, _selected)) return;
                _selected = value;
                OnPropertyChanged();
            }
        }

        public MainWindow()
        {
            InitializeComponent();
            Selected = new List<object>();
            Why.ItemsSource = new[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        }
        private void Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(Selected.Cast<object>().Aggregate("", (s, info) => $"{s}{info}, ").TrimEnd(',', ' '));
            MessageBox.Show(Extensions.GetSelected(Why).Cast<object>().Aggregate("", (s, o) => $"{s}{o}, ").TrimEnd(',', ' '));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public class Extensions
    {
        public static readonly DependencyProperty SelectedProperty = DependencyProperty.RegisterAttached(
            "Selected", typeof(IList), typeof(Extensions), new FrameworkPropertyMetadata(default(IList), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, HookSelectionChanged));

        private static void HookSelectionChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ListBox lb = sender as ListBox;
            if (lb == null)
                throw new ArgumentException("This property currently only supports DependencyObjects inheriting from Selector.", nameof(sender));
            lb.SelectionChanged += SelectionChanged;
        }

        private static void SelectionChanged(object sender, SelectionChangedEventArgs selectionChangedEventArgs)
            => SetSelected((ListBox)sender, ((ListBox)sender).SelectedItems.Cast<object>().ToList());

        public static void SetSelected(DependencyObject element, IList value) => element.SetValue(SelectedProperty, value);

        public static IList GetSelected(DependencyObject element) => (IList)element.GetValue(SelectedProperty);
    }
}

而且效果很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-24
    • 1970-01-01
    • 2020-12-14
    相关资源
    最近更新 更多