0

我在模型对象上有一个只读属性,但想双向绑定它。当绑定源应该更新时,我希望更新被“重定向”到一个单独的方法,该方法插入我们的控制器基础结构以执行更新并生成一个具有 change 属性的新模型。简单地在只读属性上使用绑定并向Binding.TargetUpdated事件添加处理程序不起作用(抛出 InvalidOperationException,指定属性应该是只读的)。

有一个简单的解决方案(创建模型的副本,具有为我执行重定向的读写属性),但我真的不想复制所有模型对象。有没有办法以编程方式做到这一点?

4

3 回答 3

1

此解决方案基于自定义标记扩展,它为某些依赖属性设置了双向绑定。绑定使用某种具有可写属性的包装器作为源。包装器调用基础结构代码以在属性更改后更新并生成新模型。

下面是硬编码场景的例子,但我认为这个想法很清楚。

namespace MyApp
{

public class MyModel
{
    //readonly property
    public string Name { get; private set; }

    public MyModel(string name)
    {
        Name = name;
    }
}

public class MyViewModel
{
    public MyModel Model { get; set; }

    public MyViewModel()
    {
        Model = new MyModel("default");
    }
}

public class Wrapper
{
    public MyViewModel ViewModel { get; set; }

    //writable property to enable two-way binding
    public object Value
    {
        get
        {
            return ViewModel.Model.Name;
        }
        set
        {
            //call your infrastructure method to 
            //update and generate new model
            ViewModel.Model = new MyModel((string)value);
        }
    }
}

[MarkupExtensionReturnType(typeof(Object))]
public class CustomBinding : MarkupExtension
{
    //you can add any properties here for your infrastructure method call
    //public string PropertyName { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
        var binding = new Binding()
        {
            //get whatever you need from target element to setup the binding and wrapper
            Source = new Wrapper()
            {
                ViewModel = (provideValueTarget.TargetObject as FrameworkElement).DataContext as MyViewModel
            },
            Path = new PropertyPath("Value")
        };
        var result = binding.ProvideValue(serviceProvider);
        return result;
    }
}

}
XAML
<StackPanel>
    <StackPanel.DataContext>
    <MyApp:MyViewModel />
    <StackPanel.DataContext>
    <TextBox Text="{MyApp:CustomBinding}" />
<StackPanel />
于 2012-11-19T23:06:03.013 回答
0

如果不绑定到新的中间对象,我认为您不会逃脱。有些人可能称之为视图模型。我想知道自定义是否IValueConverter能够根据您的需要拦截写入操作ConvertBack,但我有理由相信,如果源属性不可写,绑定系统甚至不会尝试调用转换器。

于 2012-11-19T12:40:21.347 回答
0

我找到了一个解决方案ExpandoObject- 给定一个只读模型对象,这会在运行时生成一个读写模型,每当任何属性发生变化时都会调用控制器方法:

public static dynamic GetAdapterFor(IController controller, object modelObj)
{
    if (modelObj == null)
        return null;

    ExpandoObject obj = new ExpandoObject();

    // add all the properties in the model
    foreach (var prop in modelObj.GetType().GetProperties())
    {
        ((IDictionary<string, object>)obj).Add(prop.Name, prop.GetValue(modelObj, null));
    }

    // add the handler to update the controller when a property changes
    ((INotifyPropertyChanged)obj).PropertyChanged += (s, e) => UpdateController(controller, e.PropertyName, ((IDictionary<string, object>)s)[e.PropertyName]);

    return obj;
}

private static void UpdateController(IController controller, string propertyName, object propertyValue)
{
    controller.SetPropertyValue(propertyName, propertyValue);
}
于 2012-11-20T09:28:18.893 回答