Установка значения свойства ViewModel из XAML - PullRequest
4 голосов
/ 10 июня 2011

У меня есть представление, которое объявлено в XAML (см. Ниже).Соответствующая модель представления создается автоматически с использованием MEF.Я хочу иметь возможность сделать что-то вроде этого:

<local:MyControl Owner={x:Static local:Owners.ProjectOwner} />

Желаемый чистый эффект для некоторого свойства view-model, установленного равным Owners.ProjectOwner.

Я могу достичьТребуемый результат с использованием хакерского кода, но он будет делать это через привязки или каким-либо другим способом.Может кто-нибудь предложить способ сделать это?

ОБНОВЛЕНИЕ

Я смирился с написанием поведения.Но вместо того, чтобы приложить все усилия исключительно для одного конкретного случая, я обобщил свое решение и включаю его ниже на случай, если кому-то будет интересно.Это смешанное поведение (System.Windows.Interactivity.dll), но оно также может быть обычным присоединенным поведением.

using System;
using System.Windows;
using System.Windows.Interactivity;

namespace BlendBehaviors
{
    public class SetViewModelPropertyBehavior : Behavior<FrameworkElement>
    {
        public static readonly DependencyProperty PropertyNameProperty =
            DependencyProperty.Register("PropertyName", typeof(string), typeof(SetViewModelPropertyBehavior));

        public static readonly DependencyProperty PropertyValueProperty =
            DependencyProperty.Register("PropertyValue", typeof(object), typeof(SetViewModelPropertyBehavior));

        public SetViewModelPropertyBehavior()
        { }

        public string PropertyName
        {
            get { return (string)GetValue(PropertyNameProperty); }
            set { SetValue(PropertyNameProperty, value); }
        }

        public object PropertyValue
        {
            get { return GetValue(PropertyValueProperty); }
            set { SetValue(PropertyValueProperty, value); }
        }

        protected override void OnAttached()
        {
            base.OnAttached();
            var ao = AssociatedObject;
            SetViewModel(ao.DataContext);
            ao.DataContextChanged += FrameworkElement_DataContextChanged;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.DataContextChanged -= FrameworkElement_DataContextChanged;
        }

        private void FrameworkElement_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            SetViewModel(e.NewValue);
        }

        private void SetViewModel(object viewModel)
        {
            SetViewModelProperty(viewModel, PropertyName, PropertyValue);
        }

        private static void SetViewModelProperty(object viewModel, string propertyName, object propertyValue)
        {
            if (viewModel == null || propertyName == null) {
                return;
            }
            var info = viewModel.GetType().GetProperty(propertyName);
            if (info != null && CanAssignValue(propertyValue, info.PropertyType)) {
                info.SetValue(viewModel, propertyValue, null);
            }
        }

        private static bool CanAssignValue(object value, Type targetType)
        {
            if (value == null) {
                return !targetType.IsValueType || Nullable.GetUnderlyingType(targetType) != null;
            }
            return targetType.IsAssignableFrom(value.GetType());
        }
    }
}

Затем используйте его следующим образом:

<local:MyControl>
    <i:Interaction.Behaviors>
        <bb:SetViewModelPropertyBehavior PropertyName="Owner" PropertyValue="{x:Static local:Owners.ProjectOwner}" />
        <bb:SetViewModelPropertyBehavior PropertyName="AnotherProperty" PropertyValue="{StaticResource MyResourceKey}" />
    </i:Interaction.Behaviors>
</local:MyControl>

1 Ответ

3 голосов
/ 10 июня 2011

Цель любой привязки WPF должна быть DependencyProperty.Источником может быть DependencyProperty, объект CLR, который реализует INotifyPropertyChanged, или просто какой-либо объект.Цель и источник можно поменять местами, изменив свойство Binding.Mode.

Но в этом случае один из элементов в вашей привязке является статически разрешенным свойством (Owners.ProjectOwner).Следовательно, это не DependencyProperty.Следовательно, он может отображаться только как источник.Следовательно, то, к чему вы привязываете это (цель), должно быть DependencyProperty.Следовательно, это не может быть свойством в вашей модели представления (при условии, что вы не создали модели представления на основе DependencyObject, что было бы ошибкой ).

Итак, вы не можете напрямуюпривязать свойство вашей виртуальной машины к статическому свойству.Вы можете написать прикрепленное поведение, которое делает это для вас.

...