【问题标题】:WPF custom UserControl - twoway databinding issueWPF 自定义 UserControl - 双向数据绑定问题
【发布时间】:2014-04-08 14:20:38
【问题描述】:

我对 WPF 中的数据绑定非常陌生,我在自定义文本框/标签和双向数据绑定方面遇到了问题。 Text 属性可以通过数据绑定来设置,但是当用户更改 Text 时,绑定不会更新源属性。

首先,我的对象包含源属性:


public class DataObject {

   public string MyString { get; set; }

}

然后我有我的自定义用户控件。这个 UserControl 的目的基本上是在单击时显示一个文本框,以便用户可以更改值。

....
<DockPanel >
    <Label Name="Label" MouseLeftButtonDown="EditText" Style="{StaticResource InputLabel}" Content="{Binding Path=Text, RelativeSource={RelativeSource FindAncestor, AncestorType=MyNamespace:MyCustomLabel, AncestorLevel=1},Mode=TwoWay}" ></Label>
    <TextBox Name="TextBox" Style="{StaticResource TextBox}" Visibility="Collapsed" HorizontalAlignment="Left"  HorizontalContentAlignment="Left" />
  </DockPanel>
  ....

MyCustomLabel.Xaml.cs:

public partial class MyCustomLabel : UserControl {

    private static readonly DependencyProperty TextProperty=DependencyProperty.Register("Text",typeof(string),typeof(MyCustomLabel));

    public MyCustomLabel() {
        InitializeComponent();
    }

    public string Text {
      get {
        if (TextBox.Visibility==Visibility.Visible) {
          return (string)GetValue(MyCustomLabel.TextProperty);
        } else {
          return Label.Content.ToString();
        }
      } set {
        base.SetValue(MyCustomLabel.TextProperty,value);
      }
    }

    private void EditText(object sender,MouseButtonEventArgs e) {
          TextBox.Visibility=Visibility.Visible;
          Label.Visibility=Visibility.Collapsed;
          Dispatcher.BeginInvoke((ThreadStart)delegate {
            TextBox.Focus();
            TextBox.SelectionStart=TextBox.Text.Length;
          });
    }
}

所以这将是当前流程:
1.初始化Dataobject,设置MyString属性
2. 持有 MyCustomLabel 的用户控件被初始化
3. 绑定成功,MyString 属性显示在 Label
4. 用户单击标签,TextBox 现在显示,用户更改值
5. 用户点击保存按钮,本应保存内容,但 MyString 属性未更新为新值

如果我调试并访问 MyCustomLabel.Text,则该属性已正确更改。
我尝试在每个类中实现 INotifyPropertyChanged,但这没有任何效果。

希望你能帮忙:)

------- 编辑:------

非常感谢您的回答。它为我指明了正确的方向。
@谢里丹:
我没有具有只读状态的单个文本框的原因是我需要标签的功能和布局,直到单击标签并且文本框变得可见。不过,我可能可以用自己的方式摆脱它。

无论如何,我通过将Label绑定到Textbox.Text来解决它,然后将Textbox.Text绑定到控件的Text属性,如下所示:

<DockPanel >
    <Label Name="Label" MouseLeftButtonDown="EditText" Style="{StaticResource InputLabel}" Content="{Binding ElementName=TextBox, Path=Text}" ></Label>
    <TextBox Name="TextBox" Style="{StaticResource TextBox}" Visibility="Collapsed" HorizontalAlignment="Left" HorizontalContentAlignment="Left" Text="{Binding Text, RelativeSource={RelativeSource AncestorType=MyNamespace:MyCustomLabel},Mode=TwoWay}" />
  </DockPanel>

【问题讨论】:

  • MyCustomLabel 在 XAML 中定义在哪里?
  • 你没有在任何地方调用 MyString

标签: c# wpf


【解决方案1】:

基本上,为了使“第二种”方式(即从 UI 到绑定的非 UI 端)工作,您需要实现 INotifyPropertyChanged 并从您的属性设置器中手动触发事件。一种替代方法是使用 DependencyProperty,但许多人(包括我自己)认为这太过分了。

这是一些原型代码:

  1. 为 UI 对象实现 INotifyPropertyChanged 以报告其属性更改(在您的情况下为 UserControl)
  2. 启动 PropertyChanged(this, new PropertyChangedEventArgs("Text"))。

如果您只需要将一个 UI 元素绑定到另一个 UI 元素,您可能会在相关绑定中使用 ElementName='...' 和 Path (在这种情况下您将使用无代码,这非常酷)。

【讨论】:

    【解决方案2】:

    你显然有一些问题。首先,您不能将LabelTwoWay Binding 一起使用,因为它不提供数据输入方法,例如TextBox。因此,这是不正确的:

    <Label Name="Label" MouseLeftButtonDown="EditText" Style="{StaticResource InputLabel}"
        Content="{Binding Path=Text, RelativeSource={RelativeSource FindAncestor, 
        AncestorType=MyNamespace:MyCustomLabel, AncestorLevel=1},Mode=TwoWay}" ></Label>
    

    其次,您没有在TextBox.Text 属性上设置Binding

    <TextBox Name="TextBox" Style="{StaticResource TextBox}" Visibility="Collapsed" 
        HorizontalAlignment="Left"  HorizontalContentAlignment="Left" />
    

    一般来说,最好使用一个具有只读和可编辑状态的控件,而不是像您那样使用两个控件。 TextBox 非常适合这个,因为它有一个 IsReadOnly Property。因此,您可以只显示TextBox 并切换IsReadOnly 属性而不是其他控件的Visibility

    <TextBox Name="TextBox" Style="{StaticResource TextBox}" Visibility="Collapsed" 
        HorizontalAlignment="Left" HorizontalContentAlignment="Left" Text="{Binding Text, 
        RelativeSource={RelativeSource AncestorType={MyNamespace:MyCustomLabel}}}" 
        IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource AncestorType={
        MyNamespace:MyCustomLabel}}}" />
    

    当然,您需要将新的 IsReadOnly DependencyProperty 添加到您的 UserControl 并在您的 EditText 方法中进行更新:

    private void EditText(object sender,MouseButtonEventArgs e) {
        IsReadOnly = false;
    }
    

    请注意,无需在TextBox.Text 属性上设置TwoWay Binding,因为它已设置FrameworkPropertyMetadata.BindsTwoWayByDefault 属性。来自 MSDN 上的TextBox.Text Property 页面:

    希望您现在可以设法完成控制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-21
      • 2013-01-20
      • 2014-01-30
      • 1970-01-01
      • 2020-06-11
      • 2017-02-07
      • 2011-02-27
      • 1970-01-01
      相关资源
      最近更新 更多