从XAML页面绑定后的代码中获取或设置INotifyPropertyChanged类的属性值
本文关键字:设置 INotifyPropertyChanged 属性 获取 代码 XAML 绑定 | 更新日期: 2023-09-27 18:12:38
我已经将组框绑定到INotifyPropertyChanged类。
页面资源
<Page.Resources>
<current:UserAccountsStatusHandler x:Key="UserAccounts" />
</Page.Resources>
<<p> 组框/strong> <GroupBox
Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2"
Header="Select Action:"
Foreground="{DynamicResource DynamicFrmFG}"
VerticalAlignment="Stretch" HorizontalAlignment="Left"
Height="50"
DataContext="{StaticResource ResourceKey=UserAccounts}">
<StackPanel
Orientation="Horizontal"
HorizontalAlignment="Stretch" VerticalAlignment="Center"
Height="Auto">
<RadioButton
Content="Insert"
Foreground="{DynamicResource DynamicFrmFG}" Height="16"
IsChecked="{Binding Path=UserAccountAction, Converter={StaticResource enumToBooleanConverter},
ConverterParameter={x:Static enums:UserAccountActions.Insert}, UpdateSourceTrigger=PropertyChanged}"
Margin="0,0,10,0"
Click="RadioButton_Click" />
<RadioButton
Content="Update"
Foreground="{DynamicResource DynamicFrmFG}" Height="16"
IsChecked="{Binding Path=UserAccountAction, Converter={StaticResource enumToBooleanConverter},
ConverterParameter={x:Static enums:UserAccountActions.Update}, UpdateSourceTrigger=PropertyChanged}"
Margin="0,0,10,0"
Click="RadioButton_Click" />
<RadioButton
Content="Delete"
Foreground="{DynamicResource DynamicFrmFG}" Height="16"
IsChecked="{Binding Path=UserAccountAction, Converter={StaticResource enumToBooleanConverter},
ConverterParameter={x:Static enums:UserAccountActions.Delete}, UpdateSourceTrigger=PropertyChanged}"
Margin="0,0,10,0"
Click="RadioButton_Click" />
</StackPanel>
</GroupBox>
类public class UserAccountsStatusHandler : INotifyPropertyChanged
{
private UserAccountActions userAccountAction;
public UserAccountActions UserAccountAction
{
get { return userAccountAction; }
set
{
userAccountAction = value;
IsSaveEnabled = (userAccountAction == UserAccountActions.None) ? false : true;
OnPropertyChanged("UserAccountAction");
}
}
private bool isSavedEnabled;
public bool IsSaveEnabled { get { return isSavedEnabled; } set { isSavedEnabled = value; OnPropertyChanged("IsSaveEnabled"); } }
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
这一切都工作如预期。我单击其中一个单选按钮,属性就改变了,保存按钮就启用了。然而,我试图弄清楚我如何从类中拉出这些值,在页面后面的代码中,而实际上不必从UI中拉出组框的DataContext,然后调用类。
如果我尝试在页面后面的代码中创建类的新实例,如预期的那样,我得到默认值。到目前为止,我发现如何获取/设置值的唯一方法是将变量的值设置为等于组框数据上下文,如下所示:
var test = (UserAccountsStatusHandler)tempGroupBoxName.DataContext;
test.IsSaveEnabled = false;
我读过的很多东西都说数据层不应该知道任何关于UI的事情。所以我不知道该怎么做。如有任何帮助,我将不胜感激。
编辑:添加我以前做的我认为是错误的也
private UserAccountsStatusHandler mainStatusHandler;
mainStatusHandler = new UserAccountsStatusHandler();
base.DataContext = mainStatusHandler;
在这一点上,我可以很容易地调用mainStatusHandler来获取像IsSavedEnabled
这样的东西,并确定用户从UserAccountAction
中选择了什么动作。我使用IsSavedEnabled
的唯一真正原因是禁用按钮时,标签重新加载页面。确保他们不会在没有实际选择一个操作之前点击保存按钮,然后启用保存按钮。然后他们必须点击Save按钮来执行后面的代码以将数据保存到服务器。
由于您只是将其用于某种形式的验证,因此您确实需要使用iccommand实现。因此,在本例中,修改视图模型以实现iccommand接口以及INotifyPropertyChanged。
public class UserAccountsStatusHandler : INotifyPropertyChanged, ICommand
{
private UserAccountActions userAccountAction;
public UserAccountActions UserAccountAction
{
get { return userAccountAction; }
set
{
userAccountAction = value;
IsSaveEnabled = (userAccountAction == UserAccountActions.None) ? false : true;
OnPropertyChanged("UserAccountAction");
// Refresh the CanExecute method.
OnCanExecuteChanged();
}
}
private bool isSavedEnabled;
public bool IsSaveEnabled { get { return isSavedEnabled; } set { isSavedEnabled = value; OnPropertyChanged("IsSaveEnabled"); } }
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public bool CanExecute(object parameter)
{
return userAccountAction.SomeActionSelected != null;
}
public event EventHandler CanExecuteChanged;
private void OnCanExecuteChanged()
{
if (this.CanExecuteChanged!= null)
this.CanExecuteChanged(this, new EventArgs());
}
public void Execute(object parameter)
{
// perform save code.
}
}
现在在您的XAML中,如果您的组框有UserAccountStatusHandler
作为它的数据上下文,您可以使用分配您的组框名称,并将您的按钮绑定到它。
<GroupBox x:Name="UserAccountStatusGroupBox"></GroupBox>
<Button Content="Save"
Command={Binding ElementName=UserAccountStatusGroupBox, Path=DataContext} />
当视图被加载时,按钮调用CanExecute。如果返回值为false,按钮将自动禁用。如果为true,则启用该功能。当视图模型中的属性被更改时,然后调用CanExecuteChanged
处理程序,它将重新评估保存按钮是否可以启用。
一般来说,每个视图/用户控件应该有一个视图模型。在这种情况下,视图(窗口/页面)应该将视图模型作为其数据上下文,而不是GroupBox。这是最佳实践。
我建议您仔细阅读与MVVM一起工作的命令模式。对于这样的事情,应该没有任何代码隐藏。它应该全部包含在视图模型中。视图模型的目的是支持视图
一般来说,您创建的每个视图都应该有一个ViewModel:
<Page.DataContext>
<local:MyViewModel/>
</Page.DataContext>
您的UserAccountsStatusHandler
可以是您的ViewModel在这种情况下。但是通过将它设置在Page级别作为DataContext,您就不需要太担心从后面的代码中挖掘UI了。
你可以像这样在CodeBehind中公开一个属性:
private MyViewModel ViewModel
{
get
{
return DataContext as MyViewModel;
}
}
现在你可以直接使用:
MyViewModel.IsSaveEnabled = false;
哪个更好。
但是,我会避免在代码隐藏中放入太多逻辑。我更喜欢让你的按钮调用ViewModel上的Save()方法,然后让ViewModel相应地更新自己。
通常我不设置控件的DataContext
在我的页面/窗口,而是设置根对象本身的数据上下文。我还添加了一个私有属性,以便在必要时易于使用(它只是返回DataContext
的值转换到我的视图模型的类)。
然后你只需要使用这个属性,这将使你能够访问绑定到UI的值