WPF UserControl:setter 未在多个控件中绑定一个 属性 并返回
WPF UserControl: setter not called on binding one property in multiple controls and back
我的 WPF UserControl 在多个控件中绑定一个 属性 并返回时遇到问题。业务对象的 setter 将不会被调用。我现在搜索了几个小时并尝试了一些没有用的东西。
我的代码
可以在这里下载:WpfApplicationUserControlProblem.zip
我的业务对象有 2 个要绑定的日期时间值。
public class BusinessObject
{
private DateTime _value1 = DateTime.Today.AddHours(10);
public DateTime Value1
{
get { return _value1; }
set { _value1 = value; } // will never be called but why??
}
private DateTime _value2 = DateTime.Today.AddDays(1).AddHours(15);
public DateTime Value2
{
get { return _value2; }
set { _value2 = value; } // will never be called but why??
}
}
我的 Main-Window 有 2 个用户控件来绑定我的对象的 2 个值
<Window x:Class="WpfApplicationUserControlProblem.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:WpfApplicationUserControlProblem"
mc:Ignorable="d"
Title="MainWindow" Height="120.961" Width="274.489">
<Grid>
<local:DateTimeUserControl DateTimeValue="{Binding Value1, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="241"/>
<local:DateTimeUserControl DateTimeValue="{Binding Value2, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="10,39,0,0" VerticalAlignment="Top" Width="241"/>
</Grid>
public partial class MainWindow : Window
{
private BusinessObject _businessObject = new BusinessObject();
public MainWindow()
{
InitializeComponent();
DataContext = _businessObject;
}
}
我的 UserControl DateTimeUserControl 有一个 DependencyProperty "DateTimeValue" 用于从 Main-Window 接收绑定的业务值。使用 "DateTimeValuePropertyChangedCallback",我将接收到的值重定向到 DatePicker 的 DateValue 和 HourTextBox 的 HourValue。更改 DatePicker 或 HourTextBox 应该会更新 DependencyProperty "DateTimeValue",因此也会更新绑定的业务对象。那是我的计划。
<UserControl x:Class="WpfApplicationUserControlProblem.DateTimeUserControl"
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:WpfApplicationUserControlProblem"
x:Name="_this"
mc:Ignorable="d">
<Grid>
<DatePicker SelectedDate="{Binding Path=DateValue, ElementName=_this, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Margin="0,0,61,0"/>
<TextBox Text="{Binding Path=HourValue, ElementName=_this, UpdateSourceTrigger=PropertyChanged}" Height="24" VerticalAlignment="Top" HorizontalAlignment="Right" Width="56"/>
</Grid>
public partial class DateTimeUserControl : UserControl, INotifyPropertyChanged
{
public DateTimeUserControl()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
public static readonly DependencyProperty DateTimeValueProperty = DependencyProperty.Register(nameof(DateTimeValue), typeof(DateTime), typeof(DateTimeUserControl), new PropertyMetadata(DateTimeValuePropertyChangedCallback));
public DateTime DateTimeValue
{
get { return (DateTime)GetValue(DateTimeValueProperty); }
set { SetValue(DateTimeValueProperty, value); }
}
private static void DateTimeValuePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DateTimeUserControl control = d as DateTimeUserControl;
control.FirePropertyChanged(d, new PropertyChangedEventArgs(nameof(DateValue)));
control.FirePropertyChanged(d, new PropertyChangedEventArgs(nameof(HourValue)));
}
private void FirePropertyChanged(object sender, PropertyChangedEventArgs args)
{
PropertyChanged?.Invoke(sender, args);
}
public DateTime DateValue
{
get { return DateTimeValue.Date; }
set { DateTimeValue = value.Date.AddHours(DateTimeValue.Hour); }
}
public string HourValue
{
get { return DateTimeValue.Hour.ToString(); }
set { DateTimeValue = DateTimeValue.Date.AddHours(int.Parse(value)); }
}
}
没看懂
除了在更新 DependencyProperty 时未调用业务对象的 setter 之外,一切似乎都运行良好。但为什么?我还使用 DependencyProperties 或 MultiBindingConverters 尝试了一切。我每次都失败了。
有人可以帮忙吗?
DateTimeValue
绑定应该声明为 TwoWay
,而 UpdateSourceTrigger=PropertyChanged
肯定是多余的:
<local:DateTimeUserControl DateTimeValue="{Binding Value1, Mode=TwoWay}" .../>
您还可以声明您的 DateTimeValue
依赖项 属性 默认绑定双向:
public static readonly DependencyProperty DateTimeValueProperty =
DependencyProperty.Register(
nameof(DateTimeValue),
typeof(DateTime),
typeof(DateTimeUserControl),
new FrameworkPropertyMetadata(
default(DateTime),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
DateTimeValuePropertyChangedCallback));
您可能会问为什么这对于 UserControl 的 XAML 中的两个 "internal" 绑定不是必需的,但是 DatePicker.SelectedDate
和 TextBox.Text
属性 已经在 BindsTwoWayByDefault
.
注册
我的 WPF UserControl 在多个控件中绑定一个 属性 并返回时遇到问题。业务对象的 setter 将不会被调用。我现在搜索了几个小时并尝试了一些没有用的东西。
我的代码
可以在这里下载:WpfApplicationUserControlProblem.zip
我的业务对象有 2 个要绑定的日期时间值。
public class BusinessObject
{
private DateTime _value1 = DateTime.Today.AddHours(10);
public DateTime Value1
{
get { return _value1; }
set { _value1 = value; } // will never be called but why??
}
private DateTime _value2 = DateTime.Today.AddDays(1).AddHours(15);
public DateTime Value2
{
get { return _value2; }
set { _value2 = value; } // will never be called but why??
}
}
我的 Main-Window 有 2 个用户控件来绑定我的对象的 2 个值
<Window x:Class="WpfApplicationUserControlProblem.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:WpfApplicationUserControlProblem"
mc:Ignorable="d"
Title="MainWindow" Height="120.961" Width="274.489">
<Grid>
<local:DateTimeUserControl DateTimeValue="{Binding Value1, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="241"/>
<local:DateTimeUserControl DateTimeValue="{Binding Value2, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="10,39,0,0" VerticalAlignment="Top" Width="241"/>
</Grid>
public partial class MainWindow : Window
{
private BusinessObject _businessObject = new BusinessObject();
public MainWindow()
{
InitializeComponent();
DataContext = _businessObject;
}
}
我的 UserControl DateTimeUserControl 有一个 DependencyProperty "DateTimeValue" 用于从 Main-Window 接收绑定的业务值。使用 "DateTimeValuePropertyChangedCallback",我将接收到的值重定向到 DatePicker 的 DateValue 和 HourTextBox 的 HourValue。更改 DatePicker 或 HourTextBox 应该会更新 DependencyProperty "DateTimeValue",因此也会更新绑定的业务对象。那是我的计划。
<UserControl x:Class="WpfApplicationUserControlProblem.DateTimeUserControl"
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:WpfApplicationUserControlProblem"
x:Name="_this"
mc:Ignorable="d">
<Grid>
<DatePicker SelectedDate="{Binding Path=DateValue, ElementName=_this, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Margin="0,0,61,0"/>
<TextBox Text="{Binding Path=HourValue, ElementName=_this, UpdateSourceTrigger=PropertyChanged}" Height="24" VerticalAlignment="Top" HorizontalAlignment="Right" Width="56"/>
</Grid>
public partial class DateTimeUserControl : UserControl, INotifyPropertyChanged
{
public DateTimeUserControl()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
public static readonly DependencyProperty DateTimeValueProperty = DependencyProperty.Register(nameof(DateTimeValue), typeof(DateTime), typeof(DateTimeUserControl), new PropertyMetadata(DateTimeValuePropertyChangedCallback));
public DateTime DateTimeValue
{
get { return (DateTime)GetValue(DateTimeValueProperty); }
set { SetValue(DateTimeValueProperty, value); }
}
private static void DateTimeValuePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DateTimeUserControl control = d as DateTimeUserControl;
control.FirePropertyChanged(d, new PropertyChangedEventArgs(nameof(DateValue)));
control.FirePropertyChanged(d, new PropertyChangedEventArgs(nameof(HourValue)));
}
private void FirePropertyChanged(object sender, PropertyChangedEventArgs args)
{
PropertyChanged?.Invoke(sender, args);
}
public DateTime DateValue
{
get { return DateTimeValue.Date; }
set { DateTimeValue = value.Date.AddHours(DateTimeValue.Hour); }
}
public string HourValue
{
get { return DateTimeValue.Hour.ToString(); }
set { DateTimeValue = DateTimeValue.Date.AddHours(int.Parse(value)); }
}
}
没看懂
除了在更新 DependencyProperty 时未调用业务对象的 setter 之外,一切似乎都运行良好。但为什么?我还使用 DependencyProperties 或 MultiBindingConverters 尝试了一切。我每次都失败了。
有人可以帮忙吗?
DateTimeValue
绑定应该声明为 TwoWay
,而 UpdateSourceTrigger=PropertyChanged
肯定是多余的:
<local:DateTimeUserControl DateTimeValue="{Binding Value1, Mode=TwoWay}" .../>
您还可以声明您的 DateTimeValue
依赖项 属性 默认绑定双向:
public static readonly DependencyProperty DateTimeValueProperty =
DependencyProperty.Register(
nameof(DateTimeValue),
typeof(DateTime),
typeof(DateTimeUserControl),
new FrameworkPropertyMetadata(
default(DateTime),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
DateTimeValuePropertyChangedCallback));
您可能会问为什么这对于 UserControl 的 XAML 中的两个 "internal" 绑定不是必需的,但是 DatePicker.SelectedDate
和 TextBox.Text
属性 已经在 BindsTwoWayByDefault
.