Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 直接设置绑定值_Wpf_Binding_Attached Properties - Fatal编程技术网

Wpf 直接设置绑定值

Wpf 直接设置绑定值,wpf,binding,attached-properties,Wpf,Binding,Attached Properties,是否可以在不知道绑定属性的情况下直接在双向绑定后面设置值 我有一个附加属性,它绑定到如下属性: <Element my:Utils.MyProperty="{Binding Something}" /> <MenuItem.ItemContainerStyle> <Style TargetType="MenuItem"> <Sette

是否可以在不知道绑定属性的情况下直接在双向绑定后面设置值

我有一个附加属性,它绑定到如下属性:

<Element my:Utils.MyProperty="{Binding Something}" />
                <MenuItem.ItemContainerStyle>
                    <Style TargetType="MenuItem">
                        <Setter Property="IsCheckable" Value="True"/>
                        <Setter Property="local:EnumMenuItem.EnumValue" Value="{Binding EnumMember}"/>
                        <Setter Property="local:EnumMenuItem.EnumTarget" Value="{Binding RelativeSource={RelativeSource AncestorType=local:MainWindow}, Path=DataContext.Settings.AutoUpdateModel.Ring}"/>
                        <Setter Property="Header" Value="{Binding DisplayName}"/>
                        <Setter Property="ToolTip" Value="{Binding ToolTip}"/>
                    </Style>
                </MenuItem.ItemContainerStyle>

现在,我想从附加属性的角度更改有效存储在
Something
中的值。因此,我无法直接访问绑定属性,只能引用
DependencyObject
(即元素实例)和
dependencProperty
对象本身

当通过
DependencyObject.SetValue
简单地设置它时,问题是这会有效地删除绑定,但我想更改基础绑定属性


使用
BindingOperations
我可以获得
Binding
BindingExpression
。现在有没有办法访问其背后的属性并更改其值?

请尝试在
PropertyMetadata

您可以在MSDN上找到更多信息-

以下是一个例子:

  public Boolean State
  {
    get { return (Boolean)this.GetValue(StateProperty); }
    set { this.SetValue(StateProperty, value); } 
  }
  public static readonly DependencyProperty StateProperty = DependencyProperty.Register(
    "State", typeof(Boolean), typeof(MyStateControl),new PropertyMetadata(myDefaultValue));

好的,我现在已经自己解决了这个问题,在绑定表达式上使用了一些反射技巧

我主要查看绑定路径和响应的数据项,并尝试自己解决绑定问题。对于更复杂的绑定路径,这可能会失败,但对于上面示例中的简单属性名,这应该可以正常工作

BindingExpression bindingExpression = BindingOperations.GetBindingExpression(dependencyObj, dependencyProperty);
if (bindingExpression != null)
{
    PropertyInfo property = bindingExpression.DataItem.GetType().GetProperty(bindingExpression.ParentBinding.Path.Path);
    if (property != null)
        property.SetValue(bindingExpression.DataItem, newValue, null);
}
简单地通过DependencyObject.SetValue进行设置时出现的问题是 这将有效地删除绑定,但我想更改 基础绑定属性

如果Binding.Mode设置为单向,则为真。如果设置为双向,则使用DependencyObject.SetValue不会删除其绑定

这是C#中Pro WPF 4.5的引用(第232页):

删除绑定:如果要删除绑定以便 以通常的方式设置属性,您需要 ClearBinding()或ClearAllBindings()方法。这还不够简单 将新值应用于属性。如果您使用的是双向绑定, 设置的值将传播到链接对象,并且 属性保持同步

因此,要能够使用SetValue更改(和传播)my:Utils.MyProperty,而无需删除其绑定:

<Element my:Utils.MyProperty="{Binding Something, Mode=TwoWay}" />

您可以通过虚拟对象上的绑定传递值

    public static void SetValue(BindingExpression exp, object value)
    {
        if (exp == null)
            throw new ValueCannotBeNullException(() => exp);
        Binding dummyBinding = new Binding(exp.ParentBinding.Path.Path);
        dummyBinding.Mode = BindingMode.OneWayToSource;
        dummyBinding.Source = exp.DataItem;
        SetValue(dummyBinding, value);
    }

    public static void SetValue(Binding binding, object value)
    {
        BindingDummyObject o = new BindingDummyObject();
        BindingOperations.SetBinding(o, BindingDummyObject.ValueProperty, binding);
        o.Value = value;
        BindingOperations.ClearBinding(o, BindingDummyObject.ValueProperty);
    }
这是我的虚拟对象

   internal class BindingDummyObject : DependencyObject
{
    public object Value
    {
        get
        {
            return (object)GetValue(ValueProperty);
        }
        set
        {
            SetValue(ValueProperty, value);
        }
    }

    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(BindingDummyObject));
}

我在尝试实现由枚举支持的菜单时遇到了类似的问题。我希望能够将基础属性(即枚举)设置为与菜单项关联的值

在我的示例中,我将两个属性附加到MenuItem:

    public static readonly DependencyProperty EnumTargetProperty = DependencyProperty.RegisterAttached(
        "EnumTarget",
        typeof(object),
        typeof(MenuItem),
        new PropertyMetadata(null, EnumTargetChangedCallback)
        );

    public static readonly DependencyProperty EnumValueProperty = DependencyProperty.RegisterAttached(
        "EnumValue",
        typeof(object),
        typeof(MenuItem),
        new PropertyMetadata(null, EnumValueChangedCallback)
        );
标记如下所示:

<Element my:Utils.MyProperty="{Binding Something}" />
                <MenuItem.ItemContainerStyle>
                    <Style TargetType="MenuItem">
                        <Setter Property="IsCheckable" Value="True"/>
                        <Setter Property="local:EnumMenuItem.EnumValue" Value="{Binding EnumMember}"/>
                        <Setter Property="local:EnumMenuItem.EnumTarget" Value="{Binding RelativeSource={RelativeSource AncestorType=local:MainWindow}, Path=DataContext.Settings.AutoUpdateModel.Ring}"/>
                        <Setter Property="Header" Value="{Binding DisplayName}"/>
                        <Setter Property="ToolTip" Value="{Binding ToolTip}"/>
                    </Style>
                </MenuItem.ItemContainerStyle>
对于我的复杂路径场景,这似乎很有效


我希望这有帮助

以下是我为
文本块所做的工作:

BindingExpression bindingExpression = textBlock.GetBindingExpression(TextBlock.TextProperty);
string propertyName = bindingExpression.ResolvedSourcePropertyName;
PropertyInfo propertyInfo;
Type type = bindingExpression.DataItem.GetType();
object[] indices = null;
if (propertyName.StartsWith("[") && propertyName.EndsWith("]"))
{
    // Indexed property
    propertyInfo = type.GetProperty("Item");
    indices = new object[] { propertyName.Trim('[', ']') };
} 
else
    propertyInfo = type.GetProperty(propertyName);
if (propertyInfo.PropertyType == typeof(string))
{
    propertyInfo.SetValue(bindingExpression.DataItem, text, indices);
    // To update the UI.
    bindingExpression.UpdateTarget();
}

附件中的道具是你自己写的吗?你能改变它的属性吗?我想不会吧?@HellScream是的,我自己写属性,所以如果有帮助的话,我可以更改元数据。DependencyObject.SetValue真的删除了绑定吗?如果是这样的话,绑定将被替换为什么?该属性已经有一个默认值,但我想在以后更改该值。另外,我认为在实际设置附加属性的值(绑定)时,根本不考虑默认值。当路径复杂时,默认值不起作用。因为当路径类似于Customer.Name时,BindingExpression的DataItem中不存在实际属性。它属于另一个对象(在这种情况下为客户所有)。@KubilayKara如果你阅读我的答案,你会注意到我说过它只适用于简单的属性名称。如果有复杂的绑定路径,则必须首先解析路径并遍历对象以找到正确的属性。
SetValue()
为我删除绑定,即使我处于双向模式。