WPF简单绑定问题

发布于 2024-09-10 18:15:35 字数 7306 浏览 6 评论 0原文

试图了解WPF的这个绑定过程。

请参阅底部的代码。

在我的“viewmodel”中,请参阅底部的代码,我有一个可观察的集合,它正在用项目填充列表视图。那是包含一个名为“符号”的路径的路径,用于在组合框中设置选定的索引。现在我的问题是,我需要先从另一个列表填充组合框,然后再将其添加到列表视图(一些默认值)。 由于我刚刚开始使用 WPF,我认为也许您可以在同一个类中使用 2 个不同的 ObservableCollections 来实现此目的,但这不起作用。那么,在绑定/添加到列表视图之前,如何使用默认值填充数据模板?

这是我用来填充列表视图的内容,请参阅底部的 viewmodelcontacts。

我还尝试添加另一个带有新的可观察集合的类,我可以在组合框中使用它,但我也没有让它工作。 应填充的数据来自作为我的应用程序中的资源的 XML 文件。

还有一个问题,可以给图片添加命令吗?或者命令只能从继承自 Button_base 类的控件中使用?我想在元素旁边使用图像,当用户单击该图像时,他们将删除该元素。

  • 从下面的答案来看,是否可以不添加按钮,因为我不想要按钮的感觉(例如悬停和单击时)*

Window.xaml:

<r:RibbonWindow x:Class="Onyxia_KD.Windows.ContactWorkspace"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:r="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"        
    Title="Contact card" ResizeMode="NoResize" Height="600" Width="600"
    Background="White">
<r:RibbonWindow.Resources>
    <DataTemplate x:Key="cardDetailFieldTemplate">
        <TextBox Text="{Binding Path=Field}" MinWidth="150"></TextBox>
    </DataTemplate>
    <DataTemplate x:Key="cardDetailValueTemplate">
        <TextBox Text="{Binding Path=Value}" MinWidth="150"></TextBox>
    </DataTemplate>
    <DataTemplate x:Key="cardDetailSymbolTemplate">
         <!-- Here is the problem. Populating this with some default values for each entry  before the selectedIndex is bound from the datasource -->
        <ComboBox SelectedIndex="{Binding Path=Symbol}" DataContext="_vmSettings" ItemsSource="{Binding Symbols}" Grid.Column="1" Margin="0,0,10,0" VerticalAlignment="Center" HorizontalAlignment="Center">
            <ListViewItem Padding="0,3,0,3" Content="{Binding Path=Value}" />                                    
        </ComboBox>
    </DataTemplate>
    <DataTemplate x:Key="cardDetailCategoryTemplate">
        <ComboBox SelectedIndex="{Binding Path=Category}" Grid.Column="1" Margin="0,0,10,0" VerticalAlignment="Center" HorizontalAlignment="Center">
            <!--same as the combobox above but categories instead of symbols-->                
        </ComboBox>
    </DataTemplate>
</r:RibbonWindow.Resources>
...
<ListView ItemsSource="{Binding ContactData}" Foreground="Black" SelectionMode="Single" x:Name="cardDetailList" KeyDown="cardDetailList_KeyDown">
                    <ListView.View>
                        <GridView>
                            <GridViewColumn Header="Category" Width="auto" CellTemplate="{StaticResource cardDetailCategoryTemplate}"></GridViewColumn>
                            <GridViewColumn Header="Field" Width="auto" CellTemplate="{StaticResource cardDetailFieldTemplate}"></GridViewColumn>
                            <GridViewColumn Header="Symbol" Width="70" CellTemplate="{StaticResource cardDetailSymbolTemplate}"></GridViewColumn>
                            <GridViewColumn Header="Value" Width="auto" CellTemplate="{StaticResource cardDetailValueTemplate}"></GridViewColumn>                                
                        </GridView>
                    </ListView.View>                        
                </ListView>

背后的代码:

    private ViewModelContacts _vm;  

    public ContactWorkspace()
    {
        InitializeComponent();

        _vm = new ViewModelContacts();            
        this.DataContext = _vm;

    }

    private void Run_MouseUp(object sender, MouseButtonEventArgs e)
    {
        _vm.AddNewDetail();
    }

    private void Image_MouseUp(object sender, MouseButtonEventArgs e)
    {
        _vm.AddNewDetail();
    }

    private void cardDetailList_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Delete)
        {
            if (MessageBox.Show("Are you sure that you want to delete this?", "Warning!", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
            {
                _vm.RemoveDetail(cardDetailList.SelectedIndex);
            }
        }
    }

ViewModelContacts:

public ObservableCollection<ContactCardData> ContactData { get; set; }               

    public ViewModelContacts()
    {

        ContactData = new ObservableCollection<ContactCardData>();            
        Populate();
    }

    private void Populate()
    {
        ContactData.Add(new ContactCardData("Test", 0, 0, "Value123"));
        ContactData.Add(new ContactCardData("Test2", 1, 1, "Value1234"));
        ContactData.Add(new ContactCardData("Test3", 2, 2, "Value1235"));
        ContactData.Add(new ContactCardData("Test4", 3, 3, "Value12356"));            
    }

    public void UpdateNode()
    {
        ContactData.ElementAt(0).Value = "Giraff";
    }

    public void AddNewDetail()
    {
        ContactData.Add(new ContactCardData());
    }

    public void RemoveDetail(int position)
    {
        ContactData.RemoveAt(position);
    }

ViewModelContactData:

public class ContactCardData : DependencyObject
{
    public int Category
    {
        get { return (int)GetValue(CategoryProperty); }
        set { SetValue(CategoryProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Category.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CategoryProperty =
        DependencyProperty.Register("Category", typeof(int), typeof(ContactCardData), new UIPropertyMetadata(0));

    public string Field
    {
        get { return (string)GetValue(FieldProperty); }
        set { SetValue(FieldProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Field.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FieldProperty =
        DependencyProperty.Register("Field", typeof(string), typeof(ContactCardData), new UIPropertyMetadata(""));

    public string Value
    {
        get { return (string)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(string), typeof(ContactCardData), new UIPropertyMetadata(""));

    public int Symbol
    {
        get { return (int)GetValue(SymbolProperty); }
        set { SetValue(SymbolProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Symbol.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SymbolProperty =
        DependencyProperty.Register("Symbol", typeof(int), typeof(ContactCardData), new UIPropertyMetadata(0));

    public ContactCardData()
    {
    }

    public ContactCardData(string field, int category, int symbol, string value)
    {
        this.Symbol = symbol;
        this.Category = category;
        this.Field = field;
        this.Value = value;
    }
}

Trying to understand this binding process of the WPF.

See the code at the bottom.

In my "viewmodel", see the code at the bottom, i have an observable collection that is populating the listview with the items. Thats the one that contains a path called symbol to set the selected index in the combobox. Now my problem is that i need to populate the combobox from another list before its added to the listview (some default values).
Since i just started with WPF i thought that perhaps you can use 2 different ObservableCollections in the same class to achieve this but that didn't work. So how can i populate the datatemplate with the default values before they are bound/added to the listview?

This is what i use to populate the listview, see the viewmodelcontacts at the bottom.

I also tried to add another class with a new observablecollection that i could use in my combobox, but i didn't get that to work either.
The data that should be populated comes from a XML file located as a resource in my app.

Another question, is it possible to add commands to images? or are commands only available from controls that inherit from the button_base class? I wanted to use an image next to an element and when the user clicked on that image they would remove the element.

  • From the answer below, is it possible without adding a button since i don't want the button feeling (for instance when hovering and clicking)*

Window.xaml:

<r:RibbonWindow x:Class="Onyxia_KD.Windows.ContactWorkspace"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:r="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"        
    Title="Contact card" ResizeMode="NoResize" Height="600" Width="600"
    Background="White">
<r:RibbonWindow.Resources>
    <DataTemplate x:Key="cardDetailFieldTemplate">
        <TextBox Text="{Binding Path=Field}" MinWidth="150"></TextBox>
    </DataTemplate>
    <DataTemplate x:Key="cardDetailValueTemplate">
        <TextBox Text="{Binding Path=Value}" MinWidth="150"></TextBox>
    </DataTemplate>
    <DataTemplate x:Key="cardDetailSymbolTemplate">
         <!-- Here is the problem. Populating this with some default values for each entry  before the selectedIndex is bound from the datasource -->
        <ComboBox SelectedIndex="{Binding Path=Symbol}" DataContext="_vmSettings" ItemsSource="{Binding Symbols}" Grid.Column="1" Margin="0,0,10,0" VerticalAlignment="Center" HorizontalAlignment="Center">
            <ListViewItem Padding="0,3,0,3" Content="{Binding Path=Value}" />                                    
        </ComboBox>
    </DataTemplate>
    <DataTemplate x:Key="cardDetailCategoryTemplate">
        <ComboBox SelectedIndex="{Binding Path=Category}" Grid.Column="1" Margin="0,0,10,0" VerticalAlignment="Center" HorizontalAlignment="Center">
            <!--same as the combobox above but categories instead of symbols-->                
        </ComboBox>
    </DataTemplate>
</r:RibbonWindow.Resources>
...
<ListView ItemsSource="{Binding ContactData}" Foreground="Black" SelectionMode="Single" x:Name="cardDetailList" KeyDown="cardDetailList_KeyDown">
                    <ListView.View>
                        <GridView>
                            <GridViewColumn Header="Category" Width="auto" CellTemplate="{StaticResource cardDetailCategoryTemplate}"></GridViewColumn>
                            <GridViewColumn Header="Field" Width="auto" CellTemplate="{StaticResource cardDetailFieldTemplate}"></GridViewColumn>
                            <GridViewColumn Header="Symbol" Width="70" CellTemplate="{StaticResource cardDetailSymbolTemplate}"></GridViewColumn>
                            <GridViewColumn Header="Value" Width="auto" CellTemplate="{StaticResource cardDetailValueTemplate}"></GridViewColumn>                                
                        </GridView>
                    </ListView.View>                        
                </ListView>

Code behind:

    private ViewModelContacts _vm;  

    public ContactWorkspace()
    {
        InitializeComponent();

        _vm = new ViewModelContacts();            
        this.DataContext = _vm;

    }

    private void Run_MouseUp(object sender, MouseButtonEventArgs e)
    {
        _vm.AddNewDetail();
    }

    private void Image_MouseUp(object sender, MouseButtonEventArgs e)
    {
        _vm.AddNewDetail();
    }

    private void cardDetailList_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Delete)
        {
            if (MessageBox.Show("Are you sure that you want to delete this?", "Warning!", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
            {
                _vm.RemoveDetail(cardDetailList.SelectedIndex);
            }
        }
    }

ViewModelContacts:

public ObservableCollection<ContactCardData> ContactData { get; set; }               

    public ViewModelContacts()
    {

        ContactData = new ObservableCollection<ContactCardData>();            
        Populate();
    }

    private void Populate()
    {
        ContactData.Add(new ContactCardData("Test", 0, 0, "Value123"));
        ContactData.Add(new ContactCardData("Test2", 1, 1, "Value1234"));
        ContactData.Add(new ContactCardData("Test3", 2, 2, "Value1235"));
        ContactData.Add(new ContactCardData("Test4", 3, 3, "Value12356"));            
    }

    public void UpdateNode()
    {
        ContactData.ElementAt(0).Value = "Giraff";
    }

    public void AddNewDetail()
    {
        ContactData.Add(new ContactCardData());
    }

    public void RemoveDetail(int position)
    {
        ContactData.RemoveAt(position);
    }

ViewModelContactData:

public class ContactCardData : DependencyObject
{
    public int Category
    {
        get { return (int)GetValue(CategoryProperty); }
        set { SetValue(CategoryProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Category.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CategoryProperty =
        DependencyProperty.Register("Category", typeof(int), typeof(ContactCardData), new UIPropertyMetadata(0));

    public string Field
    {
        get { return (string)GetValue(FieldProperty); }
        set { SetValue(FieldProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Field.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FieldProperty =
        DependencyProperty.Register("Field", typeof(string), typeof(ContactCardData), new UIPropertyMetadata(""));

    public string Value
    {
        get { return (string)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(string), typeof(ContactCardData), new UIPropertyMetadata(""));

    public int Symbol
    {
        get { return (int)GetValue(SymbolProperty); }
        set { SetValue(SymbolProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Symbol.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SymbolProperty =
        DependencyProperty.Register("Symbol", typeof(int), typeof(ContactCardData), new UIPropertyMetadata(0));

    public ContactCardData()
    {
    }

    public ContactCardData(string field, int category, int symbol, string value)
    {
        this.Symbol = symbol;
        this.Category = category;
        this.Field = field;
        this.Value = value;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

别忘他 2024-09-17 18:15:35

如下定义您的 Window 类(稍后将进行解释):

<Window x:Class="TestCustomTab.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:TestCustomTab="clr-namespace:TestCustomTab" Title="Window1" Height="300" Width="300">
        <Window.Resources>
            <DataTemplate x:Key="workingTemplate">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" Text="{Binding Name}"/>
                    <ComboBox Grid.Column="1" SelectedIndex="0" ItemsSource="{Binding Symbols}">
                        <ComboBox.ItemTemplate>
                            <DataTemplate>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <Ellipse Grid.Column="0" Fill="Red" Height="5" Width="5"/>
                                    <TextBlock Grid.Column="1" Text="{Binding}" />
                                </Grid>
                            </DataTemplate>
                        </ComboBox.ItemTemplate>
                    </ComboBox>
                </Grid>
            </DataTemplate>

            <DataTemplate x:Key="personalTemplate">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" Text="{Binding Name}"/>
                    <ComboBox Grid.Column="1" SelectedIndex="0" ItemsSource="{Binding Symbols}">
                        <ComboBox.ItemTemplate>
                            <DataTemplate>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <Ellipse Grid.Column="0" Fill="Green" Height="5" Width="5"/>
                                    <TextBlock Grid.Column="1" Text="{Binding}" />
                                </Grid>
                            </DataTemplate>
                        </ComboBox.ItemTemplate>
                    </ComboBox>
                </Grid>
            </DataTemplate>

            <TestCustomTab:ContactDataByTypeTemplateSelector x:Key="contactDataByTypeTemplateSelector"/>
        </Window.Resources>
        <Grid x:Name="grid">        
            <ListView ItemsSource="{Binding ContactDataCollection, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TestCustomTab:Window1}}}">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Column" Width="200" CellTemplateSelector="{StaticResource contactDataByTypeTemplateSelector}">

                        </GridViewColumn>
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>
    </Window>

让我们假设您的 ContactData 如下所示:

public class ContactData : INotifyPropertyChanged
    {
        private string _name;
        private int _homePhone;
        private int _mobilePhone;
        private string _value;
        private ContactDataType _dataType;

        public ContactData()
        {
        }

        public ContactData(string name, int homePhone, int mobilePhone, string value, ContactDataType dataType)
        {
            _name = name;
            _dataType = dataType;
            _value = value;
            _mobilePhone = mobilePhone;
            _homePhone = homePhone;
        }

        #region Implementation of INotifyPropertyChanged

        public ContactDataType DataType
        {
            get { return _dataType; }
            set
            {
                if (_dataType == value) return;
                _dataType = value;
                raiseOnPropertyChanged("DataType");
            }
        }

        public string Name
        {
            get { return _name; }
            set
            {
                if (_name == value) return;
                _name = value;
                raiseOnPropertyChanged("Name");
            }
        }

        public int HomePhone
        {
            get { return _homePhone; }
            set
            {
                if (_homePhone == value) return;
                _homePhone = value;
                raiseOnPropertyChanged("HomePhone");
            }
        }

        public int MobilePhone
        {
            get { return _mobilePhone; }
            set
            {
                if (_mobilePhone == value) return;
                _mobilePhone = value;
                raiseOnPropertyChanged("MobilePhone");
            }
        }

        public string Value
        {
            get { return _value; }
            set
            {
                if (_value == value) return;
                _value = value;
                raiseOnPropertyChanged("Value");
                raiseOnPropertyChanged("Symbols");
            }
        }

        public ReadOnlyCollection<char> Symbols
        {
            get
            {
                return !string.IsNullOrEmpty(_value) ? new ReadOnlyCollection<char>(_value.ToCharArray()) : new ReadOnlyCollection<char>(new List<char>());
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void raiseOnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }

它具有 ContactDataType 类型的 DataType 属性,该属性是枚举:

public enum ContactDataType
    {
        Working,
        Personal
    }

能够为相同的实体拥有不同的 DataTemplates,并通过某些功能来区分,您需要使用数据模板选择器。该技术是继承 DataTemplateSelector 并重写 SelectTemplate 方法。在我们的例子中:

public class ContactDataByTypeTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            var contactData = item as ContactData;
            var control = container as FrameworkElement;
            if (contactData != null & control != null)
                switch (contactData.DataType)
                {
                    case ContactDataType.Working:
                        return control.TryFindResource("workingTemplate") as DataTemplate;
                    case ContactDataType.Personal:
                        return control.TryFindResource("personalTemplate") as DataTemplate;
                    default:
                        return base.SelectTemplate(item, container);
                }

            return base.SelectTemplate(item, container);
        }
    }

这是代码后面的 Window1 类:

public partial class Window1 : Window
    {
        private ObservableCollection<ContactData> _contactDataCollection = new ObservableCollection<ContactData>();

        public Window1()
        {
            ContactDataCollection.Add(new ContactData("test1", 0, 1, "value1", ContactDataType.Working));
            ContactDataCollection.Add(new ContactData("test2", 0, 1, "value2", ContactDataType.Working));
            ContactDataCollection.Add(new ContactData("test3", 0, 1, "value3", ContactDataType.Working));
            ContactDataCollection.Add(new ContactData("test4", 0, 1, "value4", ContactDataType.Personal));
            ContactDataCollection.Add(new ContactData("test5", 0, 1, "value5", ContactDataType.Personal));

            InitializeComponent();

        }


        public ObservableCollection<ContactData> ContactDataCollection
        {
            get { return _contactDataCollection; }
        }
    }

现在解释:

  1. 我们创建了一些需要向用户表示的类 (ContactData) 并让他具有功能 - ContactDataType.

  2. 在资源中为 ContactDataType.WorkingContactDataType.Personal 创建了 2 个 DataTemplate(x:Key 很重要)

  3. 我们创建了 DataTemplateSelector 按功能拥有能力切换模板。

  4. 在我们的第一个 GridViewColumn 中,我们定义了 CellTemplateSelector 并将我们的 ContactDataByTypeTemplateSelector 绑定到它。

  5. 在运行时,只要集合发生变化,ContactDataByTypeTemplateSelector就会根据项目功能选择模板,并且我们可以为任意数量的已定义功能提供任意数量的模板。

注意:更改您的命名空间的 TestCustomTab

Define your Window class as follows (explanation will be later):

<Window x:Class="TestCustomTab.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:TestCustomTab="clr-namespace:TestCustomTab" Title="Window1" Height="300" Width="300">
        <Window.Resources>
            <DataTemplate x:Key="workingTemplate">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" Text="{Binding Name}"/>
                    <ComboBox Grid.Column="1" SelectedIndex="0" ItemsSource="{Binding Symbols}">
                        <ComboBox.ItemTemplate>
                            <DataTemplate>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <Ellipse Grid.Column="0" Fill="Red" Height="5" Width="5"/>
                                    <TextBlock Grid.Column="1" Text="{Binding}" />
                                </Grid>
                            </DataTemplate>
                        </ComboBox.ItemTemplate>
                    </ComboBox>
                </Grid>
            </DataTemplate>

            <DataTemplate x:Key="personalTemplate">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" Text="{Binding Name}"/>
                    <ComboBox Grid.Column="1" SelectedIndex="0" ItemsSource="{Binding Symbols}">
                        <ComboBox.ItemTemplate>
                            <DataTemplate>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <Ellipse Grid.Column="0" Fill="Green" Height="5" Width="5"/>
                                    <TextBlock Grid.Column="1" Text="{Binding}" />
                                </Grid>
                            </DataTemplate>
                        </ComboBox.ItemTemplate>
                    </ComboBox>
                </Grid>
            </DataTemplate>

            <TestCustomTab:ContactDataByTypeTemplateSelector x:Key="contactDataByTypeTemplateSelector"/>
        </Window.Resources>
        <Grid x:Name="grid">        
            <ListView ItemsSource="{Binding ContactDataCollection, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TestCustomTab:Window1}}}">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Column" Width="200" CellTemplateSelector="{StaticResource contactDataByTypeTemplateSelector}">

                        </GridViewColumn>
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>
    </Window>

Lets assume that your ContactData looks as follows:

public class ContactData : INotifyPropertyChanged
    {
        private string _name;
        private int _homePhone;
        private int _mobilePhone;
        private string _value;
        private ContactDataType _dataType;

        public ContactData()
        {
        }

        public ContactData(string name, int homePhone, int mobilePhone, string value, ContactDataType dataType)
        {
            _name = name;
            _dataType = dataType;
            _value = value;
            _mobilePhone = mobilePhone;
            _homePhone = homePhone;
        }

        #region Implementation of INotifyPropertyChanged

        public ContactDataType DataType
        {
            get { return _dataType; }
            set
            {
                if (_dataType == value) return;
                _dataType = value;
                raiseOnPropertyChanged("DataType");
            }
        }

        public string Name
        {
            get { return _name; }
            set
            {
                if (_name == value) return;
                _name = value;
                raiseOnPropertyChanged("Name");
            }
        }

        public int HomePhone
        {
            get { return _homePhone; }
            set
            {
                if (_homePhone == value) return;
                _homePhone = value;
                raiseOnPropertyChanged("HomePhone");
            }
        }

        public int MobilePhone
        {
            get { return _mobilePhone; }
            set
            {
                if (_mobilePhone == value) return;
                _mobilePhone = value;
                raiseOnPropertyChanged("MobilePhone");
            }
        }

        public string Value
        {
            get { return _value; }
            set
            {
                if (_value == value) return;
                _value = value;
                raiseOnPropertyChanged("Value");
                raiseOnPropertyChanged("Symbols");
            }
        }

        public ReadOnlyCollection<char> Symbols
        {
            get
            {
                return !string.IsNullOrEmpty(_value) ? new ReadOnlyCollection<char>(_value.ToCharArray()) : new ReadOnlyCollection<char>(new List<char>());
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void raiseOnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }

It has DataType property of type ContactDataType which is enum:

public enum ContactDataType
    {
        Working,
        Personal
    }

In ability to have different DataTemplates for the same entities differentiated by some feature you need to use DataTemplateSelector. The technique is in inheriting from DataTemplateSelector and overriding SelectTemplate method. In our case:

public class ContactDataByTypeTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            var contactData = item as ContactData;
            var control = container as FrameworkElement;
            if (contactData != null & control != null)
                switch (contactData.DataType)
                {
                    case ContactDataType.Working:
                        return control.TryFindResource("workingTemplate") as DataTemplate;
                    case ContactDataType.Personal:
                        return control.TryFindResource("personalTemplate") as DataTemplate;
                    default:
                        return base.SelectTemplate(item, container);
                }

            return base.SelectTemplate(item, container);
        }
    }

Here is Window1 class in code behind:

public partial class Window1 : Window
    {
        private ObservableCollection<ContactData> _contactDataCollection = new ObservableCollection<ContactData>();

        public Window1()
        {
            ContactDataCollection.Add(new ContactData("test1", 0, 1, "value1", ContactDataType.Working));
            ContactDataCollection.Add(new ContactData("test2", 0, 1, "value2", ContactDataType.Working));
            ContactDataCollection.Add(new ContactData("test3", 0, 1, "value3", ContactDataType.Working));
            ContactDataCollection.Add(new ContactData("test4", 0, 1, "value4", ContactDataType.Personal));
            ContactDataCollection.Add(new ContactData("test5", 0, 1, "value5", ContactDataType.Personal));

            InitializeComponent();

        }


        public ObservableCollection<ContactData> ContactDataCollection
        {
            get { return _contactDataCollection; }
        }
    }

Now explanation:

  1. We created some class that we need to represent to user (ContactData) and let him to have feature - ContactDataType.

  2. We created 2 DataTemplates in resources (x:Key is important) for ContactDataType.Working and ContactDataType.Personal

  3. We created DataTemplateSelector to have ability switch templates by feature.

  4. In our first GridViewColumn we defined CellTemplateSelector and bind to it our ContactDataByTypeTemplateSelector.

  5. In runtime whenever the collection changes ContactDataByTypeTemplateSelector select to us template based on item feature and we may have any number of templates for any number of defined features.

Notice: change TestCustomTab for your namespace.

吃不饱 2024-09-17 18:15:35

对于最后一个问题,您可以使用一个按钮并将其模板化以包含图像。

For the last question, you can use a button and template it to include an image.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文