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吧。

  

  

  

原文地址:https://www.cnblogs.com/zhaogaojian/p/13882106.html