3

In order to get into the WPF world and getting used to bindings, I've made a user control used to define a search filter. Depending on the wanted filter, the user can either enter a text, pick a date or select an item in a combo box. Here's an example with three instances of the created search control, each being of different type:

Search filter example

The good news is, everything is working but I'm not sure if everything has been done as intended.

SearchUserControl.xaml:

<UserControl x:Class="Zefix.View.UserControls.SearchUserControl"
             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="82" 
             d:DesignWidth="300" 
             Height="Auto"
             x:Name="SearchUserControlRoot">
    <Grid>
        <StackPanel>
            <Label Name="LabelHeaderText" Content="{Binding HeaderText, ElementName=SearchUserControlRoot}" />
            <TextBox Name="TextBoxSearchText" Text="{Binding SearchValue, ElementName=SearchUserControlRoot}" Visibility="{Binding TextBoxVisiblity, ElementName=SearchUserControlRoot}" />
            <DatePicker Name="DatePickerSearch" SelectedDate="{Binding SearchValue, ElementName=SearchUserControlRoot}" Visibility="{Binding DatePickerVisiblity, ElementName=SearchUserControlRoot}" />
            <ComboBox Name="ComboBoxSearch" Text="{Binding SearchValue, ElementName=SearchUserControlRoot}" ItemsSource="{Binding AvailableValues, ElementName=SearchUserControlRoot}" Visibility="{Binding ComboBoxVisiblity, ElementName=SearchUserControlRoot}" IsEditable="True" />
        </StackPanel>
    </Grid>
</UserControl>

SearchUserControl.xaml.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using Zefix.DataAccess;

namespace Zefix.View.UserControls {
    /// <summary>
    ///     Interaction logic for SearchUserControl.xaml
    /// </summary>
    public partial class SearchUserControl {

        #region Public Dependency Properties

        /// <summary>
        /// The search value property
        /// </summary>
        public static readonly DependencyProperty SearchValueProperty =
            DependencyProperty.Register("SearchValue", typeof (object), typeof (SearchUserControl));

        /// <summary>
        /// The available values property
        /// </summary>
        public static readonly DependencyProperty AvailableValuesProperty =
            DependencyProperty.Register("AvailableValues", typeof (IEnumerable<object>), typeof (SearchUserControl));

        /// <summary>
        /// The search type property
        /// </summary>
        public static readonly DependencyProperty SearchTypeProperty =
            DependencyProperty.Register("SearchType", typeof (SearchType), typeof (SearchUserControl));

        /// <summary>
        /// The header text property
        /// </summary>
        public static readonly DependencyProperty HeaderTextProperty =
            DependencyProperty.Register("HeaderText", typeof (string), typeof (SearchUserControl));

        #endregion

        #region Private Dependency Properties

        /// <summary>
        /// The combo box visiblity property
        /// </summary>
        private static readonly DependencyProperty ComboBoxVisiblityProperty =
            DependencyProperty.Register("ComboBoxVisiblity", typeof (Visibility), typeof (SearchUserControl));

        /// <summary>
        /// The text box visiblity property
        /// </summary>
        private static readonly DependencyProperty TextBoxVisiblityProperty =
            DependencyProperty.Register("TextBoxVisiblity", typeof (Visibility), typeof (SearchUserControl));

        /// <summary>
        /// The date picker visiblity property
        /// </summary>
        private static readonly DependencyProperty DatePickerVisiblityProperty =
            DependencyProperty.Register("DatePickerVisiblity", typeof (Visibility), typeof (SearchUserControl));

        #endregion

        #region Public Properties

        /// <summary>
        ///     Gets or sets the type of the search.
        /// </summary>
        /// <value>
        ///     The type of the search.
        /// </value>
        public SearchType SearchType {
            get { return (SearchType) GetValue(SearchTypeProperty); }
            set { SetValue(SearchTypeProperty, value); }
        }

        /// <summary>
        ///     Gets or sets the header text.
        /// </summary>
        /// <value>
        ///     The header text.
        /// </value>
        public string HeaderText {
            get { return (string) GetValue(HeaderTextProperty); }
            set { SetValue(HeaderTextProperty, value); }
        }

        /// <summary>
        /// Gets or sets the available values.
        /// </summary>
        /// <value>
        /// The available values.
        /// </value>
        public IEnumerable<object> AvailableValues {
            get { return (IEnumerable<object>) GetValue(AvailableValuesProperty); }
            set { SetValue(AvailableValuesProperty, value); }
        }

        /// <summary>
        /// Gets or sets the search value.
        /// </summary>
        /// <value>
        /// The search value.
        /// </value>
        public object SearchValue {
            get { return GetValue(SearchValueProperty); }
            set { SetValue(SearchValueProperty, value); }
        }

        #endregion

        #region Private Properties

        /// <summary>
        /// Gets or sets the combo box visiblity.
        /// </summary>
        /// <value>
        /// The combo box visiblity.
        /// </value>
        private Visibility ComboBoxVisiblity {
            get { return (Visibility) GetValue(ComboBoxVisiblityProperty); }
            set { SetValue(ComboBoxVisiblityProperty, value); }
        }

        /// <summary>
        /// Gets or sets the date picker visiblity.
        /// </summary>
        /// <value>
        /// The date picker visiblity.
        /// </value>
        private Visibility DatePickerVisiblity {
            get { return (Visibility) GetValue(DatePickerVisiblityProperty); }
            set { SetValue(DatePickerVisiblityProperty, value); }
        }

        /// <summary>
        /// Gets or sets the text box visiblity.
        /// </summary>
        /// <value>
        /// The text box visiblity.
        /// </value>
        private Visibility TextBoxVisiblity {
            get { return (Visibility) GetValue(TextBoxVisiblityProperty); }
            set { SetValue(TextBoxVisiblityProperty, value); }
        }

        #endregion

        #region Constructor

        /// <summary>
        ///     Initializes a new instance of the <see cref="SearchUserControl" /> class.
        /// </summary>
        public SearchUserControl() {
            InitializeComponent();

            DependencyPropertyDescriptor pd = DependencyPropertyDescriptor.FromProperty(SearchTypeProperty, typeof (SearchUserControl));
            pd.AddValueChanged(this, OnSearchTypePropertyChanged);

            // Initialize default parameters
            SearchType = SearchType.Unknown;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Called when the search type property has changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void OnSearchTypePropertyChanged(object sender, EventArgs e) {

            // Hide all editors
            DatePickerVisiblity = Visibility.Collapsed;
            ComboBoxVisiblity = Visibility.Collapsed;
            TextBoxVisiblity = Visibility.Collapsed;

            // Make the correct editor visible
            switch (SearchType) {
                case SearchType.Date:
                    DatePickerVisiblity = Visibility.Visible;
                    break;
                case SearchType.TextSelection:
                    ComboBoxVisiblity = Visibility.Visible;
                    break;
                case SearchType.Text:
                    TextBoxVisiblity = Visibility.Visible;
                    break;
            }
        }

        #endregion
    }
}

Instantiation of the search controls from the parent control:

        <ribbon:Tab Label="Search">
            <ribbon:Group Padding="0,5,0,5">
                <customcontrols:SearchUserControl x:Name="SearchUserControlCompanyName" HeaderText="company name" Margin="5,0,0,0" SearchType="Text" VerticalAlignment="Center" VerticalContentAlignment="Center" />
                <customcontrols:SearchUserControl x:Name="SearchUserControlCompanyNationality" HeaderText="company nationality (ISO3 code)" Margin="5,0,0,0" SearchType="TextSelection" AvailableValues="{Binding Path=CompaniesViewModel.ISO3Codes}" VerticalAlignment="Center" />
                <customcontrols:SearchUserControl x:Name="SearchUserControlDateFounded" HeaderText="date founded" Margin="5,0,0,0" SearchType="Date" VerticalAlignment="Center" VerticalContentAlignment="Center" />
                <ribbon:Button Context="StatusBarItem" Name="ButtonApplyFilter" Label="Search" ImageSourceSmall="/Resources/search_magnifying_glass_find.png" Margin="5,0,0,0" VerticalAlignment="Center" Click="OnButtonApplyFilterClicked" Command="{Binding Path=ApplyFilterCommand}" ScreenTipHeader="Apply the search filter" VerticalContentAlignment="Center" VariantSize="Large" />
            </ribbon:Group>
        </ribbon:Tab>

In the SearchControl I wanted to display the correct component (textbox, datepicker or combobox) according to the set SearchType. For this the, xxxVisibility dependency properties and properties have been created (they are being set when the SearchTypeProperty notifies a property changed event). As there is no reason to expose them as public (they are being used only inside the SearchControl), I've made them private; MSDN states that bound properties MUST be public though. The project compiles and runs without an issue, but errors are being shown for the bound xxxVisibility properties with the message 'Public member expected' (can't tell if it's visual studio or resharper telling me that).

Is my approach to create this user control correct in respect to the WPF concepts? Should the xxxVisibility properties be public (event though I don't want to expose them)?

4

1 回答 1

4

这是一个很难“回答”的问题,而不仅仅是“评论”。在我个人看来,你UserControl写得很好,据我所知,没有违反任何规则。虽然我认为声明 a 没有任何问题private DependencyProperty,但这不寻常的。在这种情况下,开发人员经常选择public Read Only DependencyProperty用 a来实现 a private DependencyPropertyKey

private static readonly DependencyPropertyKey ComboBoxVisiblityPropertyKey
    = DependencyProperty.RegisterReadOnly("ComboBoxVisiblity", typeof(int), 
    typeof(SearchUserControl), new PropertyMetadata(Visibility.Collapsed));

public static readonly DependencyProperty ComboBoxVisiblityProperty
    = ComboBoxVisiblityPropertyKey.DependencyProperty;

public int ComboBoxVisiblity
{
    get { return (int)GetValue(ComboBoxVisiblityProperty); }
    protected set { SetValue(ComboBoxVisiblityPropertyKey, value); }
}

一些开发人员可能还认为您创建类型属性Visibility而不是bool使用 s 绑定值是不寻常BoolToVisibilityConverter的,但同样……这是您的特权。总的来说,做得很好!:)

于 2013-08-20T11:54:00.680 回答