WPF——Prism介紹

KingKong90發表於2024-06-27

一.Prism介紹

二.程式啟動

1.方式1 8.0版本之前的方案

首先建立,Views和ViewModels資料夾,然後分別建立一個ViewModel類,以及一個View介面。
public class InfoViewModel
    {
        public InfoViewModel()
        {
            myVar = 333;
        }
        private int myVar;

        public int MyProperty
        {
            get { return myVar; }
            set { myVar = value; }
        }
    }
    
    public partial class InfoView : Window
    {
        public InfoView()
        {
            InitializeComponent();
            this.DataContext = new InfoViewModel();
        }
    }
       <TextBlock Text="{Binding MyProperty}" FontSize="25"></TextBlock>

然後,編寫一個BootStraper類,繼承自Prism.Unity下面的PrismBootstrapper類。複寫對應的方法。
 public class BootStraper : PrismBootstrapper
    {       
        protected override DependencyObject CreateShell()
        {
            return Container.Resolve<InfoView>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {            
        }
    }

最後,在App.xaml.cs中,複寫onstartup方法。
public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            var bs = new BootStraper();
            bs.Run();
        }
    }

啟動程式就可以實現資料的繫結。

方式二,8.0版本提供的方式

需要修改App.xaml和App.xaml.cs裡面的程式碼。

 public partial class App : PrismApplication
    {
        //protected override void OnStartup(StartupEventArgs e)
        //{
        //    base.OnStartup(e);
        //    var bs = new BootStraper();
        //    bs.Run();
        //}
        protected override Window CreateShell()
        {
            return Container.Resolve<InfoView>();
        }
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            
        }
    }

app.xaml.cs中的程式碼,需要繼承自PrismApplication,複寫其中的兩個方法。
在app.xaml中也需要更改。
<prism:PrismApplication  xmlns:prism="http://prismlibrary.com/" x:Class="Prism_01.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Prism_01"
             >
    <Application.Resources>
         
    </Application.Resources>
</prism:PrismApplication>

自動注入資料,可以直接將datacontext資料刪除掉。這種是根據命名規則來進行自動注入的。*View與*ViewModel進行自動匹配,自動繫結。條件是資料夾名稱為Views和ViewModels。

三.資料繫結

1.自定義對應規則

也可以自定資料夾和檔案的命名規則,實現自動注入資料。在App.xaml.cs下面建立對應關係。,輸入的是view的型別,返回的是viewmodel的型別。
protected override void ConfigureViewModelLocator()
        {
            base.ConfigureViewModelLocator();
            //設定統一的對應規則
            ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType)=> {
                //將view檔名替換為viewmodel檔名
               var modelName= viewType.FullName.Replace("ANDONGLU.", "").Replace("View","ViewModel").Replace("AN","");
                //將view的dll名替換為viewmodel的dll名稱。
                var moduleName = viewType.Assembly.FullName;
                var t = $"{modelName },{moduleName}";
                return Type.GetType(t);
            });
        }

2.也可以建立一對一的對應關係

 //一對一註冊,string->type
            ViewModelLocationProvider.Register(typeof(ANInfoView).ToString(), typeof(InfoViewModel));
            //type->type
            ViewModelLocationProvider.Register<ANInfoView, InfoViewModel>();
            //string=>func
            ViewModelLocationProvider.Register(typeof(ANInfoView).ToString(), () =>
            {
                return Container.Resolve<InfoViewModel>();
            });

3.在datacontext中引入物件

<Window.DataContext>
        <prism:ContainerProvider Type="{x:Type vm:InfoViewModel}"></prism:ContainerProvider>
    </Window.DataContext>

四.資料雙向繫結

 public class InfoViewModel:BindableBase
    {
        public InfoViewModel()
        {
            myVar = 333;
        }
        private int myVar;

        public int MyProperty
        {
            get { return myVar; }
            set {
                myVar = value;
                //this.RaisePropertyChanged();
                //設定屬性值
                //this.SetProperty<int>(ref myVar,value);
                //設定屬性值的同時,提供回撥函式,當值變化值可以呼叫
                //this.SetProperty<int>(ref myVar,value,()=> { 
                //});
            }
        }
    }

ViewModel類需要繼承自BindableBase型別,然後需要在屬性的set裡面設定值變化的通知。
Prism提供了多種通知方式。

五.資料驗證

資料的驗證可以在特性裡面進行驗證。在Prism.Unity裡面是透過屬性之中編寫驗證規則進行驗證。驗證結果需要放置到ErrorContainer裡面。透過繼承INotifyDataErrorInfo,處理Error資訊。所有的驗證程式碼都是在ViewModel裡面實現的。
public class InfoViewModel:BindableBase, INotifyDataErrorInfo
    {

        public InfoViewModel()
        {
            myVar = 333;
        }
        private int myVar;

        public int MyProperty
        {
            get { return myVar; }
            set {
                //myVar = value;
                //this.RaisePropertyChanged();
                //this.SetProperty<int>(ref myVar,value);
                this.SetProperty<int>(ref myVar, value, () =>
                {
                });
                if (value == 1231 || value == 12322)
                {
                    ErrorContainer.SetErrors("MyProperty", new string[] { "輸入值有誤!" });
                }
                else
                {
                    ErrorContainer.ClearErrors("MyProperty");
                }
            }
        }

        private ErrorsContainer<string> errorContainer;

        public ErrorsContainer<string> ErrorContainer
        {
            get {
                if (errorContainer == null)
                {
                    errorContainer = new ErrorsContainer<string>(propName=> {
                        ErrorsChanged?.Invoke(this,new DataErrorsChangedEventArgs(propName));
                    });
                }                               
                return errorContainer; }
            set {               
                errorContainer = value; }
        }

        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
        public bool HasErrors => ErrorContainer==null?false:ErrorContainer.HasErrors;

        public IEnumerable GetErrors(string propertyName) =>ErrorContainer==null?null:ErrorContainer.GetErrors(propertyName);
        
    }

介面程式,需要在介面上新增一個Error提示,需要建立一個模板樣式。
<Window x:Class="Prism_01.ANDONGLU.Views.ANInfoView"
        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:Prism_01.ANDONGLU.Views"
        xmlns:vm="clr-namespace:Prism_01.ViewModels"
        xmlns:prism="http://prismlibrary.com/"
        mc:Ignorable="d"        
        Title="AN" Height="450" Width="800">
    <Window.DataContext>
        <prism:ContainerProvider Type="{x:Type vm:InfoViewModel}"></prism:ContainerProvider>
    </Window.DataContext>
    <Window.Resources>
        <ControlTemplate TargetType="{x:Type TextBox}" x:Key="ct">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="auto"/>
                    <RowDefinition Height="auto"/>
                </Grid.RowDefinitions>
                <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" 
                        BorderThickness="{TemplateBinding BorderThickness}" 
                Background="{TemplateBinding Background}" SnapsToDevicePixels="True"
                CornerRadius="5">
                    <ScrollViewer x:Name="PART_ContentHost" Focusable="false"
                                  HorizontalScrollBarVisibility="Hidden" 
                                  VerticalScrollBarVisibility="Hidden"
                          VerticalContentAlignment="Center" Margin="3,5" BorderThickness="0"/>
                </Border>
                <TextBlock Grid.Row="1" Text="{Binding (Validation.Errors)[0].ErrorContent,RelativeSource={RelativeSource AncestorType=TextBox,Mode=FindAncestor}}" 
                   Foreground="Red" Margin="10,5"
                   Name="txtError"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="Visibility" Value="Visible" TargetName="txtError"/>
                    <Setter Property="ToolTip" 
                    Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Window.Resources>
    <Grid>
        <StackPanel>
        <TextBlock Text="{Binding MyProperty}" FontSize="30"></TextBlock>
        <TextBox Text="{Binding MyProperty,UpdateSourceTrigger=PropertyChanged}" FontSize="30" Template="{StaticResource ct}"></TextBox>
        </StackPanel>
    </Grid>
</Window>

相關文章