【问题标题】:WPF binded property does not updates source valueWPF 绑定属性不更新源值
【发布时间】:2018-03-26 14:28:52
【问题描述】:

我的自定义控件中有DependencyProperty。我将它绑定到某个对象中的某个属性。当我的控件出现时,它会从源中获取值并将其应用于自身。但是当我在输入字段中输入内容时,源值不会改变。我做错了什么?

控制声明:

public class ScriptComponentField : Control
{
    public enum Datatype
    {
        String,
        Integer,
        Real,
        Boolean,
        Enumerable,
        Code
    }

    public string Header
    {
        get { return (String)GetValue(HeaderProperty); }
        set { SetValue(HeaderProperty, value); }
    }
    public static readonly DependencyProperty HeaderProperty = DependencyProperty.RegisterAttached(nameof(Header), typeof(string), typeof(ScriptComponentField), new PropertyMetadata(""));

    public object Value
    {
        get { return GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }
    public static readonly DependencyProperty ValueProperty = DependencyProperty.RegisterAttached(nameof(Value), typeof(object), typeof(ScriptComponentField), new PropertyMetadata(null));

    public Datatype ValueType
    {
        get { return (Datatype)GetValue(ValueTypeProperty); }
        set { SetValue(ValueTypeProperty, Value); }
    }
    public static readonly DependencyProperty ValueTypeProperty = DependencyProperty.RegisterAttached(nameof(ValueType), typeof(Datatype), typeof(ScriptComponentField), new PropertyMetadata(Datatype.String));

    public List<string> EnumerableItems
    {
        get { return (List<string>)GetValue(EnumerableItemsProperty); }
        set { SetValue(EnumerableItemsProperty, Value); }
    }
    public static readonly DependencyProperty EnumerableItemsProperty = DependencyProperty.RegisterAttached(nameof(EnumerableItems), typeof(List<string>), typeof(ScriptComponentField), new PropertyMetadata(null));

    static ScriptComponentField()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(ScriptComponentField), new FrameworkPropertyMetadata(typeof(ScriptComponentField)));
    }
}

属性Value 具有object 类型只是因为它可以包含stringboolint 等任何值。

控制模板:

<Style TargetType="{x:Type Controls:ScriptComponentField}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Controls:ScriptComponentField}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="150" SharedSizeGroup="name"/>
                        <ColumnDefinition SharedSizeGroup="value"/>
                    </Grid.ColumnDefinitions>
                    <Label Content="{TemplateBinding Header}" HorizontalAlignment="Right" VerticalAlignment="Center"/>
                    <TextBox x:Name="InputString" Visibility="Collapsed" Grid.Column="1" Text="{TemplateBinding Value}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Center" Margin="0,2"/>
                    <Advanced:IntegerUpDown x:Name="InputInteger" Visibility="Collapsed" Grid.Column="1" Value="{TemplateBinding Value}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Center" Margin="0,2"/>
                    <CheckBox x:Name="InputBoolean" Visibility="Collapsed" Grid.Column="1" IsChecked="{TemplateBinding Value}" VerticalAlignment="Center"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="ValueType" Value="String">
                        <Setter TargetName="InputString" Property="Visibility" Value="Visible"/>
                    </Trigger>
                    <Trigger Property="ValueType" Value="Integer">
                        <Setter TargetName="InputInteger" Property="Visibility" Value="Visible"/>
                    </Trigger>
                    <Trigger Property="ValueType" Value="Boolean">
                        <Setter TargetName="InputBoolean" Property="Visibility" Value="Visible"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

【问题讨论】:

  • MaxB 从可用的有限信息中提供了一个很好的猜测;但你应该把这个问题归结为minimal reproducible example。通过这样做,您可能会自己找到它。如果没有,通过给出一个可重复的问题,其他人可以帮助你解决它。但不是这样的。
  • 现在我提供了控件类和样式的完整描述。

标签: c# wpf data-binding


【解决方案1】:

问题是你使用TemplateBindingTemplateBinding 始终是 OneWay。如果您将TemplateBinding 更改为TwoWay BindingRelativeSourceElementName,它将起作用。

<TextBox x:Name="InputString" Visibility="Collapsed" Grid.Column="1" Text="{Binding Value, RelativeSource={RelativeSource AncestorType=Controls:ScriptComponentField}, Mode=TwoWay}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalContentAlignment="Center" Margin="0,2"/>

【讨论】:

  • {TemplateBinding Value} -> {Binding Value, RelativeSource={RelativeSource AncestorType=Controls:ScriptComponentField}, Mode=TwoWay} 在模板中效果很好。谢谢。
  • @PurpleDragon 谢谢提示,忘记写代码了 ;)
  • 如前所述,设置Mode=TwoWay 是多余的。这是 Text 属性的默认模式。
  • 但也许对于其他类型可能有用。
  • 你的意思是另一个属性?当然。但问题是关于 TextBox.Text。
【解决方案2】:

您可能错过了“Mode=TwoWay”属性,如下所示:

<Button x:Name="btnMy" Content="{Binding MyText, Mode=TwoWay}" />

默认控件绑定是“OneWay”(参见下面的编辑),它“在绑定源(源)更改时更新绑定目标(目标)属性”。 © MSDN 链接如下

TwoWay Binding:“导致对源属性或目标属性的更改以自动更新另一个” © MSDN 链接如下

MSDN BindingMode

编辑:

正如 Clemens 所说,关于默认绑定模式: “默认模式是在注册属性期间由 FrameworkPropertyMetadataOptions 设置的。” © 克莱门斯
很短,它并不总是 OneWay,但大多数时候。

【讨论】:

  • 它没有帮助。我的 xaml 标签:&lt;Controls:ScriptComponentField Header="Author" Value="{Binding author, Mode=TwoWay}" ValueType="String"/&gt;
  • 那是什么控件?我想你的“输入字段”没有连接到“作者”。你看到作者的文字,然后改变这个文字,没有任何反应吗?还是您看到作者的文字,然后在任何其他不同的地方插入文字并期望作者改变?抱歉,我觉得我错过了什么
  • 它通过DataContext 属性连接。当我运行应用程序时,我看到该字段已收到来自DataContext 中的author 的值。如果ValueType="String",则显示TextBoxText 绑定到author。当我在这个TextBox 中写任何东西时,它不会影响DataContext 中的原始值。
  • @PurpleDragon 是您的“作者”本身的财产吗? (它有得到;设置;)?我会同时进行一些检查,看看为什么会发生这种情况
  • 请注意,说“默认控件绑定是 OneWay”是不正确的。默认绑定模式实际上取决于目标属性。虽然它们中的大多数默认模式是 OneWay,但也有其他模式,例如 TextBox 的 Text 属性。它的默认绑定模式是 TwoWay。默认模式是在注册属性期间由 FrameworkPropertyMetadataOptions 设置的。
猜你喜欢
  • 2019-08-05
  • 1970-01-01
  • 1970-01-01
  • 2014-04-28
  • 1970-01-01
  • 1970-01-01
  • 2020-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多