我有一个包含2数据的类:具有依赖于WPF中另一个属性值的依赖属性值是否正确?
public class Settings
{
EnumType Mode;
float Rate;
}
属性Rate
取决于属性Mode
的值的值。 我使用CoerceValue函数来更新,确保Rate值始终保持正确。
该属性以只读模式绑定到UI(单向),因为我想在写入时执行一些额外的过程。 因此,我在我的UI控件上创建了一个事件,以了解Rate属性何时更改。
在我的窗口中,UI绑定到一个静态变量SelectedSettings
。
我的问题是这样的:
当我改变SelectedSettings的值(与其他设置类),而不是在用户界面加载新的设置,将执行以下操作:
- 在UI中设置新的
Mode
值 - 上一个操作将启动coerceValue过程并修改速率值。
- 速率值的修改触发事件。
- 触发事件在
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:
这里是一个很小的项目,重现我的问题: Linked dependency property test project
想要的行为是:当我启动应用程序时,我想看到preset1(比特率32)。然后,如果我检查preset2,我想看到一个225的比特率值。
非常感谢。
你必须显示更多的代码,显示视图,你如何设置datacontext等。似乎你missunderstud依赖属性的概念,在WPF依赖属性是用于UI控件。我认为你的意思是一个'INotifyProperty'改变的对象,所以如果你希望你的对象在属性改变时更新视图,你的视图模型必须实现这个接口。 –
谢谢!我编辑了我的帖子以添加更多关于我的问题的信息。 – Tichau
从你的问题中不清楚实际的预期行为是什么。当你说_“属性值的值取决于属性模式的值”时,你的意思是说,随处可见的费率值应该根据模式而变化?或者您想要向用户呈现不同的价值,同时保持基础费率值相同?如果是后者,那么可能你不想强迫,而是使用'IMultiValueConverter'和'MultiBinding'来将模式和速率的输入组合成正确的UI呈现。 –