将 object 绑定到 UserControl
Binding object to UserControl
我正在尝试从我的主 UserControl 控制 child UserControls 的状态。我正在考虑通过在 Parent UC 中创建 DependencyProperty object 并在创建 Children UC 时在 XAML 中引用它来实现这一点。
问题是,我在 Step.xaml.cs(Child 代码后面)中得到 NullReferenceException,所有内容都引用控制器 属性,首先是 StepEnabled 属性。当我省略 XAML 绑定并让它在构造函数中实例化时,没关系,虽然我当然不能控制任何东西,但它的方式 Controller 属性 总是为空......代码如下:
Parent视图模型:
public class ParentVM : NotifyPropChanged
{
...
public StepController Step1 = new StepController();
public StepController Step2 = new StepController();
public StepController Step3 = new StepController();
public ParentVM()
{
...
GetReady();
}
public void GetReady()
{
Step1.Clear();
Step2.Clear();
Step3.Clear();
}
步进控制器:
public class StepController
{
public bool StepEnabled;
public bool? WasSuccessful;
public StepController()
{
Clear();
}
public void Clear()
{
StepEnabled = false;
WasSuccessful = null;
}
}
Child(后面的代码):
public partial class Step : UserControl
{
public static DependencyProperty ControllerProperty =
DependencyProperty.Register("Controller", typeof(StepController), typeof(Step), new UIPropertyMetadata(null));
public StepController Controller
{
get { return (StepController)GetValue(ControllerProperty); }
set { SetValue(ControllerProperty, value); }
}
...
public bool StepEnabled
{
get { return (bool)Controller.StepEnabled; }
set { Controller.StepEnabled = value; }
}
public bool IsDone
{
get
{
return (Controller.WasSuccessful != null);
}
}
public bool? WasSuccessful
{
get { return Controller.WasSuccessful; }
set { Controller.WasSuccessful = value; }
}
public Step()
{
InitializeComponent();
this.DataContext = this;
...
Controller = new StepController();
}
}
ParentUC:
...
<local:Step Controller="{Binding Path=Step1, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
...
ChildUC:
e.g.:
<TextBlock IsEnabled="{Binding StepEnabled, UpdateSourceTrigger=PropertyChanged}" />
我是 WPF 的新手,我仍然不确定很多事情,比如 DataContext 等等,所以我想我遗漏了一些明显的东西......提前感谢您的帮助!
不清楚你想用 Controller 做什么=“{Binding Path=Step1, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}
首先您将控制器创建为依赖项属性稍后您将在步骤构造函数中实例化相同的内容。由于您是新手,因此看到您的代码时您的概念看起来很混乱。
您能否详细说明您想要实现的目标,以便我们为您提供帮助?只需用一点清晰的英语说明你想要什么?
绑定不适用于字段。
声明 属性 并重命名您的字段
public StepController Step1 { get { return _step1; } set { _step1 = value; }
您的异常可能是因为您在使用 "Controller" 属性 时未对其进行空值测试。
此外,在您的 "Step" 构造函数中,您
Controller = new StepController();
如果您的目标是设置默认值,请通过
完成您的静态 DP 声明
.... UIPropertyMetadata(new Controller()));
就像@Synapse 已经提到的 DependencyProperty
在 Step
-UserControl
中应该为 StepController
class:
public static readonly DependencyProperty ControllerProperty = DependencyProperty.Register(
"Controller", typeof (StepController), typeof (Step), new PropertyMetadata(default(StepController)));
public StepController Controller
{
get { return (StepController) GetValue(ControllerProperty); }
set { SetValue(ControllerProperty, value); }
}
您的 ParentUC 应如下所示(DataContext 仅在此处设置示例):
<UserControl
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:StepControllerExample" x:Class="StepControllerExample.ParentUserControl"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<local:ParentVM/>
</UserControl.DataContext>
<StackPanel HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100">
<local:Step Controller="{Binding Step1}"/>
<local:Step Controller="{Binding Step2}"/>
<local:Step Controller="{Binding Step3}"/>
</StackPanel>
您的子用户控件 XAML 像这样:
<UserControl x:Name="userControl" x:Class="StepControllerExample.Step"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel Orientation="Vertical" d:LayoutOverrides="Height">
<TextBlock x:Name="textBlock" TextWrapping="Wrap" Text="TextBlock"/>
<CheckBox x:Name="checkBox" Content="CheckBox" IsChecked="{Binding Controller.StepEnabled, ElementName=userControl}"/>
</StackPanel>
你的子 UserControl CodeBehind 是这样的:
public partial class Step : UserControl
{
public Step()
{
InitializeComponent();
}
public static readonly DependencyProperty ControllerProperty = DependencyProperty.Register(
"Controller", typeof (StepController), typeof (Step), new PropertyMetadata(default(StepController)));
public StepController Controller
{
get { return (StepController) GetValue(ControllerProperty); }
set { SetValue(ControllerProperty, value); }
}
}
和你的 StepController
class 这样的:
public class StepController : INotifyPropertyChanged
{
private bool _stepEnabled;
private bool? _wasSuccessful;
public StepController()
{
Clear();
}
public bool StepEnabled
{
get { return _stepEnabled; }
set
{
if (value == _stepEnabled) return;
_stepEnabled = value;
OnPropertyChanged();
}
}
public bool? WasSuccessful
{
get { return _wasSuccessful; }
set
{
if (value == _wasSuccessful) return;
_wasSuccessful = value;
OnPropertyChanged();
}
}
public void Clear()
{
StepEnabled = false;
WasSuccessful = null;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
我正在尝试从我的主 UserControl 控制 child UserControls 的状态。我正在考虑通过在 Parent UC 中创建 DependencyProperty object 并在创建 Children UC 时在 XAML 中引用它来实现这一点。
问题是,我在 Step.xaml.cs(Child 代码后面)中得到 NullReferenceException,所有内容都引用控制器 属性,首先是 StepEnabled 属性。当我省略 XAML 绑定并让它在构造函数中实例化时,没关系,虽然我当然不能控制任何东西,但它的方式 Controller 属性 总是为空......代码如下:
Parent视图模型:
public class ParentVM : NotifyPropChanged
{
...
public StepController Step1 = new StepController();
public StepController Step2 = new StepController();
public StepController Step3 = new StepController();
public ParentVM()
{
...
GetReady();
}
public void GetReady()
{
Step1.Clear();
Step2.Clear();
Step3.Clear();
}
步进控制器:
public class StepController
{
public bool StepEnabled;
public bool? WasSuccessful;
public StepController()
{
Clear();
}
public void Clear()
{
StepEnabled = false;
WasSuccessful = null;
}
}
Child(后面的代码):
public partial class Step : UserControl
{
public static DependencyProperty ControllerProperty =
DependencyProperty.Register("Controller", typeof(StepController), typeof(Step), new UIPropertyMetadata(null));
public StepController Controller
{
get { return (StepController)GetValue(ControllerProperty); }
set { SetValue(ControllerProperty, value); }
}
...
public bool StepEnabled
{
get { return (bool)Controller.StepEnabled; }
set { Controller.StepEnabled = value; }
}
public bool IsDone
{
get
{
return (Controller.WasSuccessful != null);
}
}
public bool? WasSuccessful
{
get { return Controller.WasSuccessful; }
set { Controller.WasSuccessful = value; }
}
public Step()
{
InitializeComponent();
this.DataContext = this;
...
Controller = new StepController();
}
}
ParentUC:
...
<local:Step Controller="{Binding Path=Step1, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
...
ChildUC:
e.g.:
<TextBlock IsEnabled="{Binding StepEnabled, UpdateSourceTrigger=PropertyChanged}" />
我是 WPF 的新手,我仍然不确定很多事情,比如 DataContext 等等,所以我想我遗漏了一些明显的东西......提前感谢您的帮助!
不清楚你想用 Controller 做什么=“{Binding Path=Step1, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}
首先您将控制器创建为依赖项属性稍后您将在步骤构造函数中实例化相同的内容。由于您是新手,因此看到您的代码时您的概念看起来很混乱。 您能否详细说明您想要实现的目标,以便我们为您提供帮助?只需用一点清晰的英语说明你想要什么?
绑定不适用于字段。
声明 属性 并重命名您的字段
public StepController Step1 { get { return _step1; } set { _step1 = value; }
您的异常可能是因为您在使用 "Controller" 属性 时未对其进行空值测试。
此外,在您的 "Step" 构造函数中,您
Controller = new StepController();
如果您的目标是设置默认值,请通过
完成您的静态 DP 声明.... UIPropertyMetadata(new Controller()));
就像@Synapse 已经提到的 DependencyProperty
在 Step
-UserControl
中应该为 StepController
class:
public static readonly DependencyProperty ControllerProperty = DependencyProperty.Register(
"Controller", typeof (StepController), typeof (Step), new PropertyMetadata(default(StepController)));
public StepController Controller
{
get { return (StepController) GetValue(ControllerProperty); }
set { SetValue(ControllerProperty, value); }
}
您的 ParentUC 应如下所示(DataContext 仅在此处设置示例):
<UserControl
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:StepControllerExample" x:Class="StepControllerExample.ParentUserControl"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<local:ParentVM/>
</UserControl.DataContext>
<StackPanel HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100">
<local:Step Controller="{Binding Step1}"/>
<local:Step Controller="{Binding Step2}"/>
<local:Step Controller="{Binding Step3}"/>
</StackPanel>
您的子用户控件 XAML 像这样:
<UserControl x:Name="userControl" x:Class="StepControllerExample.Step"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel Orientation="Vertical" d:LayoutOverrides="Height">
<TextBlock x:Name="textBlock" TextWrapping="Wrap" Text="TextBlock"/>
<CheckBox x:Name="checkBox" Content="CheckBox" IsChecked="{Binding Controller.StepEnabled, ElementName=userControl}"/>
</StackPanel>
你的子 UserControl CodeBehind 是这样的:
public partial class Step : UserControl
{
public Step()
{
InitializeComponent();
}
public static readonly DependencyProperty ControllerProperty = DependencyProperty.Register(
"Controller", typeof (StepController), typeof (Step), new PropertyMetadata(default(StepController)));
public StepController Controller
{
get { return (StepController) GetValue(ControllerProperty); }
set { SetValue(ControllerProperty, value); }
}
}
和你的 StepController
class 这样的:
public class StepController : INotifyPropertyChanged
{
private bool _stepEnabled;
private bool? _wasSuccessful;
public StepController()
{
Clear();
}
public bool StepEnabled
{
get { return _stepEnabled; }
set
{
if (value == _stepEnabled) return;
_stepEnabled = value;
OnPropertyChanged();
}
}
public bool? WasSuccessful
{
get { return _wasSuccessful; }
set
{
if (value == _wasSuccessful) return;
_wasSuccessful = value;
OnPropertyChanged();
}
}
public void Clear()
{
StepEnabled = false;
WasSuccessful = null;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}