2015-10-15 72 views
1

我有一个包含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的比特率值。

非常感谢。

+1

你必须显示更多的代码,显示视图,你如何设置datacontext等。似乎你missunderstud依赖属性的概念,在WPF依赖属性是用于UI控件。我认为你的意思是一个'INotifyProperty'改变的对象,所以如果你希望你的对象在属性改变时更新视图,你的视图模型必须实现这个接口。 –

+0

谢谢!我编辑了我的帖子以添加更多关于我的问题的信息。 – Tichau

+0

从你的问题中不清楚实际的预期行为是什么。当你说_“属性值的值取决于属性模式的值”时,你的意思是说,随处可见的费率值应该根据模式而变化?或者您想要向用户呈现不同的价值,同时保持基础费率值相同?如果是后者,那么可能你不想强迫,而是使用'IMultiValueConverter'和'MultiBinding'来将模式和速率的输入组合成正确的UI呈现。 –

回答

0

我终于找到了如何使我的项目工作,感谢示例项目。

我并没有完全理解依赖属性的概念,并试图避免它,使用控件触发的事件。

我只是删除了所有设置我的设置的值从事件的代码,然后把属性绑定在模式“TwoWay”。我之所以没有这样做,是因为我不知道如何直接从绑定中设置我的设置。为了使它工作,我使用了(如Peter Duniho说的,谢谢!)值转换器(IValueConverter)。

谢谢大家的意见!