window 中的 WPF 用户控件 - 双击时的依赖项 属性 值为空
WPF usercontrols in window - dependency property value is null on doubleclick
我已将示例项目上传到此处:https://www.file-upload.net/download-13252079/WpfApp1.zip.html
它是一个 WPF window,里面有几个相同的用户控件。 UserControl 有一个名为 "Text" 的依赖项 属性,它绑定到 MainWindowViewModel 的 属性 并成功显示在 UserControl 的 TextBlock 中。
但是,如果我双击 UserControl 并希望它提供其依赖项 属性 的值,则该值为空。为什么是这样?
非常感谢您的帮助!
编辑:抱歉,这是一些源代码:
UserControl 的 XAML:
<UserControl x:Class="WpfApp1.UserControl1"
...
x:Name="UC1">
<StackPanel Orientation="Vertical">
<TextBlock Margin="5" Text="Test" FontSize="20"></TextBlock>
<TextBlock Margin="5" Text="{Binding ElementName=UC1, Path=Text}" FontSize="20"></TextBlock>
</StackPanel>
</UserControl>
用户控件的代码:
public partial class UserControl1 : UserControl, INotifyPropertyChanged
{
public UserControl1()
{
InitializeComponent();
}
string text;
public string Text
{
get { return text; }
set { SetProperty(ref text, value); }
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text", typeof(string), typeof(UserControl1));
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (Equals(storage, value))
{
return false;
}
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
主要window的XAML:
<Window x:Class="WpfApp1.MainWindow"
...>
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<StackPanel>
<local:UserControl1 Text="{Binding Values[0]}"
MouseDoubleClick="UserControl1_MouseDoubleClick">
</local:UserControl1>
<local:UserControl1 Text="{Binding Values[1]}"
MouseDoubleClick="UserControl1_MouseDoubleClick">
</local:UserControl1>
<local:UserControl1 Text="{Binding Values[2]}"
MouseDoubleClick="UserControl1_MouseDoubleClick">
</local:UserControl1>
<local:UserControl1 Text="{Binding Values[3]}"
MouseDoubleClick="UserControl1_MouseDoubleClick">
</local:UserControl1>
</StackPanel>
</Window>
主要的window背后的代码:
private void UserControl1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (sender is UserControl1)
{
// why is (sender as UserControl1).Text null?
MessageBox.Show("Text is: " + (sender as UserControl1).Text);
}
}
主要window的视图模型:
class MainWindowViewModel : BindableBase
{
public MainWindowViewModel()
{
Values = new ObservableCollection<string>();
Values.Add("first string");
Values.Add("second string");
Values.Add("third string");
Values.Add("fourth string");
}
#region Values
private ObservableCollection<string> values;
public ObservableCollection<string> Values
{
get { return values; }
set { SetProperty(ref values, value); }
}
#endregion
}
下面是您的 UserControl 的代码应该是这样的。您不需要实施 INotifyPropertyChanged。
有关所有详细信息,请参阅 Custom Dependency Properties。具体来说,您必须从 Text
属性 包装器的 getter 和 setter 调用 GetValue
和 SetValue
(仅此而已)。
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(
nameof(Text), typeof(string), typeof(UserControl1));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}
对于在其自己的 XAML 中绑定到 UserControl 的文本 属性,您可以使用 RelativeSource
而不是 ElementName 来保存无用的生成的 class 成员:
<UserControl x:Class="WpfApp1.UserControl1" ...>
...
<TextBlock Text="{Binding Text,
RelativeSource={RelativeSource AncestorType=UserControl}}" .../>
...
</UserControl>
我已将示例项目上传到此处:https://www.file-upload.net/download-13252079/WpfApp1.zip.html 它是一个 WPF window,里面有几个相同的用户控件。 UserControl 有一个名为 "Text" 的依赖项 属性,它绑定到 MainWindowViewModel 的 属性 并成功显示在 UserControl 的 TextBlock 中。 但是,如果我双击 UserControl 并希望它提供其依赖项 属性 的值,则该值为空。为什么是这样? 非常感谢您的帮助!
编辑:抱歉,这是一些源代码: UserControl 的 XAML:
<UserControl x:Class="WpfApp1.UserControl1"
...
x:Name="UC1">
<StackPanel Orientation="Vertical">
<TextBlock Margin="5" Text="Test" FontSize="20"></TextBlock>
<TextBlock Margin="5" Text="{Binding ElementName=UC1, Path=Text}" FontSize="20"></TextBlock>
</StackPanel>
</UserControl>
用户控件的代码:
public partial class UserControl1 : UserControl, INotifyPropertyChanged
{
public UserControl1()
{
InitializeComponent();
}
string text;
public string Text
{
get { return text; }
set { SetProperty(ref text, value); }
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text", typeof(string), typeof(UserControl1));
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (Equals(storage, value))
{
return false;
}
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
主要window的XAML:
<Window x:Class="WpfApp1.MainWindow"
...>
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<StackPanel>
<local:UserControl1 Text="{Binding Values[0]}"
MouseDoubleClick="UserControl1_MouseDoubleClick">
</local:UserControl1>
<local:UserControl1 Text="{Binding Values[1]}"
MouseDoubleClick="UserControl1_MouseDoubleClick">
</local:UserControl1>
<local:UserControl1 Text="{Binding Values[2]}"
MouseDoubleClick="UserControl1_MouseDoubleClick">
</local:UserControl1>
<local:UserControl1 Text="{Binding Values[3]}"
MouseDoubleClick="UserControl1_MouseDoubleClick">
</local:UserControl1>
</StackPanel>
</Window>
主要的window背后的代码:
private void UserControl1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (sender is UserControl1)
{
// why is (sender as UserControl1).Text null?
MessageBox.Show("Text is: " + (sender as UserControl1).Text);
}
}
主要window的视图模型:
class MainWindowViewModel : BindableBase
{
public MainWindowViewModel()
{
Values = new ObservableCollection<string>();
Values.Add("first string");
Values.Add("second string");
Values.Add("third string");
Values.Add("fourth string");
}
#region Values
private ObservableCollection<string> values;
public ObservableCollection<string> Values
{
get { return values; }
set { SetProperty(ref values, value); }
}
#endregion
}
下面是您的 UserControl 的代码应该是这样的。您不需要实施 INotifyPropertyChanged。
有关所有详细信息,请参阅 Custom Dependency Properties。具体来说,您必须从 Text
属性 包装器的 getter 和 setter 调用 GetValue
和 SetValue
(仅此而已)。
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(
nameof(Text), typeof(string), typeof(UserControl1));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}
对于在其自己的 XAML 中绑定到 UserControl 的文本 属性,您可以使用 RelativeSource
而不是 ElementName 来保存无用的生成的 class 成员:
<UserControl x:Class="WpfApp1.UserControl1" ...>
...
<TextBlock Text="{Binding Text,
RelativeSource={RelativeSource AncestorType=UserControl}}" .../>
...
</UserControl>