如何在 属性 模型更改时更新 ShellView 中的 TextBlock
How to update a TextBlock in ShellView when property changes in Model
我在使用 LoggedInUserProfile 的 FirstName 属性 更新 ShellView TextBlock 时遇到问题,LoggedInUserProfile 在用户登录后创建为单例。
我有一个 UserProfileView,它可以绑定和更新,但 ShellView(包含 UserProfileView)没有。如果我放置断点,我可以看到 LoggedInUserProfile 有正确的数据。
这是我的第一个 WPF 应用程序,我花了一个星期 运行 自己在圈子里,试图找出我做错了什么,但知道有用,因此我正在寻求指导。
我不知道,但我怀疑我没有正确处理事件、未正确绑定或对 DI 做错了什么。
下面我提供了我认为是主要组件的代码。
我想要发生的是登录用户的名字在用户登录后以及在 UserProfileView 中显示在 ShellView 的 TextBlock 中。
如果您能提供任何帮助,为我指明正确的方向,我们将不胜感激。我已经包括了我认为是下面的主要组成部分。
ShellViewModel
using Caliburn.Micro;
using CRMDesktopUI.EventModels;
using CRMDesktopUI.Library.Models;
using System.Threading;
using System.Threading.Tasks;
namespace CRMDesktopUI.ViewModels
{
public class ShellViewModel:Conductor<object>, IHandle<LogOnEvent>
{
private IEventAggregator _events;
private SimpleContainer _container;
private LoginViewModel _loginVM;
private UserProfileViewModel _userProfileVM;
private ILoggedInUserModel _loggedInUserModel;
public ShellViewModel(LoginViewModel loginVM, IEventAggregator events,ILoggedInUserModel loggedInUserModel, UserProfileViewModel userProfileVM,SimpleContainer container)
{
_events = events;
_loginVM = loginVM;
_userProfileVM = userProfileVM;
_container = container;
_loggedInUserModel = loggedInUserModel;
_events.SubscribeOnUIThread(this);
ActivateItemAsync(_loginVM);
}
Task IHandle<LogOnEvent>.HandleAsync(LogOnEvent message,CancellationToken cancellationToken)
{
_loginVM = _container.GetInstance<LoginViewModel>();
ActivateItemAsync(_userProfileVM);
return Task.CompletedTask;
}
public string FirstName
{
get //This gets called before log in screen activated
{
if(_loggedInUserModel == null)
{
return "Not logged in";
}
else
{
return _loggedInUserModel.FirstName;
}
}
set //Set never gets called
{
_loggedInUserModel.FirstName = value;
NotifyOfPropertyChange(() => FirstName);
}
}
}
}
ShellView.xaml
<Window x:Class="CRMDesktopUI.Views.ShellView"
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:CRMDesktopUI.Views"
xmlns:viewmodels="clr-namespace:CRMDesktopUI.ViewModels"
mc:Ignorable="d"
Width="1250" Height="600"
Background="#36393F"
ResizeMode="CanResizeWithGrip"
AllowsTransparency="True"
WindowStyle="None">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.ColumnSpan="2"
Background="#252525"
MouseDown="Border_MouseDown">
<Grid HorizontalAlignment="Stretch">
<Label Content="Test App"
Foreground="Gray"
FontWeight="SemiBold"
FontFamily="/Fonts/#Poppins"/>
<StackPanel HorizontalAlignment="Right"
Orientation="Horizontal">
<Button Width="20" Height="20"
Content=""
Background="Transparent"
BorderThickness="0"
Foreground="Gray"
FontWeight="Bold"
Margin=" 0 0 0 3"
Click="MinimiseButton_Click"/>
<Button Width="20" Height="20"
Content="□"
Background="Transparent"
BorderThickness="0"
Foreground="Gray"
FontWeight="Bold"
Click="MaximiseButton_Click"/>
<Button Width="20" Height="20"
Content="✕"
Background="Transparent"
BorderThickness="0"
Foreground="Gray"
FontWeight="Bold"
Click="CloseButton_Click"/>
</StackPanel>
</Grid>
</Border>
<Grid Background="#2F3136"
Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Label Content="Contacts"
VerticalAlignment="Center"
FontWeight="Medium"
Foreground="Gray"
Margin="8 0 0 0" />
<StackPanel Grid.Row="2"
Orientation="Horizontal"
Background="#292B2f">
<Border CornerRadius="25"
Width="30"
Height="30"
Background="#3bff6f"
Margin="18 0 10 0" />
<DockPanel VerticalAlignment="Center">
<TextBlock Text="First Name:"
Foreground="White"
FontWeight="Light"/>
<TextBlock Text="{Binding FirstName}" <== This does not update the textblock
TextAlignment="Right"
Foreground="White"
FontWeight="SemiBold"
Margin="5 0 10 0" />
</DockPanel>
</StackPanel>
</Grid>
<Grid Grid.Column="1" Grid.Row="1">
<ContentControl x:Name="ActiveItem"
Margin="20" />
</Grid>
</Grid>
</Window>
LoggedInUserModel
namespace CRMDesktopUI.Library.Models
{
public class LoggedInUserModel:ILoggedInUserModel
{
public string Token { get; set; }
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
}
}
LoginViewModel
using Caliburn.Micro;
using CRMDesktopUI.EventModels;
using CRMDesktopUI.Library.Api;
using System;
using System.Threading.Tasks;
namespace CRMDesktopUI.ViewModels
{
public class LoginViewModel:Screen
{
private string _username;
private string _password;
private IAPIHelper _apiHelper;
private string _errormessage;
private IEventAggregator _events;
public LoginViewModel(IAPIHelper apiHelper,IEventAggregator events)
{
_apiHelper = apiHelper;
_events = events;
}
public string ErrorMessage {
get {
return _errormessage;
}
set {
_errormessage = value;
NotifyOfPropertyChange(() => IsErrorVisible);
NotifyOfPropertyChange(() => ErrorMessage);
}
}
public string UserName {
get {
return _username;
}
set {
_username = value;
NotifyOfPropertyChange(() => UserName);
NotifyOfPropertyChange(() => CanLogIn);
}
}
public string Password {
get {
return _password;
}
set {
_password = value;
NotifyOfPropertyChange(() => Password);
NotifyOfPropertyChange(() => CanLogIn);
}
}
public bool CanLogIn {
get {
bool output = false;
if(UserName?.Length > 0 && Password?.Length > 0)
{
output = true;
}
return output;
}
}
public bool IsErrorVisible {
get {
bool output = false;
if(ErrorMessage?.Length > 0)
{
output = true;
}
return output;
}
}
public async Task LogIn()
{
try
{
ErrorMessage = "";
var result = await _apiHelper.Authenticate(UserName,Password);
//get more information about the logged in user
await _apiHelper.GetLogedInUserInfo(result.Access_Token);
await _events.PublishOnUIThreadAsync(new LogOnEvent());
}
catch(Exception ex)
{
ErrorMessage = ex.Message;
}
}
}
}
UserProfileViewModel
using Caliburn.Micro;
using CRMDesktopUI.Library.Models;
namespace CRMDesktopUI.ViewModels
{
public class UserProfileViewModel : Screen
{
ILoggedInUserModel _loggedInUserModel;
public UserProfileViewModel(ILoggedInUserModel loggedInUserModel)
{
_loggedInUserModel = loggedInUserModel;
}
public string FirstName
{
get //This gets called after user logs in
{
return _loggedInUserModel.FirstName;
}
set //This never gets called
{
_loggedInUserModel.FirstName = value;
NotifyOfPropertyChange(() => FirstName);
}
}
}
}
UserProfileView
<UserControl x:Class="CRMDesktopUI.Views.UserProfileView"
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:CRMDesktopUI.Views"
xmlns:viewmodels="clr-namespace:CRMDesktopUI.ViewModels"
d:DataContext="{d:DesignInstance Type=viewmodels:UserProfileViewModel}"
mc:Ignorable="d"
Width="800" Height="450">
<StackPanel>
<TextBlock Text="User Profile"
Foreground="White"
FontSize="28"
HorizontalAlignment="Left"
Margin="0 0 0 20"/>
<StackPanel Orientation="Horizontal">
<Border Width="800"
Height="200">
<Border.Background>
<LinearGradientBrush StartPoint="0,0"
EndPoint="1,2">
<GradientStop Color="#5bc3ff"
Offset="0.0"/>
<GradientStop Color="#3aa0ff"
Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Border.Clip>
<RectangleGeometry RadiusX="10"
RadiusY="10"
Rect="0 0 800 200"/>
</Border.Clip>
<Grid>
<StackPanel>
<TextBlock Text="{Binding FirstName}"
Foreground="White"
FontSize="28"
Margin="20 10 10 0"/>
</StackPanel>
<Image Width="150"
Height="180"
Source="/Images/822739_user_512x512.png"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Margin="0,0,-39,-31"
RenderTransformOrigin="0.804,0.953">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="0"/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
</Grid>
</Border>
</StackPanel>
</StackPanel>
</UserControl>
HelperClass
using CRMDesktopUI.Library.Models;
using CRMDesktopUI.Models;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace CRMDesktopUI.Library.Api
{
public class APIHelper:IAPIHelper
{
private HttpClient apiClient;
private ILoggedInUserModel _loggedInUser;
public APIHelper(ILoggedInUserModel loggedInUser)
{
InitialiseClient();
_loggedInUser = loggedInUser;
}
private void InitialiseClient()
{
string api = ConfigurationManager.AppSettings["api"];
apiClient = new HttpClient();
apiClient.BaseAddress = new Uri(api);
apiClient.DefaultRequestHeaders.Accept.Clear();
apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<AuthenticatedUser> Authenticate(string username,string password)
{
var data = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", username),
new KeyValuePair<string, string>("password", password)
});
using(var response = await apiClient.PostAsync("/Token",data))
{
if(response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<AuthenticatedUser>();
return result;
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
}
public async Task GetLogedInUserInfo(string token)
{
apiClient.DefaultRequestHeaders.Clear();
apiClient.DefaultRequestHeaders.Accept.Clear();
apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
apiClient.DefaultRequestHeaders.Add("Authorization",$"Bearer {token}");
using(var response = await apiClient.GetAsync("/Api/User"))
{
if(response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<LoggedInUserModel>();
_loggedInUser.Token = token.ToString();
_loggedInUser.Id = result.Id;
_loggedInUser.FirstName = result.FirstName;
_loggedInUser.LastName = result.LastName;
_loggedInUser.EmailAddress = result.EmailAddress;
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
}
}
}
引导程序
using Caliburn.Micro;
using CRMDesktopUI.Helpers;
using CRMDesktopUI.Library.Api;
using CRMDesktopUI.Library.Models;
using CRMDesktopUI.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace CRMDesktopUI
{
public class Bootstrapper:BootstrapperBase
{
private SimpleContainer _container = new SimpleContainer();
public Bootstrapper()
{
Initialize();
ConventionManager.AddElementConvention<PasswordBox>(
PasswordBoxHelper.BoundPasswordProperty,
"Password",
"PasswordChanged");
}
protected override void Configure()
{
_container.Instance(_container);
_container
.Singleton<IWindowManager,WindowManager>()
.Singleton<IEventAggregator,EventAggregator>()
.Singleton<ILoggedInUserModel,LoggedInUserModel>()
.Singleton<IAPIHelper, APIHelper>();
GetType().Assembly.GetTypes()
.Where(type => type.IsClass)
.Where(type => type.Name.EndsWith("ViewModel"))
.ToList()
.ForEach(viewModelType => _container.RegisterPerRequest(viewModelType,viewModelType.ToString(),viewModelType));
}
protected override void OnStartup(object sender,StartupEventArgs e)
{
DisplayRootViewFor<MainViewModel>();
}
protected override object GetInstance(Type service,string key)
{
return _container.GetInstance(service,key);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[] { Assembly.GetExecutingAssembly() };
}
}
}
成功登录后,您需要通知 FirstName 属性 已更改。
Task IHandle<LogOnEvent>.HandleAsync(LogOnEvent message,CancellationToken cancellationToken)
{
_loginVM = _container.GetInstance<LoginViewModel>(); // Not sure why you do this.
ActivateItemAsync(_userProfileVM);
// Since User has logged now, you need to notify change in FirstName
NotifyOfPropertyChange(nameof(FirstName));
return Task.CompletedTask;
}
这将确保 ShellView 知道 FirstName 属性 已更改。
或者您可以订阅 LoginViewModel 的 PropertyNotifyChanges 并过滤掉 FirstName 的更改,但是,由于您在登录成功后只需要名字,因此 LogOnEvent 可能更合适。
另请注意,您可以将 FirstName 属性 设置为只读,因为它很可能不会被视图编辑。
public string FirstName => _loggedInUserModel.FirstName;
我在使用 LoggedInUserProfile 的 FirstName 属性 更新 ShellView TextBlock 时遇到问题,LoggedInUserProfile 在用户登录后创建为单例。
我有一个 UserProfileView,它可以绑定和更新,但 ShellView(包含 UserProfileView)没有。如果我放置断点,我可以看到 LoggedInUserProfile 有正确的数据。
这是我的第一个 WPF 应用程序,我花了一个星期 运行 自己在圈子里,试图找出我做错了什么,但知道有用,因此我正在寻求指导。
我不知道,但我怀疑我没有正确处理事件、未正确绑定或对 DI 做错了什么。
下面我提供了我认为是主要组件的代码。
我想要发生的是登录用户的名字在用户登录后以及在 UserProfileView 中显示在 ShellView 的 TextBlock 中。
如果您能提供任何帮助,为我指明正确的方向,我们将不胜感激。我已经包括了我认为是下面的主要组成部分。
ShellViewModel
using Caliburn.Micro;
using CRMDesktopUI.EventModels;
using CRMDesktopUI.Library.Models;
using System.Threading;
using System.Threading.Tasks;
namespace CRMDesktopUI.ViewModels
{
public class ShellViewModel:Conductor<object>, IHandle<LogOnEvent>
{
private IEventAggregator _events;
private SimpleContainer _container;
private LoginViewModel _loginVM;
private UserProfileViewModel _userProfileVM;
private ILoggedInUserModel _loggedInUserModel;
public ShellViewModel(LoginViewModel loginVM, IEventAggregator events,ILoggedInUserModel loggedInUserModel, UserProfileViewModel userProfileVM,SimpleContainer container)
{
_events = events;
_loginVM = loginVM;
_userProfileVM = userProfileVM;
_container = container;
_loggedInUserModel = loggedInUserModel;
_events.SubscribeOnUIThread(this);
ActivateItemAsync(_loginVM);
}
Task IHandle<LogOnEvent>.HandleAsync(LogOnEvent message,CancellationToken cancellationToken)
{
_loginVM = _container.GetInstance<LoginViewModel>();
ActivateItemAsync(_userProfileVM);
return Task.CompletedTask;
}
public string FirstName
{
get //This gets called before log in screen activated
{
if(_loggedInUserModel == null)
{
return "Not logged in";
}
else
{
return _loggedInUserModel.FirstName;
}
}
set //Set never gets called
{
_loggedInUserModel.FirstName = value;
NotifyOfPropertyChange(() => FirstName);
}
}
}
}
ShellView.xaml
<Window x:Class="CRMDesktopUI.Views.ShellView"
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:CRMDesktopUI.Views"
xmlns:viewmodels="clr-namespace:CRMDesktopUI.ViewModels"
mc:Ignorable="d"
Width="1250" Height="600"
Background="#36393F"
ResizeMode="CanResizeWithGrip"
AllowsTransparency="True"
WindowStyle="None">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.ColumnSpan="2"
Background="#252525"
MouseDown="Border_MouseDown">
<Grid HorizontalAlignment="Stretch">
<Label Content="Test App"
Foreground="Gray"
FontWeight="SemiBold"
FontFamily="/Fonts/#Poppins"/>
<StackPanel HorizontalAlignment="Right"
Orientation="Horizontal">
<Button Width="20" Height="20"
Content=""
Background="Transparent"
BorderThickness="0"
Foreground="Gray"
FontWeight="Bold"
Margin=" 0 0 0 3"
Click="MinimiseButton_Click"/>
<Button Width="20" Height="20"
Content="□"
Background="Transparent"
BorderThickness="0"
Foreground="Gray"
FontWeight="Bold"
Click="MaximiseButton_Click"/>
<Button Width="20" Height="20"
Content="✕"
Background="Transparent"
BorderThickness="0"
Foreground="Gray"
FontWeight="Bold"
Click="CloseButton_Click"/>
</StackPanel>
</Grid>
</Border>
<Grid Background="#2F3136"
Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<Label Content="Contacts"
VerticalAlignment="Center"
FontWeight="Medium"
Foreground="Gray"
Margin="8 0 0 0" />
<StackPanel Grid.Row="2"
Orientation="Horizontal"
Background="#292B2f">
<Border CornerRadius="25"
Width="30"
Height="30"
Background="#3bff6f"
Margin="18 0 10 0" />
<DockPanel VerticalAlignment="Center">
<TextBlock Text="First Name:"
Foreground="White"
FontWeight="Light"/>
<TextBlock Text="{Binding FirstName}" <== This does not update the textblock
TextAlignment="Right"
Foreground="White"
FontWeight="SemiBold"
Margin="5 0 10 0" />
</DockPanel>
</StackPanel>
</Grid>
<Grid Grid.Column="1" Grid.Row="1">
<ContentControl x:Name="ActiveItem"
Margin="20" />
</Grid>
</Grid>
</Window>
LoggedInUserModel
namespace CRMDesktopUI.Library.Models
{
public class LoggedInUserModel:ILoggedInUserModel
{
public string Token { get; set; }
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
}
}
LoginViewModel
using Caliburn.Micro;
using CRMDesktopUI.EventModels;
using CRMDesktopUI.Library.Api;
using System;
using System.Threading.Tasks;
namespace CRMDesktopUI.ViewModels
{
public class LoginViewModel:Screen
{
private string _username;
private string _password;
private IAPIHelper _apiHelper;
private string _errormessage;
private IEventAggregator _events;
public LoginViewModel(IAPIHelper apiHelper,IEventAggregator events)
{
_apiHelper = apiHelper;
_events = events;
}
public string ErrorMessage {
get {
return _errormessage;
}
set {
_errormessage = value;
NotifyOfPropertyChange(() => IsErrorVisible);
NotifyOfPropertyChange(() => ErrorMessage);
}
}
public string UserName {
get {
return _username;
}
set {
_username = value;
NotifyOfPropertyChange(() => UserName);
NotifyOfPropertyChange(() => CanLogIn);
}
}
public string Password {
get {
return _password;
}
set {
_password = value;
NotifyOfPropertyChange(() => Password);
NotifyOfPropertyChange(() => CanLogIn);
}
}
public bool CanLogIn {
get {
bool output = false;
if(UserName?.Length > 0 && Password?.Length > 0)
{
output = true;
}
return output;
}
}
public bool IsErrorVisible {
get {
bool output = false;
if(ErrorMessage?.Length > 0)
{
output = true;
}
return output;
}
}
public async Task LogIn()
{
try
{
ErrorMessage = "";
var result = await _apiHelper.Authenticate(UserName,Password);
//get more information about the logged in user
await _apiHelper.GetLogedInUserInfo(result.Access_Token);
await _events.PublishOnUIThreadAsync(new LogOnEvent());
}
catch(Exception ex)
{
ErrorMessage = ex.Message;
}
}
}
}
UserProfileViewModel
using Caliburn.Micro;
using CRMDesktopUI.Library.Models;
namespace CRMDesktopUI.ViewModels
{
public class UserProfileViewModel : Screen
{
ILoggedInUserModel _loggedInUserModel;
public UserProfileViewModel(ILoggedInUserModel loggedInUserModel)
{
_loggedInUserModel = loggedInUserModel;
}
public string FirstName
{
get //This gets called after user logs in
{
return _loggedInUserModel.FirstName;
}
set //This never gets called
{
_loggedInUserModel.FirstName = value;
NotifyOfPropertyChange(() => FirstName);
}
}
}
}
UserProfileView
<UserControl x:Class="CRMDesktopUI.Views.UserProfileView"
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:CRMDesktopUI.Views"
xmlns:viewmodels="clr-namespace:CRMDesktopUI.ViewModels"
d:DataContext="{d:DesignInstance Type=viewmodels:UserProfileViewModel}"
mc:Ignorable="d"
Width="800" Height="450">
<StackPanel>
<TextBlock Text="User Profile"
Foreground="White"
FontSize="28"
HorizontalAlignment="Left"
Margin="0 0 0 20"/>
<StackPanel Orientation="Horizontal">
<Border Width="800"
Height="200">
<Border.Background>
<LinearGradientBrush StartPoint="0,0"
EndPoint="1,2">
<GradientStop Color="#5bc3ff"
Offset="0.0"/>
<GradientStop Color="#3aa0ff"
Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Border.Clip>
<RectangleGeometry RadiusX="10"
RadiusY="10"
Rect="0 0 800 200"/>
</Border.Clip>
<Grid>
<StackPanel>
<TextBlock Text="{Binding FirstName}"
Foreground="White"
FontSize="28"
Margin="20 10 10 0"/>
</StackPanel>
<Image Width="150"
Height="180"
Source="/Images/822739_user_512x512.png"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Margin="0,0,-39,-31"
RenderTransformOrigin="0.804,0.953">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="0"/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
</Grid>
</Border>
</StackPanel>
</StackPanel>
</UserControl>
HelperClass
using CRMDesktopUI.Library.Models;
using CRMDesktopUI.Models;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace CRMDesktopUI.Library.Api
{
public class APIHelper:IAPIHelper
{
private HttpClient apiClient;
private ILoggedInUserModel _loggedInUser;
public APIHelper(ILoggedInUserModel loggedInUser)
{
InitialiseClient();
_loggedInUser = loggedInUser;
}
private void InitialiseClient()
{
string api = ConfigurationManager.AppSettings["api"];
apiClient = new HttpClient();
apiClient.BaseAddress = new Uri(api);
apiClient.DefaultRequestHeaders.Accept.Clear();
apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<AuthenticatedUser> Authenticate(string username,string password)
{
var data = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", username),
new KeyValuePair<string, string>("password", password)
});
using(var response = await apiClient.PostAsync("/Token",data))
{
if(response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<AuthenticatedUser>();
return result;
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
}
public async Task GetLogedInUserInfo(string token)
{
apiClient.DefaultRequestHeaders.Clear();
apiClient.DefaultRequestHeaders.Accept.Clear();
apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
apiClient.DefaultRequestHeaders.Add("Authorization",$"Bearer {token}");
using(var response = await apiClient.GetAsync("/Api/User"))
{
if(response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<LoggedInUserModel>();
_loggedInUser.Token = token.ToString();
_loggedInUser.Id = result.Id;
_loggedInUser.FirstName = result.FirstName;
_loggedInUser.LastName = result.LastName;
_loggedInUser.EmailAddress = result.EmailAddress;
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
}
}
}
引导程序
using Caliburn.Micro;
using CRMDesktopUI.Helpers;
using CRMDesktopUI.Library.Api;
using CRMDesktopUI.Library.Models;
using CRMDesktopUI.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace CRMDesktopUI
{
public class Bootstrapper:BootstrapperBase
{
private SimpleContainer _container = new SimpleContainer();
public Bootstrapper()
{
Initialize();
ConventionManager.AddElementConvention<PasswordBox>(
PasswordBoxHelper.BoundPasswordProperty,
"Password",
"PasswordChanged");
}
protected override void Configure()
{
_container.Instance(_container);
_container
.Singleton<IWindowManager,WindowManager>()
.Singleton<IEventAggregator,EventAggregator>()
.Singleton<ILoggedInUserModel,LoggedInUserModel>()
.Singleton<IAPIHelper, APIHelper>();
GetType().Assembly.GetTypes()
.Where(type => type.IsClass)
.Where(type => type.Name.EndsWith("ViewModel"))
.ToList()
.ForEach(viewModelType => _container.RegisterPerRequest(viewModelType,viewModelType.ToString(),viewModelType));
}
protected override void OnStartup(object sender,StartupEventArgs e)
{
DisplayRootViewFor<MainViewModel>();
}
protected override object GetInstance(Type service,string key)
{
return _container.GetInstance(service,key);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _container.GetAllInstances(service);
}
protected override void BuildUp(object instance)
{
_container.BuildUp(instance);
}
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[] { Assembly.GetExecutingAssembly() };
}
}
}
成功登录后,您需要通知 FirstName 属性 已更改。
Task IHandle<LogOnEvent>.HandleAsync(LogOnEvent message,CancellationToken cancellationToken)
{
_loginVM = _container.GetInstance<LoginViewModel>(); // Not sure why you do this.
ActivateItemAsync(_userProfileVM);
// Since User has logged now, you need to notify change in FirstName
NotifyOfPropertyChange(nameof(FirstName));
return Task.CompletedTask;
}
这将确保 ShellView 知道 FirstName 属性 已更改。
或者您可以订阅 LoginViewModel 的 PropertyNotifyChanges 并过滤掉 FirstName 的更改,但是,由于您在登录成功后只需要名字,因此 LogOnEvent 可能更合适。
另请注意,您可以将 FirstName 属性 设置为只读,因为它很可能不会被视图编辑。
public string FirstName => _loggedInUserModel.FirstName;