2016-01-27 4 views
0

Я создал пользовательский элемент управления, FontSelector, который объединяет ComboBox для выбора FontFamily и три параметра ToggleButtons для жирных, курсивных, подчеркнутых параметров. У меня возникла проблема с свойством SelectedItem ComboBox, затрагивающим все экземпляры этого элемента управления пользователя в том же окне. Например, изменение выбора ComboBox на одном, автоматически изменит другое. Для ясности. Я не хочу этого поведения. Я очень удивлен тем, что пользовательский контроль неявно влияет на другой элемент управления пользователя.Пользовательские элементы управления дочерними элементами Значение для нескольких экземпляров

XAML

<Grid x:Name="Grid" Background="White" DataContext="{Binding RelativeSource={RelativeSource AncestorType=local:FontSelector}}">   
    <ComboBox x:Name="comboBox" Width="135" 
       SelectedItem="{Binding Path=SelectedFontFamily}" Style="{StaticResource FontChooserComboBoxStyle}" 
           ItemsSource="{Binding Source={StaticResource SystemFontFamilies}}"/> 
</Grid> 

Код За

Среда CLR недвижимости, что SelectedItem в ComboBox является привязано. Код, показанный здесь, находится в коде управления пользователя позади файла, а не в ViewModel.

 private FontFamily _SelectedFontFamily; 
    public FontFamily SelectedFontFamily 
    { 
     get 
     { 
      return _SelectedFontFamily; 
     } 
     set 
     { 
      if (_SelectedFontFamily != value) 
      { 
       _SelectedFontFamily = value; 

       // Modify External Dependency Property Value. 
       if (value != SelectedFont.FontFamily) 
       { 
        SelectedFont = new Typeface(value, GetStyle(), GetWeight(), FontStretches.Normal); 
       } 

       // Notify. 
       RaisePropertyChanged(nameof(SelectedFontFamily)); 
      } 
     } 
    } 

Зависимость от недвижимости, которая обновляет это значение, основанное на значении в ComboBox в SelectedItem собственности. Он эффективно упаковывает значение FontFamily в объект Typeface.

public Typeface SelectedFont 
    { 
     get { return (Typeface)GetValue(SelectedFontProperty); } 
     set { SetValue(SelectedFontProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for SelectedFont. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty SelectedFontProperty = 
     DependencyProperty.Register("SelectedFont", typeof(Typeface), typeof(FontSelector), 
      new FrameworkPropertyMetadata(new Typeface("Arial"), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, 
       new PropertyChangedCallback(OnSelectedFontPropertyChanged))); 

    private static void OnSelectedFontPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var instance = d as FontSelector; 
     var newFont = e.NewValue as Typeface; 

     if (newFont != null) 
     { 
      instance.SelectedFontFamily = newFont.FontFamily; 

     } 
    } 

EDIT

Я думаю, что я, возможно, понял, что происходит. Я могу воспроизвести его, привязав ItemsSource к следующему источнику просмотра коллекции.

<CollectionViewSource x:Key="SystemFontFamilies" Source="{Binding Source={x:Static Fonts.SystemFontFamilies}}"> 
     <CollectionViewSource.SortDescriptions> 
      <scm:SortDescription PropertyName="Source"/> 
     </CollectionViewSource.SortDescriptions> 
    </CollectionViewSource> 

Вы можете повторить поведение путем размещения 2 ComboBoxes и привязка их обоих к CollectionViewSource. Теперь они, казалось бы, неявно отслеживают друг друга SelectedItem. Даже без привязки данных за пределами ItemsSource. Казалось бы, CollectionViewSource каким-то образом играет роль в том, что такое SelectedItem.

+1

Является ли свойство 'SelectedFontFamily' у вас ViewModel? Может быть, когда один UC обновит его, свойство обновит другие UC. –

+0

Забыл упомянуть. Я не использую View Model для этого конкретного элемента управления. Источник привязки реализован в Code Behind File. Я решил не использовать виртуальную машину для этого, потому что, казалось, было много дополнительной работы, чтобы вернуть данные, сгенерированные VM, в свойство Dependency в фактическом коде управления пользователя. –

+0

Я думаю, вопрос в том, что вы привязываете свойство SelectedFontFamily в окне. Потому что тогда изменение в одном элементе обновит форму модели формы, которая, в свою очередь, обновит другие элементы управления. – Geoffrey

ответ

1

Я бы сделал это немного иначе. Я представлю это решение, используя только String, а не FontFamily или FontWeight, так как у меня здесь нет VS. (Для того, чтобы он работал, пожалуйста, измените список FontFamilies в список строк, чтобы связать их.)

Ваш UserControl селектор:
- ваш xaml нормально (но вы не будете нуждаться в x:Name)
- CodeBehind of UserControl (позже: UC) должен измениться, мы разрешим его с привязкой.Вы должны иметь DependencyProperty, позволяет назвать это SelectedFontFamily, который будет представлять выбранную строку из ComboBox:

public string SelectedFontFamily 
{ 
    get { return (string)GetValue(SelectedFontFamilyProperty); } 
    set { SetValue(SelectedFontFamilyProperty, value); } 
} 

public static readonly DependencyProperty SelectedFontFamilyProperty = DependencyProperty.Register("SelectedFontFamily", typeof(string), typeof(YourUC), new PropertyMetadata(string.Empty)); 

окно, которое содержит UC:
- Вы должны включать пространство имен папка УНЦ в открывающем теге окна, например:

<Window 
... 
xmlns:view="clr-namespace:YourProjectName.Views.UserControls"> 

- DataContext окна должен иметь свойство с общественным набором опцией (не стесняйтесь implemen т INotifyPropertyChange на него):

public string FontFamily {get; set;} 

- в XAML окна вы будете использовать УНЦ таким образом:

<view:YourUC SelectedFontFamily="{Binding FontFamily, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 

Это двухстороннее связывание. Вы увидите выбранную строку как значение свойства FontFamily каждый раз, когда вы меняете SelectedItem.

Редактировать: вам понадобится класс Model Model для окна, использующего UserControl. Создайте его, внесите в него интерфейс INotifyPropertyChanged и установите его как DataContext для вашего потребительского окна. WPF не похож на WF, вы можете найти больше об этом, если у вас Google «WPF MVVM» или что-то в этом роде.

0

Обнаружена проблема. Я был привязан к CollectionViewSource, определенному в Ресурсах приложений. До сих пор я не знал, что привязка к CollectionViewSource также повлияет на SelectedItem. Данные SelectedItem сохраняются как часть CollectionViewSource. Установка свойства IsSynchronizedWithCurrentItem для False в ComboBox решила проблему.

existing answer У меня есть Найдено.

Thanks

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