2013-08-20 3 views
2

Чтобы попасть в мир WPF и привыкнуть к привязкам, я создал пользовательский элемент управления, используемый для определения фильтра поиска. В зависимости от выбранного фильтра пользователь может ввести текст, выбрать дату или выбрать элемент в поле со списком. Вот пример с тремя экземплярами созданного управления поиском, каждый из которых разного типа:Привязки внутри пользовательского элемента управления WPF

Search filter example

Хорошая новость в том, что все работает, но я не уверен, что все было сделано, как предполагалось.

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

Конкретизация управления поиска из родительского контроля:

 <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> 

В SearchControl я хотел для отображения правильного компонента (текстовое поле, датапиксера или выпадающего списка) в соответствии с набором «Море» rchType. Для этого были созданы свойства и свойства зависимостей xxxVisibility (они устанавливаются, когда SearchTypeProperty уведомляет об изменении свойства). Поскольку нет причин раскрывать их как общедоступные (они используются только внутри SearchControl), я сделал их частными; MSDN заявляет, что связанные свойства ДОЛЖНЫ быть общедоступными. Проект компилируется и запускается без каких-либо проблем, но отображаются ошибки для связанных свойств xxxVisibility с сообщением «Ожидаемый публичный член» (не могу сказать, это визуальная студия или resharper, рассказывающая мне об этом).

Является ли мой подход к созданию этого пользовательского элемента управления правильным в отношении концепций WPF? Должны ли свойства xxxVisibility быть общедоступными (событие, хотя я не хочу их раскрывать)?

+1

Как насчет того, чтобы использовать их как «CLR» и внедрять «INPC» в вашем классе? –

+0

Это, вероятно, сделало бы трюк. Понятно, что у меня все еще есть проблема, поскольку публичные события, поднятые через INotifyPropertyChanged.PropertyChanged, предназначены для использования внутри пользовательского элемента управления, но бесполезны для внешнего мира. – Philippe

+2

Связанные свойства должны быть общедоступными. Связывание не работает, что вы можете проверить в окне вывода VS. –

ответ

3

Это очень сложный вопрос для ответа, а не просто комментарий. По моему личному мнению, ваш UserControl написан хорошо, и, насколько я вижу, не нарушает никаких правил. Хотя я не вижу никаких проблем с объявлением privateDependencyProperty, это является необычным. В этой ситуации разработчики часто решили реализовать publicRead Only DependencyProperty с privateDependencyPropertyKey вместо:

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 значения с BoolToVisibilityConverter с , но опять же ... это ваша прерогатива. В целом, молодец! :)

+0

Спасибо :) Извините за «неопределенный» вопрос, я хотел проверить, не сделал ли я что-то принципиально неправильно. Я выбрал свойство Visibility, чтобы избежать дополнительного конвертера видимости bool-> :) – Philippe

Смежные вопросы