从UserControl属性绑定到其视图模型不起作用

问题描述

我有一个简化的案例:

  • MainWindow显示一个TextBox和一个UserControl。
  • UserControl具有一个依赖项属性,用于接收TextBox文本(在XAML窗口中绑定)
  • 接收到的文本绑定到UserControl代码后台的view-model属性。
  • 视图模型将输入文本转换为驼峰式大小写。
  • 使用UserControl中的TextBlock显示驼峰案例文本。

我可以看到用户控件收到了正确的TextBox值,但是该值没有到达视图模型,我不明白为什么。

MainWindow

Window x:Class="WpfApp5.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp5"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">

    <StackPanel>
        <Label Content="Original:"/>
        <TextBox x:Name="tb"/>
        <local:CamelStringBox OriginalText="{Binding ElementName=tb,Path=Text,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>
</Window>

隐藏代码:

using System.Windows;

namespace WpfApp5 {
    public partial class MainWindow : Window {
        public MainWindow () {
            InitializeComponent ();
        }
    }
}

UserControl CamelStringBox

<UserControl 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" 
         mc:Ignorable="d" 
         
         x:Class="WpfApp5.CamelStringBox"
         xmlns:local="clr-namespace:WpfApp5">

    <UserControl.DataContext>
        <local:CamelStringBoxViewModel x:Name="vm"/>
    </UserControl.DataContext>

    <StackPanel>
        <Label Content="Camelized String:"/>
        <TextBlock Text="{Binding ElementName=vm,Path=CamelizedText}"/>
    </StackPanel>
</UserControl>

隐藏代码:

using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace WpfApp5 {

    public partial class CamelStringBox : UserControl {

        public string OriginalText {
            get { return (string) GetValue (OriginalTextProperty); }
            set { SetValue (OriginalTextProperty,value); }
        }

        public static readonly DependencyProperty OriginalTextProperty =
            DependencyProperty.Register (
                "OriginalText",typeof (string),typeof (CamelStringBox),new PropertyMetadata (
                    (d,e) => Debug.WriteLine ($"Value received by UserControl: {e.NewValue}")));

        public CamelStringBox () {
            InitializeComponent ();

            // Bind user control OriginalText to view-model Text (doesn't work)
            if (DataContext == null) Debug.WriteLine ($"{GetType ()}: DataContext is null");
            else SetBinding (OriginalTextProperty,new Binding {
                Path = new PropertyPath (nameof (CamelStringBoxViewModel.Text)),Mode = BindingMode.TwoWay
            });
        }
    }

    public class CamelStringBoxViewModel : ChangeNotifier {
        private string text;
        private string camelizedText;

        public string Text {
            get => text;
            set {
                text = value;
                RaisePropertyChanged ();
            }
        }

        public string CamelizedText {
            get => camelizedText;
            private set {
                camelizedText = value;
                RaisePropertyChanged ();
            }
        }

        // Never triggered
        private void OnPropertyChanged (object sender,PropertyChangedEventArgs e) {
            if (e.PropertyName == nameof (Text)) CamelizedText = Camelize (Text);
        }

        private string Camelize (string text) {
            if (text == null || text.Length == 0) return null;
            string[] s = text.ToLower ().Split (' ');
            for (int i = 0; i < s.Length; i++) s[i] = char.ToUpper (s[i][0]) + s[i].Substring (1);
            return string.Join (" ",s);
        }
    }

    public class ChangeNotifier : INotifyPropertyChanged {
        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChanged ([CallerMemberName] string propertyName = null) {
            PropertyChanged?.Invoke (this,new PropertyChangedEventArgs (propertyName));
        }
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)