上篇文章中的面板是重写MeasureOverride()和 ArrangeOverride()方法,实现布局的,这次为了实现像ListBox控件一样,子元素可以按自定义轨迹拖动,这次就不用这两种方法,自定义方法。代码如下:
public class SemiCircalPanel:Canvas
{
[Category("面板设置")]// 元素最小宽度
public double ChildWidth{ get { return (double)GetValue(ChildWidthProperty); }set { SetValue(ChildWidthProperty, value); }}
public static readonly DependencyProperty ChildWidthProperty =
DependencyProperty.Register("ChildWidth", typeof(double), typeof(SemiCircalPanel), new FrameworkPropertyMetadata(30.0, FrameworkPropertyMetadataOptions.AffectsArrange));
[Category("面板设置")]// // 元素最小高度
public double ChildHeight{ get { return (double)GetValue(ChildHeightProperty); }set { SetValue(ChildHeightProperty, value); } }
public static readonly DependencyProperty ChildHeightProperty =
DependencyProperty.Register("ChildHeight", typeof(double), typeof(SemiCircalPanel), new FrameworkPropertyMetadata(20.0, FrameworkPropertyMetadataOptions.AffectsArrange));
private Point start = new Point(0, 0);
private bool IsMouseDown = false;
public SemiCircalPanel()
{
BrushConverter brushConverter = new BrushConverter();
Brush brush = (Brush)brushConverter.ConvertFromString("#01000000");
this.Background = brush;//背景不可设置成完全透明,否则会影响拖动效果
this.Loaded+=new RoutedEventHandler(SemiCircalPanel_Loaded);
this.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(PanelControl_MouseDown);
this.MouseMove += new System.Windows.Input.MouseEventHandler(PanelControl_MouseMove);
this.MouseLeave += new System.Windows.Input.MouseEventHandler(PanelControl_MouseLeave);
this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(PanelControl_MouseUp);
}
private void SemiCircalPanel_Loaded(object sender, RoutedEventArgs e)
{
try
{
SetUIElement();
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
public void AddChildren(UIElement e)
{
this.Children.Add(e);
SetUIElement();
}
private void SetUIElement()
{
double a = this.Children.Count;
for (int i = 0; i < a; i++)
{
PositionChild(i, this.RenderSize);
}
}
/// <summary>
/// 计算元素初始位置和大小
/// </summary>
/// <param name="index"></param>
/// <param name="panelSize"></param>
private void PositionChild(int index, Size panelSize)
{
if (this.Children.Count >= 2)
{
double ang = (double)index * (Math.PI / (this.Children.Count - 1)) + Math.PI / 2; //取得对应位置的角度值
var st = new ScaleTransform();
this.Children[index].SetValue(Panel.ZIndexProperty, (int)(-Math.Cos(ang) * panelSize.Width)); //设置显示层次值,在Y坐标上值大图片的覆盖值小的图片
double newScale = 1 - (double)Math.Cos(ang);
if (newScale >= 0)
{ //根据角度确定椭圆轨迹上的坐标值
double myX = (double)Math.Cos(ang) * panelSize.Width + panelSize.Width - ChildWidth; //取得X轴坐标值
double myY = (double)Math.Sin(ang) * (panelSize.Height - ChildHeight) / 2 + (panelSize.Height - ChildHeight) / 2; //取得Y轴坐标值
st.ScaleX = newScale;
st.ScaleY = newScale;
this.Children[index].RenderTransform = st;
var fe = this.Children[index] as FrameworkElement;
if (fe != null)
{
fe.Tag = ang;
fe.Name = "E"+index.ToString();
fe.Width = newScale * ChildWidth;
fe.Height = newScale * ChildHeight;
Canvas.SetLeft(this.Children[index], myX);
Canvas.SetTop(this.Children[index], myY);
}
}
}
}
/// <summary>
/// 鼠标按起时,重置标志值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void PanelControl_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
IsMouseDown = false;
}
/// <summary>
/// 鼠标离开时,重置标志值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void PanelControl_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
IsMouseDown = false;
}
/// <summary>
/// 鼠标移动时,根据Y值差值,计算元素新大小和位置
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void PanelControl_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (IsMouseDown)
{
Point p = e.GetPosition((IInputElement) sender);
double d_value = p.Y - start.Y;
SetPosition(d_value);//重设元素大小和位置
start = p;
}
}
/// <summary>
/// 重新设置元素大小和位置
/// </summary>
/// <param name="dValue"></param>
private void SetPosition(double dValue)
{
double a = this.Children.Count;
for (int index = 0; index < a; index++)
{
if (this.Children.Count >= 2)
{
var fe = this.Children[index] as FrameworkElement;
double dangle = 0;
if (fe != null && fe.Tag != null)
{
double ang = 0;
if (dValue <= 0)
{
dangle = Math.Asin(-dValue / this.RenderSize.Width);
ang = (double)fe.Tag + dangle;
}
else
{
dangle = Math.Asin(dValue / this.RenderSize.Width);
ang = (double)fe.Tag - dangle;
}
var st = new ScaleTransform();
this.Children[index].RenderTransform = st;
this.Children[index].SetValue(Panel.ZIndexProperty,
(int)(-Math.Cos(ang) * this.RenderSize.Width));
//设置显示层次值,在Y坐标上值大图片的覆盖值小的图片
double newScale = 1 - (double)Math.Cos(ang);
if (newScale >= 0)
{
//根据角度确定椭圆轨迹上的坐标值
double myX = (double)Math.Cos(ang) * this.RenderSize.Width +
this.RenderSize.Width - ChildWidth; //取得X轴坐标值
double myY = (double)Math.Sin(ang) * (this.RenderSize.Height - ChildHeight) / 2 +
(this.RenderSize.Height - ChildHeight) / 2; //取得Y轴坐标值
st.ScaleX = newScale;
st.ScaleY = newScale;
fe.Tag = ang;
fe.Width = newScale * ChildWidth;
fe.Height = newScale * ChildHeight;
Canvas.SetLeft(this.Children[index], myX);
Canvas.SetTop(this.Children[index], myY);
}
}
}
}
}
/// <summary>
/// 鼠标按下时,记下点击时的位置
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void PanelControl_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
IsMouseDown = true;
start = e.GetPosition((IInputElement)sender);
}
}
到此,面板已完成。