【问题标题】:WPF Two Way Data Binding to Textbox.Text only working in one directionWPF 双向数据绑定到 Textbox.Text 仅在一个方向上工作
【发布时间】:2019-09-20 19:32:07
【问题描述】:

我的问题不是关于序列化我让序列化部分工作得很好,但是对于上下文我试图序列化用户以 WPF 形式设置的一些属性,因此需要双向绑定(我只能朝一个方向工作:目标到源的更新)。

假设我已经定义了一个应用程序属性,它是我想要序列化的属性的容器:

public SerializableApplicationProperties ThisAppsSerializableProperties { get; set; }

SerializableApplicationProperties 类如下所示:

[Serializable]
public class SerializableApplicationProperties
{

    public SerializableApplicationProperties()
    {
        UserSelectedPreFillFilePath = new ObservableString();
    }

    public SerializableApplicationProperties(string defaultFilePath)
    {
        UserSelectedPreFillFilePath = new ObservableString(defaultFilePath);
    }

    public ObservableString UserSelectedPreFillFilePath { get; set; }

}

到目前为止,我已经定义了一个属性,我需要在代码中建立一个双向绑定(是的,在代码中)。请不要建议我如何在 XAML 标记中执行此操作,除非您还完全在代码中解释了如何执行此操作。

属性是“UserSelectedPreFillFilePath”,你可以看到它的类型是“ObservableString”。

ObservableString 类如下所示:

 [Serializable]
    public class ObservableString : INotifyPropertyChanged
    {

        private string _stringValue;
        public string StringValue
        {
            get { return _stringValue; }
            set
            {
                _stringValue = value;
                OnPropertyChanged("StringValue");
            }
        }

        public ObservableString() { }

        public ObservableString(string value)
        {
            this._stringValue = value;
        }

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

    }

一个非常简单的类,它包含一个“StringValue”属性并实现 INotifyChange。

然后,我尝试在此“UserSelectedPreFillFileLocation”和主窗口上的文本框之间建立双向绑定。

我想要一个双向绑定,以便在关闭应用程序之前,我可以序列化 UserSelectedPreFillFileLocation 属性(该属性应该根据用户在窗口文本框中输入的内容自动更新)。

然后,当应用程序从文件加载(反序列化)时,该文本框会通过绑定自动填充 UserSelectedPreFillFileLocation 值。

倒数第二件事,我的转换器类定义:

[ValueConversion(typeof(ObservableString), typeof(string))]
class ObservableStringToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        ObservableString myVar = (ObservableString)value;
        return myVar.StringValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string myVar = (string)value;
        return new ObservableString(myVar);
    }
}

最后是绑定的定义。绑定适用于目标到源,但不是相反。 IE。当用户更新文本框时,UserSelectedPreFillFileLocation 会更新,但不会反过来。

        Binding UserSelectedPreFillFilePathBinding = new Binding();
        UserSelectedPreFillFilePathBinding.Path = new PropertyPath(nameof(ThisAppsSerializableProperties.UserSelectedPreFillFilePath));
        UserSelectedPreFillFilePathBinding.Source = ThisAppsSerializableProperties;          
        UserSelectedPreFillFilePathBinding.Converter = new ObservableStringToStringConverter();
        UserSelectedPreFillFilePathBinding.Mode = BindingMode.TwoWay;
        UserSelectedPreFillFilePathBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        ThisAppInstanceMainWindow.TxtbxPrefillFileLocation.SetBinding(TextBox.TextProperty, UserSelectedPreFillFilePathBinding);

【问题讨论】:

  • UserSelectedPreFillFilePath 需要在其设置器中提高PropertyChanged。当您替换该属性的值时,您不会通知 UI。或者,您可以将UserSelectedPreFillFilePath 设为只读 ObservableString 属性,并且只设置或绑定到它的Value 属性。附言在 XAML 中进行绑定。
  • UserSelectedPreFillFilePath 确实在 setter 中更改了属性,不是吗?因为它是 ObservableString 类型(它实现了 INotifyPropertyChanged)。
  • 这里是UserSelectedPreFillFilePath的setter的完整文本:set;。而已。这就是你给我们的一切。它没有引发任何事件,SerializableApplicationProperties 没有定义任何事件或实现 INotifyPropertyChanged。您是说实际代码与您的问题不同吗?
  • 这样想:ObservableString a = null;ObservableString.Value 的 setter 是如何被调用的?
  • ObservableString 类没有定义 Value 属性(除非有一些隐含的 Value 属性是我不知道的每个类的一部分)。

标签: c# wpf data-binding


【解决方案1】:

我发现我做错了什么。

我确实定义了一个 ObservableString 并且引发属性更改事件的 observable 属性是类中的 StringValue。

因此,在这种情况下,我什至不需要转换器,因为我应该为绑定定义的源属性是 StringValue,而源对象应该是 UserSelectedPreFillFilePath。

更正后的代码现在可以很好地使用双向绑定:

        Binding UserSelectedPreFillFilePathBinding = new Binding();
        UserSelectedPreFillFilePathBinding.Path = new PropertyPath(nameof(ThisAppsSerializableProperties.UserSelectedPreFillFilePath.StringValue));
        UserSelectedPreFillFilePathBinding.Source = ThisAppsSerializableProperties.UserSelectedPreFillFilePath;
        UserSelectedPreFillFilePathBinding.Mode = BindingMode.TwoWay;
        UserSelectedPreFillFilePathBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        ThisAppInstanceMainWindow.TxtbxPrefillFileLocation.SetBinding(TextBox.TextProperty, UserSelectedPreFillFilePathBinding);

【讨论】:

  • 如果你绑定到StringValue,转换器是干什么用的?当您将新的 ObservableString 对象分配给 UserSelectedPreFillFilePath 时,仍然没有通知任何人更改会发生什么?你只是把自己挖得更深了。
  • 我对 WPF 和 .NET 比较陌生,所以我不想争论或假装是专家,但我所做的改变正是我所期望的做。请随时发布相反的答案,以显示您将采取不同措施的代码。我在答案中发布了我删除了转换器,所以我不确定你为什么询问转换器。我的理解是,因为 UserSelectedPreFillFilePath 是 ObservableString 类型(它实现了 INotifyPropertyChanged),所以会通知更改。它按原样为我工作。
  • 我关于转换器的错误,我一定误读了你的答案。你这里有一个脆弱的解决方法。
  • 我很欣赏你的 cmets,但如果你没有展示任何你会做不同的代码,而不是你的批评只是批评,它不会帮助其他人理解应该做不同的事情。
  • 我在五天前解释了你应该做的不同的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-16
  • 2016-03-01
  • 2019-11-13
  • 2015-05-21
  • 1970-01-01
  • 2021-01-27
相关资源
最近更新 更多