WPF自定义UserControl - twoway数据绑定问题

时间:2014-04-08 14:20:39

标签: c# wpf

我对WPF中的数据绑定很新,我遇到了自定义Textbox / Label和TwoWay数据绑定的问题。可以通过数据绑定设置Text属性,但是当用户更改Text时,绑定doesent会更新source属性。

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


public class DataObject {

   public string MyString { get; set; }

}

然后我有我的自定义UserControl。此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属性显示在标签
中 4.用户单击Label,TextBox现在显示,用户更改值
5.用户单击保存按钮,内容应该保存,但MyString属性不会使用新值更新

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

希望你能提供帮助:)

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

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

无论如何,我通过将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>

2 个答案:

答案 0 :(得分:3)

基本上是为了&#34;第二&#34;您需要实现INotifyPropertyChanged并从您的属性设置器中手动触发事件的方式(即从UI到绑定的非UI端)。另一种方法是使用DependencyProperty,但它被许多人认为是一种矫枉过正(包括我自己)。

这里有一些原型代码:

  1. 为报告其属性更改的UI对象实现INotifyPropertyChanged(在您的情况下为UserControl)
  2. 启动PropertyChanged(这是一个新的PropertyChangedEventArgs(&#34; Text&#34;))。
  3. 如果您只需要将一个UI元素绑定到另一个UI元素,那么您可能会使用ElementName =&#39; ...&#39;相关绑定中的路径和路径(在这种情况下你会变得无代码,这太酷了。)

答案 1 :(得分:1)

你显然有一些问题。首先,您不能将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>

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

<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方法中更新{<1}}:

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

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

enter image description here

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