【问题标题】:WPF Custom Control, Combine multiple ComboBox values into single DependencyPropertyWPF 自定义控件,将多个 ComboBox 值组合成单个 DependencyProperty
【发布时间】:2021-12-29 14:05:16
【问题描述】:

我有一个自定义控件,其中包含两个 ComboBoxes,其中包含硬编码的 ComboBoxItems,我希望能够通过单个 DependencyProperty 绑定到值,但似乎无法使绑定工作。也许我的方法很遥远,但我应该怎么做才能让它发挥作用?

Generic.xaml:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyApp.Components">
    <Style TargetType="{x:Type local:ContractLimitSelector}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ContractLimitSelector}">
                    <ControlTemplate.Resources>
                        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
                    </ControlTemplate.Resources>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="auto" />
                            <ColumnDefinition Width="auto" />
                        </Grid.ColumnDefinitions>
                        <ComboBox x:Name="PART_ComboAA" Grid.Column="0" SelectedValue="{TemplateBinding SelectedAA}" />
                        <ComboBox x:Name="PART_ComboFA" Grid.Column="1" SelectedValue="{TemplateBinding SelectedFA}" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

自定义控件:

public class SelectorItems
{
    public string AA { get; set; }
    public string FA { get; set; }
}

public class ContractLimitSelector : Control
{
    private static List<string> ComboBoxSource = new List<string>()
    {
        "-",
        "BE",
        "EE",
    };

    static ContractLimitSelector()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(ContractLimitSelector), new FrameworkPropertyMetadata(typeof(ContractLimitSelector)));
    }

    public override void OnApplyTemplate()
    {
        var comboAA = Template.FindName("PART_ComboAA", this) as ComboBox;
        var comboFA = Template.FindName("PART_ComboFA", this) as ComboBox;

        comboAA.ItemsSource = ComboBoxSource;
        comboFA.ItemsSource = ComboBoxSource;

        base.OnApplyTemplate();
    }

    private SelectorItems GetAllValues()
    {
        var AA = (string)GetValue(SelectedAAProperty);
        var FA = (string)GetValue(SelectedFAProperty);

        return new SelectorItems() { AA = AA, FA = FA };
    }

    public static readonly DependencyProperty VisibleHeaderProperty =
        DependencyProperty.Register("VisibleHeader", typeof(bool), typeof(ContractLimitSelector),
            new PropertyMetadata(false));

    public bool VisibleHeader
    {
        get { return (bool)GetValue(VisibleHeaderProperty); }
        set { SetValue(VisibleHeaderProperty, value); }
    }

    public static readonly DependencyProperty SelectedAAProperty =
        DependencyProperty.Register("SelectedAA", typeof(string), typeof(ContractLimitSelector),
            new PropertyMetadata(string.Empty));

    public string SelectedAA
    {
        get { return (string)GetValue(SelectedAAProperty); }
        set
        {
            var all = GetAllValues();
            SetValue(SelectedValuesProperty, new SelectorItems() { AA = value, FA = all.FA, });
            SetValue(SelectedAAProperty, value);
        }
    }

    public static readonly DependencyProperty SelectedFAProperty =
        DependencyProperty.Register("SelectedFA", typeof(string), typeof(ContractLimitSelector),
            new PropertyMetadata(string.Empty));

    public string SelectedFA
    {
        get { return (string)GetValue(SelectedFAProperty); }
        set
        {
            var all = GetAllValues();
            SetValue(SelectedValuesProperty, new SelectorItems() { AA = all.AA, FA = value, });
            SetValue(SelectedFAProperty, value);
        }
    }

    public SelectorItems SelectedValues
    {
        get
        {
            return new SelectorItems()
            {
                AA = (string)GetValue(SelectedAAProperty),
                FA = (string)GetValue(SelectedFAProperty),
            };
        }
        set
        {
            SetValue(SelectedAAProperty, value.AA);
            SetValue(SelectedFAProperty, value.FA);
        }
    }

    public static readonly DependencyProperty SelectedValuesProperty =
        DependencyProperty.Register("SelectedValues", typeof(SelectorItems), typeof(ContractLimitSelector),
            new PropertyMetadata(new SelectorItems()));
}

我这样使用它: XAML:

<custom:ContractLimitSelector SelectedValues="{Binding PrepareLockHouseValue, Mode=TwoWay}" />

视图模型:

private SelectorItems _contractValues;
public SelectorItems ContractValues
{
    get
    {
        return _contractValues;
    }
    set
    {
        _contractValues = value;
        OnPropertyChanged(nameof(ContractValues));
    }
}

我认为只要 ComboBoxes 的任何更改都会触发“共享”SelectedValues DependecyProperty,则使用 SetValue,但什么都不会触发...

我错过了什么?

【问题讨论】:

    标签: c# wpf custom-controls dependency-properties


    【解决方案1】:

    调用时不会调用SelectedAASelectedFA 属性设置器

    SetValue(SelectedAAProperty, value.AA);
    SetValue(SelectedFAProperty, value.FA);
    

    你必须写

    SelectedAA = value.AA;
    SelectedFA = value.FA;
    

    最好移动除

    之外的所有代码
    SetValue(SelectedAAProperty, value);
    

    SetValue(SelectedFAProperty, value);
    

    在设置器中添加 PropertyChangedCallbacks 以执行其他代码。

    这些属性也可以与数据绑定和其他可能的值源一起正常工作。


    通常,依赖属性的 CLR 包装器的 get 和 set 方法不得包含除 GetValueSetValue 调用之外的任何其他内容,因为框架可能会绕过 get/set。

    详情请见XAML Loading and Dependency Properties

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      • 1970-01-01
      • 1970-01-01
      • 2016-12-14
      • 2011-06-20
      • 1970-01-01
      相关资源
      最近更新 更多