如何从自定义用户控件 WPF、C# 中的枚举自定义属性中获取值?

Posted

技术标签:

【中文标题】如何从自定义用户控件 WPF、C# 中的枚举自定义属性中获取值?【英文标题】:How to get the value from an enum custom property in custom usercontrol WPF,C#? 【发布时间】:2021-08-07 12:59:56 【问题描述】:

我正在使用 3 个自定义属性创建一个简单的用户控件:其中两个可以正常工作,但我对第三个是枚举的问题进行了故障排除。 我的用户控件是一个组合框,它显示与数据库(mysql、Sql server...)的连接,并且由于 TypeOfDatabase 属性,我想显示所有连接、MySql、SqlServer 等连接。

我的问题是我的 TypeOfDatabase 属性等于 BaseConnection.xaml.cs 开关中的“全部”,因此我不能只有 MySql 连接。

我是 WPF 的新手,我不知道如何获取值集。

我希望你能解释我做错了什么并给我一个解决方案。 感谢提前。

没有更多的文字,但我的代码会有所帮助......

我的用户控制:

BaseConnection.xaml

<UserControl x:Class="WpfCommonControls.Utils.UserControls.BaseConnection"
             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:WpfCommonControls.Utils.UserControls"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="400"
             x:Name="BaseConnectionUserControl">
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Resources/UserControlsResources.en-EN.xaml"/>
                <ResourceDictionary Source="Resources/UserControlsResources.fr-FR.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>
    <Grid>
        <StackPanel Orientation="Vertical">
            <Label x:Name="lbl_Connection_uc" Padding="0"
                   Content="DynamicResource LabelBaseConnection"/>
            <ComboBox x:Name="cbbox_Connections_uc" Margin="0 5 5 0"
                      ItemsSource="Binding ElementName=BaseConnectionUserControl, Path=UcConnectionList"
                      SelectedValuePath="Name"
                      SelectedValue="Binding ElementName=BaseConnectionUserControl, Path=UcConnectionName, UpdateSourceTrigger=PropertyChanged"
                      DisplayMemberPath="Name">
            </ComboBox>
        </StackPanel>
    </Grid>
</UserControl>

BaseConnection.xaml.cs

namespace WpfCommonControls.Utils.UserControls

    /// <summary>
    /// Interaction logic for BaseConnection.xaml
    /// </summary>
    public partial class BaseConnection : UserControl
    

        #region Properties
        public static readonly DependencyProperty ConnectionNameProperty = DependencyProperty.Register("UcConnectionName", typeof(String), typeof(BaseConnection));

        public String UcConnectionName
        
            get
            
                return (String)GetValue(ConnectionNameProperty);
            
            set
            
                SetValue(ConnectionNameProperty, value);
            
        

        public static readonly DependencyProperty ConnectionListProperty = DependencyProperty.Register("UcConnectionList", typeof(List<UcConnection>), typeof(BaseConnection));

        public List<UcConnection> UcConnectionList
        
            get
            
                return (List<UcConnection>)GetValue(ConnectionListProperty);
            
            set
            
                SetValue(ConnectionListProperty, value);
            
        


        public static readonly DependencyProperty TypeOfDatabaseProperty = DependencyProperty.Register("TypeOfDatabase", typeof(DataBaseType), typeof(BaseConnection));

        public DataBaseType TypeOfDatabase
        
            get
            
                return (DataBaseType)GetValue(TypeOfDatabaseProperty);
            
            set
            
                SetValue(TypeOfDatabaseProperty, value);
            
        

        #endregion Properties

        #region Private Properties
        private String _languageCode = "en-EN";
        private CultureHelper _cultureHelper = new CultureHelper();
        private UcConnection _ucConnection = new UcConnection();
        #endregion Private Properties
        public BaseConnection()
        
            InitializeComponent();
            _languageCode = Thread.CurrentThread.CurrentCulture.Name;
            this.Resources = _cultureHelper.FindRessourcesDictionnary(this.Resources, "UserControlsResources", _languageCode);
            List<UcConnection> connectionListByDatabaseType = new List<UcConnection>();
            switch (TypeOfDatabase)
            
                case DataBaseType.MySql:
                    foreach (UcConnection ucConnection in UcConnectionList)
                    
                        if (ucConnection.DriverName.ToLower().Contains("mysql"))
                        
                            connectionListByDatabaseType.Add(ucConnection);
                        
                    
                    UcConnectionList = connectionListByDatabaseType;
                    
                    break;
                case DataBaseType.SqlServer:
                    break;
                default:
                    break;

            
        

        public BaseConnection(String connectionName, List<UcConnection> connections)
        
            InitializeComponent();
            UcConnectionList = connections;
            connectionName = UcConnectionName;
            _languageCode = Thread.CurrentThread.CurrentCulture.Name;
            this.Resources = _cultureHelper.FindRessourcesDictionnary(this.Resources, "UserControlsResources", _languageCode);
        
    

我的枚举 UserControlEnum.cs

namespace WpfCommonControls.Utils.UserControls

    /// <summary>
    /// Enumeration for the databasetype to display in the base connection combobox
    /// </summary>
    public enum DataBaseType
    
        [Description("All available connections")]
        All = 0,
        [Description("Only MySql connections")]
        MySql = 1,
        [Description("Only Sql server connections")]
        SqlServer = 2
    

我的 UcConnection 课程 UcConnection.cs

namespace WpfCommonControls.CommonClasses

    public class UcConnection
    
        public String Name  get; set; 
        public String ServerName  get; set; 
        public String ServerPort  get; set; 
        public String DatabaseName  get; set; 
        public String UserName  get; set; 
        public String UserPassword  get; set; 
        public String DriverName  get; set; 

        public UcConnection()
        

        
        public UcConnection(String nameConnection, String serverName, String serverPort, String databaseName, String userName, String userPassword, String driverName)
        
            Name = nameConnection;
            ServerName = serverName;
            ServerPort = serverPort;
            DatabaseName = databaseName;
            UserName = userName;
            UserPassword = userPassword;
            DriverName = driverName;
        


        public List<UcConnection> UcConnections
        
            get
            
                return _UcConnections;
            
            set
            
                _UcConnections = value;
            
        

        private List<UcConnection> _UcConnections = new List<UcConnection>();
        public static UcConnection GetUcConnection(String name, List<UcConnection> connections)
        
            UcConnection selectedConnection = new UcConnection();
            if (connections == null)
            
                connections = new List<UcConnection>();
            

            foreach (UcConnection cn in connections)
            
                if (cn.Name == name)
                
                    selectedConnection = cn;
                    break;
                
            

            return selectedConnection;
        
    


我如何在窗口

中使用我的用户控件
xmlns:commonUserControls="clr-namespace:WpfCommonControls.Utils.UserControls;assembly=WpfCommonControls"
<commonUserControls:BaseConnection x:Name="uc_BaseConnection"
                                   UcConnectionList="Binding Path=ConnectionList"
                                   UcConnectionName="Binding Path = ConnectionName, UpdateSourceTrigger = Explicit, Mode=TwoWay"
                                   TypeOfDatabase="MySql"/>

在 BaseConnection.xaml.cs 中,我试过了,但没有解决问题

public static readonly DependencyProperty TypeOfDatabaseProperty = DependencyProperty.Register("TypeOfDatabase", typeof(DataBaseType), typeof(BaseConnection), new PropertyMetadata(DataBaseType.All, new PropertyChangedCallback(OnTypeOfDatabaseChanged)));

        private static void OnTypeOfDatabaseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        
            var control = (BaseConnection)d;
            control.TypeOfDatabase = (DataBaseType)e.NewValue;
        

        public DataBaseType TypeOfDatabase
        
            get
            
                return (DataBaseType)GetValue(TypeOfDatabaseProperty);
            
            set
            
                SetValue(TypeOfDatabaseProperty, value);
            
        

【问题讨论】:

【参考方案1】:

您在设置属性之前在构造函数中打开TypeOfDatabase

switch 语句移动到OnTypeOfDatabaseChanged 回调或Loaded 事件处理程序:

public BaseConnection()

    InitializeComponent();
    _languageCode = Thread.CurrentThread.CurrentCulture.Name;
    this.Resources = _cultureHelper.FindRessourcesDictionnary(this.Resources, "UserControlsResources", _languageCode);

    Loaded += OnLoaded;


private void OnLoaded(object sender, RoutedEventArgs e)

    List<UcConnection> connectionListByDatabaseType = new List<UcConnection>();
    switch (TypeOfDatabase)
    
        case DataBaseType.MySql:
            foreach (UcConnection ucConnection in UcConnectionList)
            
                if (ucConnection.DriverName.ToLower().Contains("mysql"))
                
                    connectionListByDatabaseType.Add(ucConnection);
                
            
            UcConnectionList = connectionListByDatabaseType;

            break;
        case DataBaseType.SqlServer:
            break;
        default:
            break;

    

【讨论】:

非常感谢。我终于使用 Loaded 事件使用了您的答案,并且效果很好。要知道为什么我没有将开关放在回调中,请参阅我在 @Rekshino 的回答中的评论【参考方案2】:

首先,我不建议您在 DPChanged 回调中更改依赖属性的值。然后你在构造函数中所做的,你必须在 DPChanged 回调中做。

这应该可行:

public DataBaseType TypeOfDatabase

    get
    
        return (DataBaseType)GetValue(TypeOfDatabaseProperty);
    
    set
    
        SetValue(TypeOfDatabaseProperty, value);
    

public static readonly DependencyProperty TypeOfDatabaseProperty = DependencyProperty.Register(nameof(TypeOfDatabase), typeof(DataBaseType), typeof(BaseConnection), new PropertyMetadata(DataBaseType.All, new PropertyChangedCallback(OnTypeOfDatabaseChanged)));

private static void OnTypeOfDatabaseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

    var connectionListByDatabaseType = new List<UcConnection>();
    switch((DataBaseType)e.NewValue)
    
        case DataBaseType.MySql:
            foreach(UcConnection ucConnection in UcConnectionList)
            
                if(ucConnection.DriverName.ToLower().Contains("mysql"))
                
                    connectionListByDatabaseType.Add(ucConnection);
                
            
            UcConnectionList = connectionListByDatabaseType;
            break;
        case DataBaseType.SqlServer:
            break;
        default:
            break;
    

【讨论】:

我尝试了您的解决方案,但我遇到了编译器错误 CS0120,即“非静态字段、方法或属性 BaseConnection.UcConnectionList 需要对象引用。因此我添加了这些行 var control = (BaseConnection)d; control.TypeOfDatabase = (DataBaseType)e.NewValue; 和控制在 UcConnectionList (control.UcConnectionList) 之前,但是当我尝试运行应用程序时,我在 control.UcConnectionList 上有 System NullReference。实际上,UcConnectionList 是在 mywindow 加载事件上设置的。谢谢您的回答。

以上是关于如何从自定义用户控件 WPF、C# 中的枚举自定义属性中获取值?的主要内容,如果未能解决你的问题,请参考以下文章

C#中如何实现WPF调用Winform中用户自定义的控件呢?

在 WPF C# 中无法访问用户控件的自定义属性

从自定义控件的模板部分中删除事件处理程序

[原创]c# wpf自定义 任意颜色阴影特效融合winform的探索之路

如何引用VB6.0编 用户自定义控件

做WPF页面的时候我想通过C#代码触发自定义控件中的事件怎么做