【问题标题】:Update TextBlock with binding not working使用绑定更新 TextBlock 不起作用
【发布时间】:2014-09-07 01:02:57
【问题描述】:

我有一个关于数据绑定的问题! 我正在为其中包含一些(不同)节点的“节点编辑器”编写代码。 我使用派生自 INotifyPropertyChangedBaseViewModel 类。

有一个“基础”NodeViewModel(派生自它)具有 ObservableCollection 和其他属性,例如节点的 Name 属性。它的实现如下所示:

(在 公共类 NodeViewModel : BaseViewModel):

protected String mName = String.Empty;

public String Name {
    get { return mName; }
    set {
        if (mName == value) {
            return;
        }
        mName = value;
        OnPropertyChanged("Name");
    }
}

使用如下所示的 OnPropertyChanged 处理程序:

(在 BaseViewModel 中)

protected virtual void OnPropertyChanged(string propertyName) {
    if (PropertyChanged != null) {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

现在我有一个额外的 RoomViewModel 派生自 NodeViewModel

我使用另一个不同的 ViewModel,我称之为 RoomCollectionViewModel 来对一些房间进行分组。 现在,当我将一个房间添加到我的 roomcollection(通过在它们之间绘制连接)时,我会测试所有连接的房间是否具有相同的名称。

如果集合中存在具有相同房间名称的已连接房间(例如“新房间”),我想将这两个房间的名称更改为例如“新房间#1”和“新房间#2”。目前没问题。

每个节点控件(使用 DataTemplates 创建,并将 DataContext 设置为 ViewModel)都包含一个显示节点名称的 TextBlock(修改后的)。

这就是问题所在:

我使用修改后的文本块,因为我希望能够通过双击它来修改节点的名称。而且效果很好,只有当我在代码中修改 RoomViewModel 的名称时,这个(修改后的)TextBlock 才不会更新。

奇怪的是: 当集合中的两个同名房间被我的代码重命名,然后我双击可编辑的 TextBlock(在该过程中转换为 TextBox)时,我已经看到了修改后的 Text。所以我假设我的 DataBinding 和我的代码是正确的,只是不完整:)

那么如何强制更新我的 EditableTextBlock,Text (DependencyProperty) 似乎已正确更新...

我希望你明白我的问题是什么!感谢您的帮助。

更新 1 这是我的 EditableTextBlock 的 XAML 代码(来自这里:http://www.codeproject.com/Articles/31592/Editable-TextBlock-in-WPF-for-In-place-Editing

<UserControl x:Class="NetworkUI.EditableTextBlock"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:NetworkUI"
         mc:Ignorable="d" 
         d:DesignHeight="60" d:DesignWidth="240" x:Name="mainControl">
<UserControl.Resources>
    <DataTemplate x:Key="EditModeTemplate">
        <TextBox KeyDown="TextBox_KeyDown" Loaded="TextBox_Loaded" LostFocus="TextBox_LostFocus"
                 Text="{Binding ElementName=mainControl, Path=Text, UpdateSourceTrigger=PropertyChanged}"
                 Margin="0" BorderThickness="1" />
    </DataTemplate>
    <DataTemplate x:Key="DisplayModeTemplate">
        <TextBlock Text="{Binding ElementName=mainControl, Path=FormattedText}" Margin="5,3,5,3" MouseDown="TextBlock_MouseDown" />
    </DataTemplate>

    <Style TargetType="{x:Type local:EditableTextBlock}">
        <Style.Triggers>
            <Trigger Property="IsInEditMode" Value="True">
                <Setter Property="ContentTemplate" Value="{StaticResource EditModeTemplate}" />
            </Trigger>
            <Trigger Property="IsInEditMode" Value="False">
                <Setter Property="ContentTemplate" Value="{StaticResource DisplayModeTemplate}" />
            </Trigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>

这是代码隐藏文件:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace NetworkUI {
/// <summary>
/// Interaction logic for EditableTextBlock.xaml
/// </summary>
public partial class EditableTextBlock : UserControl {
    #region Dependency Properties, Events
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(String), typeof(EditableTextBlock),
        new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    public static readonly DependencyProperty IsEditableProperty =
        DependencyProperty.Register("IsEditable", typeof(Boolean), typeof(EditableTextBlock), new PropertyMetadata(true));
    public static readonly DependencyProperty IsInEditModeProperty =
        DependencyProperty.Register("IsInEditMode", typeof(Boolean), typeof(EditableTextBlock), new PropertyMetadata(false));
    public static readonly DependencyProperty TextFormatProperty =
        DependencyProperty.Register("TextFormat", typeof(String), typeof(EditableTextBlock), new PropertyMetadata("{0}"));
    #endregion ///Dependency Properties, Events


    #region Variables and Properties
    /// <summary>
    /// We keep the old text when we go into editmode
    /// in case the user aborts with the escape key
    /// </summary>
    private String oldText;
    /// <summary>
    /// Text content of this EditableTextBlock
    /// </summary>
    public String Text {
        get { return (String)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }
    /// <summary>
    /// Is this EditableTextBlock editable or not
    /// </summary>
    public Boolean IsEditable {
        get { return (Boolean)GetValue(IsEditableProperty); }
        set { SetValue(IsEditableProperty, value); }
    }
    /// <summary>
    /// Is this EditableTextBlock currently in edit mode
    /// </summary>
    public Boolean IsInEditMode {
        get {
            if (IsEditable)
                return (Boolean)GetValue(IsInEditModeProperty);
            else
                return false;
        }
        set {
            if (IsEditable) {
                if (value)
                    oldText = Text;
                SetValue(IsInEditModeProperty, value);
            }
        }
    }
    /// <summary>
    /// The text format for the TextBlock
    /// </summary>
    public String TextFormat {
        get { return (String)GetValue(TextFormatProperty); }
        set  {
            if (value == "")
                value = "{0}";
            SetValue(TextFormatProperty, value);
        }
    }
    /// <summary>
    /// The formatted text of this EditablTextBlock
    /// </summary>
    public String FormattedText {
        get { return String.Format(TextFormat, Text); }
    }
    #endregion ///Variables and Properties


    #region Constructor
    /// <summary>
    /// Default constructor for the editable text block
    /// </summary>
    public EditableTextBlock() {
        InitializeComponent();
        Focusable = true;
        FocusVisualStyle = null;
    }
    #endregion ///Constructor


    #region Methods, Functions and Eventhandler
    /// <summary>
    /// Invoked when we enter edit mode
    /// </summary>
    /// <param name="sender">Sender</param>
    /// <param name="e">Event arguments</param>
    void TextBox_Loaded(object sender, RoutedEventArgs e) {
        TextBox txt = sender as TextBox;
        /// Give the TextBox input focus
        txt.Focus();
        txt.SelectAll();
    }
    /// <summary>
    /// Invoked when we exit edit mode
    /// </summary>
    /// <param name="sender">Sender</param>
    /// <param name="e">Event arguments</param>
    void TextBox_LostFocus(object sender, RoutedEventArgs e) {
        IsInEditMode = false;
    }
    /// <summary>
    /// Invoked when the user edits the annotation.
    /// </summary>
    /// <param name="sender">Sender</param>
    /// <param name="e">Event arguments</param>
    void TextBox_KeyDown(object sender, KeyEventArgs e) {
        if (e.Key == Key.Enter) {
            IsInEditMode = false;
            e.Handled = true;
        }
        else if (e.Key == Key.Escape) {
            IsInEditMode = false;
            Text = oldText;
            e.Handled = true;
        }
    }
    /// <summary>
    /// Invoked when the user double-clicks on the textblock
    /// to edit the text
    /// </summary>
    /// <param name="sender">Sender (the Textblock)</param>
    /// <param name="e">Event arguments</param>
    private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e) {
        if (e.ClickCount == 2)
            IsInEditMode = true;
    }
    #endregion ///Methods, Functions and Eventhandler

}

感谢您的帮助!

更新 2

我更改了以下代码行:

<TextBlock Text="{Binding ElementName=mainControl, Path=FormattedText}" Margin="5,3,5,3" MouseDown="TextBlock_MouseDown" />

到:

<TextBlock Text="{Binding ElementName=mainControl, Path=Text}" Margin="5,3,5,3" MouseDown="TextBlock_MouseDown" />

现在它正在工作!

我一开始没有看到使用 FormattedText 的 TextBlock!呃,非常感谢,现在一切都完美更新了!

【问题讨论】:

  • 这个问题听起来像是在您的 EditableTextBlock 代码中(或者可能是您使用它的方式)。这是来自框架还是您创建的东西?查看它的代码会很有帮助。
  • 我同意@LeeO。如果 OP 说的是真的,那么 Name 属性或 INotifyPropertyChange 实现没有任何问题。
  • 我使用 codeproject 中的 EditableTextBlock 更新了帖子。问题是,如果我进入“编辑模式”,更改会立即在其他地方可见。
  • 嗯....在我看来问题是 TextBlock 绑定到 FormattedText。我认为 UI 无法在 Text 值更改时知道 FormattedText 值已更改。这通常会在您的 ViewModel 中通过在 Text setter 中为 FormattedText 引发 PropertyChanged 通知来处理。
  • 非常感谢!我完全删除了 FormattedText 并直接绑定到 Text,现在它可以工作了!对不起,我一开始没有看到它

标签: c# wpf mvvm data-binding datatemplate


【解决方案1】:

正如 Lee O. 的帖子,问题确实是来自我的 EditableTextBlock 控件的绑定属性。

TextBlock 使用了由我的 Binding 更新的 FormattedText 属性。现在我对 TextBlock 和 TextBox 控件都使用 Text 属性。

我只是从 EditableTextBlock 中删除了 FormattedText 属性以及 TextFormatProperty (DependencyProperty) 和 TextFormat 属性,因为我不打算使用它们。

再次感谢您!

【讨论】:

    猜你喜欢
    • 2014-08-25
    • 1970-01-01
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 2017-07-31
    • 2011-12-14
    • 1970-01-01
    • 2016-10-25
    相关资源
    最近更新 更多