簡體   English   中英

在WPF中具有依賴於另一個屬性值的依賴屬性值是否正確?

[英]Is it correct to have a dependency property value that depend on another property value in WPF?

我有一個包含2個數據的類:

public class Settings
{
    EnumType Mode;
    float Rate;
}

屬性Rate的值取決於屬性Mode的值。 我使用CoerceValue函數更新以確保Rate值始終正確。

該屬性以只讀模式(一種方式)綁定到UI,因為我想在寫入時執行一些其他處理。 因此,我在UI控件上創建了一個事件,以了解Rate屬性何時更改。

在我的窗口中,UI綁定到靜態變量SelectedSettings

我的問題如下:

當我更改SelectedSettings的值(使用另一個設置類)時,它執行以下操作,而不是在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

這是一個重現我的問題的最小項目: 鏈接依賴項屬性測試項目

所需的行為是:當我啟動應用程序時,我想查看預設1(比特率32)。 然后,如果我檢查預設2,我想查看225的比特率值。

非常感謝。

由於示例項目,我終於找到了使我的項目工作的方法。

我沒有完全理解依賴屬性的概念,而是嘗試使用控件觸發的事件來避免依賴屬性。

我只是從事件中刪除所有設置設置值的代碼,然后將屬性綁定設置為“ TwoWay”模式。 我之所以沒有這樣做,是因為我不知道如何直接從綁定中設置設置。 為了使其工作,我使用了(如Peter Duniho所說的,謝謝!)值轉換器(IValueConverter)。

謝謝大家的意見!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM