2015-10-15 62 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)。

謝謝大家的意見!