在 WPF 中的用户控件上创建可绑定 属性 的正确方法是什么?
What is the proper method for creating a bindable property on a user control in WPF?
这是 this 问题的跟进。
我已经为控件开发了一个简单的界面,该界面应该允许用户能够以最简单的方式定义颜色 - 通过控制颜色本身的 ARGB 通道。
我希望此控件能够直接绑定到颜色 属性 以便允许用户通过滑块进行调整。
我碰壁了 - 我试图用它实现 MVVM,但这不起作用,因为这样做我完全无法从控件中提取颜色 属性由控件本身定义。
实际上,我什至不认为这是解决此问题的正确方法。我需要有几个控件允许用户更改我们应用程序的行为和外观,但我无法弄清楚如何让 UserControl 绑定到应用程序的设置(我已经能够绑定单个,简单的控件,但是当涉及到像这样的复合控件时,我不知道在哪里)。
这是控件本身和 MVVM 的代码:
public partial class ColorDefiner : UserControl {
public static readonly DependencyProperty
_Color = DependencyProperty.Register( "Color", typeof( Color ), typeof( ColorDefiner ) );
public Color Color {
get { return ( Color )this.GetValue( ColorDefiner._Color ); }
set { this.SetValue( ColorDefiner._Color, value ); }
}
public ColorDefiner( ) { InitializeComponent( ); }
}
public class ColorViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private Color _Color = Colors.Black;
public double A {
get { return this.Color.ScA; }
set {
this._Color.ScA = ( float )value;
if ( this.PropertyChanged != null ) {
this.PropertyChanged( this, new PropertyChangedEventArgs( "A" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
}
}
}
public double R {
get { return this.Color.ScR; }
set {
this._Color.ScR = ( float )value;
if ( this.PropertyChanged != null ) {
this.PropertyChanged( this, new PropertyChangedEventArgs( "R" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Red" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
}
}
}
public double G {
get { return this.Color.ScG; }
set {
this._Color.ScG = ( float )value;
if ( this.PropertyChanged != null ) {
this.PropertyChanged( this, new PropertyChangedEventArgs( "G" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Green" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
}
}
}
public double B {
get { return this._Color.ScB; }
set {
this._Color.ScB = ( float )value;
if ( this.PropertyChanged != null ) {
this.PropertyChanged( this, new PropertyChangedEventArgs( "B" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Blue" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
}
}
}
public Color Color {
get { return this._Color; }
set {
this._Color = value;
if ( this.PropertyChanged != null )
this.AllChanged( );
}
}
public Color Red { get { return Color.FromScRgb( 1.0F, ( float )this.R, 0.0F, 0.0F ); } }
public Color Green { get { return Color.FromScRgb( 1.0F, 0.0F, ( float )this.G, 0.0F ); } }
public Color Blue { get { return Color.FromScRgb( 1.0F, 0.0F, 0.0F, ( float )this.B ); } }
private void AllChanged( ) {
this.PropertyChanged( this, new PropertyChangedEventArgs( "A" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "R" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "G" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "B" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Red" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Green" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Blue" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
}
}
我尝试在代码中将颜色依赖项 属性 绑定到颜色视图模型;我试过通过样式 Setter in XAML 绑定它:
<UserControl.Resources>
<Style TargetType="Controls:ColorDefiner">
<Setter Property="Color" Value="{Binding Color, Mode=TwoWay}"/>
</Style>
</UserControl.Resources>
没有任何效果 - 执行此操作的适当方法是什么? (或者最好的方法,或者最合适的方法,或者最普遍接受的做法?)如何从附加到控件的颜色视图模型中提取定义的颜色 属性?这甚至是正确的方法吗?
创建Color
UserColorSelected
属性:
public Color UserColorSelected
{
get { return userColorSelected;}
set{
userColorSelected=value;
this.PropertyChanged(this, new PropertyChangedEventArgs("UserControlSelected"));
}
和每个ARGB 属性,设置UserColorSelected
实例。
public int A
{
get
{
return a;
}
set
{
a = value;
this.UserColorSelected = Color.FromArgb(value, this.R, this.G, this.B);
this.PropertyChanged(this, new PropertyChangedEventArgs("A"));
}
}
做,类似 属性 R、G 和 B。
当颜色 属性 发生变化时,您的 ColorDefiner 控件没有反应。它应该注册一个具有依赖性 属性 元数据的 PropertyChangedCallback。 属性 元数据也可用于指定 属性 默认绑定双向。您还应该遵循 WPF 中的命名约定,并将 DependencyProperty 字段命名为 ColorProperty
:
public partial class ColorDefiner : UserControl
{
public static readonly DependencyProperty ColorProperty =
DependencyProperty.Register(
"Color", typeof(Color), typeof(ColorDefiner),
new FrameworkPropertyMetadata(
Colors.Black,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
(o, e) => ((ColorDefiner)o).ColorPropertyChanged((Color)e.NewValue)));
public Color Color
{
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
public ColorDefiner()
{
InitializeComponent();
}
private void ColorPropertyChanged(Color color)
{
sliderA.Value = (double)color.A;
sliderR.Value = (double)color.R;
sliderG.Value = (double)color.G;
sliderB.Value = (double)color.B;
}
private void SliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Color = Color.FromArgb((byte)sliderA.Value,
(byte)sliderR.Value, (byte)sliderG.Value, (byte)sliderB.Value);
}
}
SliderValueChanged
事件处理程序用于控件 XAML:
中的所有四个滑块
<UserControl ...>
<StackPanel>
<Slider x:Name="sliderA" Maximum="255" ValueChanged="SliderValueChanged"/>
<Slider x:Name="sliderR" Maximum="255" ValueChanged="SliderValueChanged"/>
<Slider x:Name="sliderG" Maximum="255" ValueChanged="SliderValueChanged"/>
<Slider x:Name="sliderB" Maximum="255" ValueChanged="SliderValueChanged"/>
</StackPanel>
</UserControl>
这个简单的例子展示了控件的工作原理:
<Grid>
<Grid.Background>
<SolidColorBrush x:Name="brush" Color="AliceBlue"/>
</Grid.Background>
<local:ColorDefiner Color="{Binding Color, ElementName=brush}"/>
</Grid>
它可以类似地绑定到具有 Color
属性 的任何视图模型。
这是 this 问题的跟进。 我已经为控件开发了一个简单的界面,该界面应该允许用户能够以最简单的方式定义颜色 - 通过控制颜色本身的 ARGB 通道。
我希望此控件能够直接绑定到颜色 属性 以便允许用户通过滑块进行调整。
我碰壁了 - 我试图用它实现 MVVM,但这不起作用,因为这样做我完全无法从控件中提取颜色 属性由控件本身定义。
实际上,我什至不认为这是解决此问题的正确方法。我需要有几个控件允许用户更改我们应用程序的行为和外观,但我无法弄清楚如何让 UserControl 绑定到应用程序的设置(我已经能够绑定单个,简单的控件,但是当涉及到像这样的复合控件时,我不知道在哪里)。
这是控件本身和 MVVM 的代码:
public partial class ColorDefiner : UserControl {
public static readonly DependencyProperty
_Color = DependencyProperty.Register( "Color", typeof( Color ), typeof( ColorDefiner ) );
public Color Color {
get { return ( Color )this.GetValue( ColorDefiner._Color ); }
set { this.SetValue( ColorDefiner._Color, value ); }
}
public ColorDefiner( ) { InitializeComponent( ); }
}
public class ColorViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private Color _Color = Colors.Black;
public double A {
get { return this.Color.ScA; }
set {
this._Color.ScA = ( float )value;
if ( this.PropertyChanged != null ) {
this.PropertyChanged( this, new PropertyChangedEventArgs( "A" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
}
}
}
public double R {
get { return this.Color.ScR; }
set {
this._Color.ScR = ( float )value;
if ( this.PropertyChanged != null ) {
this.PropertyChanged( this, new PropertyChangedEventArgs( "R" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Red" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
}
}
}
public double G {
get { return this.Color.ScG; }
set {
this._Color.ScG = ( float )value;
if ( this.PropertyChanged != null ) {
this.PropertyChanged( this, new PropertyChangedEventArgs( "G" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Green" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
}
}
}
public double B {
get { return this._Color.ScB; }
set {
this._Color.ScB = ( float )value;
if ( this.PropertyChanged != null ) {
this.PropertyChanged( this, new PropertyChangedEventArgs( "B" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Blue" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
}
}
}
public Color Color {
get { return this._Color; }
set {
this._Color = value;
if ( this.PropertyChanged != null )
this.AllChanged( );
}
}
public Color Red { get { return Color.FromScRgb( 1.0F, ( float )this.R, 0.0F, 0.0F ); } }
public Color Green { get { return Color.FromScRgb( 1.0F, 0.0F, ( float )this.G, 0.0F ); } }
public Color Blue { get { return Color.FromScRgb( 1.0F, 0.0F, 0.0F, ( float )this.B ); } }
private void AllChanged( ) {
this.PropertyChanged( this, new PropertyChangedEventArgs( "A" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "R" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "G" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "B" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Red" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Green" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Blue" ) );
this.PropertyChanged( this, new PropertyChangedEventArgs( "Color" ) );
}
}
我尝试在代码中将颜色依赖项 属性 绑定到颜色视图模型;我试过通过样式 Setter in XAML 绑定它:
<UserControl.Resources>
<Style TargetType="Controls:ColorDefiner">
<Setter Property="Color" Value="{Binding Color, Mode=TwoWay}"/>
</Style>
</UserControl.Resources>
没有任何效果 - 执行此操作的适当方法是什么? (或者最好的方法,或者最合适的方法,或者最普遍接受的做法?)如何从附加到控件的颜色视图模型中提取定义的颜色 属性?这甚至是正确的方法吗?
创建Color
UserColorSelected
属性:
public Color UserColorSelected
{
get { return userColorSelected;}
set{
userColorSelected=value;
this.PropertyChanged(this, new PropertyChangedEventArgs("UserControlSelected"));
}
和每个ARGB 属性,设置UserColorSelected
实例。
public int A
{
get
{
return a;
}
set
{
a = value;
this.UserColorSelected = Color.FromArgb(value, this.R, this.G, this.B);
this.PropertyChanged(this, new PropertyChangedEventArgs("A"));
}
}
做,类似 属性 R、G 和 B。
当颜色 属性 发生变化时,您的 ColorDefiner 控件没有反应。它应该注册一个具有依赖性 属性 元数据的 PropertyChangedCallback。 属性 元数据也可用于指定 属性 默认绑定双向。您还应该遵循 WPF 中的命名约定,并将 DependencyProperty 字段命名为 ColorProperty
:
public partial class ColorDefiner : UserControl
{
public static readonly DependencyProperty ColorProperty =
DependencyProperty.Register(
"Color", typeof(Color), typeof(ColorDefiner),
new FrameworkPropertyMetadata(
Colors.Black,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
(o, e) => ((ColorDefiner)o).ColorPropertyChanged((Color)e.NewValue)));
public Color Color
{
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
public ColorDefiner()
{
InitializeComponent();
}
private void ColorPropertyChanged(Color color)
{
sliderA.Value = (double)color.A;
sliderR.Value = (double)color.R;
sliderG.Value = (double)color.G;
sliderB.Value = (double)color.B;
}
private void SliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Color = Color.FromArgb((byte)sliderA.Value,
(byte)sliderR.Value, (byte)sliderG.Value, (byte)sliderB.Value);
}
}
SliderValueChanged
事件处理程序用于控件 XAML:
<UserControl ...>
<StackPanel>
<Slider x:Name="sliderA" Maximum="255" ValueChanged="SliderValueChanged"/>
<Slider x:Name="sliderR" Maximum="255" ValueChanged="SliderValueChanged"/>
<Slider x:Name="sliderG" Maximum="255" ValueChanged="SliderValueChanged"/>
<Slider x:Name="sliderB" Maximum="255" ValueChanged="SliderValueChanged"/>
</StackPanel>
</UserControl>
这个简单的例子展示了控件的工作原理:
<Grid>
<Grid.Background>
<SolidColorBrush x:Name="brush" Color="AliceBlue"/>
</Grid.Background>
<local:ColorDefiner Color="{Binding Color, ElementName=brush}"/>
</Grid>
它可以类似地绑定到具有 Color
属性 的任何视图模型。