2015-10-09 37 views
3

方案Silverlight的扶養屬性沒有在自定義控件

通知我有一個自定義組合框,在那裏我有在下拉列表框中選擇一個標籤。我需要改變標籤,正如我在第二張圖片中注意到的那樣。但是我只想通過選中複選框來選擇項目。我可以選擇多個項目,因此標籤應該更新爲選定項目的逗號分隔值。如果沒有足夠的空間顯示標籤的全文,則應該有「...」符號表示在組合框中選擇了更多項目。

enter image description here

我通過繼承文本框控件,我做的依賴屬性的回調事件的所有更改創建的自定義標籤。 (檢查自定義文本框代碼)

現在的問題是,在更改視圖模型中的有界屬性時,自定義文本框控件中的回調事件不會觸發(我正在通過將值添加到可觀察集合在檢查事件複選框後面的代碼中,請檢查複選框事件代碼)。

我可以看到,第一次當我在視圖模型的線由斷點在「吸氣劑」的「SelectedFilterResources」部分命中加載默認數據。但我從來沒有在房產的二傳手部分受到打擊。

自定義文本框

自定義文本框具有「CaptionCollectionChanged」回調事件。這是我有全部邏輯來實現我的場景的地方。 「資源項目」這裏是一個類型的模型。

public class ResourceSelectionBoxLable : TextBox 
    { 
     public override void OnApplyTemplate() 
     { 
     base.OnApplyTemplate(); 
     IsReadOnly = true; 
     } 


     public static List<ResourceItem> LocalFilterdResources = new List<ResourceItem>(); 

     #region Dependancy Properties 

     public static readonly DependencyProperty FilterdResourcesProperty = 
      DependencyProperty.Register("SelectedFilterdResources", 
       typeof (ObservableCollection<ResourceItem>), 
       typeof (ResourceSelectionBoxLable), 
       new PropertyMetadata(new ObservableCollection<ResourceItem>(), 
        CaptionCollectionChanged)); 

     public ObservableCollection<ResourceItem> SelectedFilterdResources 
     { 
      get 
      { 
       return 
       (ObservableCollection<ResourceItem>) GetValue(FilterdResourcesProperty); 
      } 
      set 
      { 
       SetValue(FilterdResourcesProperty, value); 
       LocalFilterdResources = new List<ResourceItem>(SelectedFilterdResources); 
      } 
     } 

     #endregion 

     private static void CaptionCollectionChanged(DependencyObject d, 
      DependencyPropertyChangedEventArgs e) 
     { 
      var resourceSelectionBoxLable = d as ResourceSelectionBoxLable; 
      if (resourceSelectionBoxLable != null) 
      { 
       if (LocalFilterdResources.Count <= 0) 
       { 
        resourceSelectionBoxLable.Text = "Resources" 
       } 
       else 
       { 
        var actualwidthOflable = resourceSelectionBoxLable.ActualWidth; 
        var newValue = e.NewValue as string; 

        //Get the Wdith of the Text in Lable 
        TextBlock txtMeasure = new TextBlock(); 
        txtMeasure.FontSize = resourceSelectionBoxLable.FontSize; 
        txtMeasure.Text = newValue; 
        double textwidth = txtMeasure.ActualWidth; 

        //True if Text reach the Limit 
        if (textwidth > actualwidthOflable) 
        { 
         var appendedString = string.Join(", ", 
          LocalFilterdResources.Select(item => item.ResourceCaption) 
           .ToArray()); 
         resourceSelectionBoxLable.Text = appendedString; 
        } 
        else 
        { 
         if (LocalFilterdResources != null) 
         { 
          var morestring = string.Join(", ", 
           (LocalFilterdResources as IEnumerable<ResourceItem>).Select(item => item.ResourceCaption) 
            .ToArray()); 

          var subsring = morestring.Substring(0, Convert.ToInt32(actualwidthOflable) - 4); 
          resourceSelectionBoxLable.Text = subsring + "..."; 
         } 
        } 
       } 
      } 
     } 
    } 

自定義組合框。

這是我用上面的自定義標籤的控制。這也是一個自定義控件,因此此控件中的大多數屬性和樣式都是自定義的。 「DPItemSlectionBoxTemplate」是一個依賴屬性,我通過添加附加屬性來控制模板使組合框的選擇框。這個控制工作正常,因爲我在我的系統中的其他地方使用這個控件用於不同的目的。

    <styles:CommonMultiComboBox 
           x:Name="Resourcescmb" IsEnabled="{Binding IsResourceComboEnable,Mode=TwoWay}" 
           IsTabStop="False" 
           > 

         <styles:CommonMultiComboBox.ItemDataTemplate> 
          <DataTemplate> 
           <CheckBox IsChecked="{Binding IsSelect, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Click="CheckBox_Click" 
              Content="{Binding ResourceCaption}" 
              Style="{StaticResource CommonCheckBoxStyle}" 
              Tag ="{Binding}" 
              Checked="Resource_ToggleButton_OnChecked" /> 
          </DataTemplate> 
         </styles:CommonMultiComboBox.ItemDataTemplate> 

         <styles:CommonMultiComboBox.DPItemSlectionBoxTemplate> 
          <DataTemplate> 
           <filtersTemplate:ResourceSelectionBoxLable 
            Padding="0" 
            Height="15" 
            FontSize="10" 
            SelectedFilterdResources="{Binding DataContext.FilterdResources,ElementName=root ,Mode=TwoWay}" /> 

          </DataTemplate> 
         </styles:CommonMultiComboBox.DPItemSlectionBoxTemplate> 
        </styles:CommonMultiComboBox> 

視圖模型

private ObservableCollection<ResourceItem> _resourceItems; 
     public ObservableCollection<ResourceItem> FilterdResources 
     { 
      get { return _resourceItems; } 
      set 
      { 
       SetOnChanged(value, ref _resourceItems, "FilterdResources"); 
      } 
     } 

觀的構造模式

FilterdResources=new ObservableCollection<ResourceItem>(); 

「SetOnChanged」是在視圖模型基類,我們有一個方法inotify的性質的實現。

複選框事件

private void Resource_ToggleButton_OnChecked(object sender, RoutedEventArgs e) 
     { 

      var senderControl = sender as CheckBox; 
      if(senderControl==null) 
       return; 

      var selectedContent=senderControl.Tag as ResourceItem; 

      if (selectedContent != null) 
      { 
        ViewModel.FilterdResources.Add(selectedContent); 

      } 
} 

我可以從後面的代碼通過視圖模型屬性訪問視圖模型。

爲什麼在更改有界值時沒有通知回調事件?我在這裏錯過了什麼嗎?依賴屬性應該適用於雙向綁定,不是嗎?任何人都可以幫我解決這個問題嗎?

在此先感謝。

+1

我注意到有一些問題可能會咬你一天,我想讓你知道:1.你設置「SelectedFilterdResources」的默認值的方式[原文如此]依賴項屬性創建一個意外的單身人士。 2.我會堅持按照慣例命名依賴屬性,就像靜態DP背景一樣。 3.不要將代碼放在DP的setter中,它不會被綁定引擎調用,而是使用propertyChangedCallback。 – Martin

+0

@ Martin.Thanks。 Yap我從Setter中移動代碼來回調event.Can你可以更多地解釋一下SelectedFilterdResources如何無意中創建Singleton? – Thabo

+1

靜態的backingfield只允許靜態的東西(也就是所有的實例都一樣)與它相關聯。因此,作爲默認值創建的收集實例在所有實例中共享,因此是單例。改爲使用構造函數,您可以將新創建​​的集合實例指定爲DP中的默認值。 – Martin

回答

1

看起來像您的問題是,當綁定集合發生更改(即添加或刪除的項目)時,您期望觸發事件觸發事件。事實上,只有當您更改綁定對象的實例時,該事件纔會觸發。

你需要在這裏做的是訂閱的ObservableCollectionCollectionChanged在二傳手或更改回調事件 - 你的依賴屬性的(你已經有CaptionCollectionChanged)。

public static readonly DependencyProperty FilterdResourcesProperty = 
     DependencyProperty.Register("SelectedFilterdResources", 
      typeof (ObservableCollection<ResourceItem>), 
      typeof (ResourceSelectionBoxLable), 
      new PropertyMetadata(new ObservableCollection<ResourceItem>(), 
       CaptionCollectionChanged)); 


private static void CaptionCollectionChanged(DependencyObject d, 
     DependencyPropertyChangedEventArgs args) 
    { 
     var collection = args.NewValue as INotifyCollectionChanged; 
     if (collection != null) 
     { 
      var sender = d as ResourceSelectionBoxLable; 
      if (sender != null) 
      { 
       collection.CollectionChanged += sender.BoundItems_CollectionChanged; 
      }     
     } 
    } 

    private void BoundItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     // Do your control logic here. 
    } 

不要忘記添加清理邏輯 - 在收集實例更改時取消訂閱集合更改等。

+0

。謝謝。現在,當我更改有界列表時,我可以收到通知。 – Thabo