【问题标题】:Setting a ViewModel Property Value From XAML从 XAML 设置 ViewModel 属性值
【发布时间】:2011-09-12 07:53:58
【问题描述】:

我有一个在 XAML 中声明的视图(见下文)。关联的视图模型是使用 MEF 自动创建的。我希望能够做这样的事情:

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

所需的最终效果是将某些视图模型属性设置为 Owners.ProjectOwner。

我可以使用 hacky 代码隐藏来实现所需的结果,但我宁愿通过绑定或类似的方式来实现。任何人都可以建议这样做的方法吗?

更新

我辞职写了一个行为。但是,我并没有为一个特定案例付出所有努力,而是对我的解决方案进行了通用化,并将其包含在下面以防万一有人感兴趣。这是一种混合行为 (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>

【问题讨论】:

    标签: wpf xaml mvvm properties mef


    【解决方案1】:

    任何 WPF 绑定的目标都必须是 DependencyProperty。源可以是DependencyProperty、实现INotifyPropertyChanged 的CLR 对象,或者只是某个对象。可以通过更改 Binding.Mode 属性来交换目标和源。

    但在这种情况下,您的绑定中的一项是静态解析的属性 (Owners.ProjectOwner)。因此,它不是DependencyProperty。因此,它只能作为来源出现。因此,您将其绑定到(目标)的必须是DependencyProperty。因此,它不能是您的视图模型上的属性(假设您尚未创建基于DependencyObject 的视图模型,即a mistake)。

    因此,您不能直接将 VM 上的属性绑定到静态属性。不过,您可以编写一个附加行为来为您执行此操作。

    【讨论】:

    • 我理解并同意你所说的一切。我不一定要在 MyControl 上声明一个名为“Owner”的 DependencyProperty - 示例代码只是说明性的。我可以编写附加行为,但首先希望在不使用对视图模型的强类型引用的情况下解决这个问题。会考虑这个并回复你。
    • 我最终实现了混合行为:请参阅我的更新。感谢您的贡献。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多