使用 WPF、MVVM 和 DP 的用户控件
UserControl using WPF, MVVM and DP
我正在尝试设计一个 UserControl,特别是一个 NumericUpDownControl。
<UserControl x:Class="SettingsDialog.Controls.NumericUpDownControl"
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:SettingsDialog.Controls"
xmlns:viewModels="clr-namespace:SettingsDialog.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="18"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="{Binding Value}" Grid.Row="0" Grid.RowSpan="2" Height="20" VerticalContentAlignment="Center"/>
<RepeatButton Content="5" Grid.Column="1" Grid.Row="0" FontSize="8" Height="10" FontFamily="Marlett" VerticalContentAlignment="Center"/>
<RepeatButton Content="6" Grid.Column="1" Grid.Row="1" FontSize="8" Height="10" FontFamily="Marlett" VerticalContentAlignment="Center"/>
</Grid>
</UserControl>
在 UserControl 的代码隐藏中,我有以下内容:
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(
"Value", typeof(int),
typeof(NumericUpDownControl)
);
public int Value
{
get => (int)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
它工作正常,因为我可以像这样在我的 MainWindow.xaml 中使用它:
<controls:NumericUpDownControl Width="100" Value="10"/>
但问题是我还想为我的 UserControl 使用 ViewModel。当我设置它时,我的 UserControl 中的 TextBox
不再识别 Value
依赖项 属性。我怎样才能拥有一个 ViewModel 并同时从 UserControl 外部设置 Value
?我做错了什么吗?
您不能同时将 UserControl 绑定到自身和 ViewModel。
您必须从 UserControl 中删除 DataContext="{Binding RelativeSource={RelativeSource Self}}"
,并确保在将它集成到您的 UI.
中时将正确的 DataContext
传递给 UserControl
这应该将 TextBox
的 Text
属性 绑定到 UserControl
的 Value
属性 而不管其 DataContext
:
<TextBox Text="{Binding Value, RelativeSource={RelativeSource AncestorType=UserControl}}" Grid.Row="0" Grid.RowSpan="2" Height="20" VerticalContentAlignment="Center"/>
由于您正在制作一种自定义控件,另一种解决问题的方法是简单地使用 属性changed 依赖项的回调 属性,每次它发生变化时,您只需更新文本框的文字 属性:
public partial class NumericUpDownControl : UserControl
{
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(int),typeof(NumericUpDownControl),new PropertyMetadata(OnValueChanged));
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((NumericUpDownControl) d).TextBox.Text = e.NewValue?.ToString() ?? string.Empty;
}
public int Value
{
get => (int)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public NumericUpDownControl()
{
InitializeComponent();
}
}
}
我正在尝试设计一个 UserControl,特别是一个 NumericUpDownControl。
<UserControl x:Class="SettingsDialog.Controls.NumericUpDownControl"
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:SettingsDialog.Controls"
xmlns:viewModels="clr-namespace:SettingsDialog.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="18"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="{Binding Value}" Grid.Row="0" Grid.RowSpan="2" Height="20" VerticalContentAlignment="Center"/>
<RepeatButton Content="5" Grid.Column="1" Grid.Row="0" FontSize="8" Height="10" FontFamily="Marlett" VerticalContentAlignment="Center"/>
<RepeatButton Content="6" Grid.Column="1" Grid.Row="1" FontSize="8" Height="10" FontFamily="Marlett" VerticalContentAlignment="Center"/>
</Grid>
</UserControl>
在 UserControl 的代码隐藏中,我有以下内容:
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(
"Value", typeof(int),
typeof(NumericUpDownControl)
);
public int Value
{
get => (int)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
它工作正常,因为我可以像这样在我的 MainWindow.xaml 中使用它:
<controls:NumericUpDownControl Width="100" Value="10"/>
但问题是我还想为我的 UserControl 使用 ViewModel。当我设置它时,我的 UserControl 中的 TextBox
不再识别 Value
依赖项 属性。我怎样才能拥有一个 ViewModel 并同时从 UserControl 外部设置 Value
?我做错了什么吗?
您不能同时将 UserControl 绑定到自身和 ViewModel。
您必须从 UserControl 中删除 DataContext="{Binding RelativeSource={RelativeSource Self}}"
,并确保在将它集成到您的 UI.
DataContext
传递给 UserControl
这应该将 TextBox
的 Text
属性 绑定到 UserControl
的 Value
属性 而不管其 DataContext
:
<TextBox Text="{Binding Value, RelativeSource={RelativeSource AncestorType=UserControl}}" Grid.Row="0" Grid.RowSpan="2" Height="20" VerticalContentAlignment="Center"/>
由于您正在制作一种自定义控件,另一种解决问题的方法是简单地使用 属性changed 依赖项的回调 属性,每次它发生变化时,您只需更新文本框的文字 属性:
public partial class NumericUpDownControl : UserControl
{
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(int),typeof(NumericUpDownControl),new PropertyMetadata(OnValueChanged));
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((NumericUpDownControl) d).TextBox.Text = e.NewValue?.ToString() ?? string.Empty;
}
public int Value
{
get => (int)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public NumericUpDownControl()
{
InitializeComponent();
}
}
}