WPF programming treasure -- on custom elements
Written in front
I finished the first half of this section yesterday, and then I wrote a color control according to the example in the book. It didn't work... Today, this article will tell you how to write a color control and several main problems in the process.
Building basic user controls
Create project
Today we're going to use what we learned earlier to write a color selector. First of all, we need to create a user control library. This is the first big hole. Don't learn to create a custom control library as mentioned in the book. If you don't believe in evil, you can try. Then add a user control to the project, of course, you can also use it to help you initialize the blank user control.
Define properties, methods, and events
The simplest starting point of user control is to design the public interface of user control to the outside world. It's the part that users can use. In this part, we need to use dependency properties to define, because many features of WPF need dependency properties to use.
The main property of a Color selector is Color. Then there is the attribute of retrieving Color value. RGB value is used in the book. We will follow the selection in the book.
//Dependency properties public static DependencyProperty ColorProperty; public static DependencyProperty RedProperty; public static DependencyProperty GreenProperty; public static DependencyProperty BlueProperty;
Don't forget that the end of the dependency Property is - Property, which is the Convention between programmers. Unless you want to be attacked by everyone.
Defining a static field for a property is only the first step, and you need a static constructor. Because the dependency property is to be registered.
static ColorPicker() { ColorProperty = DependencyProperty.Register( "Color", typeof(Color), typeof(ColorPicker), new FrameworkPropertyMetadata(Colors.Black, new PropertyChangedCallback(OnColorChanged))); RedProperty = DependencyProperty.Register( "Red", typeof(byte), typeof(ColorPicker), new FrameworkPropertyMetadata( new PropertyChangedCallback(OnColorRGBChanged))); GreenProperty = DependencyProperty.Register( "Green", typeof(byte), typeof(ColorPicker), new FrameworkPropertyMetadata( new PropertyChangedCallback(OnColorRGBChanged))); BlueProperty = DependencyProperty.Register( "Blue", typeof(byte), typeof(ColorPicker), new FrameworkPropertyMetadata( new PropertyChangedCallback(OnColorRGBChanged))); }
If this step is finished, Congratulations, you are one step away from success. Use the standard property wrapper to make them more accessible.
public Color Color { get { return (Color)GetValue(ColorProperty); } set { SetValue(ColorProperty, value); } } public byte Red { get { return (byte)GetValue(RedProperty); } set { SetValue(RedProperty, value); } } public byte Green { get { return (byte)GetValue(GreenProperty); } set { SetValue(GreenProperty, value); } } public byte Blue { get { return (byte)GetValue(BlueProperty); } set { SetValue(BlueProperty, value); } }
This is where you create four dependency properties for your user control.
Wait, haven't you found out what's wrong?
When we register dependency properties, we register their own property change callback events for them. Because RGB value is used to retrieve Color, when RGB changes, the Color attribute will change accordingly.
private static void OnColorRGBChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ColorPicker colorPicker = (ColorPicker)d; Color color = colorPicker.Color; if (e.Property == RedProperty) { color.R = (byte)e.NewValue; } else if (e.Property == GreenProperty) { color.G = (byte)e.NewValue; } else if (e.Property == BlueProperty) { color.B = (byte)e.NewValue; } colorPicker.Color = color; }
Similarly, if the RGB value changes will affect the Color attribute, then the Color attribute changes will certainly affect the RGB value.
private static void OnColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Color newcolor = (Color)e.NewValue; Color oldcolor = (Color)e.OldValue; ColorPicker colorPicker = (ColorPicker)d; colorPicker.Red = newcolor.R; colorPicker.Green = newcolor.G; colorPicker.Blue = newcolor.B; }
Here some students will ask, so Color changes affect RGB value, RGB value changes affect Color, that is not trapped in a dead cycle, ask good! There is a mechanism in WPF that "does not repeatedly enter the property change callback function". That is to say, the property change in the property change callback function will not trigger the next property change callback function. It's a bit of a detour.. Read it a few more times and you will understand.
Then the good properties and methods are defined, and then there is the event. The meaning of the event is notification. So here we define a routing event, which can make the event bubble or tunnel. Because it is a Color selector, it is notified when the Color property changes. The steps to create dependency properties are almost the same, which will not be explained in sections here
//Create static objects public static readonly RoutedEvent ColorChangedEvent; //Static constructor static ColorPicker() { ColorChangedEvent = EventManager.RegisterRoutedEvent( "ColorChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<Color>), typeof(ColorPicker)); } //Wrapper public event RoutedPropertyChangedEventHandler<Color> ColorChanged { add { AddHandler(ColorChangedEvent, value); } remove { RemoveHandler(ColorChangedEvent, value); } } //When to trigger private static void OnColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { RoutedPropertyChangedEventArgs<Color> args = new RoutedPropertyChangedEventArgs<Color>(oldcolor, newcolor); args.RoutedEvent = ColorPicker.ColorChangedEvent; colorPicker.RaiseEvent(args); }
Add mark
<Grid> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/> </Grid.ColumnDefinitions> <Slider Name="sliderRed" Minimum="0" Maximum="255" Value="{Binding ElementName=colorPicker,Path=Red}" Margin="5"></Slider> <TextBlock Name="txtRed" Margin="5" Grid.Column="1" Width="20" Text="{Binding ElementName=sliderRed,Path=Value}"></TextBlock> <Slider Name="sliderGreen" Minimum="0" Maximum="255" Value="{Binding ElementName=colorPicker,Path=Green}" Grid.Row="1" Margin="5"></Slider> <TextBlock Name="txtGreen" Margin="5" Grid.Row="1" Grid.Column="1" Width="20" Text="{Binding ElementName=sliderGreen,Path=Value}"></TextBlock> <Slider Name="sliderBlue" Minimum="0" Maximum="255" Value="{Binding ElementName=colorPicker,Path=Blue}" Grid.Row="2" Margin="5"></Slider> <TextBlock Name="txtBlue" Margin="5" Grid.Row="2" Grid.Column="1" Width="20" Text="{Binding ElementName=sliderBlue,Path=Value}"></TextBlock> <Rectangle Grid.Column="2" Grid.RowSpan="3" Width="50" Stroke="Black" StrokeThickness="1" Margin="5"> <Rectangle.Fill> <SolidColorBrush Color="{Binding ElementName=colorPicker,Path=Color}"></SolidColorBrush> </Rectangle.Fill> </Rectangle> </Grid>
Using tutorials
Maybe many students don't want to see this tutorial. They think it's not easy to use it. I'm sorry, it's not easy. I'm stuck in this step. To use the user control, first compile the user control library to generate a. dll file, and then use it as a general control. However, it should be noted that after use, we may not be satisfied here. The user control will be changed. At this time, the page using this control will display an exclamation mark on the control. At this time, you need to recompile the user control to update the. dll file.
Write at the end
Today's teaching is here. The reason is that I haven't read half of the content. I may have seen it and thought it's not very important. I don't want to write it. I feel that I've been a little slack in my study recently. I may need to adjust my mind recently. The update time can be a little longer. I'm not afraid that you won't be afraid that you won't learn, because the time of updating the software industry is too short, you may fall behind one version without paying attention, but sometimes you can't stop playing games. If you have any way to restrain yourself, you can share it with me and share it with you!