尝试理解WPF的这种绑定过程。
请参阅底部的代码。
在我的“viewmodel”中,查看底部的代码,我有一个可观察的集合,用项目填充listview。这是包含一个名为symbol的路径的路径,用于在组合框中设置所选索引。现在我的问题是我需要在添加到listview之前从另一个列表中填充组合框(一些默认值)。 因为我刚刚开始使用WPF,我认为也许你可以在同一个类中使用2个不同的ObservableCollections来实现这一点,但这不起作用。那么如何在将数据模板绑定/添加到列表视图之前使用默认值填充数据模板?
这是我用来填充列表视图的内容,请参阅底部的viewmodelcontacts。
我还尝试添加另一个带有一个新的observablecollection的类,我可以在我的组合框中使用它,但我也没有这样做。 应填充的数据来自位于我的应用程序中作为资源的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;
}
}
答案 0 :(得分:4)
按如下方式定义您的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。该技术是继承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; }
}
}
现在解释:
我们创建了一些我们需要向用户表示的类(ContactData
)并让他拥有功能 - ContactDataType
。
我们在x:Key
和ContactDataType.Working
ContactDataType.Personal
非常重要)
我们创建了DataTemplateSelector
按功能切换模板。
在我们的第一个GridViewColumn
我们定义了CellTemplateSelector
并将ContactDataByTypeTemplateSelector
绑定到它。
在运行时,只要集合发生变化ContactDataByTypeTemplateSelector
,就根据项目功能选择我们模板,我们可以为任意数量的已定义功能提供任意数量的模板。
注意:更改名称空间的TestCustomTab
。
答案 1 :(得分:1)
对于最后一个问题,您可以使用按钮并将其模板化以包含图像。