c# - 在 WPF 中的用户控件上创建可绑定(bind)属性的正确方法是什么?

标签 c# wpf xaml mvvm data-binding

这是 this 的后续内容问题。 我为控件开发了一个简单的界面,该控件应该允许用户能够以最简单的方式定义颜色 - 通过控制颜色本身的 ARGB channel 。

enter image description here

我希望此控件能够直接绑定(bind)到颜色属性,以便允许用户通过 slider 进行调整。

我遇到了困难 - 我尝试用它来实现 MVVM,但这不起作用,因为这样做我完全无法从控件中提取控件本身定义的颜色属性。

实际上,我什至不认为这是解决此问题的正确方法。我需要放置几个控件来允许用户更改应用程序的行为和外观,但我无法弄清楚如何让 UserControl 绑定(bind)到应用程序的设置(我已经能够绑定(bind)单个、简单的控件,但当涉及到像这样的复合控件时,我一无所获)。

这是控件本身和 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" ) );
    }
}

我尝试在代码中将颜色依赖属性绑定(bind)到颜色 View 模型;我尝试通过 XAML 中的样式 setter 绑定(bind)它:

<UserControl.Resources>
    <Style TargetType="Controls:ColorDefiner">
        <Setter Property="Color" Value="{Binding Color, Mode=TwoWay}"/>
    </Style>
</UserControl.Resources>

没有任何作用 - 执行此操作的适当方法是什么? (或者最好的方法,或者最合适的方法,或者最普遍接受的做法?)如何从附加到控件的颜色 View 模型中提取定义的颜色属性?这是这样做的正确方法吗?

最佳答案

当颜色属性更改时,您的 ColorDefiner 控件不会使用react。它应该使用依赖项属性元数据注册 PropertyChangedCallback。属性元数据还可用于指定属性默认双向绑定(bind)。您还应该遵循 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 中的所有四个 slider :

<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>

它可以类似地绑定(bind)到具有 Color 属性的任何 View 模型。

关于c# - 在 WPF 中的用户控件上创建可绑定(bind)属性的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29763254/

相关文章:

c# - 使组合框可编辑

C#使用存储过程批量更新数据库

c# - 在 Xaml (Xamarin.Forms) 中设置网格行的最小或最大高度

c# - 如何在 C# 中访问泛型类型的元素

c# - 并行处理并将列表一分为二 - 它会加速整个操作吗?

c# - WebView2 Source 属性不启动 CoreWebView2

WPF TreeView 想要在选择父级时选择第一个子级

c# - 使用 RenderTargetBitmap 时如何获得高质量的文本?

c# - Windows 8.1 中 MediaElement 的样式

wpf - 如何在XAML中按颜色组件定义Silverlight颜色?