在UserControl中为双向绑定实现自定义DependencyProperty的适当方法是什么?

时间:2012-07-19 00:45:20

标签: wpf user-controls dependency-properties

我正在尝试实现名为ParityTypeSelect的UserControl,其中包含两个RadioButton - Odd& Even,UserControl将有一个名为ParityType的DependencyProperty,它将用于双向绑定。这个想法很简单 - 如果选择了OddParityType应该返回1,如果选择Even,则ParityType应该返回0。 这是代码 -

XAML(UserControl):

<StackPanel Orientation="Horizontal">
    <RadioButton Name="rdoOdd" Content="Odd" Margin="5" Checked="rdoOdd_CheckedChnaged" Unchecked="rdoOdd_CheckedChnaged" />
    <RadioButton Name="rdoEven" Content="Even" Margin="5"/>
</StackPanel>  

Code-Behind(UserControl):

public partial class ParityTypeSelect : UserControl
{
    //Some Code

    static ParityTypeSelect()
    {
        FrameworkPropertyMetadata parityTypeMetaData =
            new FrameworkPropertyMetadata(new PropertyChangedCallback(OnParityTypeChanged),
                                          new CoerceValueCallback(CoerceParityTypeValue));
        ParityTypeProperty = DependencyProperty.Register("ParityType", typeof(int?), typeof(ParityTypeSelect),
                                                         parityTypeMetaData,
                                                         new ValidateValueCallback(ValidateParityTypeValue));
    }

    public static readonly DependencyProperty ParityTypeProperty;
    public int? ParityType
    {
        get { return (int?)GetValue(ParityTypeProperty); }
        set { SetValue(ParityTypeProperty, value); }
    }

    private static void OnParityTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ParityTypeSelect select = (ParityTypeSelect)d;
        int? newValue = (int?)e.NewValue;

        if (newValue != null && newValue <= 1)
        {
            if (newValue == 1)
                select.rdoOdd.IsChecked = true;
            else
                select.rdoEven.IsChecked = true;
        }
        else
            return;
    }

    private void rdoOdd_CheckedChnaged(object sender, RoutedEventArgs e)
    {
        RadioButton radioButton = (RadioButton)sender;
        if (radioButton.IsChecked != null)
        {
            if (radioButton.IsChecked.Value)
                SetValue(ParityTypeProperty, 1);
            else
                SetValue(ParityTypeProperty, 0);
        }
    }

    //Some more Code
}  

XAML(消费者):

<StackPanel>
     <aucl:ParityTypeSelect ParityType="{Binding Path=Format.FisrtBitType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>                
</StackPanel>  

......它正在发挥作用。但事实是,这是我第一次实现DependencyProperty。所以如果我做得对,我有点担心。我是否以正确的方式使用OnParityTypeChanged方法?是使用rdoOdd_CheckedChnaged事件处理程序来设置proerty值吗?有没有更好或更合适的方法来完成这整个实现?我一直期待着高质量的编码。因此,感谢任何建议,改进建议,WPF家伙的评论。

2 个答案:

答案 0 :(得分:1)

我试图在评论中写这个,但我会把它作为一个单独的答案。我会绑定属性而不是在后面的代码中执行它。你需要一个转换器,因为int?将需要转换为布尔。为了使转换器尽可能通用,我会使用EqualityConverter,你可以这样绑定:

<RadioButton Content="Odd" Margin="5" IsChecked="{Binding ParityTypeSelect,Mode=TwoWay,Converter={StaticResource equalityConverter}, ConverterParameter=1}" />

转换器的代码在这里:

public class EqualityConverter : IValueConverter
{
    public object TrueValue { get; set; }
    public object FalseValue { get; set; }

    public EqualityConverter()
    {
        //default the TrueValue and FalseValue to true and false.
        //this way we can easily use the same converter for simple comparison or as an IIF statement
        TrueValue = true;
        FalseValue = false;
    }
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null && parameter == null) return TrueValue;
        if (value == null && parameter != null) return FalseValue;

        //in some cases we might need to compare an enum value to an integer.
        //this will fail unless we specifically convert them
        if (value is int && parameter is Enum)
            parameter = System.Convert.ToInt32(parameter);
        else if (value is Enum && parameter is int)
            value = System.Convert.ToInt32(value);

        return value.Equals(parameter) ? TrueValue : FalseValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null && TrueValue == null) return true;
        if (value == null && FalseValue == null) return false;
        if (value.Equals(TrueValue)) return true;
        return false;
    }
}

我要说的其他一些事情: - 而不是使用usercontrol,你最好从Control继承(就像标准类一样,没有xaml)。然后,将xaml放入名为Generic.xaml的文件中。涉及的内容很少,因此您需要搜索详细信息 - 您对CoerceParityTypeValue和ValidateParityTypeValue进行了不必要的调用,您可以将其保留。 - 定义依赖道具时只需键入“propdp”(不带引号)和push tab - 通常控件的控件以PART_开头命名,例如PART_OddButton

编辑:这篇文章似乎显示了要点但不完整: http://wpftutorial.net/HowToCreateACustomControl.html

答案 1 :(得分:0)

但有一件事可能会更好,而不是在已更改的事件代码中设置单选按钮的值,您可以将它们绑定在xaml中,如

<RadioButton Name="rdoOdd" Content="Odd" Margin="5" IsChecked="{Binding ParityTypeSelect,Mode=TwoWay,Converter=StaticResource booltoNullIntConverter }" />

booltoNullIntConverter是一个根据您的要求将bool更改为null int的转换器。我希望这会有所帮助。