简体   繁体   English

更新TextBlock绑定不起作用

[英]Update TextBlock with binding not working

I have a question about databinding! 我有一个关于数据绑定的问题! I am writing code for a 'node editor' that has some (different) nodes in it. 我正在为其中有一些(不同)节点的“节点编辑器”编写代码。 I use a BaseViewModel class that derives from INotifyPropertyChanged . 我使用从INotifyPropertyChanged派生的BaseViewModel类。

There is a 'base' NodeViewModel (that derives from it) with an ObservableCollection and other Properties, like the Node's Name property. 有一个“基本” NodeViewModel (从中派生),它带有ObservableCollection和其他属性,例如Node的Name属性。 It's implementation looks like this: 它的实现如下所示:

(in public class NodeViewModel : BaseViewModel ): (在公共类NodeViewModel:BaseViewModel中 ):

protected String mName = String.Empty;

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

With an OnPropertyChanged handler that looks like this: 使用如下所示的OnPropertyChanged处理程序:

(in BaseViewModel ) (在BaseViewModel中

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

Now I have one additional RoomViewModel that derives from NodeViewModel . 现在,我还有一个从NodeViewModel派生的RoomViewModel

I use another different ViewModel that I call RoomCollectionViewModel to group some rooms. 我使用另一个称为RoomCollectionViewModel的不同ViewModel来对一些房间进行分组。 Now when I add a room to my roomcollection (by drawing a connection between them) I test all connected rooms for the same name. 现在,当我将一个房间添加到我的房间集合中(通过在它们之间绘制连接)时,我将测试所有连接的房间是否具有相同的名称。

If an already connected room exists in the collection with the same room name (eg "new room") I want to change those two room's names to eg "new room #1" and "new room #2". 如果集合中存在一个已经连接的房间,且房间名称相同(例如“新房间”),我想将这两个房间的名称更改为“新房间#1”和“新房间#2”。 No problem so far. 到目前为止没有问题。

Every node control (created using DataTemplates with set DataContext set to the ViewModel) contains a TextBlock (a modified one) that displays the node's name. 每个节点控件(使用将DataContext设置为ViewModel的DataTemplates创建)都包含一个TextBlock(已修改的一个),该TextBlock显示节点的名称。

This is where it gets problematic: 这是有问题的地方:

I use a modified Textblock because I want to be able to modify the node's name by double-clicking on it. 我使用修改后的Textblock,因为我希望能够通过双击它来修改节点的名称。 And that works perfectly, only if I modify the RoomViewModel's name in Code, this (modified) TextBlock won't update. 而且,仅当我在Code中修改RoomViewModel的名称时,此方法才能完美运行,此TextBlock(已修改)不会更新。

The strange thing is this: When two equally named rooms in a collection get renamed by my code and I then double-click on the editable TextBlock (which converts to a TextBox in that process), I already see the modified Text. 奇怪的是:当集合中的两个同名房间被我的代码重命名,然后双击可编辑的TextBlock(在该过程中将其转换为TextBox)时,我已经看到了修改后的Text。 So I assume my DataBinding and my code is correct, just not complete :) 所以我假设我的数据绑定和我的代码是正确的,只是不完整:)

So how is it possible to force an update of my EditableTextBlock , the Text (DependencyProperty) seems to be updated correctly... 因此,如何强制更新EditableTextBlock ,文本(DependencyProperty)似乎已正确更新...

I hope you understand what my problem is! 希望您理解我的问题所在! Thank you for any help. 感谢您的任何帮助。

Update 1 This is the XAML code for my EditableTextBlock (it comes from here: http://www.codeproject.com/Articles/31592/Editable-TextBlock-in-WPF-for-In-place-Editing ) 更新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>

And here is the code-behind file: 这是代码隐藏文件:

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

}

Thank you for any help! 感谢您的任何帮助!

Update 2 更新2

I changed the following line of code: 我更改了以下代码行:

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

to: 至:

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

and now it is working! 现在它正在工作!

I didn't see the TextBlock using the FormattedText in the first place! 我首先没有看到使用FormattedText的TextBlock! Ugh, thank you very much, now everything updates perfectly! gh,非常感谢您,现在一切都完美更新了!

As postes by Lee O. the problem was indeed the bound property from my EditableTextBlock control. 正如Lee O.的帖子所述,问题确实是我的EditableTextBlock控件的bound属性。

The TextBlock used the FormattedText property that was updated by my Binding. TextBlock使用了由我的Binding更新的FormattedText属性。 Now I use the Text property for both, the TextBlock and the TextBox controls. 现在,我将Text属性用于TextBlock和TextBox控件。

I simply removed the FormattedText property as well as the TextFormatProperty (DependencyProperty) and TextFormat property from my EditableTextBlock because I didn't plan to use those. 我只是从我的EditableTextBlock中删除了FormattedText属性以及TextFormatProperty(DependencyProperty)和TextFormat属性,因为我不打算使用它们。

Thank you again! 再次感谢你!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM