WPF Customcontrol,Templates,Inheritance和Dependencyproperties

时间:2015-03-12 08:07:58

标签: c# wpf xaml

我遇到了一些我需要创建的自定义控件的麻烦。我试着先解释你的需求

我需要一个组合框允许一次检查多个项目(带复选框),但我希望它能够智能地绑定到特定类型。

我找到了一些MultiSelectionComboBox,但没有一个能反映我的需求。 顺便说一句我的主要问题是我希望有一个通用类

public class BaseClass<T> : BaseClass
{
    public static readonly DependencyProperty ItemsSourceProperty =
      DependencyProperty.Register("ItemsSource", typeof(IEnumerable<T>), typeof(BaseClass<T>), new FrameworkPropertyMetadata(null,
 new PropertyChangedCallback(BaseClass<T>.OnItemsSourceChanged)));

    private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        int i = 0;
        //MultiSelectComboBox control = (MultiSelectComboBox)d;
        //control.DisplayInControl();
    }

    public IEnumerable<T> ItemsSource
    {
        get { return (IEnumerable<T>)GetValue(ItemsSourceProperty); }
        set
        {
            SetValue(ItemsSourceProperty, value);
        }
    }
}

public class BaseClass : Control
{

}

以及更具上下文的项目,例如

public class MultiCurr : BaseClass<Currency>
{
    static MultiCurr()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiCurr), new FrameworkPropertyMetadata(typeof(MultiCurr)));
    }
}

在我的App.xaml中,我将资源定义为

 <ResourceDictionary>
        <Style TargetType="local:MultiCurr">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:MultiCurr">
                        <ComboBox Width="120" Background="Red" Height="30" ItemsSource="{Binding ItemsSource}" DisplayMemberPath="Description" ></ComboBox>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>

在我的MainWindow中,我创建了一个对象

<Grid>
    <local:MultiCurr x:Name="test" ItemsSource="{Binding Currencies}"></local:MultiCurr>
</Grid>

,MainWindow.cs定义为

public partial class MainWindow:Window,INotifyPropertyChanged     {         私人IList货币;

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
        this.Loaded += MainWindow_Loaded;
    }

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        var lst = new List<Currency>();
        for (int i = 0; i < 10; i++)
        {
            var curr = new Currency
            {
                ID = i,
                Description = string.Format("Currency_{0}", i)
            };

            lst.Add(curr);
        }

        Currencies = lst;
    }
    public IList<Currency> Currencies
    {
        get
        {
            return this.currencies;
        }
        set
        {
            this.currencies = value;
            NotifyPropertyChanged("Currencies");

        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    // This method is called by the Set accessor of each property.
    // The CallerMemberName attribute that is applied to the optional propertyName
    // parameter causes the property name of the caller to be substituted as an argument.
    private void NotifyPropertyChanged(String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

这是结果...... The result is this one

我想知道我做错了什么?我有什么可能实现的目标?

由于

更新#1:

我已经看到主要问题是自定义用户控件的datacontext

  <Application.Resources>
    <ResourceDictionary>
        <Style TargetType="local:MultiCurr">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:MultiCurr">
                        <ComboBox Width="120" Background="Red" Height="30" ItemsSource="{Binding **Currencies**}" DisplayMemberPath="{Binding **DisplayMemeberPath**}" ></ComboBox>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>
</Application.Resources>

如果我将ItemsSource作为货币(它是MainWindow的一个属性),它会显示。 如果我把ItemsSource和DisplayMemberPath(在BaseClass中定义没有..我怎样才能将usercontrol的上下文设置为自己?)

更新#2 如果有人想尝试解决方案,我已经为项目here添加了GoogleDrive链接

由于

1 个答案:

答案 0 :(得分:1)

  1. Combobox不适合多选的控制,因为它给出了行为,当你选择项目时,Combobox自行关闭。这就是为什么Combobox没有像ListBox那样具有SelectionMode属性的原因。我认为扩展器中的 ListBox是你需要的
  2. 通用类型不是一种方法。 WPF处理这种不同的,更好的方式。以列表框为例。如果将listbox.itemssource绑定到泛型可观察集合,并尝试定义例如ItemTemplate,则在编写绑定时会获得完整的智能感知,如果绑定到不存在的属性,则会发出警告。 http://visualstudiomagazine.com/articles/2014/03/01/~/media/ECG/visualstudiomagazine/Images/2014/03/Figure8.ashx WPF设计器自动识别可观察集合的类型参数。您需要使用以下内容指定页面中的datacontext类型:d:DataContext="{d:DesignInstance search:AdvancedSearchPageViewModel}"。但是你的控制不必是,并且不应该知道项目的类型
  3. 以下示例演示了符合您要求的控件:

    <Expander>
        <Expander.Header>
            <ItemsControl ItemsSource="{Binding ElementName=PART_ListBox, Path=SelectedItems}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock>
                            <Run Text="{Binding Mode=OneWay}" />
                            <Run Text=";" />
                        </TextBlock>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </Expander.Header>
        <Expander.Content>
            <ListBox x:Name="PART_ListBox" SelectionMode="Multiple">
                <ListBox.ItemsSource>
                    <x:Array Type="system:String">
                        <system:String>ABC</system:String>
                        <system:String>DEF</system:String>
                        <system:String>GHI</system:String>
                        <system:String>JKL</system:String>
                    </x:Array>
                </ListBox.ItemsSource>
            </ListBox>
        </Expander.Content>
    </Expander>
    

    我建议您创建从ListBox派生的控件(而不是usercontrol)。 我有硬编码的datatemplates,但您应该在自定义依赖项属性中公开它们,并在控件模板中使用TemplateBinding。当然你需要修改扩展器,使它看起来像combobox和ListBoxItem样式,所以它看起来像CheckBox,但它很容易。