WPF中将多个函数返回值分别绑定至界面控件
一、内容简述
WPF的一个优势是对于逻辑层中数据在界面的展示具有很好的支持,可通过Binding即数据绑定实现。本文的应用场景为使用数据绑定实现:使用界面中Textbox控件获取用户的输入,然后进行一定的函数运算,随输入的变化实时将函数返回值显示至界面的TextBlock控件。下面对于单独一个函数返回值和多个函数返回值的情况分别进行介绍。
二、场景一:只有一个函数返回值
2.1通过ObjectDataProvider实现
ObjectDataProvider,就是将对象作为数据源提供给Binding,将内含具体功能运算的函数的对象包装起来。
示例代码如下:
public void SetBinding01()
{
ObjectDataProvider objectDataProvider01 = new ObjectDataProvider();
objectDataProvider01.ObjectInstance = new ResultCalculator_ObjectDataProvider();
objectDataProvider01.MethodName = "Calculator";
objectDataProvider01.MethodParameters.Add("");
objectDataProvider01.MethodParameters.Add("");
Binding binding01 = new Binding("MethodParameters[0]")
{
Source = objectDataProvider01,
BindsDirectlyToSource = true,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
Binding binding02 = new Binding("MethodParameters[1]")
{
Source = objectDataProvider01,
BindsDirectlyToSource = true,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
Binding binding03 = new Binding(".") { Source = objectDataProvider01 };
this.textBox01.SetBinding(TextBox.TextProperty, binding01);
this.textBox02.SetBinding(TextBox.TextProperty, binding02);
this.textBlock01.SetBinding(TextBlock.TextProperty, binding03);
}
其中ResultCalculator_ObjectDataProvider类为包含具体功能函数的自定义类,ObjectDataProvider使用MethodName属性定义绑定的函数名称,向MethodParameters添加变量类型,变量类型要与函数的输入参数类型一致,有几个变量就添加几个,最后将输入输出绑定,Source都为ObjectDataProvider对象,输入绑定的Path为MethodParameters[],输出绑定的Path为".",因为此时函数只输出一个数据。
ResultCalculator_ObjectDataProvider类定义如下:
public class ResultCalculator_ObjectDataProvider
{
public string Calculator(string arg01, string arg02)
{
double d01, d02, d03;
if (!double.TryParse(arg01, out d01))
{
return "输入有误";
}
if (!double.TryParse(arg02, out d02))
{
return "输入有误";
}
d03 = d01 + d02;
return d03.ToString();
}
}
2.2通过继承INotifyPropertyChanged接口的自定义类实现
示例代码如下:
public void setBinding02()
{
ResultCalculator resultCalculator01 = new ResultCalculator();
RangeValidationRule rangeValidationRule = new RangeValidationRule();
Binding binding01 = new Binding("Arg01");
binding01.BindsDirectlyToSource = true;
binding01.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding01.Source = resultCalculator01;
Binding binding02 = new Binding("Arg02");
binding02.BindsDirectlyToSource = true;
binding02.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding02.Source = resultCalculator01;
this.textBox01.SetBinding(TextBox.TextProperty, binding01);
this.textBox02.SetBinding(TextBox.TextProperty, binding02);
this.textBlock01.SetBinding(TextBlock.TextProperty, new Binding("Result01") { Source = resultCalculator01 });
}
其中ResultCalculator为继承了INotifyPropertyChanged接口的自定义的一个类,类中包含了两个输入参数和一个输出参数三个属性,这三个属性值分别绑定至对应的控件。
ResultCalculator类定义如下:
public class ResultCalculator : INotifyPropertyChanged
{
private string arg01;
private string arg02;
private string result01;
public string Arg01
{
get { return arg01; }
set
{
arg01 = value;
Calculator();
}
}
public string Arg02
{
get { return arg02; }
set
{
arg02 = value;
Calculator();
}
}
public string Result01
{
get
{
return result01;
}
set
{
result01 = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Result01"));
}
}
}
public void Calculator()
{
double d01, d02, d03;
if (!double.TryParse(arg01, out d01))
{
Result01 = "输入有误";
return;
}
if (!double.TryParse(arg02, out d02))
{
Result01 = "输入有误";
return;
}
d03 = d01 + d02;
Result01 = d03.ToString();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
根据类中定义,当输入参数属性值发生变化后,通过调用内部函数对输出参数属性值进行更新,而输出参数属性已与控件绑定,所以会实时更新显示。
三、场景二:多个函数返回值
当有多个函数返回值时,还需要明确多个函数的输入是否相同。
3.1情况一:输入相同
如果输入相同,则可将多个函数合并为一个函数,而将输出值组成为列表输出,最后依次将多个输出绑定至相应控件上。此时可通过ObjectDataProvider实现,示例代码如下:
public void SetBinding01()
{
ObjectDataProvider objectDataProvider01 = new ObjectDataProvider();
objectDataProvider01.ObjectInstance = new ResultCalculator_ObjectDataProvider();
objectDataProvider01.MethodName = "Calculator";
objectDataProvider01.MethodParameters.Add("");
objectDataProvider01.MethodParameters.Add("");
Binding binding01 = new Binding("MethodParameters[0]")
{
Source = objectDataProvider01,
BindsDirectlyToSource = true,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
Binding binding02 = new Binding("MethodParameters[1]")
{
Source = objectDataProvider01,
BindsDirectlyToSource = true,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
Binding binding03 = new Binding("[0]") { Source = objectDataProvider01 };
Binding binding04 = new Binding("[1]") { Source = objectDataProvider01 };
this.textBox01.SetBinding(TextBox.TextProperty, binding01);
this.textBox02.SetBinding(TextBox.TextProperty, binding02);
this.textBlock01.SetBinding(TextBlock.TextProperty, binding03);
this.textBlock02.SetBinding(TextBlock.TextProperty, binding04);
}
ResultCalculator_ObjectDataProvider类定义如下:
public class ResultCalculator_ObjectDataProvider
{
public List<string> Calculator(string arg01, string arg02)
{
double d01, d02, d03, d04;
if (!double.TryParse(arg01, out d01))
{
return new List<string> { "输入有误", "输入有误" };
}
if (!double.TryParse(arg02, out d02))
{
return new List<string> { "输入有误", "输入有误" };
}
d03 = d01 + d02;
d04 = d01 - d02;
return new List<string> { d03.ToString(), d04.ToString() };
}
}
需要注意的是,此时输出绑定时使用“[]”进行索引,以实现对输出列表中不同输出元素进行绑定。
3.2情况二:输入不同
此时不同函数的输入不尽相同,由于ObjectDataProvider类创造的对象只能绑定单个函数,所以可以创造多个对象用于多个函数绑定,但由于输入参数与界面控件相绑定,而控件只能进行一次数据绑定,所以此时要求各个函数之间的输入参数不能相同。
而使用继承INotifyPropertyChanged接口的自定义类进行数据绑定则对输入参数是否相同没有要求,所以此种情况下比使用ObjectDataProvider更为方便。
相关代码在上述代码的基础上简单更改即可。
参考文档
《深入浅出WPF》,作者刘铁猛,2010年7月中国水利水电出版社出版。