我有一個問題,因為我不知道如何將服務注入頁面。這就是我的 App.xaml.cs 的樣子
public partial class App : Application
{
public IServiceProvider ServiceProvider { get; set; }
public IConfiguration Configuration { get; set; }
protected override void OnStartup(StartupEventArgs e)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", false, true);
Configuration = builder.Build();
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
ServiceProvider = serviceCollection.BuildServiceProvider();
var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
mainWindow.Show();
}
private void ConfigureServices(ServiceCollection serviceCollection)
{
serviceCollection.AddTransient<IPage1ViewModel, Page1ViewModel>();
serviceCollection.AddTransient(typeof(MainWindow));
}
}
我有帶框架的 MainWindow,在框架中我有名為 Home.xml 的默認頁面和按鈕。
<Window x:Class="WpfDITest.MainWindow"
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:WpfDITest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Menu Grid.Row="0" Grid.Column="0">
<MenuItem Header = "Help" HorizontalAlignment="Center" VerticalAlignment="Center">
<MenuItem Name="about" Header = "about t" HorizontalAlignment = "Stretch"/>
</MenuItem>
</Menu>
<Frame Grid.Row="1" Grid.Column="0" Source="/Views/Home.xaml" NavigationUIVisibility="Hidden" />
</Grid>
當您單擊按鈕時,它會將您導航到名為 Page1 的新頁面。
public partial class Home : Page
{
public Home()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var uri = "/Views/Page1.xaml";
NavigationService.Navigate(new Uri(uri, UriKind.Relative));
}
}
我想將 IPage1ViewModel 注入到我的 Page1 所以我想我會像在 asp.net 應用程式中那樣向建構式注入服務,但問題是導航服務會在沒有引數的情況下觸發建構式,所以現在我不知道如何實作這一點。
public partial class Page1 : Page
{
private readonly IPage1ViewModel _page1ViewModel;
public Page1(IPage1ViewModel page1ViewModel)
{
_page1ViewModel = page1ViewModel;
InitializeComponent();
}
public Page1() //this constructor fires
{
InitializeComponent();
GetData();
}
public void GetData()
{
_page1ViewModel.GetTitle(); // How to get this?
}
}
Page1ViewModel
public class Page1ViewModel : IPage1ViewModel
{
public Page1ViewModel()
{
}
public string GetTitle()
{
return "Welcome";
}
}
在我的情況下使用依賴注入是個好主意嗎?如果是這樣,我該如何解決我的問題?
uj5u.com熱心網友回復:
您必須Page使用工廠(抽象工廠模式或工廠委托)顯式實體化。
當您通過 XAML 實體化控制元件時,無論是通過定義元素還是通過 URI,XAML 引擎將始終使用默認建構式創建實體(因此對于 XAML 實體化來說這是必需的)。
如果您的控制元件必須使用依賴注入,則必須顯式實體化它們,以便可以呼叫適當的建構式,通常在工廠的幫助下。
- 使
Home請求Page1工廠委托(aFunc<Page1>)作為建構式依賴項。然后使用它顯式創建Page1實體:
public partial class Home : Page
{
private Func<Page1> Page1Factory { get; }
public Home(Func<Page1> page1Factory)
{
InitializeComponent();
this.Page1Factory = page1Factory;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Page1 nextPage = this.Page1Factory.Invoke();
NavigationService.Navigate(nextPage);
}
}
- 注冊
Page1型別(具有適當的生命周期)及其工廠委托(或抽象工廠型別)
private void ConfigureServices(ServiceCollection serviceCollection)
{
serviceCollection.AddTransient<IPage1ViewModel, Page1ViewModel>();
serviceCollection.AddTransient(typeof(MainWindow));
serviceCollection.AddTransient<Page1>();
serviceCollection.AddSingleton<Func<Page1>>(serviceProvider => serviceProvider.GetService<Page1>);
}
- 通常,您會將 的 UI 元素系結
Page1到其DataContext. 因此,您必須將注入的視圖模型設定為DataContext. 此外,您應該洗掉默認建構式(或至少 make itprivate),因為它不會正確初始化型別(即DataContext缺少視圖模型)。此外,public裸Get...方法預計會回傳結果。要么重命名方法,要么讓它回傳結果,或者至少private也讓它回傳。
public partial class Page1 : Page
{
private IPage1ViewModel Page1ViewModel { get; }
// This constructor also calls the private default constructor
// (in case this type has multiple constructor overloads.
// Otherwise, move the private default constructor code to this constructor).
public Page1(IPage1ViewModel page1ViewModel) : this()
{
this.Page1ViewModel = page1ViewModel;
this.DataContext = this.Page1ViewModel;
}
private Page1()
{
InitializeComponent();
Initialize();
}
private void Initialize()
{
this.Page1ViewModel.GetTitle();
}
}
- 因為建議使用資料系結(資料系結概述 (WPF .NET)),所以您的視圖模型類必須實作
INotifyPropertyChanged(有關示例,請參閱 Microsoft 檔案
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/494724.html
上一篇:從現有的堆疊面板創建新的堆疊面板
