BindableBase - SetProperty 无法使用 ViewModel 的实例
BindableBase - SetProperty does not work using the instance of the ViewModel
我正在尝试使用 LoginViewModel 中的 MainViewModel 实例从 LoginViewModel 设置 MainViewModel 的 属性。但是 XAML 中的绑定没有得到通知!我在 MainViewModel 中设置了断点,它显示正在设置值,但如果它通过实例设置则不起作用。谁能帮忙?
下面是两个视图模型的代码。如您所见,在我的登录视图模型中,我使用 MainViewModel 的实例设置 public 属性 :
MainViewModel.Instance.Mainviewpageindex = 1;
MainViewModel
namespace DataRetrieval.ViewModels
{
public class MainViewModel : BindableBase
{
private static MainViewModel _instance = new MainViewModel();
public static MainViewModel Instance { get { return _instance; }
}
private int _mainviewpageindex;
public int Mainviewpageindex
{
get {
return _mainviewpageindex; }
set {
SetProperty(ref _mainviewpageindex, value);
// _mainviewpageindex = value;
// RaisePropertyChangedEvent("Mainviewpageindex");
}
}
public MainViewModel()
{
Mainviewpageindex = 0;
}
public DelegateCommand<object> _loginCommand;
public ICommand LoginCommand
{
get
{
_loginCommand = new DelegateCommand<object>(Login, VerifyLogin);
return _loginCommand;
}
}
private void Login(object context)
{
Mainviewpageindex = 1;
}
private bool VerifyLogin(object context)
{
return true;
}
}
登录视图模型
namespace DataRetrieval.ViewModels
{
public class LoginViewModel : BindableBase
{
// public SecureString SecurePassword { private get; set; }
private string _uname;
public string Uname
{
get { return _uname; }
set {
SetProperty(ref _uname, value);
_loginCommand.RaiseCanExecuteChanged();
}
}
private SecureString _securePassword;
public SecureString SecurePassword
{
get { return _securePassword; }
set {
SetProperty(ref _securePassword, value);
_loginCommand.RaiseCanExecuteChanged();
}
}
public LoginViewModel()
{
}
public DelegateCommand<object> _loginCommand;
public ICommand LoginCommand
{
get
{
_loginCommand = new DelegateCommand<object>(Login, VerifyLogin);
return _loginCommand;
}
}
private void Login(object context)
{
if (SecurePassword != null || Uname != null)
{
//PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// bool validated = ctx.ValidateCredentials(Uname, SecureStringToString(SecurePassword));
MainViewModel.Instance.Mainviewpageindex = 1;
}else
{
}
}
String SecureStringToString(SecureString value)
{
IntPtr valuePtr = IntPtr.Zero;
try
{
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
return Marshal.PtrToStringUni(valuePtr);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
}
}
private bool VerifyLogin(object context)
{
return true;
}
}
}
XAML:
<Window x:Class="DataRetrieval.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:DataRetrieval.Views"
xmlns:prism="http://www.codeplex.com/prism"
xmlns:viewModels="clr-namespace:DataRetrieval.ViewModels"
Title="Data Retrieval Tool" Height="Auto" Width="900" Icon="Resources/colorful_query_mark_light_bulb_28261523_y2o_icon.ico">
<Window.DataContext>
<viewModels:MainViewModel />
</Window.DataContext>
<TabControl Name="TabControl1" BorderBrush="{x:Null}" Background="White" SelectedIndex="{Binding Mainviewpageindex, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<TabControl.ItemContainerStyle>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
</TabControl.ItemContainerStyle>
<TabItem Header="General">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*" MaxWidth="300"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="auto" />
<RowDefinition Height="300"/>
</Grid.RowDefinitions>
<views:Login HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="1" Grid.Row="1" />
<TextBlock TextWrapping="Wrap" TextAlignment="Center" Text="User your OneAbbott domain user name and password to login into the system" Grid.Column="1" Grid.Row="2"/>
<Button x:Name="btnLogin" Content="Login" Margin="20" Command="{Binding LoginCommand}"/>
</Grid>
</TabItem>
<TabItem Header="Second Tab">
<StackPanel>
<TextBlock TextWrapping="Wrap" TextAlignment="Center" Text="Login Successfull" Grid.Column="1" Grid.Row="2"/>
</StackPanel>
</TabItem>
</TabControl>
</Window>
您正在处理 MainViewModel 的两个不同实例。真正连接到您的视图的是 XAML 解析器在遇到设置数据上下文的代码时构造的。
另一个您在视图模型中创建为单独的静态对象并通过实例公开 属性。
您需要一种不同的方式来在 ViewModel 实例之间进行通信。 Prism 中的 Pub-Sub 事件是处理这种情况的最佳方式,尽管使用 CompositeCommand 也可以。
似乎实现 ModelView 之间通信的最佳方式是使用 prism 事件聚合!
MSDN 上提供了一个示例:https://msdn.microsoft.com/en-us/library/ff921173(v=pandp.40).aspx
我正在尝试使用 LoginViewModel 中的 MainViewModel 实例从 LoginViewModel 设置 MainViewModel 的 属性。但是 XAML 中的绑定没有得到通知!我在 MainViewModel 中设置了断点,它显示正在设置值,但如果它通过实例设置则不起作用。谁能帮忙? 下面是两个视图模型的代码。如您所见,在我的登录视图模型中,我使用 MainViewModel 的实例设置 public 属性 :
MainViewModel.Instance.Mainviewpageindex = 1;
MainViewModel
namespace DataRetrieval.ViewModels
{
public class MainViewModel : BindableBase
{
private static MainViewModel _instance = new MainViewModel();
public static MainViewModel Instance { get { return _instance; }
}
private int _mainviewpageindex;
public int Mainviewpageindex
{
get {
return _mainviewpageindex; }
set {
SetProperty(ref _mainviewpageindex, value);
// _mainviewpageindex = value;
// RaisePropertyChangedEvent("Mainviewpageindex");
}
}
public MainViewModel()
{
Mainviewpageindex = 0;
}
public DelegateCommand<object> _loginCommand;
public ICommand LoginCommand
{
get
{
_loginCommand = new DelegateCommand<object>(Login, VerifyLogin);
return _loginCommand;
}
}
private void Login(object context)
{
Mainviewpageindex = 1;
}
private bool VerifyLogin(object context)
{
return true;
}
}
登录视图模型
namespace DataRetrieval.ViewModels
{
public class LoginViewModel : BindableBase
{
// public SecureString SecurePassword { private get; set; }
private string _uname;
public string Uname
{
get { return _uname; }
set {
SetProperty(ref _uname, value);
_loginCommand.RaiseCanExecuteChanged();
}
}
private SecureString _securePassword;
public SecureString SecurePassword
{
get { return _securePassword; }
set {
SetProperty(ref _securePassword, value);
_loginCommand.RaiseCanExecuteChanged();
}
}
public LoginViewModel()
{
}
public DelegateCommand<object> _loginCommand;
public ICommand LoginCommand
{
get
{
_loginCommand = new DelegateCommand<object>(Login, VerifyLogin);
return _loginCommand;
}
}
private void Login(object context)
{
if (SecurePassword != null || Uname != null)
{
//PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// bool validated = ctx.ValidateCredentials(Uname, SecureStringToString(SecurePassword));
MainViewModel.Instance.Mainviewpageindex = 1;
}else
{
}
}
String SecureStringToString(SecureString value)
{
IntPtr valuePtr = IntPtr.Zero;
try
{
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
return Marshal.PtrToStringUni(valuePtr);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
}
}
private bool VerifyLogin(object context)
{
return true;
}
}
}
XAML:
<Window x:Class="DataRetrieval.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:DataRetrieval.Views"
xmlns:prism="http://www.codeplex.com/prism"
xmlns:viewModels="clr-namespace:DataRetrieval.ViewModels"
Title="Data Retrieval Tool" Height="Auto" Width="900" Icon="Resources/colorful_query_mark_light_bulb_28261523_y2o_icon.ico">
<Window.DataContext>
<viewModels:MainViewModel />
</Window.DataContext>
<TabControl Name="TabControl1" BorderBrush="{x:Null}" Background="White" SelectedIndex="{Binding Mainviewpageindex, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<TabControl.ItemContainerStyle>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
</TabControl.ItemContainerStyle>
<TabItem Header="General">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*" MaxWidth="300"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="auto" />
<RowDefinition Height="300"/>
</Grid.RowDefinitions>
<views:Login HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="1" Grid.Row="1" />
<TextBlock TextWrapping="Wrap" TextAlignment="Center" Text="User your OneAbbott domain user name and password to login into the system" Grid.Column="1" Grid.Row="2"/>
<Button x:Name="btnLogin" Content="Login" Margin="20" Command="{Binding LoginCommand}"/>
</Grid>
</TabItem>
<TabItem Header="Second Tab">
<StackPanel>
<TextBlock TextWrapping="Wrap" TextAlignment="Center" Text="Login Successfull" Grid.Column="1" Grid.Row="2"/>
</StackPanel>
</TabItem>
</TabControl>
</Window>
您正在处理 MainViewModel 的两个不同实例。真正连接到您的视图的是 XAML 解析器在遇到设置数据上下文的代码时构造的。
另一个您在视图模型中创建为单独的静态对象并通过实例公开 属性。
您需要一种不同的方式来在 ViewModel 实例之间进行通信。 Prism 中的 Pub-Sub 事件是处理这种情况的最佳方式,尽管使用 CompositeCommand 也可以。
似乎实现 ModelView 之间通信的最佳方式是使用 prism 事件聚合!
MSDN 上提供了一个示例:https://msdn.microsoft.com/en-us/library/ff921173(v=pandp.40).aspx