WPF .netCore使用MVVM
WPF MVVM模式一直没怎么用过,.net5正式版就要出来了,趁这个时间看看各个微软的前后端.netCore的功能,使用.netCore下WPF实现一个简单的从数据库读取数据显示功能,
示例主要用到了按钮,编辑框,树控件,列表控件, 代码东拼西凑的,只贴几个片段。
1、XAML
<Page x:Class="NEasyCode.PageDataBase"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:NEasyCode"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="PageDataBase"
>
<Page.DataContext>
<local:DataBaseViewModel />
</Page.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<DockPanel >
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Label Name="LabelFilter" Grid.Column="0">表名过滤:</Label>
<TextBox Margin="0,0,0,0" Grid.Column="1" Name="TextFilter" Text="{Binding Path=SearchText, Mode=TwoWay}"/>
<Button Name="ButtonRefresh" Content="刷新" Grid.Column="2" Width="40" DockPanel.Dock="Right" Command="{Binding Path=QueryCommand}"></Button>
</Grid>
<TreeView Margin="0,0,0,0"
Name="TreeDataBase"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding TreeViewItems}">
</TreeView>
</DockPanel>
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Left" />
<DockPanel Grid.Column="2" >
<DataGrid Name="TableProp" ItemsSource="{Binding Path=TableInfoList}">
<DataGrid.Columns>
<DataGridTextColumn Header="编号" Width="90" Binding="{Binding ColumnId}"/>
<DataGridTextColumn Header="列名" Width="90" Binding="{Binding ColumnName}"/>
<DataGridTextColumn Header="主键" Width="90" Binding="{Binding ColumnIsPrimaryKey}"/>
<DataGridTextColumn Header="标识列" Width="90" Binding="{Binding ColumnIsIdentity}"/>
<DataGridTextColumn Header="列类型" Width="90" Binding="{Binding ColumnType}"/>
<DataGridTextColumn Header="长度" Width="90" Binding="{Binding ColumnLength}"/>
<DataGridTextColumn Header="精度" Width="90" Binding="{Binding ColumnPrecision}"/>
<DataGridTextColumn Header="小数点" Width="90" Binding="{Binding ColumnScale}"/>
<DataGridTextColumn Header="允许空" Width="90" Binding="{Binding ColumnIsNullAble}"/>
<DataGridTextColumn Header="默认值" Width="90" Binding="{Binding ColumnDefaultValue}"/>
<DataGridTextColumn Header="列描述" Width="90" Binding="{Binding ColumnDesc}"/>
<DataGridTextColumn Header="索引" Width="90" Binding="{Binding ColumnIndexName}"/>
<DataGridTextColumn Header="排序" Width="90" Binding="{Binding ColumnIndexSort}"/>
</DataGrid.Columns>
</DataGrid >
<DataGrid Name="TableData" ItemsSource="{Binding}">
<DataGrid.Columns>
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Grid>
</Page>
2、DataBaseModel.cs
using NEasyCode.Entity;
using NEasyCode.Util;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;
using System.Windows.Controls;
using System.Windows.Input;
namespace NEasyCode
{
public class DataBaseViewModel : INotifyPropertyChanged
{
#region Fields
private string _searchText;
private ObservableCollection<TableInfo> _resultList;
#endregion
#region Properties
private ObservableCollection<TableInfo> tableInfoList;
public ObservableCollection<TableInfo> TableInfoList
{
get {
return tableInfoList;
}
set
{
tableInfoList = value;
RaisePropertyChanged("TableInfoList");
}
}
public ObservableCollection<string> TableList { get; set; } = new ObservableCollection<string>();
public ObservableCollection<TreeViewItem> TreeViewItems { get; set; } = new ObservableCollection<TreeViewItem>();
// 查询关键字
public string SearchText
{
get { return _searchText; }
set
{
_searchText = value;
RaisePropertyChanged("SearchText");
}
}
public ICommand QueryCommand
{
get { return new QueryCommand(SearchTable, CanSearching); }
}
#endregion
#region Construction
public DataBaseViewModel()
{
SearchTable();
ViewTableInfo("dghr_userinfo");
}
#endregion
#region Command Handler
/// <summary>
/// 查看表信息
/// </summary>
/// <param name="tableName"></param>
public void ViewTableInfo(string tableName)
{
//TableInfoList.Clear();
TableInfoList = DbUtil.GetTableProp(tableName).ToObservableCollection();
//_resultList = TableInfoList;
}
/// <summary>
/// 查找表
/// </summary>
public void SearchTable()
{
TableList.Clear();
var tableList= DbUtil.GetAllDataBase().ToObservableCollection();
if (string.IsNullOrWhiteSpace(SearchText))
{
TableList = tableList;
}
else
{
foreach (string p in tableList)
{
if (p.Contains(SearchText))
{
TableList.Add(p);
}
}
}
TreeViewItems.Clear();
for (int i = 0; i < TableList.Count; i++)
{
TreeViewItem item = new TreeViewItem();
item.Header = TableList[i];
item.Selected += Item_Selected;
item.MouseDoubleClick += Item_MouseDoubleClick;
TreeViewItems.Add(item);
}
}
private void Item_Selected(object sender, System.Windows.RoutedEventArgs e)
{
var v= ((TreeViewItem)(e.Source)).Header.ToString();
ViewTableInfo(v);
}
private void Item_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
//ViewTableInfo(e.ToString)
}
public bool CanSearching()
{
return true;
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region Methods
private void RaisePropertyChanged(string propertyName)
{
// take a copy to prevent thread issues
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
3、Command
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Input;
namespace NEasyCode
{
class QueryCommand : ICommand
{
#region Fields
private Action _execute;
private Func<bool> _canExecute;
#endregion
public QueryCommand(Action execute)
: this(execute, null)
{
}
public QueryCommand(Action execute, Func<bool> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#region ICommand Member
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
{
CommandManager.RequerySuggested += value;
}
}
remove
{
if (_canExecute != null)
{
CommandManager.RequerySuggested -= value;
}
}
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute();
}
public void Execute(object parameter)
{
_execute();
}
#endregion
}
}
4、TableInfo实体
using System;
using System.Collections.Generic;
using System.Text;
namespace NEasyCode.Entity
{
public class TableInfo
{
public string TableName { get; set; }
public string TableDesc { get; set; }
public int ColumnId { get; set; }
public string ColumnName { get; set; }
public bool ColumnIsPrimaryKey { get; set; }
public bool ColumnIsIdentity { get; set; }
public string ColumnType { get; set; }
public int ColumnLength { get; set; }
public int ColumnPrecision { get; set; }
public int ColumnScale { get; set; }
public bool ColumnIsNullAble { get; set; }
public string ColumnDefaultValue { get; set; }
public string ColumnDesc { get; set; }
public string ColumnIndexName { get; set; }
public string ColumnIndexSort { get; set; }
public DateTime ColumnCreateDate { get; set; }
public DateTime ColumnModifyDate { get; set; }
}
}
5、运行效果

6、有几点问题,研究的不深,可能因为使用的不算完全纯正的mvvm的原因,有几点疑惑。
6.1 树控件数据源不需要调用RaisePropertyChanged,但是DataGrid需要,没有搞明白为什么这样。
6.2 树控件的绑定事件按网上的无法使用,.netCore下无法引入NuGet下的System.Windows.Interactivity,其它引入方式未试验,直接使用事件绑定的方式了。
通过Command绑定事件
在项目中引用 System.Windows.Interactivity.WPF(简单来说该插件可以将页面控件的Event转为ViewModel中的Command)
在窗体中添加引用
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
绑定Command到SelectedItemChanged事件
<TreeView x:Name="treeView" ItemsSource="{Binding TypeList}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction Command="{Binding SelectItemChangeCommand}"
CommandParameter="{Binding ElementName=treeView,Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
后续测试:在.net5 预览版下是可以的,.netCore下不行,


7、在xp下无法运行,传家项目没有必须升级的需求还是用.net4.0吧。
本博客是个人工作中记录,更深层次的问题可以提供有偿技术支持。
另外建了几个QQ技术群:
2、全栈技术群:616945527
2、硬件嵌入式开发: 75764412
3、Go语言交流群:9924600
闲置域名WWW.EXAI.CN (超级人工智能)出售。
另外建了几个QQ技术群:
2、全栈技术群:616945527
2、硬件嵌入式开发: 75764412
3、Go语言交流群:9924600
闲置域名WWW.EXAI.CN (超级人工智能)出售。

浙公网安备 33010602011771号