2017-02-07 66 views
1

我有一個包含組合框的自定義用戶控件。我已經添加了一個ComboBoxWidth依賴項屬性,允許開發人員設置寬度,如果他們想。使用樣式設置器,我想將所有這些組合框的寬度設置爲另一個用戶控件上的相同值以實現尺寸一致性。但是,它不工作。如果我在每個控件上分別設置大小,它將起作用。當在樣式設置器中指定大小時,它將被忽略。如果將屬性字符串從「ComboBoxWidth」更改爲「寬度」,則會更改所有控件的整個寬度。所以,它看起來像樣式格式是正確的。我錯過了什麼嗎?這是我第一次嘗試將樣式應用於我自己的自定義依賴項屬性。WPF風格設置器不工作

注意:AngleUserControl基於通用用戶控件(不包括任何在代碼中創建的xaml控件)。 ComboBoxWidth屬性位於通用基類中。我不確定這是否與此有關。

樣式代碼(在用戶控制包含若干AngleUserControl對照):

<UserControl.Resources> 
    <Style TargetType="wpfControls:AngleUserControl"> 
     <Setter Property="ComboBoxWidth" Value="400"/> 
    </Style> 
</UserControl.Resources> 

UnitControlBase:

/// <summary> 
/// Control that displays value in different units depending on selected unit type. 
/// </summary> 
/// <typeparam name="TSelectionTypeEnum">The enumeration type for all the available units.</typeparam> 
/// <typeparam name="TConverterType">The MultiValueConverter that converts the value between the different types of units.</typeparam> 
/// <typeparam name="TValueType">The underlying type of the stored value.</typeparam> 
public class UnitControlBase<TSelectionTypeEnum, TConverterType, TValueType> : UserControl 
    where TSelectionTypeEnum : struct, IConvertible 
    where TConverterType : IMultiValueConverter, new() 
{ 
    #region Private Fields 

    // Metadata for the dependency properties. 
    private static FrameworkPropertyMetadata valuePropertyMetadata = new FrameworkPropertyMetadata(default(TValueType)); 
    private static FrameworkPropertyMetadata valueTypePropertyMetadata = new FrameworkPropertyMetadata(default(TSelectionTypeEnum)); 
    private static FrameworkPropertyMetadata displayValueTypePropertyMetadata = new FrameworkPropertyMetadata(default(TSelectionTypeEnum)); 
    private static FrameworkPropertyMetadata comboBoxWidthPropertyMetadata = new FrameworkPropertyMetadata(0.0); 
    private static FrameworkPropertyMetadata valueFormatPropertyMetadata = new FrameworkPropertyMetadata(string.Empty); 

    #endregion 

    #region Constructor 

    /// <summary> 
    /// Constructor 
    /// </summary> 
    public UnitControlBase() 
    { 
     ValueFormat = "#,##0.00"; 
     ComboBoxWidth = 75.0; 

     // Create main grid and add to control. 
     Grid mainGrid = new Grid(); 
     mainGrid.Name = "LayoutRoot"; 
     this.AddChild(mainGrid); 

     // Create grid columns. 
     ColumnDefinition col1 = new ColumnDefinition(); 
     col1.Width = GridLength.Auto; 
     ColumnDefinition col2 = new ColumnDefinition(); 
     mainGrid.ColumnDefinitions.Add(col1); 
     mainGrid.ColumnDefinitions.Add(col2); 

     // Create the text box that will display the value. 
     Label displayValueLabel = new Label(); 
     displayValueLabel.Name = "DisplayValueLabel"; 
     Grid.SetColumn(displayValueLabel, 0); 
     mainGrid.Children.Add(displayValueLabel); 

     // Bind to the multi-value converter that will convert between the types. 
     MultiBinding mb = new MultiBinding(); 
     mb.Converter = new TConverterType(); 
     mb.Bindings.Add(new Binding("Value") { Source = this }); 
     mb.Bindings.Add(new Binding("ValueType") { Source = this }); 
     mb.Bindings.Add(new Binding("DisplayValueType") { Source = this }); 
     mb.Bindings.Add(new Binding("ValueFormat") { Source = this }); 
     displayValueLabel.SetBinding(Label.ContentProperty, mb); 
     displayValueLabel.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Right;    

     // Create the combo box that will display selected unit. 
     ComboBox displayValueComboBox = new ComboBox(); 
     displayValueComboBox.Name = "DisplayValueComboBox"; 
     displayValueComboBox.SetBinding(ComboBox.WidthProperty, new Binding("ComboBoxWidth") { Source = this }); 
     Grid.SetColumn(displayValueComboBox, 1); 
     mainGrid.Children.Add(displayValueComboBox); 

     // Bind available units and selected units. 
     displayValueComboBox.ItemsSource = Enum.GetValues(typeof(TSelectionTypeEnum)); 
     displayValueComboBox.SetBinding(ComboBox.SelectedItemProperty, new Binding("DisplayValueType") { Source = this }); 
    } 

    #endregion 

    #region Dependency Properties 

    /// <summary> 
    /// Value Dependency Property 
    /// </summary> 
    public static readonly DependencyProperty ValueProperty = 
     DependencyProperty.Register("Value", typeof(TValueType), typeof(UnitControlBase<TSelectionTypeEnum, TConverterType, TValueType>), valuePropertyMetadata); 

    /// <summary> 
    /// Value Type Dependency Property 
    /// </summary> 
    public static readonly DependencyProperty ValueTypeProperty = 
     DependencyProperty.Register("ValueType", typeof(TSelectionTypeEnum), typeof(UnitControlBase<TSelectionTypeEnum, TConverterType, TValueType>), valueTypePropertyMetadata); 

    /// <summary> 
    /// Display Value Type Dependency Property 
    /// </summary> 
    public static readonly DependencyProperty DisplayValueTypeProperty = 
     DependencyProperty.Register("DisplayValueType", typeof(TSelectionTypeEnum), typeof(UnitControlBase<TSelectionTypeEnum, TConverterType, TValueType>), displayValueTypePropertyMetadata); 

    /// <summary> 
    /// Combo Box Width Dependency Property 
    /// </summary> 
    public static readonly DependencyProperty ComboBoxWidthProperty = 
     DependencyProperty.Register("ComboBoxWidth", typeof(double), typeof(UnitControlBase<TSelectionTypeEnum, TConverterType, TValueType>), comboBoxWidthPropertyMetadata); 

    /// <summary> 
    /// Value Format Dependency Property 
    /// </summary> 
    public static readonly DependencyProperty ValueFormatProperty = 
     DependencyProperty.Register("ValueFormat", typeof(string), typeof(UnitControlBase<TSelectionTypeEnum, TConverterType, TValueType>), valueFormatPropertyMetadata); 

    #endregion 

    #region Public Properties 

    /// <summary> 
    /// The underlying stored value. 
    /// </summary> 
    public TValueType Value 
    { 
     get 
     { 
      return (TValueType)GetValue(ValueProperty); 
     } 
     set 
     { 
      SetValue(ValueProperty, value); 
     } 
    } 

    /// <summary> 
    /// The unit type for the underlying stored value. 
    /// </summary> 
    public TSelectionTypeEnum ValueType 
    { 
     get 
     { 
      return (TSelectionTypeEnum)GetValue(ValueTypeProperty); 
     } 
     set 
     { 
      SetValue(ValueProperty, value); 
     } 
    } 

    /// <summary> 
    /// The unit type for the displayed value. 
    /// </summary> 
    public TSelectionTypeEnum DisplayValueType 
    { 
     get 
     { 
      return (TSelectionTypeEnum)GetValue(DisplayValueTypeProperty); 
     } 
     set 
     { 
      SetValue(DisplayValueTypeProperty, value); 
     } 
    } 

    /// <summary> 
    /// Width of combo box displaying available units. 
    /// </summary> 
    public double ComboBoxWidth 
    { 
     get 
     { 
      return (double)GetValue(ComboBoxWidthProperty); 
     } 
     set 
     { 
      SetValue(ComboBoxWidthProperty, value); 
     } 
    } 

    /// <summary> 
    /// The format of the displayed value. 
    /// </summary> 
    public string ValueFormat 
    { 
     get 
     { 
      return (string)GetValue(ValueFormatProperty); 
     } 
     set 
     { 
      SetValue(ValueFormatProperty, value); 
     } 
    } 

    #endregion 
} 

AngleUserControl.cs

/// <summary> 
/// Control allowing user to display a value in degrees, radians, or semicircles. 
/// </summary> 
public class AngleUserControl : UnitControlBase<AngleSelectionType, AngleMultiValueConverter, double> 
{ 
    #region Constructor 

    /// <summary> 
    /// Constructor. 
    /// </summary> 
    public AngleUserControl() 
    { 
     this.ComboBoxWidth = 175.0; 
    } 

    #endregion 
} 
+1

顯示完整控件模板 – Steve

+0

@Steve,這兩個文件都已添加。 – bsh152s

+0

顯然沒有模板 - 查看C#代碼,控件的結構是手動構建的。看看構造函數。 –

回答

3

所謂 「局部值」的依賴屬性,如

this.ComboBoxWidth = 175.0; 

具有較高的優先級值比從樣式設置器的值,像

<Setter Property="ComboBoxWidth" Value="400"/> 

因此樣式設置器不起作用。

你應該通過重寫依賴項屬性的元數據分配一個新的默認值:

public class AngleUserControl : ... 
{ 
    static AngleUserControl() 
    { 
     ComboBoxWidthProperty.OverrideMetadata(
      typeof(AngleUserControl), 
      new PropertyMetadata(175d)); 
    } 
} 

參考見Dependency Property Value Precedence

+0

要搭載,如果具體類具有不同的默認寬度(請注意,基類設置寬度爲75,具體爲175),請使用OverrideMetadata在具體類上設置不同的默認值。 (https://msdn.microsoft.com/en-us/library/ms597491(v=vs.110).aspx) –

+0

@AdamSills感謝您指出這一點,我編輯了答案。 – Clemens

+0

謝謝你們。這就像一個魅力。 – bsh152s