欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何搭建新的WPF項(xiàng)目框架

 更新時(shí)間:2015年07月27日 17:28:55   作者:New丶Power  
這篇文章主要介紹了如何搭建新的WPF項(xiàng)目框架,在項(xiàng)目開(kāi)發(fā)中比較常見(jiàn)的開(kāi)發(fā)模式就是MVVM模式,使用MVVM框架開(kāi)發(fā)好處:1、框架較輕,2、學(xué)習(xí)成本低、3、適用大多數(shù)中小型項(xiàng)目,4、相對(duì)于微軟的prism框架更容易上手,需要的朋友可以參考下

下面就WPF項(xiàng)目框架搭建步驟一步一步的分享給大家。

在WPF項(xiàng)目開(kāi)發(fā)中最常用的開(kāi)發(fā)模式無(wú)疑是MVVM模式,  MVVM模式開(kāi)發(fā)的好處,在這里就不詳細(xì)討論, 還有 本文中所使用MVVMLight框架,為什么使用MVVM框架(1、框架較輕,2、學(xué)習(xí)成本低、3、適用大多數(shù)中小型項(xiàng)目,4、相對(duì)于微軟的prism框架更容易上手)   
下面開(kāi)始 一步一步 搭建框架

第一步: 利用反射創(chuàng)建VM構(gòu)造器

 

public class ViewModelFactory
{
 private static Dictionary<string, object> vmMap = new Dictionary<string, object>();<br>
 public static T GetViewModel<T>() where T : ViewModelBase
 {
  Type vmType = typeof(T);
  if (vmMap.ContainsKey(vmType.FullName))
  {
   return (T)vmMap[vmType.FullName];
  }
  else
  {
   object vm = Activator.CreateInstance(vmType);
   vmMap.Add(vmType.FullName, vm);
   return (T)vm;
  }
 }

 public static T GetViewModel<T>(object[] data,string id) where T : ViewModelBase
 {
  Type vmType = typeof(T);
  if (vmMap.ContainsKey(id))
  {
   return (T)vmMap[id];
  }
  else
  {
   object vm = Activator.CreateInstance(vmType, data);
   vmMap.Add(id, vm);
   return (T)vm;
  }
 }
}

為什么用一個(gè)Dictionary  將ViewModel  緩存起來(lái),相信利用MVVM模式開(kāi)發(fā)大多數(shù)的開(kāi)發(fā)者碰到的問(wèn)題無(wú)疑是各個(gè)VM之間的數(shù)據(jù)通信問(wèn)題,利用Dictionary緩存起來(lái)有兩個(gè)好處:

1、可以解決VM之間相互通信的問(wèn)題(當(dāng)然你也可以用MvvmLight的 Message機(jī)制來(lái)通信,PS:個(gè)人認(rèn)為完全沒(méi)必要用MvvmLight中的 Messgae,如果我們框架搭的合理完全可以規(guī)避去用MvvmLight中 Message,Message比較難于管理,如果在我們的代碼中出現(xiàn)大量的Message無(wú)疑是一件痛苦的事情,所以筆者不推薦用MvvmLight中的Message)

2、如果我們的應(yīng)用程序要頻繁的與服務(wù)器做交互,我們完全可以用緩存,以避免每次都去請(qǐng)求服務(wù)器(可以緩存一些在應(yīng)用程序中一直使用的數(shù)據(jù),規(guī)避二次請(qǐng)求)

public static T GetViewModel<T>() where T : ViewModelBase  這個(gè)函數(shù)(將我們的VM完全限定名作為KEY緩存)適用于單例模式的VM,

public static T GetViewModel<T>(object[] data,string id) where T : ViewModelBase 這個(gè)函數(shù)(主要構(gòu)件帶參數(shù)的VM構(gòu)造函數(shù),id是唯一ID),為什么會(huì)用到它,舉個(gè)例子

例如我們的QQ聊天窗口,所有聊天窗口基本相同用到的VM類(lèi)型也是相同,所以這時(shí)候就需要多個(gè)VM實(shí)例了,第一種方法就行不通了 所以會(huì)用到這種方法去構(gòu)建VM,并將id作為KEY值緩存起來(lái)

第二步:構(gòu)建我們的ViewModel 基類(lèi):

public delegate void CloseEventHandle(object sender);
 public class CustomViewModel : ViewModelBase
 {

  public event CloseEventHandle CloseEvent;
 protected bool hasData;

  public CustomViewModel()
  {
  LoadCommand = new RelayCommand(() =>
   {
    if (!hasData)
    {

     ThreadPool.QueueUserWorkItem((obj) =>
     {
      lock (this)
      {
       OnLoad();
       hasData = true;
      }
     });
    }
   });
  }public RelayCommand LoadCommand { private set; get; }

  protected virtual void OnLoad()
  {

  }

  protected void OnClose(object sender)
  {
   if (sender != null && CloseEvent != null)
   {
    CloseEvent(sender);
   }
  }
 }

上面CustomViewModel 繼承的ViewModelBase 是MvvmLight中的ViewModelBase,至于MvvmLight用法不在本文中討論,

1、為什么要聲明LoadCommand,因?yàn)榇蠖鄶?shù)的時(shí)候我們會(huì)在窗體或用戶(hù)控件Loaded的時(shí)候去加載數(shù)據(jù),有可能是異步加載,也有可能是同步加載,所以我們?cè)贑ustomViewModel中

聲明省去了各個(gè)VM子類(lèi)中去聲明LoadCommand的麻煩,使用時(shí)我們直接在XAML利用MvvmLight提供的EventToCommand 去綁定LoadCommand,然后在對(duì)應(yīng)的VM去重寫(xiě)CustomViewModel基類(lèi)中的OnLoad方法就可以了。

2、CloseEvent 故名思議是用來(lái)在VM中關(guān)閉窗體用的(詳細(xì)用法會(huì)在下文中討論)

3、我們也可以將一些公有的數(shù)據(jù)都提煉到VM中來(lái)。

第三步  管理窗口:

  在開(kāi)發(fā)程序的時(shí)候我們通常要去管理窗口的如果你沒(méi)用到MVVM模式 或者是傳統(tǒng)的Winform 你可以隨便的去new Window(),或者隨便的去改Window的構(gòu)造函數(shù),或者隨意的去構(gòu)造單例窗體,但是如果用到了MVVM模式似乎以上所說(shuō)的一切都變得復(fù)雜了,剛開(kāi)始的時(shí)候我也是挺傷腦筋的,后來(lái)在不斷的重構(gòu)代碼中找到了解決方法,(PS:本人也是一名菜鳥(niǎo),只想把自己在開(kāi)發(fā)中的問(wèn)題及解決方法分享出來(lái),未必就是好的解決方案,所以大神們勿噴)下面上代碼: 構(gòu)建我們的ShowHelper類(lèi):


public class ShowHelper
 {
  private static Dictionary<string, Window> windowManager = new Dictionary<string, Window>();

  public static void ShowDiaglogUc<T>(string title, object[] constructors = null, bool isDialog = false) where T : UserControl
  {
   Type controlType = typeof(T);
   string key;

   if (constructors == null) //如果構(gòu)造參數(shù)為null
   {
    key = controlType.FullName; //key = T 的完全限定名
   }
   else
   {
    // 如果不為空 并且 第二個(gè)構(gòu)造參數(shù)為string(第二個(gè)參數(shù)代表id -->有可能是GroupId 有可能是UserId);
    if (constructors.Length == 2 && constructors[1] is string) //ps:這里本人寫(xiě)死了可以根據(jù)需求自行修改
    {
     key = controlType.FullName + constructors[1].ToString(); //key = 控件 完全限定名+id;
    }
    else //不滿(mǎn)足條件
    {
     key = controlType.FullName; //key = 限定名
    }

   }

   if (windowManager.ContainsKey(key)) //如果包含KEY
   {
    windowManager[key].Topmost = true; //設(shè)置TopMost
    return;
   }

   UserControl content;
   if (constructors == null)
   {
    content = Activator.CreateInstance(controlType) as UserControl;
   }
   else
   {
    content = Activator.CreateInstance(controlType, constructors) as UserControl;
   }

   BaseWindow window = new BaseWindow(); //PS這是自己封裝 的Window,(可以用直接用原始的Wpf Widnow)
   window.Title = title;
   windowManager.Add(key, window);
   window.Closed += (sen, cloE) =>
   {
    windowManager.Remove(key);
   };
   if (isDialog)
   {
    window.ShowDialog();
   }
   else
   {
    window.Show();
   }
   #region 注冊(cè)關(guān)閉事件
   if (content.DataContext as CustomViewModel != null)
   {
    CustomViewModel vm = content.DataContext as CustomViewModel;
    vm.CloseEvent += (obj) =>
    {
     if (content.DataContext.Equals(obj))
     {
      window.Close();
     }
    };
   }
   #endregion
  }


  public static CustomDialogResult ShowOkCancleUC<T>(string title, MsgBoxBtn okCancle, out object data) where T : Control
  {
   Type vmType = typeof(T);
   Control content = Activator.CreateInstance(vmType) as Control;
   OkCanleWindow window = new OkCanleWindow();
   window.ShowInTaskbar = false;
   return window.ShowDialog(title, okCancle, content, out data);
  }

  public static CustomDialogResult MessageBoxDialog(string title, string message, MsgBoxBtn okCancle)
  {
   OkCanleWindow window = new OkCanleWindow();
   window.ShowInTaskbar = false;
   object none;
   return window.ShowDialog(title, okCancle, new MessageUC() { Message = message }, out none);
  }


、(1)開(kāi)始剖析 public static void ShowDiaglogUc<T>(string title, object[] constructors = null, bool isDialog = false) where T : UserControl
  ShowDialogUc 是用來(lái)在VM中用來(lái)創(chuàng)建UserControl并顯示在Window中的。你可能會(huì)問(wèn)為啥用windowManager 將窗口緩存起來(lái)(PS這里主要還是為了解決單例窗口的麻煩),

  至于 下面這段代碼,我們可以回到創(chuàng)建的CustomerViewModel中,對(duì)這里需要注冊(cè)VM中CloseEvent事件,這樣我們?cè)赩M中就可以直接調(diào)用OnClose()方法就OK了

  #region 注冊(cè)關(guān)閉事件
   if (content.DataContext as CustomViewModel != null)
   {
    CustomViewModel vm = content.DataContext as CustomViewModel;
    vm.CloseEvent += (obj) =>
    {
     if (content.DataContext.Equals(obj))
     {
      window.Close();
     }
    };
   }
  #region 注冊(cè)關(guān)閉事件

(2)開(kāi)始剖析 public static void ShowDiaglogUc<T>(string title, object[] constructors = null, bool isDialog = false) where T : UserControl 函數(shù)中的 constructors 參數(shù)

  在開(kāi)始剖析 constructors 之前先讓我們 聯(lián)想一下應(yīng)用場(chǎng)景(可以先想下,QQ的聊天窗口,例如群聊天吧,所有的群聊天都是相同界面,也就是說(shuō)他們所對(duì)應(yīng)的VM應(yīng)該是統(tǒng)一類(lèi)型的      VM,如果我們雙擊群,則會(huì)彈出對(duì)應(yīng)相應(yīng)的聊天窗口,正常的思維是會(huì)給聊天窗口傳遞參數(shù)也就是組ID 這時(shí)候我們的VM就需要構(gòu)造參數(shù)了,還有一個(gè)問(wèn)題就是每個(gè)群組聊天窗口只能有一個(gè),總不能每次雙擊就new一個(gè)聊天窗口了吧 所以這時(shí)候我們就需要做緩存了,) 綜上constructors參數(shù)在配合ViewModelFactory中的 public static T GetViewModel<T>(object[] data,string id) where T : ViewModelBase 方法  可以解決我們VM中需要傳遞參數(shù)的問(wèn)題,windowManager 可以解決窗口緩存問(wèn)題(如果你現(xiàn)在還看不明白請(qǐng) 仔細(xì)看上面代碼(雖然代碼有點(diǎn)渣),如果實(shí)在看不明白可以在留言板吐槽)。

1、 開(kāi)始 剖析 public static CustomDialogResult ShowOkCancleUC<T>(string title, MsgBoxBtn okCancle, out object data) where T : Control

  (1)開(kāi)始剖析該函數(shù)前讓我們 新建一個(gè)自己的帶返回值的 ShowDialog 窗口

     新建xaml窗口

<controls:BaseWindow x:Class="Common.OkCanleWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:controls="clr-namespace:Controls;assembly=Controls"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="MessageBoxWindow">
 <Grid x:Name="grid">
  <Grid.RowDefinitions>
   <RowDefinition/>
   <RowDefinition Height="50"/>
  </Grid.RowDefinitions>
  <Grid.ColumnDefinitions>
   <ColumnDefinition/>
   <ColumnDefinition/>
  </Grid.ColumnDefinitions>
  <Button Content="確 定" x:Name="okBtn" Click="okBtn_Click" Grid.Row="1" Height="30" Width="120" HorizontalAlignment="Right" Margin="0 0 10 0"/>
  <Button Content="取 消" x:Name="canleBtn" Click="canleBtn_Click" Grid.Row="1" Grid.Column="1" Height="30" Width="120" HorizontalAlignment="Left" Margin="10 0 0 0"/>

 </Grid>
</controls:BaseWindow>

  后臺(tái)代碼:

public partial class OkCanleWindow : BaseWindow
 {
  public OkCanleWindow()
  {
   InitializeComponent();
this.Closed += (s, e) =>
    {
     if (result == CustomDialogResult.None)
     {
      result = CustomDialogResult.Cancel;
     }

    };
  }
  private System.Windows.Controls.Control control;

  CustomDialogResult result;
  public CustomDialogResult ShowDialog(string title, MsgBoxBtn btnState, Control uc, out object dataContext)
  {
   #region 設(shè)置控件
   if (btnState == MsgBoxBtn.Ok) //如果為OK狀態(tài)
   {
    Grid.SetColumnSpan(okBtn, 2); //設(shè)置OK按鈕跨兩列
    okBtn.HorizontalAlignment = System.Windows.HorizontalAlignment.Center; //設(shè)置OK按鈕居中對(duì)齊
    canleBtn.Visibility = System.Windows.Visibility.Collapsed; //設(shè)置Cancel 按鈕隱藏;
    if (uc != null)
    {
     control = uc;  
     Grid.SetRow(uc, 0); //設(shè)置控件所在Grid 的行
     Grid.SetColumnSpan(uc, 2); //設(shè)置控件所在Grid 的列
     this.Width = uc.Width; //設(shè)置窗體寬度
     this.Height = uc.Height + grid.RowDefinitions[1].Height.Value + 35; //設(shè)置窗體寬度 高度
     grid.Children.Add(uc); //加入控件
    }
   }
   if (btnState == MsgBoxBtn.None) //如果為None 既沒(méi)有OK 也沒(méi)有 Cancle
   {
    grid.RowDefinitions.RemoveAt(1);
    okBtn.Visibility = System.Windows.Visibility.Collapsed;
    canleBtn.Visibility = System.Windows.Visibility.Hidden;
    if(uc !=null)
    {
     control = uc;
     Grid.SetRow(uc, 0); //設(shè)置控件所在Grid 的行
     Grid.SetColumnSpan(uc, 2); //設(shè)置控件所在Grid 的列
     this.Width = uc.Width; //設(shè)置窗體寬度
     this.Height = uc.Height + 35;
     grid.Children.Add(uc); //加入控件
    }
   }
   
   this.Title = title;
   dataContext = uc.DataContext;
   #endregion
   this.ShowDialog();return result;
  }

  private void okBtn_Click(object sender, RoutedEventArgs e)
  {
   result = CustomDialogResult.OK;
   this.Close();
  }

  private void canleBtn_Click(object sender, RoutedEventArgs e)
  {
   result = CustomDialogResult.Cancel;
   this.Close();
  }
 }

 public enum CustomDialogResult 
 {
  None,OK,Cancel
 }

 public enum MsgBoxBtn 
 {
  None,Ok,OkCancel
 }

剖析 ShowDialog(string title, MsgBoxBtn btnState, Control uc, out object dataContext) 方法

在Control uc 代表我們要ShowDialog的UC,dataContext 可以輸出一些數(shù)據(jù),另外我們要自定義一些枚舉

public static CustomDialogResult MessageBoxDialog(string title, string message, MsgBoxBtn okCancle)  主要用來(lái)顯示自定義MessageBoxUserControl;和上面得方法差不多,

以上分為三大步驟對(duì)WPF 項(xiàng)目框架搭建的介紹,并結(jié)合代碼做剖析,希望對(duì)大家有所幫助。

相關(guān)文章

  • Unity制作游戲自定義按鍵詳解

    Unity制作游戲自定義按鍵詳解

    這篇文章主要介紹了在Unity中如何實(shí)現(xiàn)游戲自定義按鍵,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Unity有一定幫助,感興趣的可以跟隨小編學(xué)習(xí)一下
    2022-01-01
  • c# n個(gè)數(shù)排序?qū)崿F(xiàn)代碼

    c# n個(gè)數(shù)排序?qū)崿F(xiàn)代碼

    c# n個(gè)數(shù)排序?qū)崿F(xiàn)代
    2009-07-07
  • c#實(shí)現(xiàn)輸出本月的月歷

    c#實(shí)現(xiàn)輸出本月的月歷

    本篇文章是對(duì)使用c#輸出本月月歷的實(shí)現(xiàn)的代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • C#實(shí)現(xiàn)的上傳圖片、保存圖片、加水印、生成縮略圖功能示例

    C#實(shí)現(xiàn)的上傳圖片、保存圖片、加水印、生成縮略圖功能示例

    這篇文章主要介紹了C#實(shí)現(xiàn)的上傳圖片、保存圖片、加水印、生成縮略圖功能,結(jié)合實(shí)例形式較為詳細(xì)的分析了C#圖片上傳、保存、水印、縮略圖等相關(guān)操作技巧,需要的朋友可以參考下
    2019-02-02
  • C#使用ZXing.Net實(shí)現(xiàn)生成二維碼和條碼

    C#使用ZXing.Net實(shí)現(xiàn)生成二維碼和條碼

    ZXing用Java實(shí)現(xiàn)的多種格式的一維二維條碼圖像處理庫(kù),而ZXing.Net是其.Net版本的實(shí)現(xiàn),下面我們就來(lái)看看 C#如何使用ZXing.Net實(shí)現(xiàn)生成二維碼和條碼吧
    2023-12-12
  • C#與java TCP通道加密通信實(shí)例

    C#與java TCP通道加密通信實(shí)例

    這篇文章主要介紹了C#與java TCP通道加密通信,文章通過(guò)真實(shí)的案例詳細(xì)講解說(shuō)明C#與java TCP通道加密通信的相關(guān)資料,需要的小伙伴可以參考一下
    2021-10-10
  • 一文詳解C#中方法重載的底層玩法

    一文詳解C#中方法重載的底層玩法

    最近在看C++的方法重載,就在想C#中的重載底層是怎么玩的。畢竟很多朋友應(yīng)該知道C是不支持重載的。本文將來(lái)詳細(xì)講講C#中方法重載的底層玩法,感興趣的可以了解一下<BR>
    2022-06-06
  • C#實(shí)現(xiàn)給PDF文檔設(shè)置過(guò)期時(shí)間

    C#實(shí)現(xiàn)給PDF文檔設(shè)置過(guò)期時(shí)間

    我們可以給一些重要文檔或者臨時(shí)文件設(shè)置過(guò)期時(shí)間和過(guò)期信息提示來(lái)提醒讀者或管理者文檔的時(shí)效性,并及時(shí)對(duì)文檔進(jìn)行調(diào)整、更新等。下面本文將介紹如何通過(guò)C#來(lái)給PDF文檔設(shè)置過(guò)期時(shí)間的方法。需要的可以參考一下
    2022-01-01
  • Unity實(shí)現(xiàn)背景圖片淡入淡出效果

    Unity實(shí)現(xiàn)背景圖片淡入淡出效果

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)背景圖片淡入淡出,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • C#中使用IrisSkin2.dll美化WinForm程序界面的方法

    C#中使用IrisSkin2.dll美化WinForm程序界面的方法

    這篇文章主要介紹了c#中使用IrisSkin2.dll美化WinForm程序界面的實(shí)現(xiàn)方法,需要的朋友可以參考下
    2013-05-05

最新評(píng)論