在WPF中,一个依赖属性值依赖于另一个属性值是否正确?
本文关键字:属性 依赖于 另一个 是否 依赖 一个 WPF | 更新日期: 2023-09-27 18:17:49
我有一个包含2个数据的类:
public class Settings
{
EnumType Mode;
float Rate;
}
属性Rate
的值取决于属性Mode
的值。我使用CoerceValue函数来更新以确保Rate值在任何时候都是正确的。
属性以只读模式绑定到UI(一种方式),因为我想在写时做一些额外的处理。所以我在UI控件上创建了一个事件来知道Rate属性何时改变。
在我的窗口UI被绑定到一个静态变量SelectedSettings
。
我的问题如下:
当我改变SelectedSettings的值时(使用另一个settings类),而不是在UI中加载新的设置,它执行以下操作:
- 在UI中设置新的
Mode
值 - 上述操作启动"coerceValue"进程,修改"Rate"值。
- 速率值的修改触发事件。
- 触发事件将rate的新值写入
SelectedSettings
。 - 设置新的
Rate
值(现在不正确)
我做错了什么?我对依赖属性和强制系统的使用是否无效?
编辑:这里有更多关于我实际状态的信息
我创建了一个用户控件来显示两个设置选项
public partial class EncodingQualitySliderControl : UserControl
{
public static readonly DependencyProperty BitrateProperty = DependencyProperty.Register(
"Bitrate",
typeof(double),
typeof(EncodingQualitySliderControl),
new FrameworkPropertyMetadata(new PropertyChangedCallback(EncodingQualitySliderControl.OnBitrateValueChanged), new CoerceValueCallback(EncodingQualitySliderControl.CoerceBitrateValue)));
public static readonly DependencyProperty EncodingModeProperty = DependencyProperty.Register(
"EncodingMode",
typeof(EncodingMode),
typeof(EncodingQualitySliderControl),
new PropertyMetadata(new PropertyChangedCallback(EncodingQualitySliderControl.OnEncodingModeValueChanged)));
public event EventHandler<double> BitrateValueChanged;
public EncodingQualitySliderControl()
{
this.InitializeComponent();
this.CoerceValue(EncodingQualitySliderControl.BitrateProperty);
Debug.Assert(this.slider != null);
this.slider.ValueChanged += this.Slider_ValueChanged;
}
public EncodingMode EncodingMode
{
get
{
return (EncodingMode)this.GetValue(EncodingQualitySliderControl.EncodingModeProperty);
}
set
{
this.SetCurrentValue(EncodingQualitySliderControl.EncodingModeProperty, value);
}
}
public double Bitrate
{
get
{
return (double)this.GetValue(EncodingQualitySliderControl.BitrateProperty);
}
set
{
this.SetCurrentValue(EncodingQualitySliderControl.BitrateProperty, this.GetNearestTickValue(value));
}
}
private static void OnBitrateValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs eventArgs)
{
EncodingQualitySliderControl encodingQualitySliderControl = sender as EncodingQualitySliderControl;
encodingQualitySliderControl.slider.Value = (double)eventArgs.NewValue;
}
private static object CoerceBitrateValue(DependencyObject sender, object basevalue)
{
EncodingQualitySliderControl encodingQualitySliderControl = sender as EncodingQualitySliderControl;
return encodingQualitySliderControl.GetNearestTickValue((double)basevalue);
}
private static void OnEncodingModeValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs eventArgs)
{
EncodingQualitySliderControl encodingQualitySliderControl = sender as EncodingQualitySliderControl;
Slider sliderControl = encodingQualitySliderControl.slider;
// ... Some code that change the user control depending on the new mode.
encodingQualitySliderControl.CoerceValue(EncodingQualitySliderControl.BitrateProperty);
// Send ValueChanged in case of bitrate value change from coerce value.
encodingQualitySliderControl.BitrateValueChanged?.Invoke(encodingQualitySliderControl, encodingQualitySliderControl.Bitrate);
}
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
this.SetCurrentValue(EncodingQualitySliderControl.BitrateProperty, e.NewValue);
// Only send the bitrate value changed event if the value change come from the slider.
this.BitrateValueChanged?.Invoke(this, e.NewValue);
}
}
然后我有一个类与我的设置数据:
public class ConversionPreset : INotifyPropertyChanged
{
private EncodingMode mode;
private double bitrate;
public event PropertyChangedEventHandler PropertyChanged;
[XmlAttribute]
public EncodingMode Mode
{
get
{
return this.mode;
}
set
{
this.mode = value;
this.OnPropertyChanged();
}
}
[XmlAttribute]
public double Bitrate
{
get
{
return this.bitrate;
}
set
{
this.bitrate= value;
this.OnPropertyChanged();
}
}
}
然后在我的设置类和我的用户控件之间有一个数据绑定。
<controls:EncodingQualitySliderControl x:Name="EncodingQualitySlider" BitrateValueChanged="EncodingQualitySlider_ValueChanged"
EncodingMode="{Binding SelectedPreset.Mode, ElementName=window, Mode=OneWay}"
Bitrate="{Binding SelectedPreset.Bitrate, ElementName=window, Mode=OneWay}" />
和主窗口中的一些代码来应用修改
private void EncodingQualitySlider_ValueChanged(object sender, double bitrateValue)
{
this.SelectedPreset?.Bitrate = bitrateValue;
}
编辑2 :
这是一个最小的项目,再现我的问题:链接依赖属性测试项目
想要的行为是:当我启动应用程序时,我想看到preset1(比特率32)。然后如果我检查preset2,我想看到比特率值为225。
多亏了这个示例项目,我终于找到了如何使我的项目工作的方法。
我没有完全理解依赖属性的概念,并试图避免它,使用控件触发的事件。
我只是删除了所有从事件中设置值的代码,然后将属性绑定在模式"two - way"中。我一开始没有这样做,因为我不知道如何直接从绑定设置。为了使它工作,我使用了(就像Peter Duniho说的,谢谢!)值转换器(IValueConverter)。
谢谢大家的评论!