【问题标题】:Databinding not working with usercontrol数据绑定不适用于用户控件
【发布时间】:2016-01-22 04:49:15
【问题描述】:

我正在尝试实现对树节点的就地编辑。我相当接近,但没有雪茄。所有绑定似乎都是正确的。应用程序运行良好,没有输出消息,树视图被填充。我可以选择一个节点,按 F2,我可以编辑该节点,但是一旦我按 Enter 键,文本就会恢复到以前的状态,就好像我没有进行编辑一样。如果我在应用程序的其他位置编辑 Name 属性,则更改会反映在 EditableTextBlock 中,包括 TextBlock 和 TextBox 中。为什么我不能使更改持久化?好像绑定只以一种方式工作。

这是用户控件的 xaml:

<UserControl x:Class="WPFApplication.EditableTextBlock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFApplication"
x:Name="MyUserControl">
<UserControl.Resources>

    <DataTemplate x:Key="EditModeTemplate">
        <TextBox KeyDown="TextBox_KeyDown" Loaded="TextBox_Loaded" LostFocus="TextBox_LostFocus"
                 Text="{Binding Path=Text, ElementName=MyUserControl, Mode=TwoWay}"
                 Margin="0" BorderThickness="1" />
    </DataTemplate>

    <DataTemplate x:Key="DisplayModeTemplate">
        <TextBlock Text="{Binding ElementName=MyUserControl, Path=Text, Mode=TwoWay}"/>
    </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.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace WPFApplication
{
    public partial class EditableTextBlock : UserControl
    {

        #region Constructor

        public EditableTextBlock()
        {
            InitializeComponent();
            base.Focusable = true;
            base.FocusVisualStyle = null;
        }

        #endregion Constructor

        #region Member Variables

        // We keep the old text when we go into editmode
        // in case the user aborts with the escape key
        private string oldText;

        #endregion Member Variables

        #region Properties

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register(
            "Text",
            typeof(string),
            typeof(EditableTextBlock),
            new PropertyMetadata(""));

        public bool IsEditable
        {
            get { return (bool)GetValue(IsEditableProperty); }
            set { SetValue(IsEditableProperty, value); }
        }
        public static readonly DependencyProperty IsEditableProperty =
            DependencyProperty.Register(
            "IsEditable",
            typeof(bool),
            typeof(EditableTextBlock),
            new PropertyMetadata(true));

        public bool IsInEditMode
        {
            get 
            {
                if (IsEditable)
                    return (bool)GetValue(IsInEditModeProperty);
                else
                    return false;
            }
            set
            {
                if (IsEditable)
                {
                    if (value) oldText = Text;
                    SetValue(IsInEditModeProperty, value);
                }
            }
        }
        public static readonly DependencyProperty IsInEditModeProperty =
            DependencyProperty.Register(
            "IsInEditMode",
            typeof(bool),
            typeof(EditableTextBlock),
            new PropertyMetadata(false));

        public string TextFormat
        {
            get { return (string)GetValue(TextFormatProperty); }
            set
            {
                if (value == "") value = "{0}";
                SetValue(TextFormatProperty, value);
            }
        }
        public static readonly DependencyProperty TextFormatProperty =
            DependencyProperty.Register(
            "TextFormat",
            typeof(string),
            typeof(EditableTextBlock),
            new PropertyMetadata("{0}"));

        public string FormattedText
        {
            get { return String.Format(TextFormat, Text); }
        }

        #endregion Properties

        #region Event Handlers

        // Invoked when we enter edit mode.
        void TextBox_Loaded(object sender, RoutedEventArgs e)
        {
            TextBox txt = sender as TextBox;

            // Give the TextBox input focus
            txt.Focus();

            txt.SelectAll();
        }

        // Invoked when we exit edit mode.
        void TextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            this.IsInEditMode = false;
        }

        // Invoked when the user edits the annotation.
        void TextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                this.IsInEditMode = false;
                e.Handled = true;
            }
            else if (e.Key == Key.Escape)
            {
                this.IsInEditMode = false;
                Text = oldText;
                e.Handled = true;
            }
        }

        #endregion Event Handlers

    }
}

然后树视图使用这个数据模板:

<HierarchicalDataTemplate DataType="{x:Type localvm:TreeViewItemViewModel}" ItemsSource="{Binding Children}">
<StackPanel>
    <local:EditableTextBlock Text="{Binding Name}"/>
</StackPanel>

【问题讨论】:

  • 除了Resources 之外,您的EditableTextBlock XAML 中肯定还有其他内容。您能否也用这些更新您的答案?
  • 您是否尝试将 Text DP 的 PropertyMetadata 转换为 FrameworkMetaData 并设置 BindsTwoWayByDefault = true?
  • @Szabolcs Dézsi 不,没有。 @nkoniishvt 是的,我只是重试了,但这并没有什么不同

标签: c# wpf xaml data-binding


【解决方案1】:

好的,我最后尝试了,问题是 Text 属性从未设置,因为您的 TextBox 从未失去焦点(似乎)。

所以我更改了 TextBox 的 Text 绑定以添加 UpdateSourceTrigger=PropertyChanged 和 RelativeSource 而不是 ElementName:

Text="{Binding Path=Text, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:EditableTextBlock}}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

成功了

【讨论】:

  • 这很奇怪。我只是做了那个编辑,它没有任何区别。您如何得出 TextBox 没有失去焦点的结论。如果我没记错的话,绑定只会在失去焦点时更新,这样才有意义。
  • @JefPatat 我在从未引发过的 DP 更改上添加了一个回调函数。
  • 很抱歉给您带来了困惑。您的修复工作正常,文本没有恢复,但分层模板中的绑定没有更新。为了解决这个问题,我必须将其更改为 &lt;local:EditableTextBlock Text="{Binding Name, Mode=TwoWay}"/&gt;。我很高兴我让它工作了,现在我会试着理解为什么它不起作用。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2013-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-21
  • 1970-01-01
  • 1970-01-01
  • 2014-12-07
相关资源
最近更新 更多