ViewModel.Attach由于已经注册而在XAML中导致ArgumentException

时间:2015-01-27 18:27:44

标签: c# wpf user-controls dependencies

我有以下方法向ViewModel事件注册进度条UserControl:

private void SetProgressBar(ProgressBar progressBar)
        {
            _progressBar = progressBar;
            _progressBar.SizeChanged += (s, e) => ComputeViewModelProperties();
            RegisterForNotification("Value", progressBar, (d, e) => ComputeViewModelProperties());
            RegisterForNotification("Maximum", progressBar, (d, e) => ComputeViewModelProperties());
            RegisterForNotification("Minimum", progressBar, (d, e) => ComputeViewModelProperties());

            ComputeViewModelProperties();
        }

private void RegisterForNotification(string propertyName, FrameworkElement element, PropertyChangedCallback callback)
        {

            //Bind to a dependency property  
            Binding b = new Binding(propertyName) { Source = element };



            Prop = System.Windows.DependencyProperty.RegisterAttached(
                "ListenAttached" + propertyName,
                typeof(object),
                typeof(UserControl),
                new PropertyMetadata(callback));

            element.SetBinding(Prop, b);
        }

当我第一次将ProgressBar控件添加到XAML时,我没有收到任何错误。但是,在编辑XAML以添加其他控件时,我剪切并粘贴了ProgressBar以移动它,并收到错误:

ArgumentException: 'ListenAttachedValue' property was already registered by 'UserControl'.

为什么删除和添加此控件会导致错误?为什么它在第一次实施时没有引起问题?如果没有相应的错误注册"最大"和"最低?"

我的XAML:

<ProgressBar Value="{Binding Value}"  
                 Width="80" Height="80" 
                 Grid.Row="1" Grid.Column="1"
                 Style="{StaticResource SegmentedProgressBarStyle}" />

编辑:来自源代码的更多代码

public static CircularProgressBarViewModel GetAttach(DependencyObject d)
        {
            return (CircularProgressBarViewModel)d.GetValue(AttachProperty);
        }

        public static void SetAttach(DependencyObject d, CircularProgressBarViewModel value)
        {
            d.SetValue(AttachProperty, value);
        }

        /// <summary>
        /// Change handler for the Attach property
        /// </summary>
        private static void OnAttachChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // set the view model as the DataContext for the rest of the template
            FrameworkElement targetElement = d as FrameworkElement;
            CircularProgressBarViewModel viewModel = e.NewValue as CircularProgressBarViewModel;
            targetElement.DataContext = viewModel;

            // handle the loaded event
            targetElement.Loaded += new RoutedEventHandler(Element_Loaded);
        }

        /// <summary>
        /// Handle the Loaded event of the element to which this view model is attached
        /// in order to enable the attached
        /// view model to bind to properties of the parent element
        /// </summary>
        static void Element_Loaded(object sender, RoutedEventArgs e)
        {
            FrameworkElement targetElement = sender as FrameworkElement;
            CircularProgressBarViewModel attachedModel = GetAttach(targetElement);

            // find the ProgressBar and associated it with the view model
            var progressBar = targetElement.Ancestors<ProgressBar>().Single() as ProgressBar;
            attachedModel.SetProgressBar(progressBar);
        }

完整来源:circular progress bar

1 个答案:

答案 0 :(得分:0)

我解决了这个特殊问题:

public static DependencyProperty AttachedProperty;

由于该属性已注册一次,我只是重用它来绑定回调。

private void RegisterForNotification(string propertyName, FrameworkElement element, PropertyChangedCallback callback)
{

  //Bind to a dependency property  
  Binding b = new Binding(propertyName) { Source = element };
        if (AttachedProperty == null)
        {
          AttachedProperty = DependencyProperty.RegisterAttached(
          "ListenAttached" + propertyName,
          typeof(object),
          typeof(MainWindow),
          new PropertyMetadata(callback));
        }

  element.SetBinding(AttachedProperty, b);
}

不幸的是,这个Silverlight项目还有一些工作要先在你的WPF应用程序中使用它,我想这是我们的共同目标。