1.前言
这里写的是我个人都方法,当然还有很多绑定的方法,仅作参考。
首先我们创建一个公共方法文件以便于将数据绑定到一个对象上。
2.公共方法
代码很长,不用去看,复制就好了,写成一个公共的方法,用于引用
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.Common;
using System.Dynamic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Shapes;
namespace CommonExtend
{
/// <summary>
/// 扩展函数,此类中的函数对所有模块有效,请慎重修改
/// </summary>
public static class Extend
{
#region 关闭数据库连接
/// <summary>
/// 关闭数据库连接
/// </summary>
/// <param name="connection">要关闭的数据库连接</param>
public static void CloseEx(this DbConnection connection)
{
if (connection.State != ConnectionState.Closed)
{
try
{
connection.Close();
}
catch { }
}
}
#endregion
#region 通用类型转换
/// <summary>
/// 通用类型转换
/// </summary>
/// <typeparam name="T">目标类型</typeparam>
/// <param name="Source">源对象</param>
/// <returns></returns>
public static T ChangeOrDefault<T>(this object Source)
{
object result = default(T);
if (Source != null && !(Source is DBNull))
{
try
{
if (typeof(T) == Source.GetType() || typeof(T).IsAssignableFrom(Source.GetType()))
{
result = Source;
}
else if (Source is string && typeof(T) == typeof(Guid))
{
result = new Guid(Source as string);
}
else if (Source is string && typeof(T) == typeof(Version))
{
result = new Version(Source as string);
}
else if (typeof(T).IsEnum)
{
if (Source is string)
{
result = Enum.Parse(typeof(T), Source as string);
}
else
{
result = Enum.ToObject(typeof(T), Source);
}
}
else if (!typeof(T).IsInterface && typeof(T).IsGenericType)
{
Type innerType = typeof(T).GetGenericArguments()[0];
object innerValue = Convert.ChangeType(Source, innerType);
result = Activator.CreateInstance(typeof(T), new object[] { innerValue });
}
else if (Source is IConvertible)
{
result = Convert.ChangeType(Source, typeof(T));
}
}
catch { }
}
return (T)result;
}
#endregion
#region DataTable扩展
/// <summary>
/// DataTable转动态字典
/// </summary>
/// <param name="Source">DataTable对象</param>
/// <returns></returns>
public static Dictionary<string, ExpandoObject> ToDictionary(this DataTable Source)
{
Dictionary<string, ExpandoObject> result = new Dictionary<string, ExpandoObject>();
for (int i = 0; i < Source.Rows.Count; i++)
{
DataRow row = Source.Rows[i];
ExpandoObject item = new ExpandoObject();
IDictionary<string, object> idic = item;
foreach (DataColumn column in Source.Columns)
{
if (row[column] is DBNull)
{
idic[column.ColumnName.ToUpper()] = null;
}
else
{
idic[column.ColumnName.ToUpper()] = row[column];
}
}
result[i.ToString()] = item;
}
return result;
}
/// <summary>
/// Convert DataRow[] to Dictionary<string, ExpandoObject>
/// </summary>
/// <param name="Source">The DataRow[] object</param>
/// <returns>The Dictionary<string, ExpandoObject> Object</returns>
public static Dictionary<string, ExpandoObject> ToDictionary(this DataRow[] Source)
{
Dictionary<string, ExpandoObject> result = new Dictionary<string, ExpandoObject>();
for (int i = 0; i < Source.Length; i++)
{
DataRow row = Source[i];
ExpandoObject item = new ExpandoObject();
IDictionary<string, object> idic = item;
foreach (DataColumn column in Source[i].Table.Columns)
{
if (row[column] is DBNull)
{
idic[column.ColumnName.ToUpper()] = null;
}
else
{
idic[column.ColumnName.ToUpper()] = row[column];
}
}
result[i.ToString()] = item;
}
return result;
}
/// <summary>
/// DataTable转字典
/// </summary>
/// <typeparam name="TKey">字典键类型</typeparam>
/// <param name="Source">Source</param>
/// <param name="Selector">键值选择</param>
/// <returns></returns>
public static Dictionary<TKey, ExpandoObject> ToDictionary<TKey>(this DataTable Source, Func<DataRow, TKey> Selector)
{
lock (Source.Rows)
{
Dictionary<TKey, ExpandoObject> result = new Dictionary<TKey, ExpandoObject>();
foreach (DataRow row in Source.Rows)
{
ExpandoObject item = new ExpandoObject();
IDictionary<string, object> idic = item;
foreach (DataColumn column in Source.Columns)
{
if (row[column] is DBNull)
{
idic[column.ColumnName] = null;
}
else
{
idic[column.ColumnName] = row[column];
}
}
result[Selector(row)] = item;
}
return result;
}
}
#endregion
#region Dictionary扩展
/// <summary>
/// Dictionary转ExpandoObject
/// </summary>
/// <param name="dictionary">源字典</param>
/// <returns></returns>
public static ExpandoObject ToExpandoObject(this Dictionary<string, ExpandoObject> dictionary)
{
ExpandoObject result = new ExpandoObject();
IDictionary<string, object> idic = result;
foreach (KeyValuePair<string, ExpandoObject> pair in dictionary)
{
idic[pair.Key] = pair.Value;
}
return result;
}
/// <summary>
/// 字典合并,键值相同时取第二个字典值
/// </summary>
/// <typeparam name="TKey">字典键</typeparam>
/// <typeparam name="TValue">字典值</typeparam>
/// <param name="first">合并第一个字典</param>
/// <param name="second">合并第二个字典</param>
/// <returns></returns>
public static Dictionary<TKey, TValue> Merge<TKey, TValue>(this Dictionary<TKey, TValue> first, Dictionary<TKey, TValue> second)
{
foreach (var pair in second)
{
first[pair.Key] = pair.Value;
}
return first;
}
/// <summary>
/// 设置字典的错误对象
/// </summary>
/// <param name="dictionary">字典对象</param>
/// <param name="exception">错误对象</param>
/// <returns></returns>
public static Dictionary<string, ExpandoObject> SetException(this Dictionary<string, ExpandoObject> dictionary, Exception exception)
{
dictionary["Exception"] = exception.ToExpandoObject();
return dictionary;
}
#endregion
#region Exception扩展
/// <summary>
/// Exception转ExpandoObject
/// </summary>
/// <param name="ex">异常对象</param>
/// <returns></returns>
public static ExpandoObject ToExpandoObject(this Exception ex)
{
ExpandoObject result = new ExpandoObject();
result.SetValue("StackTrace", ex.StackTrace ?? Environment.StackTrace);
result.SetValue("Message", ex.Message);
result.SetValue("Source", ex.Source);
return result;
}
#endregion
#region ExpandoObject扩展
/// <summary>
/// 获取ExpandoObject是否包含某属性
/// </summary>
/// <param name="eo"></param>
/// <param name="mi"></param>
/// <returns></returns>
public static bool HasValue(this ExpandoObject eo, string mi)
{
return (eo as IDictionary<string, object>).ContainsKey(mi);
}
/// <summary>
/// 获取ExpandoObject属性值
/// </summary>
/// <param name="eo">ExpandoObject对象</param>
/// <param name="mi">ExpandoObject属性名</param>
/// <returns></returns>
public static object GetValue(this ExpandoObject eo, string mi)
{
object result = default(object);
IDictionary<string, object> dic = eo as IDictionary<string, object>;
if (dic.ContainsKey(mi))
{
result = dic[mi];
}
return result;
}
/// <summary>
/// 获取ExpandoObject属性值
/// </summary>
/// <typeparam name="T">泛型类型</typeparam>
/// <param name="eo">ExpandoObject对象</param>
/// <param name="mi">ExpandoObject属性名</param>
/// <returns></returns>
public static T GetValue<T>(this ExpandoObject eo, string mi)
{
T t = default(T);
IDictionary<string, object> dic = eo as IDictionary<string, object>;
if (dic.ContainsKey(mi))
{
try
{
t = dic[mi].ChangeOrDefault<T>();
}
catch { }
}
return t;
}
/// <summary>
/// 获取ExpandoObject属性值(如果属性不存在则设置将属性设置为nv值并返回)
/// </summary>
/// <typeparam name="T">泛型类型</typeparam>
/// <param name="eo">ExpandoObject对象</param>
/// <param name="mi">ExpandoObject属性名</param>
/// <returns></returns>
public static T GetOrSetValue<T>(this ExpandoObject eo, string mi) where T : new()
{
lock (eo)
{
T result = eo.GetValue<T>(mi);
if (EqualityComparer<T>.Default.Equals(result, default(T)))
{
result = new T();
eo.SetValue(mi, result);
}
return result;
}
}
/// <summary>
/// 设置ExpandoObject属性值
/// </summary>
/// <typeparam name="T">设置的泛型值类型</typeparam>
/// <param name="eo">ExpandoObject对象</param>
/// <param name="mi">ExpandoObject属性名</param>
/// <param name="va">ExpandoObject属性值</param>
/// <returns></returns>
public static ExpandoObject SetValue<T>(this ExpandoObject eo, string mi, T va)
{
if (!(eo.GetValue(mi) != null && eo.GetValue(mi).GetType() == typeof(T)) || !EqualityComparer<T>.Default.Equals(eo.GetValue<T>(mi), va))
{
(eo as IDictionary<string, object>)[mi] = va;
}
return eo as ExpandoObject;
}
/// <summary>
/// 对比更新,仅对所有属性均为值类型的动态对象使用,用update更新source并返回source
/// </summary>
/// <param name="source">源对象</param>
/// <param name="update">新对象</param>
/// <returns></returns>
public static void UpdateFrom(this ExpandoObject source, ExpandoObject update)
{
IDictionary<string, object> old_obj = source as IDictionary<string, object>;
IDictionary<string, object> new_obj = update as IDictionary<string, object>;
List<KeyValuePair<string, object>> mod = new List<KeyValuePair<string, object>>();
List<KeyValuePair<string, object>> del = new List<KeyValuePair<string, object>>();
foreach (var pair in old_obj)
{
if (new_obj.ContainsKey(pair.Key))
{
mod.Add(new KeyValuePair<string, object>(pair.Key, new_obj[pair.Key]));
new_obj.Remove(pair.Key); //这里不能用Remove(pair),pair不属于new_obj,移除无效
}
else
{
del.Add(pair);
}
}
foreach (var pair in del)
{
old_obj.Remove(pair);
}
foreach (var pair in mod)
{
old_obj[pair.Key] = pair.Value;
}
foreach (var pair in new_obj)
{
old_obj.Add(pair);
}
}
#endregion
#region List<ExpandoObject>扩展
/// <summary>
/// 对比更新,仅对所有属性均为值类型的动态对象集合使用
/// 如果source和update的数量都不同,则跳过更新,直接返回true,否则用update更新source并返回false
/// </summary>
/// <param name="source">源集合</param>
/// <param name="update">新集合</param>
/// <param name="field">检索键</param>
/// <returns>如果数量上有更新返回true,没有更新返回false</returns>
public static bool UpdateFrom(this List<ExpandoObject> source, List<ExpandoObject> update, string field)
{
if (source.Count != update.Count) return true;
for (int i = source.Count - 1; i >= 0; i--)
{
object key = source[i].GetValue(field);
if (key == null) continue;
ExpandoObject find = update.Find(x => x.GetValue(field).Equals(key));
if (find == default(ExpandoObject))
{
return true;
}
else
{
source[i].UpdateFrom(find);
update.Remove(find); //找得到就从update中移除,从而update中就只剩下source中没有的了
}
}
foreach (ExpandoObject item in update)
{
source.Add(item);
return true;
}
return false;
}
#endregion
#region Window扩展
/// <summary>
/// 修改模板
/// </summary>
/// <param name="window"></param>
public static void AdaptTemplate(this Window window)
{
window.WindowStyle = WindowStyle.None;
if (window.ResizeMode != ResizeMode.NoResize)
{
window.ResizeMode = ResizeMode.CanMinimize;
}
//边框
FrameworkElementFactory border = new FrameworkElementFactory(typeof(Border)) { Name = "Border" };
border.SetValue(Border.BorderBrushProperty, new SolidColorBrush((Color)ColorConverter.ConvertFromString("#0077CC")));
Style borderStyle = new Style(typeof(Border));
borderStyle.Setters.Add(new Setter(Border.BorderThicknessProperty, new Thickness(1)));
DataTrigger dt = new DataTrigger();
dt.Binding = new Binding() { RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(Window), 1), Path = new PropertyPath("WindowState") };
dt.Value = WindowState.Maximized;
dt.Setters.Add(new Setter(Border.BorderThicknessProperty, new Thickness(0)));
borderStyle.Triggers.Add(dt);
border.SetValue(FrameworkElement.StyleProperty, borderStyle);
//布局
FrameworkElementFactory grid = new FrameworkElementFactory(typeof(Grid));
grid.SetValue(Grid.BackgroundProperty, (window.Background == new SolidColorBrush(Colors.Transparent)) ? new SolidColorBrush(Colors.White) : window.Background);
FrameworkElementFactory row1 = new FrameworkElementFactory(typeof(RowDefinition));
row1.SetValue(RowDefinition.HeightProperty, new GridLength(32));
grid.AppendChild(row1);
FrameworkElementFactory row2 = new FrameworkElementFactory(typeof(RowDefinition));
row2.SetValue(RowDefinition.HeightProperty, new GridLength(100, GridUnitType.Star));
grid.AppendChild(row2);
border.AppendChild(grid);
//拖动
FrameworkElementFactory thumb = new FrameworkElementFactory(typeof(Thumb)) { Name = "Thumb" };
thumb.SetValue(Thumb.BackgroundProperty, new SolidColorBrush((Color)ColorConverter.ConvertFromString("#0077CC")));
ControlTemplate thumbTemplate = new ControlTemplate();
FrameworkElementFactory rectangle = new FrameworkElementFactory(typeof(Rectangle));
rectangle.SetBinding(Rectangle.FillProperty, new Binding() { RelativeSource = RelativeSource.TemplatedParent, Path = new PropertyPath("Background") });
rectangle.AddHandler(Border.MouseLeftButtonDownEvent, new MouseButtonEventHandler((obj, eve) =>
{
window.DragMove();
}));
thumbTemplate.VisualTree = rectangle;
thumb.SetValue(Thumb.TemplateProperty, thumbTemplate);
if (window.ResizeMode != ResizeMode.NoResize && window.SizeToContent == SizeToContent.Manual)
{
thumb.AddHandler(Thumb.MouseDoubleClickEvent, new MouseButtonEventHandler((obj, eve) =>
{
if (window.WindowState == WindowState.Maximized)
{
window.WindowState = WindowState.Normal;
}
else
{
window.WindowState = WindowState.Maximized;
}
}));
}
grid.AppendChild(thumb);
//标题
FrameworkElementFactory textBlock = new FrameworkElementFactory(typeof(TextBlock)) { Name = "Title" };
textBlock.SetValue(TextBlock.IsHitTestVisibleProperty, false);
textBlock.SetValue(TextBlock.MarginProperty, new Thickness(8, 0, 8, 0));
textBlock.SetValue(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Center);
textBlock.SetValue(TextBlock.VerticalAlignmentProperty, VerticalAlignment.Center);
textBlock.SetValue(TextBlock.ForegroundProperty, new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FFFFFF")));
textBlock.SetBinding(TextBlock.TextProperty, new Binding() { RelativeSource = RelativeSource.TemplatedParent, Path = new PropertyPath("Title") });
grid.AppendChild(textBlock);
//关闭
FrameworkElementFactory close = new FrameworkElementFactory(typeof(Grid)) { Name = "Close" };
close.SetValue(FrameworkElement.WidthProperty, 32.0);
close.SetValue(FrameworkElement.HorizontalAlignmentProperty, HorizontalAlignment.Right);
close.SetValue(FrameworkElement.UseLayoutRoundingProperty, true);
close.SetValue(FrameworkElement.SnapsToDevicePixelsProperty, true);
close.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
Style closeStyle = new Style();
closeStyle.TargetType = typeof(Grid);
closeStyle.Setters.Add(new Setter(Grid.BackgroundProperty, new SolidColorBrush((Color)ColorConverter.ConvertFromString("#C73B3B"))));
Trigger trigger = new Trigger() { Property = FrameworkElement.IsMouseOverProperty, Value = true };
trigger.Setters.Add(new Setter(Grid.BackgroundProperty, new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF0000"))));
closeStyle.Triggers.Add(trigger);
close.SetValue(FrameworkElement.StyleProperty, closeStyle);
FrameworkElementFactory line1 = new FrameworkElementFactory(typeof(Line));
line1.SetValue(Line.X1Property, 8.0);
line1.SetValue(Line.Y1Property, 8.0);
line1.SetValue(Line.X2Property, 24.0);
line1.SetValue(Line.Y2Property, 24.0);
line1.SetValue(Line.StrokeProperty, new SolidColorBrush(Colors.White));
close.AppendChild(line1);
FrameworkElementFactory line2 = new FrameworkElementFactory(typeof(Line));
line2.SetValue(Line.X1Property, 8.0);
line2.SetValue(Line.Y1Property, 24.0);
line2.SetValue(Line.X2Property, 24.0);
line2.SetValue(Line.Y2Property, 8.0);
line2.SetValue(Line.StrokeProperty, new SolidColorBrush(Colors.White));
close.AppendChild(line2);
close.AddHandler(FrameworkElement.MouseLeftButtonUpEvent, new MouseButtonEventHandler((obj, eve) =>
{
window.Close();
}));
grid.AppendChild(close);
//模板
FrameworkElementFactory contentPresenter = new FrameworkElementFactory(typeof(ContentPresenter));
contentPresenter.SetValue(Grid.RowProperty, 1);
grid.AppendChild(contentPresenter);
window.Template = new ControlTemplate() { TargetType = typeof(Window), VisualTree = border }; //这里如果不加上typeof(Window),将导致contentPresenter没有内容
}
/// <summary>
/// 普通弹出
/// </summary>
/// <param name="window"></param>
public static void ShowEx(this Window window)
{
window.FontFamily = (FontFamily)window.FindResource("FontFamily");
window.FontSize = (double)window.FindResource("FontSize");
window.Owner = Application.Current.MainWindow;
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
window.AdaptTemplate();
window.Activated += (object obj, EventArgs eve) =>
{
Window child = obj as Window;
if (child != null && child.WindowState == WindowState.Minimized)
{
child.WindowState = WindowState.Normal;
}
};
window.SourceInitialized += (object sender, EventArgs e) =>
{
HwndSource source = PresentationSource.FromVisual(window) as HwndSource;
if (source != null)
{
source.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) =>
{
switch (msg)
{
case 0x0086:
(window.Template.FindName("Thumb", window) as Thumb).Opacity = (wParam.ToInt32() == 1) ? 1 : 0.5;
break;
}
return IntPtr.Zero;
});
}
};
window.Show();
}
/// <summary>
/// 模式弹出
/// </summary>
/// <param name="window"></param>
/// <returns></returns>
public static bool? ShowDialogEx(this Window window)
{
window.FontFamily = (FontFamily)window.FindResource("FontFamily");
window.FontSize = (double)window.FindResource("FontSize");
window.Owner = Application.Current.MainWindow;
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
window.AdaptTemplate();
window.Activated += (object obj, EventArgs eve) =>
{
Window child = obj as Window;
if (child != null && child.WindowState == WindowState.Minimized)
{
child.WindowState = WindowState.Normal;
}
};
window.SourceInitialized += (object sender, EventArgs e) =>
{
HwndSource source = PresentationSource.FromVisual(window) as HwndSource;
if (source != null)
{
source.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) =>
{
switch (msg)
{
case 0x0086:
(window.Template.FindName("Thumb", window) as Thumb).Opacity = (wParam.ToInt32() == 1) ? 1 : 0.5;
break;
}
return IntPtr.Zero;
});
}
};
return window.ShowDialog();
}
#endregion
}
}
当然这里包含了一些其他的公用方法,我这里就不做删除了,也许能用上。
3.Demo
然后写了个小demo 测试绑定
XAML页面设计代码:
<Window x:Class="DateBindingDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DateBindingDemo"
mc:Ignorable="d"
Title="MainWindow" Height="174.529" Width="305.661" WindowStartupLocation="CenterScreen">
<Window.Resources>
<ResourceDictionary>
<ObjectDataProvider x:Key="Data"/>
</ResourceDictionary>
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource Data}}">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="5"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Margin="5" VerticalAlignment="Center" Text="Name:" Grid.Row="0"/>
<TextBox Margin="60,5,5,0" x:Name="textBoxName" Grid.Row="0" Text="{Binding ENTITY.INFO.NAME}" />
<StackPanel Grid.Row="2">
<Button Margin="5" Height="24" Content="测试绑定" Click="Binding_Click" x:Name="btnBinding"/>
<Button Margin="5" Height="24" Content="清除绑定" Click="Clear_Click" x:Name="btnClear"/>
</StackPanel>
</Grid>
</Window>
目的很明确,点击“测试绑定”,能将我们需要的数据绑定到“Name"后面的Textbox中。
点击“清除绑定”清除掉Textbox中的数据。
后台代码:
using CommonExtend;
using System.Dynamic;
using System.Windows;
using System.Windows.Data;
namespace DateBindingDemo
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public dynamic eoData = new ExpandoObject();
public MainWindow()
{
InitializeComponent();
(this.FindResource("Data") as ObjectDataProvider).ObjectInstance = eoData;
}
private void Binding_Click(object sender, RoutedEventArgs e)
{
string name = "张三"; // name可为数据库取出来的数据或者是其他地方的数据
((ExpandoObject)eoData).GetOrSetValue<ExpandoObject>("ENTITY").GetOrSetValue<ExpandoObject>("INFO").SetValue("NAME", name);
}
private void Clear_Click(object sender, RoutedEventArgs e)
{
((ExpandoObject)eoData).GetOrSetValue<ExpandoObject>("ENTITY").GetOrSetValue<ExpandoObject>("INFO").SetValue("NAME", "");
}
}
}
4.结果
成功实现绑定。