前言
在WPF中,前台控件应该很好的与数据进行绑定关联,不在像WinForm那样在后台拿着控件去操作,基于数据驱动的原则,写好绑定可以方便后台代码逻辑,并且代码看着更加简结。
1、XmlDocument与控件绑定
使用XPath选择需要显露的数据
前台代码
<ListView x:Name="listViewStudents" Height="130" Margin="5">
<ListView.View>
<GridView>
<GridViewColumn Header="Id" Width="80" DisplayMemberBinding="{Binding XPath=@Id}"/>
<GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding XPath=Name}"/>
<GridViewColumn Header="Age" Width="80" DisplayMemberBinding="{Binding XPath=Age}"/>
</GridView>
</ListView.View>
</ListView>
后台代码
XmlDocument doc = new XmlDocument();
doc.Load("XMLFile1.xml");
XmlDataProvider xdp = new XmlDataProvider();
xdp.Document = doc;
//使用XPath选择需要显露的数据
xdp.XPath = @"/StudentList/Student";
this.listViewStudents.DataContext = xdp;
this.listViewStudents.SetBinding(ListView.ItemsSourceProperty, new Binding());
数据文件
<?xml version="1.0" encoding="utf-8" ?>
<StudentList>
<Student Id="1">
<Name>Tim</Name>
<Age>20</Age>
</Student>
<Student Id="2">
<Name>Tom</Name>
<Age>25</Age>
</Student>
<Student Id="3">
<Name>Vina</Name>
<Age>28</Age>
</Student>
<Student Id="4">
<Name>Emily</Name>
<Age>33</Age>
</Student>
</StudentList>
2、XmlDataProvider绑定
数据代码
<Window.Resources>
<XmlDataProvider x:Key="xdp" XPath="FileSystem/Folder">
<x:XData>
<FileSystem xmlns="">
<Folder Name="Programming">
<Folder Name="Windows">
<Folder Name="WPF"/>
<Folder Name="MFC"/>
<Folder Name="Delphi"/>
</Folder>
</Folder>
<Folder Name="Tools">
<Folder Name="Development"/>
<Folder Name="Designment"/>
<Folder Name="Players"/>
</Folder>
</FileSystem>
</x:XData>
</XmlDataProvider>
</Window.Resources>
控件关联
<TreeView ItemsSource="{Binding Source={StaticResource xdp}}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding XPath=Folder}">
<TextBlock Text="{Binding XPath=@Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
3、数据列表直接关联
前台
<ListView x:Name="listViewStudents" Height="143" Margin="5">
<ListView.View>
<GridView>
<GridViewColumn Header="Id" Width="60" DisplayMemberBinding="{Binding ID}"/>
<GridViewColumn Header="Name" Width="100" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Age" Width="80" DisplayMemberBinding="{Binding Age}"/>
</GridView>
</ListView.View>
</ListView>
后台
this.listViewStudents.ItemsSource = from stu in stuList where stu.Name.StartsWith("T") select stu;
List<Student> stuList = new List<Student>()
{
new Student(){ID=0,Name="Tim",Age=29},
new Student(){ID=1,Name="Tom",Age=28},
new Student(){ID=2,Name="Kyle",Age=27},
new Student(){ID=3,Name="Tony",Age=26},
new Student(){ID=4,Name="Vina",Age=25},
new Student(){ID=5,Name="Mike",Age=24},
};
数据结构
class Student
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
4、ObjectDataProvider使用
前台
<StackPanel>
<TextBox x:Name="tb_arg1" Margin="5"/>
<TextBox x:Name="tb_arg2" Margin="5"/>
<TextBox x:Name="tbResult" Margin="5"/>
<Button x:Name="text" Content="11" Click="text_Click"></Button>
</StackPanel>
后台
private void SetBinding()
{
//创建并配置ObjectDataProvider对象
ObjectDataProvider odp = new ObjectDataProvider();
odp.ObjectInstance = new Calculator();
odp.MethodName = "Add";
odp.MethodParameters.Add("0");
odp.MethodParameters.Add("0");
//以ObjectDataProvider对象为Source创建Binding
Binding bidingToArg1 = new Binding("MethodParameters[0]")
{
Source = odp,
BindsDirectlyToSource = true,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
Binding bidingToArg2 = new Binding("MethodParameters[1]")
{
Source = odp,
BindsDirectlyToSource = true,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
Binding bindingToResult = new Binding(".") { Source = odp };
//将Binding关联到UI元素上
this.tb_arg1.SetBinding(TextBox.TextProperty, bidingToArg1);
this.tb_arg2.SetBinding(TextBox.TextProperty, bidingToArg2);
this.tbResult.SetBinding(TextBox.TextProperty, bindingToResult);
}
计算逻辑
class Calculator
{
public string Add(string arg1,string arg2)
{
double x = 0;
double y = 0;
double z = 0;
if (double.TryParse(arg1,out x)&&double.TryParse(arg2,out y))
{
z = x + y;
return z.ToString();
}
return "Input Error!";
}
}
5、两个控件关联
前台
<StackPanel>
<TextBox x:Name="textBox1" Margin="10"/>
<Slider x:Name="slider1" Minimum="-10" Maximum="110" Margin="5"/>
</StackPanel>
后台
Binding binding = new Binding("Value") { Source = this.slider1 };
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
RangeValidationRule rvr = new RangeValidationRule();
rvr.ValidatesOnTargetUpdated = true;
binding.ValidationRules.Add(rvr);
binding.NotifyOnValidationError = true;
this.textBox1.SetBinding(TextBox.TextProperty, binding);
this.textBox1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(this.ValidationError));
void ValidationError(object sender,RoutedEventArgs e)
{
if (Validation.GetErrors(this.textBox1).Count>0)
{
this.textBox1.ToolTip = Validation.GetErrors(this.textBox1)[0].ErrorContent.ToString();
}
}
输入验证
public class RangeValidationRule:ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
double d = 0;
if (double.TryParse(value.ToString(),out d))
{
if (d>=0&&d<=100)
{
return new ValidationResult(true, null);
}
}
return new ValidationResult(false, "Validation Failed");
}
}
6、转换器使用
前台
<ListBox x:Name="listBoxPlane" Height="160" Margin="5">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="20" Height="20" Source="{Binding Path=Category,Converter={StaticResource cts}}"/>
<TextBlock Text="{Binding Path=Name}" Width="60" Margin="80,0"/>
<CheckBox IsThreeState="True" IsChecked="{Binding Path=State,Converter={StaticResource stnb}}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
后台
关联数据源:
List<Plane> planlist = new List<Plane>()
{
new Plane(){Category=Category.Bomber,Name="B-1",State=State.Unknown},
new Plane(){Category=Category.Bomber,Name="B-2",State=State.Unknown},
new Plane(){Category=Category.Fighter,Name="F-22",State=State.Unknown},
new Plane(){Category=Category.Fighter,Name="Su-47",State=State.Unknown},
new Plane(){Category=Category.Bomber,Name="B-52",State=State.Unknown},
new Plane(){Category=Category.Fighter,Name="J-10",State=State.Unknown},
};
this.listBoxPlane.ItemsSource = planlist;
图像与枚举转换器
public class CategoryToSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Category c = (Category)value;
switch (c)
{
case Category.Bomber:
return @"Icons\1.png";
case Category.Fighter:
return @"Icons\2.png";
default:
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
复选框与状态转换器
public class StateToNullableBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
State s = (State)value;
switch (s)
{
case State.Available:
return true;
case State.Locked:
return false;
case State.Unknown:
default:
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool? nb = (bool?)value;
switch (nb)
{
case true:
return State.Available;
case false:
return State.Locked;
case null:
default:
return State.Unknown;
}
}
}
7、多值绑定
前台
<StackPanel Background="LightBlue">
<TextBox x:Name="tb1" Height="23" Margin="5"/>
<TextBox x:Name="tb2" Height="23" Margin="5,0"/>
<TextBox x:Name="tb3" Height="23" Margin="5"/>
<TextBox x:Name="tb4" Height="23" Margin="5,0"/>
<Button x:Name="button1" Content="Submit" Width="80" Margin="5"/>
</StackPanel>
后台
private void SetMulitBinding()
{
//准备基础Binding
Binding b1 = new Binding("Text") { Source = this.tb1 };
Binding b2 = new Binding("Text") { Source = this.tb2 };
Binding b3 = new Binding("Text") { Source = this.tb3 };
Binding b4 = new Binding("Text") { Source = this.tb4 };
//准备MultiBinding
MultiBinding mb = new MultiBinding() { Mode = BindingMode.OneWay };
mb.Bindings.Add(b1); //注意:MultiBinding对Add子Binding的顺序是敏感的
mb.Bindings.Add(b2);
mb.Bindings.Add(b3);
mb.Bindings.Add(b4);
//获取或设置用于在源值和目标值之间来回转换的转换器。
mb.Converter = new LogonMultiBindingConverter();
//将Buttion与MultiBinding对象关联
this.button1.SetBinding(Button.IsEnabledProperty, mb);
}
转换器
public class LogonMultiBindingConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (!values.Cast<string>().Any(text=>string.IsNullOrEmpty(text))
&&values[0].ToString()==values[1].ToString()
&&values[2].ToString()==values[3].ToString())
{
return true;
}
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}