【问题标题】:WPF usercontrols in window - dependency property value is null on doubleclick窗口中的 WPF 用户控件-双击时依赖属性值为空
【发布时间】:2018-07-31 07:44:54
【问题描述】:

我已经在这里上传了我的示例项目:https://www.file-upload.net/download-13252079/WpfApp1.zip.html 它是一个 WPF 窗口,其中包含多个相同的用户控件。 UserControl 有一个名为“Text”的依赖属性,它绑定到 MainWindowViewModel 的属性并成功显示在 UserControl 的 TextBlock 中。 但是,如果我双击 UserControl 并希望它给出其依赖属性的值,则该值为 null。为什么是这样? 非常感谢您的帮助!

编辑:对不起,这是一些源代码: 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>

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));
    }
}

主窗口的 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>

主窗口后面的代码:

    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);
        }
    }

主窗口的视图模型:

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
}

【问题讨论】:

  • 你为什么在依赖属性上实现INotifyPropertyChanged?首先是从 Text 的 setter 中删除 SetProperty,并像 SetCurrentValue(TextProperty, value 一样调用它,像 return (string)GetValue(TextPropetry) 那样调用它。
  • 这是 Dependency 属性的样子:public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(String), typeof(UserControl1), new FrameworkPropertyMetadata("")); public String Text { get { return (String)GetValue(TextProperty); } set { SetValue(TextProperty, value); } }
  • 谢谢你们,就是这样!我发现在依赖属性上实现 INotifyPropertyChanged 是愚蠢的。

标签: c# wpf user-controls dependency-properties double-click


【解决方案1】:

您的 UserControl 代码如下所示。您不需要实现 INotifyPropertyChanged。

有关所有详细信息,请参阅Custom Dependency Properties。具体来说,您必须从 Text 属性包装器的 getter 和 setter 调用 GetValueSetValue(仅此而已)。

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 的 Text 属性,您可以使用 RelativeSource 而不是 ElementName 来保存无用的生成类成员:

<UserControl x:Class="WpfApp1.UserControl1" ...>    
    ...
    <TextBlock Text="{Binding Text,
                      RelativeSource={RelativeSource AncestorType=UserControl}}" .../>
    ...
</UserControl>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多