问题
I'm working on a project which is a basic WPF "Paint" app. I have three options, draw an Ellipse, draw a Line, or draw a 'shape' (a line where closed sections are filled in). These three options are represented with radio buttons. I have up to this part working. Here's an example screenshot:
http://i.stack.imgur.com/naPyI.jpg
Basically what I need to do now is, when the user changes the sliders for R, G, B, and A (opacity / alpha), a small preview area showing the new color should be updated, and that color should be set as the line or fill color, depending on which group of sliders is changed. All of this needs to be done with data binding.
I'm not really sure as to to best approach this problem. Should I have individual values for each slider (RGBA) and pass those values into Color.FromArgb(R,G,B,A)??
EDIT: Here is my code
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.ComponentModel;
namespace WpfPaint
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public bool start = false;
public Ellipse myEllipse;
public Polyline myLine;
public Line myRegLine = new Line();
public double xPos;
public double yPos;
public MainWindow()
{
InitializeComponent();
MyCanvas.Children.Add(myRegLine);
}
private void MyCanvas_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (this.ellipse.IsChecked ?? false)
{
if (start)
{
start = !start;
myEllipse = null;
}
else
{
start = true;
myEllipse = new Ellipse();
xPos = e.GetPosition(MyCanvas).X;
yPos = e.GetPosition(MyCanvas).Y;
MyCanvas.Children.Add(myEllipse);
myEllipse.StrokeThickness = 5;
if (comboBox2.Text == "Red")
{
myEllipse.Fill = Brushes.Red;
fillR.Value = 255;
fillG.Value = 0;
fillB.Value = 0;
}
else if (comboBox2.Text == "Green")
{
myEllipse.Fill = Brushes.Green;
fillR.Value = 0;
fillG.Value = 255;
fillB.Value = 0;
}
else if (comboBox2.Text == "Blue")
{
myEllipse.Fill = Brushes.Blue;
fillR.Value = 0;
fillG.Value = 0;
fillB.Value = 255;
}
if (comboBox1.Text == "Red")
{
myEllipse.Stroke = Brushes.Red;
lineR.Value = 255;
lineG.Value = 0;
lineB.Value = 0;
}
else if (comboBox1.Text == "Green")
{
myEllipse.Stroke = Brushes.Green;
lineR.Value = 0;
lineG.Value = 255;
lineB.Value = 0;
}
else if (comboBox1.Text == "Blue")
{
myEllipse.Stroke = Brushes.Blue;
lineR.Value = 0;
lineG.Value = 0;
lineB.Value = 255;
}
}
}
else
{
switch (e.ClickCount)
{
case 1:
if (myLine == null)
{
myLine = new Polyline();
MyCanvas.Children.Add(myLine);
myLine.StrokeThickness = 5;
if (comboBox1.Text == "Red")
{
myLine.Stroke = Brushes.Red;
lineR.Value = 255;
lineG.Value = 0;
lineB.Value = 0;
}
else if (comboBox1.Text == "Green")
{
myLine.Stroke = Brushes.Green;
lineR.Value = 0;
lineG.Value = 255;
lineB.Value = 0;
}
else if (comboBox1.Text == "Blue")
{
myLine.Stroke = Brushes.Blue;
lineR.Value = 0;
lineG.Value = 0;
lineB.Value = 255;
}
if (this.shape.IsChecked ?? false)
{
if (comboBox2.Text == "Red")
{
myLine.Fill = Brushes.Red;
fillR.Value = 255;
fillG.Value = 0;
fillB.Value = 0;
}
else if (comboBox2.Text == "Green")
{
myLine.Fill = Brushes.Green;
fillR.Value = 0;
fillG.Value = 255;
fillB.Value = 0;
}
else if (comboBox2.Text == "Blue")
{
myLine.Fill = Brushes.Blue;
fillR.Value = 0;
fillG.Value = 0;
fillB.Value = 255;
}
}
}
myLine.Points.Add(e.GetPosition(MyCanvas));
e.Handled = true;
break;
case 2:
myLine = null;
myRegLine = new Line();
MyCanvas.Children.Add(myRegLine);
break;
}
}
}
private void MyCanvas_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (start)
{
myEllipse.Height = Math.Abs(e.GetPosition(MyCanvas).X - xPos) * 2;
myEllipse.Width = Math.Abs(e.GetPosition(MyCanvas).X - xPos) * 2;
Canvas.SetTop(myEllipse, ((yPos) - myEllipse.Height / 2));
Canvas.SetLeft(myEllipse, ((xPos) - myEllipse.Width / 2));
}
else
{
if (myLine != null)
{
myRegLine.Stroke = myLine.Stroke;
myRegLine.X1 = myLine.Points.Last().X;
myRegLine.Y1 = myLine.Points.Last().Y;
myRegLine.X2 = e.GetPosition(MyCanvas).X;
myRegLine.Y2 = e.GetPosition(MyCanvas).Y;
}
}
}
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
private void comboBox2_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
}
}
and here is my XAML
<Window x:Class="WpfPaint.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<RadioButton Content="Line" Height="16" HorizontalAlignment="Left" Margin="12,10,0,0" Name="line" GroupName="options" VerticalAlignment="Top" IsChecked="True" />
<RadioButton Content="Shape" Height="16" HorizontalAlignment="Left" Margin="12,34,0,0" Name="shape" GroupName="options" VerticalAlignment="Top" />
<RadioButton Content="Ellipse" Height="16" HorizontalAlignment="Left" Margin="12,56,0,0" Name="ellipse" GroupName="options" VerticalAlignment="Top" />
<Label Content="R" Margin="210,5,270,0" Height="31" VerticalAlignment="Top" />
<Slider Height="23" HorizontalAlignment="Left" Margin="229,5,0,0" Name="lineR" VerticalAlignment="Top" Width="50" IsMoveToPointEnabled="False" Interval="1" IsSelectionRangeEnabled="False" Maximum="255" />
<Slider Height="23" Margin="306,5,147,0" Name="lineG" VerticalAlignment="Top" IsMoveToPointEnabled="False" Interval="1" Maximum="255" />
<Label Content="G" Margin="282,3,203,0" Height="30" VerticalAlignment="Top" />
<Slider Height="23" HorizontalAlignment="Left" Margin="380,5,0,0" Name="lineB" VerticalAlignment="Top" Width="50" Interval="1" Maximum="255" />
<Label Content="B" Margin="358,3,129,280"/>
<Slider Height="23" HorizontalAlignment="Left" Margin="453,5,0,0" Name="lineA" VerticalAlignment="Top" Width="50" Interval="1" Maximum="255" Value="255" />
<Label Content="A" Margin="428,3,56,0" Height="28" VerticalAlignment="Top" />
<Canvas Name="MyCanvas" Background="#FFDADADA" Margin="0,76,0,0" PreviewMouseDown="MyCanvas_PreviewMouseDown" PreviewMouseMove="MyCanvas_PreviewMouseMove"></Canvas>
<ComboBox Height="23" HorizontalAlignment="Left" Margin="127,5,0,0" Name="comboBox1" VerticalAlignment="Top" Width="70" SelectionChanged="comboBox1_SelectionChanged">
<ComboBoxItem Content="Red" IsSelected="True" />
<ComboBoxItem Content="Green" />
<ComboBoxItem Content="Blue" />
</ComboBox>
<Label Content="Line" Height="28" HorizontalAlignment="Left" Margin="89,3,0,0" Name="label1" VerticalAlignment="Top" />
<Label Content="Fill" Height="28" HorizontalAlignment="Left" Margin="96,42,0,0" Name="label2" VerticalAlignment="Top" />
<ComboBox Height="23" HorizontalAlignment="Left" Margin="127,44,0,0" Name="comboBox2" VerticalAlignment="Top" Width="70" SelectionChanged="comboBox2_SelectionChanged">
<ComboBoxItem Content="Red" IsSelected="True" />
<ComboBoxItem Content="Green" />
<ComboBoxItem Content="Blue" />
</ComboBox>
<Label Content="R" Margin="210,42,270,238" />
<Slider Height="23" HorizontalAlignment="Left" IsMoveToPointEnabled="False" Margin="229,44,0,0" Name="fillR" VerticalAlignment="Top" Width="50" Maximum="255" Interval="1" />
<Slider Height="23" HorizontalAlignment="Left" IsMoveToPointEnabled="False" Margin="306,44,0,0" Name="fillG" VerticalAlignment="Top" Width="50" Maximum="255" Interval="1" />
<Label Content="G" Margin="282,40,203,241" />
<Slider Height="23" HorizontalAlignment="Left" Margin="380,44,0,0" Name="fillB" VerticalAlignment="Top" Width="50" Maximum="255" Interval="1" />
<Label Content="B" Margin="358,42,0,241" HorizontalAlignment="Left" Width="16" />
<Slider Height="23" HorizontalAlignment="Left" Margin="453,44,0,0" Name="fillA" VerticalAlignment="Top" Width="50" Value="255" Interval="1" Maximum="255" />
<Label Content="A" Margin="428,42,56,241" />
</Grid>
回答1:
Not sure if this is the best way to do it but you can have 5 public properties in your viewmodel: one for Alpha, one for Red, one for Green, one for Blue, and one user defined structure that you will use to "group" the 4 values together (let's call it FillValue). Bind your 4 sliders to Alpha, Red, Green, and Blue. in the setters for those 4 properties, you set the corresponding field in FillValue then call NotifyPropertyChanged for both properties. Something like this:
public double Red
{
get { return FillValue.Red; }
set
{
FillValue.Red = value;
NotifyPropertyChanged("Red");
NotifyPropertyChanged("FillValue");
}
}
Then bind your preview's fill property to FillValue and add a converter to convert the FillValue to a brush. The binding will look something like this:
<StackPanel>
<StackPanel.Resources>
<RGBExample:FillValueCvtr x:Key="ColorCvtr"/>
</StackPanel.Resources>
<Rectangle Fill="{Binding FillValue, Converter={StaticResource ColorCvtr}}"/>
</StackPanel>
来源:https://stackoverflow.com/questions/4194668/creating-and-using-a-new-brush-or-color-using-sliders-and-dependency-properties