用户控制子元素跨多个实例共享值

时间:2016-01-27 11:17:52

标签: c# wpf data-binding combobox

我制作了一个用户控件FontSelector,它将用于FontFamily Selection的ComboBox和用于粗体,斜体,下划线选项的三个ToggleButtons组合在一起。我遇到了ComboBox的SelectedItem属性的问题,该属性影响同一Window中该用户控件的所有实例。例如,在一个上更改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>

代码背后

ComboBox的SelectedItem所绑定的CLR属性。此处显示的代码位于文件后面的用户控制代码中,而不是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值打包到一个字体对象中。

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;

        }
    }

修改

我想我可能已经知道发生了什么。我可以通过将ItemsSource绑定到以下集合视图源来复制它。

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

然后,您可以通过放置2个ComboBox并将它们绑定到CollectionViewSource来复制行为。他们现在,似乎隐含地跟踪彼此SelectedItem。即使没有ItemsSource之外的任何数据绑定。似乎CollectionViewSource以某种方式参与了SelectedItem的作用。

2 个答案:

答案 0 :(得分:1)

我让它有点不同。我将仅使用String而不是FontFamily或FontWeight来介绍此解决方案,因为我现在没有VS。 (为了让它工作,请将FontFamilies列表更改为绑定它们的字符串列表。)

您的选择器UserControl:
- 您的xaml没问题(但您不会需要x:Name
- UserControl的CodeBehind(后来: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:
- 您应该在窗口的开始标记中包含UC文件夹的命名空间,例如:

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

- 窗口的DataContext应该有一个带有公共设置选项的属性(随意在其上实现INotifyPropertyChange):

public string FontFamily {get; set;}

- 在Window的xaml中,你会以这种方式使用UC:

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

这是一种双向约束。每次更改SelectedItem时,您都会找到所选字符串作为FontFamily属性的值。

编辑:您将需要使用UserControl的Window的View Model类。创建它,使其实现INotifyPropertyChanged接口,并将其设置为消费者窗口的DataContext。 WPF与WF不同,如果您支持Google,那么您可以找到更多相关信息。 WPF MVVM &#34;或类似的东西。

答案 1 :(得分:0)

发现问题。我绑定到Application Resources中定义的CollectionViewSource。到目前为止,我还没有意识到绑定到CollectionViewSource也会影响SelectedItem。 SelectedItem数据存储为CollectionViewSource的一部分。在ComboBox上将IsSynchronizedWithCurrentItem属性设置为False解决了这个问题。

这是我现在找到的existing answer

由于