public class NavigatePanel : Panel
{
public enum Direction
{
LeftToRight,
RightToLeft
}
private NavigateArgs mArgs;//Navigate参数
private Dictionary<string, INavigate> mNaviDic;//所有的Navigate的dic集合
private Dictionary<string, int> mIndexDic;//每个Navigate对应一个id 该id用来决定是左移动还是右移动
private Dictionary<string, bool> mInitFlagDic;//每个Navigate的flag都为true 只有flag为ture才可以初始化该Navigate
//*****mCurrent 的key可能会不等于mCurrentKey
//那是由于Navigate()函数前,准备数据阶段启动Tick之前,需要把mCurrentKey设为mNext的key
private INavigate mCurrent;//当前的Navigate对象
private INavigate mNext;//目标Navigate对象
private String mCurrentKey;//当前的key
private int mTotalLength;
private int mLength;//不需要知道干什么的 只知道他是Tick里面移动的一部分就成
private Direction mDirection;
private Timer mTimer;
/// <summary>
/// 如果Navigating为true则表明mTimer
/// 控件为true且执行Tick操作即正在跳转
/// </summary>
private bool Navigating
{
get { return this.mTimer.Enabled; }
set { this.mTimer.Enabled = value; }
}
public String CurrentKey
{
get { return mCurrentKey; }
}
public NavigatePanel()
{
this.Font = new System.Drawing.Font("Microsoft YaHei", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
// 设置控件基本Style
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.UpdateStyles();
this.Padding = new Padding(0);
this.mTimer = new Timer();
this.mTimer.Tick += mTimer_Tick;
}
public void Init(List<KeyValuePair<string, INavigate>> controls, string defControl)
{
this.InitBase(controls, defControl, NavigateArgsBuilder.BuildLowSpeed());
}
public void Init(List<KeyValuePair<string, INavigate>> controls, string defControl, NavigateArgs args)
{
this.InitBase(controls, defControl, args);
}
/// <summary>
/// 向目标跳转
/// 导航时一定会触发BeginShow
/// </summary>
/// <param name="nextControl"></param>
public void Navigate(string nextControl)
{
if (string.IsNullOrEmpty(this.mCurrentKey))
throw new InvalidOperationException("this panel is not inited");
if (!this.mNaviDic.ContainsKey(nextControl))
throw new ArgumentException("target is not exist");
if (nextControl == this.mCurrentKey)//若果目标Navigate==当前的 就不用跳转了
{
this.mCurrent.BeginShow(this.GetInitFlag());//nextControl 对应的Control 的BeginShow()EndShow()自会判断是否初始化
this.mCurrent.EndShow(this.GetInitFlag());
return;
}
//一个小关口,处理一种情况:如果正在跳转,你又摁了跳转的情况
if (this.Navigating)//如果正在跳转 那么结束跳转
{
this.EndNavigate();
}
this.mTotalLength = this.Width;//设置移动的总长度
this.mLength = 0;
this.mDirection = GetDirection(nextControl);//根据目标Navigate获取它的出现方向
this.mNext = this.mNaviDic[nextControl];//设置 this.mNext
ReadyForNavigate(nextControl);
//设置Navigating为true 启动mTimer 执行Tick
this.Navigating = true;
}
public INavigate GetINavigate(string key)
{
if (this.mNaviDic == null || !this.mNaviDic.ContainsKey(key))
return null;
return this.mNaviDic[key];
}
/// <summary>
/// 为跳转做准备 Tick还没执行
/// </summary>
/// <param name="nextControl"></param>
private void ReadyForNavigate(string nextControl)
{
this.mNext.UIControl.Size = new Size(this.Width, this.Height);
this.mNext.UIControl.Margin = new Padding(0);
this.mNext.UIControl.Padding = new Padding(0);
this.mNext.UIControl.Location =
new Point(this.mDirection == Direction.RightToLeft ? this.Width : -1 * this.Width, 0);
this.SuspendLayout();
this.mCurrent.UIControl.Dock = DockStyle.None;
this.mCurrent.UIControl.Location = new Point(0, 0);
this.mCurrent.UIControl.Size = new Size(this.Width, this.Height);
this.Controls.Add(this.mNext.UIControl);
this.ResumeLayout(true);
this.mCurrentKey = nextControl;//*****这里只是把next的key给了mCurrentKey
this.mNext.BeginShow(this.GetInitFlag());
this.mCurrent.BeginHide();
}
/// <summary>
/// 利用正弦函数计算平滑曲线步长值
/// </summary>
/// <returns></returns>
private int GetStepLength()
{
double angle = Math.PI * (this.mArgs.MaxAngle * mLength / mTotalLength) / 180.0;
int step = this.mArgs.BaseStepLength + (int)(this.mArgs.MaxStepLength * Math.Sin(angle));
if (this.mDirection == Direction.RightToLeft)
step *= -1;
return step;
}
/// <summary>
///
/// </summary>
/// <param name="controls">所有的Navigate</param>
/// <param name="defControl">默认Navigate对应的key字符串</param>
/// <param name="args">Navigate所需要的参数</param>
private void InitBase(List<KeyValuePair<string, INavigate>> controls, string defControl, NavigateArgs args)
{
if (controls == null)
throw new ArgumentNullException("controls");
//实例化
this.mNaviDic = new Dictionary<string, INavigate>();
this.mInitFlagDic = new Dictionary<string, bool>();
this.mIndexDic = new Dictionary<string, int>();
//循环塞入数据
int index = 0;
foreach (var item in controls)
{
this.mNaviDic.Add(item.Key, item.Value);
this.mInitFlagDic.Add(item.Key, true);
this.mIndexDic.Add(item.Key, index++);
}
this.mArgs = args;//赋值Navigate参数
this.mTimer.Interval = args.TimerInterval;//设置Interval
this.mCurrent = this.mNaviDic[defControl];//根据传过来的 默认key 设为当前控件
this.mCurrentKey = defControl;//设置当前key
this.mCurrent.UIControl.Location = new Point(0, 0);
this.mCurrent.UIControl.Size = new Size(this.Width, this.Height);
this.mCurrent.UIControl.Margin = new Padding(0);
this.mCurrent.UIControl.Padding = new Padding(0);
this.mCurrent.UIControl.Dock = DockStyle.Fill;
this.Controls.Add(this.mCurrent.UIControl);
this.mCurrent.BeginShow(this.GetInitFlag());//先BeginShow
this.mCurrent.EndShow(this.GetInitFlag());//后EndShow
this.SetInitFlagFalse();//设置对应flag为false
}
/// <summary>
/// 获取移动方向
/// </summary>
/// <param name="nextControl">要移动到的控件key</param>
/// <returns></returns>
private Direction GetDirection(string nextControl)
{
if (this.mIndexDic[this.mCurrentKey] < this.mIndexDic[nextControl])//若当前id<要跳转到的id
return Direction.LeftToRight; //就是从左向右移动
return Direction.RightToLeft; //else 从右向左移动
}
/// <summary>
/// 获取当前Navigate的flag
/// </summary>
/// <returns>只有flag为ture才可以初始化该Navigate</returns>
private bool GetInitFlag()
{
if (this.mInitFlagDic == null || !this.mInitFlagDic.ContainsKey(this.mCurrentKey))
return true;
return this.mInitFlagDic[this.mCurrentKey];//返回mInitFlagDic中当前Navigate对应的flag
}
/// <summary>
/// 设置初始化flag为false 由于此时该Navigate对象已经初始化
/// </summary>
private void SetInitFlagFalse()
{
if (this.mInitFlagDic == null || !this.mInitFlagDic.ContainsKey(this.mCurrentKey))
return;
this.mInitFlagDic[this.mCurrentKey] = false;
}
/// <summary>
/// 停止移动
/// 一般为移动完毕即跳转完毕
/// </summary>
private void EndNavigate()
{
this.Navigating = false;//设置false
this.SuspendLayout();//挂起
this.Controls.Remove(this.mCurrent.UIControl);//移除当前
this.mNext.UIControl.Location = new Point(0, 0);
this.mNext.UIControl.Dock = DockStyle.Fill;
this.ResumeLayout(true);//恢复
this.mCurrent.EndHide();
this.mNext.EndShow(this.GetInitFlag());//是否初始化
this.SetInitFlagFalse();//设置false
this.mCurrent = this.mNext;//更改当前
this.mNext = null;//清空next
}
/// <summary>
/// Tick只执行了对控件的移动
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void mTimer_Tick(object sender, EventArgs e)
{
int step = GetStepLength();
this.mLength += Math.Abs(step);
if (this.mLength >= this.mTotalLength)
{
this.EndNavigate();
return;
}
this.SuspendLayout();
this.mCurrent.UIControl.Left += step;
this.mNext.UIControl.Left += step;
this.ResumeLayout(true);
}
}