<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      .NET6: 開發基于WPF的摩登三維工業軟件 (8) - MVVM

      基于WPF開發界面的一個很大優勢是可以方便地基于MVVM設計模式開發應用。本文從應用的角度基于MVVM實現參數化管材的創建界面。

      1 MVVM

      MVVM是Model-View-ViewModel的簡寫,即模型-視圖-視圖模型。網上有若干對MVVM的介紹,本文在此不做過多的贅述,本文將從具體的是應用案例讓大家來體會MVVM的優勢,即實現UI部分的代碼與核心業務邏輯、數據模型分離,達到高耦合低內聚的軟件架構目標。

      來自網上的截圖

      2 界面設計

      我們希望打開一個對話框,在其中可以顯示管材模型;修改管材的參數能夠實時看到管材形狀的變化。如下圖所示:

      其中管子的外徑由管子的內徑加上管子壁厚,不需要用戶輸入。
      當然也可以實現用戶修改外徑,減掉管壁來得到內徑。這個可以根據業務需要來調整。

      3 程序設計

      基于MVVM設計模式,我們實現這樣的類設計:

      其中:

      • AddSectionBarDlg

      基于XAML實現的UI布局相關代碼,即View層;

      • SectionBarVM

      實現ViewModel層,即View和Model的橋梁,業務邏輯檢查,比如半徑不能小于0,壁厚不能小于0等。

      • ShapeElement

      基于AnyCAD的數據存儲類ShapeElement實現Model層。

      4 程序實現

      我們采用自底向上的實現順序,逐步實現Model、ViewModel和View。

      4.1 Model實現

      由于是基于AnyCAD內置的組件,可以直接略過。

      ShapeElement 可以用來保存TopoShape對象外,可以保存用戶自定義的參數。比如管材的長度、內徑、厚度等。重點關注以下方法:

      //設置參數
      void SetParameter (String name, ParameterValue val);
      //查找參數
      ParameterValue 	FindParameter (String name);
      

      4.2 ViewModel實現

      4.2.1 更新界面的能力

      SectionBarVM從INotifyPropertyChanged繼承,獲得PropertyChanged的能力,即通知View層說:
      “嗨,兄弟,該更新界面啦!"

      //SectionBarVM.cs
          public class SectionBarVM : INotifyPropertyChanged
          {
              public event PropertyChangedEventHandler? PropertyChanged;
              public void OnPropertyChanged(string e)
              {
                  if (PropertyChanged != null)
                      PropertyChanged(this, new PropertyChangedEventArgs(e));
              }
              ...
          }
      

      4.2.2 更新數據能力

      基于屬性機制實現。當外部更新,會調用屬性set方法的時候,對數據進行合法檢查。
      若符合要求,更新Model,并調用OnPropertyChanged發起通知。

      //SectionBarVM.cs
              private ShapeElement mModel;
      
              public SectionBarVM(ShapeElement model)
              {
                  mModel = model;
              }
      
              public static string NAME = "Name";
              public string Name {
                  get { return mModel.GetName(); }
                  set { 
                      if(value != "")
                      {
                          mModel.SetName(value); 
                          OnPropertyChanged(NAME);
                      }
                      else
                      {
                          throw new ArgumentException("名稱不能為空。");
                      }
                  }
              }
      

      尺寸參數屬性實現:

      //SectionBarVM.cs
              public static string INNER_RADIUS = "InnerRadius";
              public static string THICKNESS = "Thickness";
              public static string LENGTH = "Length";
              public static string OUTTER_RADIUS = "OutterRadius";
      
               public double InnerRadius { 
                  get { return ParameterCast.Cast(mModel.FindParameter(INNER_RADIUS), 100.0); }
                  set {
                      if (value > 0)
                      {
                          mModel.SetParameter(INNER_RADIUS, ParameterCreator.Create(value));
                          OnPropertyChanged(INNER_RADIUS);
                          OnPropertyChanged(OUTTER_RADIUS);
                      }
                      else
                      {
                          throw new ArgumentException("半徑太小。");
                      }
                  } 
              }
              public double Thickness { 
                  get { return ParameterCast.Cast(mModel.FindParameter(THICKNESS), 5.0);  }
                  set { 
                      if (value > 0)
                      {
                          mModel.SetParameter(THICKNESS, ParameterCreator.Create(value));
                          OnPropertyChanged(THICKNESS);
                          OnPropertyChanged(OUTTER_RADIUS);
                      }
                      else
                      {
                          throw new ArgumentException("厚度太小。");
                      }
                  } 
              }
      
              public double OutterRadius
              {
                  get { return InnerRadius + Thickness; }
              }
              public double Length { 
                  get { return ParameterCast.Cast(mModel.FindParameter(LENGTH), 1000.0);  }
                  set { 
                      if (value > 0)
                      {
                          mModel.SetParameter(LENGTH, ParameterCreator.Create(value));
                          OnPropertyChanged(LENGTH);
                      }
                      else
                      {
                          throw new ArgumentException("長度太小。");
                      }
                  } 
              }
      

      這里需要注意的是OutterRadius的實現。由于OutterRadius依賴了InnerRadius和Thickness屬性,當被依賴的屬性修改后,也需要觸發依賴屬性的消息。否則界面OutterRadius的值不會再更新。

      4.3 View實現

      4.3.1 界面布局

      增加一個窗口AddSectionBarDlg.xaml,按照設計要求進行布局。

      • 數據雙向綁定

      Path="InnerRadius"將會跟SectionBarVM的InnerRadius綁定。當UI修改的時候會調用InnerRadius set; 當界面初始化和數據更新的時候,UI會調用InnerRadius get。

          <TextBox Width="150">
              <Binding Path="InnerRadius">
                  <Binding.ValidationRules>
                      <ExceptionValidationRule/>
                  </Binding.ValidationRules>
              </Binding>
          </TextBox>
      
      • 數據單向綁定

      Mode="OneWay" 表示UI只會從ViewModel獲取數據。

          <TextBox Width="150" IsEnabled="False">
              <Binding Path="OutterRadius" Mode="OneWay">
              </Binding>
          </TextBox>
      

      XAML完整代碼:

      //AddSectionBarDlg.xaml
      <Window x:Class="Rapid.Sketch.Plugin.UI.AddSectionBarDlg"
              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:Rapid.Sketch.Plugin.UI"
              xmlns:anycad="clr-namespace:AnyCAD.WPF;assembly=AnyCAD.WPF.NET6"
              mc:Ignorable="d"
              Title="創建型材" Height="450" Width="650" ResizeMode="NoResize" Icon="/Rapid.Common.Res;component/Image/SectionBar.png">
          <Grid Margin="7">
              <Grid.ColumnDefinitions>
                  <ColumnDefinition Width="400"></ColumnDefinition>
                  <ColumnDefinition Width="Auto"></ColumnDefinition>
              </Grid.ColumnDefinitions>
              
              <anycad:RenderControl Name="mView3d"  Grid.Column="0" ViewerReady="MView3d_ViewerReady"/>
      
              <Grid Grid.Column="1" Margin="7">
                  <Grid.RowDefinitions>
                      <RowDefinition Height="360"></RowDefinition>
                      <RowDefinition Height="28"></RowDefinition>
                  </Grid.RowDefinitions>
             
                  <StackPanel Grid.Row="0">
                      <StackPanel Orientation="Horizontal">
                          <Label Width="60" Content="名稱:"></Label>
                          <TextBox Width="150">
                              <Binding Path="Name">
                              </Binding>
                          </TextBox>
                      </StackPanel>
                      <StackPanel Orientation="Horizontal" Margin="0,7,0,0">
                          <Label Width="60" Content="內徑:"></Label>
                          <TextBox Width="150">
                              <Binding Path="InnerRadius">
                                  <Binding.ValidationRules>
                                      <ExceptionValidationRule/>
                                  </Binding.ValidationRules>
                              </Binding>
                          </TextBox>
                      </StackPanel>
                      <StackPanel Orientation="Horizontal" Margin="0,7,0,0">
                          <Label Width="60" Content="厚度:"></Label>
                          <TextBox Width="150">
                              <Binding Path="Thickness">
                                  <Binding.ValidationRules>
                                      <ExceptionValidationRule/>
                                  </Binding.ValidationRules>
                              </Binding>
                          </TextBox>
                      </StackPanel>
                      <StackPanel Orientation="Horizontal" Margin="0,7,0,0">
                          <Label Width="60" Content="外徑:"></Label>
                          <TextBox Width="150" IsEnabled="False">
                              <Binding Path="OutterRadius" Mode="OneWay">
                              </Binding>
                          </TextBox>
                      </StackPanel>                
                      <StackPanel Orientation="Horizontal" Margin="0,7,0,0">
                          <Label Width="60" Content="長度:"></Label>
                          <TextBox Width="150">
                              <Binding Path="Length">
                                  <Binding.ValidationRules>
                                      <ExceptionValidationRule/>
                                  </Binding.ValidationRules>
                              </Binding>
                          </TextBox>
                      </StackPanel>
                  </StackPanel>
                  <StackPanel Orientation="Horizontal" Grid.Row="1" HorizontalAlignment="Right" Margin="0,0,0,7">
                      <Button Content="取消" Width="60" Margin="7,0,7,0"></Button>
                      <Button Content="確定" Width="60" Margin="7,0,7,0"></Button>
                  </StackPanel>
              </Grid>
          </Grid>
      </Window>
      
      

      4.3.2 View與ViewModel綁定

      把ViewModel對象設置給Window的DataContext屬性,即可實現UI與ViewModel的關聯。

      另外我們希望更改數據后也能更新三維窗口,在這里我們先用比較笨的辦法實現,即硬編碼實現參數與三維模型的聯動。詳見SbVM_PropertyChanged方法的實現。

          /// <summary>
          /// AddSectionBarDlg.xaml 的交互邏輯
          /// </summary>
          public partial class AddSectionBarDlg : Window
          {
              SectionBarVM m_Bar;
              public AddSectionBarDlg(SectionBarVM sbVM)
              {
                  InitializeComponent();
                  this.Owner = App.Current.MainWindow;
                  this.DataContext = sbVM;
      
                  sbVM.PropertyChanged += SbVM_PropertyChanged;
      
                  m_Bar = sbVM;
              }
      
              private void SbVM_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
              {
                 if(e.PropertyName == SectionBarVM.THICKNESS ||
                      e.PropertyName == SectionBarVM.INNER_RADIUS ||
                      e.PropertyName == SectionBarVM.LENGTH)
                  {
                      mView3d.View3D.ClearAll();
      
                      var shape = m_Bar.CreateShape();
                      mView3d.ShowShape(shape, ColorTable.LightGrey);
      
                      mView3d.View3D.ZoomAll(1.6f);
                  }
              }
      
              private void MView3d_ViewerReady()
              {
                  mView3d.View3D.SetBackgroundColor(30.0f / 255, 30.0f / 255, 30.0f / 255, 0);
      
                  var shape = m_Bar.CreateShape();
                  mView3d.ShowShape(shape, ColorTable.LightGrey);
                  mView3d.View3D.ZoomAll(1.6f);
              }
          }
      

      5 功能集成

      暫時在草圖項目中增加一個按鈕,可以調用對話框:

          <Fluent:RibbonGroupBox Header="型材" IsLauncherVisible="False" Margin="7,0,0,0">
              <Fluent:Button Header="管材" Icon="/Rapid.Common.Res;component/Image/SectionBar.png" Size="Large" Command="{x:Static local:SketchRibbonTab.ExecuteCommand}"
                                         CommandParameter="pipeTube" Margin="0,0,7,0"/>
          </Fluent:RibbonGroupBox>
      
      
          case "pipeTube":
              {
                  //臨時創建一個對象
                  var se = new ShapeElement();
                  se.SetName("管子");
                  var dlg = new AddSectionBarDlg(new SectionBarVM(se));
                  dlg.ShowDialog();
              }
      

      運行效果:

      6 總結

      從實現代碼的結構來看,使用MVVM設計模式確實可以讓代碼層次更清楚,界面類不再臃腫不堪。Microsoft設計XAML之初的一個目標是希望做UI布局的UX與寫代碼邏輯的開發能夠分工協作,甚至為此開發了獨立的設計工具Blend給UX使用,以讓開發能夠直接重用UX實現的XAML……
      雖然現實并沒有想象的那么美好,但基于MVVM模式確實可以實現界面布局和核心業務邏輯分離,甚至把不同層的功能分給不同水平的程序員來實現。

      posted @ 2022-03-13 22:30  AnyCAD  閱讀(3638)  評論(3)    收藏  舉報
      主站蜘蛛池模板: av在线播放国产一区| 中文字幕久久国产精品| 日韩卡一卡2卡3卡4卡| 久久精品一区二区三区综合| 亚洲国产精品18久久久久久| 永济市| 噜妇插内射精品| 亚洲av无一区二区三区| 免费av网站| 国内精品自线在拍| 国产精品区一二三四久久| 亚洲国产综合一区二区精品| 国产97视频人人做人人爱| 亚洲天堂男人的天堂在线| 亚洲欧美中文字幕5发布| 亚洲2022国产成人精品无码区| 中文成人无字幕乱码精品区| 天堂av资源在线免费| 人妻中文字幕亚洲一区| 亚洲欧美日韩高清一区二区三区| 澳门永久av免费网站| 中文文字幕文字幕亚洲色| 男女xx00上下抽搐动态图| 中文在线最新版天堂| 亚洲香蕉伊综合在人在线| 亚洲精品三区二区一区一| 精品一区二区三区女性色| 日本熟妇hdsex视频| 精品人妻一区二区三区四区在线| 亚洲一本大道在线| 亚洲国产美女精品久久久| 无码专区 人妻系列 在线| 国产一区二区三区色噜噜| 色爱综合激情五月激情| 五峰| 亚洲中文字字幕精品乱码| 亚洲av片在线免费观看| 自拍偷拍视频一区二区三区| 综合色一色综合久久网| 日韩精品国产另类专区| 国产精品天干天干综合网|