窗体间传值 - 下篇

上篇:传送门

在上一篇里面讲了一些关于窗体间传值的问题 在上一篇看到的主要是相互取数据为主 比如Form2需要Form1上面的某个数据 或者Form1需要Form2上面的某个数据 但是很多时候可能不仅仅是相互交换数据而已 可能还牵扯到某些行为的发生 比如当Form2只是作为一个Form1的辅助窗体之类的 而在Form2上面做一些操作的时候希望触发Form1的某种行为 比如用过PS的人可能都知道要设置某个滤镜的时候或者调色的时候 都会弹出一个窗体来 然后在窗体上修改数据 后面的图像立即动态呈现效果:


这里就做一个相似的超级简单的例子 不搞那么复杂:

弹一个窗口出来设置Form1的背景色 在FrmRGB上面改变值的时候Form1上动态变化 当然这个例子很简单 直接用上一篇的方式都能完成直接把Form1传给FrmRGB然后直接在FrmRGB里面修改Form1的背景色

不过在这一篇里面 换一个方式 先来看看代码 Form1:

public partial class Form1 : Form
{
    public Form1() {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e) {
        Color temp = this.BackColor;//保存原来颜色
        FrmRGB frm = new FrmRGB(this);
        if (frm.ShowDialog() != DialogResult.OK) {
            this.BackColor = temp;//如果点的不是确定恢复原来颜色
        }
    }
    //用来让FrmRGB调用
    public void SetColor(Color clr) {
        this.BackColor = clr;
    }
}

在Form1中提供了一个方法去设置窗体的背景色 而FrmRGB得到传过去的Form1的时候就可以调用这个方法去设置 窗体的背景色 当然你也可以不用把Form1传递过去 可以直接通过上一篇里面的说的Owner属性来搞、、、

然后是FrmRGB:

public partial class FrmRGB : Form
{
    public FrmRGB(Form1 frm) {
        InitializeComponent();
        m_frm1 = frm;
        this.BindValue(frm.BackColor);

        track_r.ValueChanged += new EventHandler(track_ValueChanged);
        track_g.ValueChanged += new EventHandler(track_ValueChanged);
        track_b.ValueChanged += new EventHandler(track_ValueChanged);

        btn_ok.Click += (s, e) => this.DialogResult = DialogResult.OK;
        btn_cancel.Click += (s, e) => this.Close();
    }

    private Form1 m_frm1;

    private void track_ValueChanged(object sender, EventArgs e) {
        //当然这里你可以直接用 m_frm1.BackColor 属性 那就失去意义了
        m_frm1.SetColor(Color.FromArgb(track_r.Value, track_g.Value, track_b.Value));
    }

    private void BindValue(Color clr) {
        track_r.Value = clr.R;
        track_g.Value = clr.G;
        track_b.Value = clr.B;
    }
}

在上面看到代码可能会觉得怪怪的 觉得调用Form1上面的SetColor方法有点多此一举 直接通过m_frm1.BackColor来赋值就行了 这里的确是这样的 因为这个例子比较简单 如果说需求是一些跟复杂的要求 什么代码都写在Form2中估计就会感觉很恶心了 因为那样做的话本该让Form1做的事情结果你在FrmRGB里面做了 如果代码比较多 到时候就会有种很凌乱的感觉 所以在这里FrmRGB就只管调用Form1上面的SetColor方法叫Form1自己去搞定 FrmRGB应该只负责给他数据通知他就行了、而不是帮Form1做事情

下面还是同样的需求 把上面的代码再换一个方式 用事件的方式去做 如果你不懂啥叫事件委托 这里有一篇张子阳的文章:

http://www.cnblogs.com/JimmyZhang/archive/2007/09/23/903360.html(张子阳 C#中的委托和事件)

如果你确实不知道 那你可以先记着有这个方法 等那天你得任督二脉被打通的时候再去了解也行

先来看看修改之后的FrmRGB的代码:

public partial class FrmRGB : Form
{
    public FrmRGB(Color clr) {
        InitializeComponent();
        this.Color = clr;

        track_r.ValueChanged += new EventHandler(track_ValueChanged);
        track_g.ValueChanged += new EventHandler(track_ValueChanged);
        track_b.ValueChanged += new EventHandler(track_ValueChanged);

        btn_ok.Click += (s, e) => this.DialogResult = DialogResult.OK;
        btn_cancel.Click += (s, e) => this.Close();
    }

    public Color RGB {
        set { this.BindValue(value); }
        get { return Color.FromArgb(track_r.Value, track_g.Value, track_b.Value); }
    }

    public event EventHandler ValueChange;//创建一个事件
    protected virtual void OnValueChange(EventArgs e){
        if (ValueChange != null) ValueChange(this, e);
    }

    private void track_ValueChanged(object sender, EventArgs e) {
        this.OnValueChange(e);//当值发生改变的时候触发事件
    }

    private void BindValue(Color clr) {
        track_r.Value = clr.R;
        track_g.Value = clr.G;
        track_b.Value = clr.B;
    }
}

在上面创建了一个事件 而当值发生改变的时候 就去触发事件就是了至于结果 这里通过RGB属性来交换数据 通过构造器把Color传进来绑定一个初始的显示 不传进来通过FrmRGB.Color去设置也行

Form1的代码:

public partial class Form1 : Form
{
    public Form1() {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e) {
        Color temp = this.BackColor;//保存原来颜色
        FrmRGB frm = new FrmRGB(temp);
        //绑定事件
        frm.ValueChange += new EventHandler(frm_ValueChange);
        if (frm.ShowDialog() != DialogResult.OK) {
            this.BackColor = temp;//如果点的不是确定恢复原来颜色
        }
    }
    //当FrmRGB上面的值改变的时候 就会执行这个代码
    private void frm_ValueChange(object sender, EventArgs e) {
        this.BackColor = ((FrmRGB)sender).RGB;
    }
}
和刚才代码相比 没有传值了多了一个绑定事件的 把原来的SetColor方法撤了、、当在FrmRGB上操作的时候 就会触发事件 因为在Form1中在创建FrmRGB的时候绑定了事件 所以当FrmRGB上面的值发生改变的时候 就会去触发事件然后就会执行rm_ValueChange方法 然后在里面通过sender去取RGB的值 如果你觉得这样取值不爽 想通过e去取值那么代码就要改一下了 就需要自己定义委托了而不是自带的EventHandler了:
//自定义委托
public delegate void ValueChangeEventHandler(object sender, ValueChangeEventArgs e);
public event ValueChangeEventHandler ValueChange;//创建一个事件
protected virtual void OnValueChange(ValueChangeEventArgs e) {
    if (ValueChange != null) ValueChange(this, e);
}
//事件参数
public class ValueChangeEventArgs : EventArgs
{
    private Color _Color;
    public Color Color {
        get { return _Color; }
        set { _Color = value; }
    }

    public ValueChangeEventArgs(Color clr) {
        this._Color = clr;
    }
}
这里是自定义了一个委托 因为要用自定义的e 所以只有自己去定义委托了

然后FrmRGB的代码就变成这个样子了:

public partial class FrmRGB : Form
{
    public FrmRGB(Color clr) {
        InitializeComponent();
        this.RGB = clr;

        track_r.ValueChanged += new EventHandler(track_ValueChanged);
        track_g.ValueChanged += new EventHandler(track_ValueChanged);
        track_b.ValueChanged += new EventHandler(track_ValueChanged);

        btn_ok.Click += (s, e) => this.DialogResult = DialogResult.OK;
        btn_cancel.Click += (s, e) => this.Close();
    }

    public Color RGB {
        set { this.BindValue(value); }
        get { return Color.FromArgb(track_r.Value, track_g.Value, track_b.Value); }
    }
    //自定义委托
    public delegate void ValueChangeEventHandler(object sender, ValueChangeEventArgs e);
    public event ValueChangeEventHandler ValueChange;//创建一个事件
    protected virtual void OnValueChange(ValueChangeEventArgs e) {
        if (ValueChange != null) ValueChange(this, e);
    }

    private void track_ValueChanged(object sender, EventArgs e) {
        this.OnValueChange(new ValueChangeEventArgs(
                Color.FromArgb(track_r.Value, track_g.Value, track_b.Value)
            ));//当值发生改变的时候触发事件
    }

    public void BindValue(Color clr) {
        track_r.Value = clr.R;
        track_g.Value = clr.G;
        track_b.Value = clr.B;
    }
}

public class ValueChangeEventArgs : EventArgs
{
    private Color _Color;
    public Color Color {
        get { return _Color; }
        set { _Color = value; }
    }

    public ValueChangeEventArgs(Color clr) {
        this._Color = clr;
    }
}

下面的类是定义的事件参数

然后对于Form1而言代码就变成这个样子了:

public partial class Form1 : Form
{
    public Form1() {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e) {
        Color temp = this.BackColor;//保存原来颜色
        FrmRGB frm = new FrmRGB(temp);
        //绑定事件
        frm.ValueChange += new FrmRGB.ValueChangeEventHandler(frm_ValueChange);
        frm.BindValue(this.BackColor);
        if (frm.ShowDialog() != DialogResult.OK) {
            this.BackColor = temp;//如果点的不是确定恢复原来颜色
        }
    }
    //当FrmRGB上面的值改变的时候 就会执行这个代码
    private void frm_ValueChange(object sender, ValueChangeEventArgs e) {
        this.BackColor = e.Color;//直接通过事件参数获取数据
    }
}
这样 就可以直接通过e来获取数据了

可能你会觉得本来这个东西可以直接就通过把Form1传给FrmRGB直接在里面设置背景几句代码就能搞定的东西 结果却扯了这么多出来 先是扯了一个方法出来调用 然后又事件什么的 的确 因为这个例子本来比较简单 所以可以直接传值然后修改背景色 如果功能复杂点 估计就不那么好使了 而且重点是、、、

看看事件的方式 确实代码比较多 但是你有没有发现他已经和Form1完全脱离关系了 在FrmRGB的构造器里面 他已经不需要接受和Form1相关的任何东西了 这也就意味着 FrmRGB可以独立使用了 他可以直接原封不动的拷贝到任何一个工程里面去 如果按照最上面的方式可行吗? 因为FrmRGB需要接收一个Form1参数 所以你拷贝到其他工程里面也必须要有一个叫Form1的窗体 而且窗体必须要有一个叫SetColor的方法、、、如果用事件 就大大的减少了耦合度 通过事件去通知Form1 而Form1得到这个通知要怎么做FrmRGB也不用管 如果有数据要传递则通过事件参数传递或者FrmRGB提供属性给调用者 虽然写起来可能麻烦了点 不过质量确是很不错的、、、

这里接着上篇的就列举这么多 仅供参考、、、

上篇:传送门


添加时间:2014-04-18 02:31:46 编辑时间:2016-12-02 22:35:29 阅读:1401 
常见的一些问题 C#常见问题
还没有人留言 要不你来抢一个沙发?
  • 编写评论

      我觉得区分大小写是一个码农的基本素质
[访问统计] 今天:33 总数:147806 提示:未成年人 请在大人陪同下浏览本站内容 还有:世界上最帅的码农 -> 石头 RSS:http://st233.com/rss Powered by -> Crystal_lz