C# WPF Customcontrol、模板、继承和从属属性

C# WPF Customcontrol、模板、继承和从属属性,c#,wpf,xaml,C#,Wpf,Xaml,我需要创建的自定义控件遇到一些问题。我试着先向你解释我的需要 我需要一个允许一次检查多个项目的组合框(使用复选框),但我希望它足够智能,能够绑定到特定类型 我找到了一些MultiSelectionComboBox,但没有一个能反映我的需要。 顺便说一句,我的主要问题是我希望有一个泛型类 public class BaseClass<T> : BaseClass { public static readonly DependencyProperty ItemsSourcePro

我需要创建的自定义控件遇到一些问题。我试着先向你解释我的需要

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

我找到了一些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
{

}
公共类基类:基类
{
公共静态只读依赖项Property ItemsSourceProperty=
DependencyProperty.Register(“ItemsSource”、typeof(IEnumerable)、typeof(BaseClass)、new FrameworkPropertyMetadata(null、,
新属性ChangedCallback(BaseClass.OnItemSourceChanged));
私有静态资源已更改(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
int i=0;
//MultiSelectComboBox控件=(MultiSelectComboBox)d;
//控件。显示InControl();
}
公共IEnumerable ItemsSource
{
get{return(IEnumerable)GetValue(ItemsSourceProperty);}
设置
{
设置值(ItemsSourceProperty,value);
}
}
}
公共类基类:控件
{
}
还有一个更特定于上下文的项目,例如

public class MultiCurr : BaseClass<Currency>
{
    static MultiCurr()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiCurr), new FrameworkPropertyMetadata(typeof(MultiCurr)));
    }
}
公共类多币种:基类
{
静态多curr()
{
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>

在我的主窗口中,我创建了一个对象作为

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

并且MainWindow.cs定义为

公共部分类主窗口:窗口,INotifyPropertyChanged { 私人货币

    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));
        }
    }
}
public主窗口()
{
初始化组件();
this.DataContext=this;
this.Loaded+=主窗口\u Loaded;
}
已加载无效主窗口(对象发送器、路由目标)
{
var lst=新列表();
对于(int i=0;i<10;i++)
{
var curr=新货币
{
ID=i,
Description=string.Format(“货币{0}”,i)
};
第一次添加(当前);
}
货币=lst;
}
公共货币
{
得到
{
返回此文件。请选择其他货币;
}
设置
{
货币=价值;
通知财产变更(“货币”);
}
}
公共事件属性更改事件处理程序属性更改;
//此方法由每个属性的集合访问器调用。
//应用于可选propertyName的CallerMemberName属性
//参数导致调用方的属性名被替换为参数。
私有void NotifyPropertyChanged(字符串propertyName=“”)
{
if(PropertyChanged!=null)
{
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
}
}
这是结果。。。

我想知道我做错了什么?有没有可能我想要达到什么目的

谢谢

更新#1:

我已经看到,主要问题是定制usercontrol的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>
如果有人想尝试解决方案

谢谢

  • Combobox不适合用于multiselection的控件,因为它提供了一种行为,即当您选择项时,Combobox会自动关闭。这就是为什么Combobox没有像ListBox那样的SelectionMode属性。我认为扩展器中的列表框是您所需要的
  • 泛型类型不是一条出路。WPF以不同、更好的方式处理此问题。以listbox为例。如果您将listbox.itemssource绑定到泛型observable集合,并尝试定义例如ItemTemplate,则在编写绑定时会获得完整的intellisense,如果绑定到不存在的属性,则会发出警告。WPF设计器自动识别可观察集合的类型参数。当然,您需要在页面中指定datacontext的类型,方法如下:
    d:datacontext=“{d:DesignInstance search:AdvancedSearchPageViewModel}”
    。但是,您的控件不必是,并且不应该知道项目的类型
  • 以下示例演示了满足您的要求的控件:

    <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>
    
    
    基础知识
    DEF
    GHI
    JKL
    
    我建议您创建从ListBox派生的控件(不是usercontrol)。
    我有硬编码的数据模板,但您应该在自定义依赖项属性中公开它们,并在控制模板中使用TemplateBinding。当然,您需要修改expander,使其看起来像combobox和ListBoxItem样式,使其看起来像CheckBox,但这很简单。

    在您的控制模板中,使用模板绑定iso binding.is
    Currences
    是一种
    可观察到的集合吗
    ?顺便说一句,你不应该为你的列表设置setter。谢谢你的建议,但就我而言,我90%都在工作。。。combobox工作正常我只是在将ItemsSource从mainview传递到usercontrol时遇到一些问题…顺便说一句,我会看一看,谢谢您需要在usercontrol中创建ItemsSource DependecProperty。数据绑定你的组合框或者类似的东西:Liero如果你看我上面的代码,我已经在样式中定义了一个组合框,我刚刚创建了属性