2010-07-23 2 views
1

Попытка понять этот процесс связывания WPF.WPF простая проблема с привязкой

См. Код внизу.

В моей "viewmodel", см. Код внизу, у меня есть наблюдаемая коллекция, которая заполняет список с помощью элементов. Это тот, который содержит путь, называемый символом, для установки выбранного индекса в поле со списком. Теперь моя проблема в том, что мне нужно заполнить combobox из другого списка до его добавления в список (некоторые значения по умолчанию). Поскольку я только начал с WPF, я подумал, что, возможно, вы можете использовать 2 разных ObservableCollections в одном классе для достижения этого, но это не сработало. Итак, как я могу заполнить datatemplate значениями по умолчанию, прежде чем они будут связаны/добавлены в список?

Это то, что я использую для заполнения списка, см. В разделе 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; 
    } 
} 

ответ

4

Определите класс окна следующим образом (объяснение будет позже):

<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> 

Давайте предположим, что ваш КонтактныеДанные выглядит следующим образом:

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 
    } 

имеет DataType свойство типа ContactDataType которое перечисление :

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; } 
     } 
    } 

Теперь объяснение:

  1. Мы создали некоторый класс, что нам нужно, чтобы представить пользователю (ContactData) и пусть у него будет функция - ContactDataType.

  2. Мы создали 2 DataTemplates в ресурсах (x:Key важно) для ContactDataType.Working и ContactDataType.Personal

  3. Мы создали DataTemplateSelector иметь шаблоны возможность переключения с помощью функции.

  4. В нашем первом GridViewColumn мы определили CellTemplateSelector и привязали к нему наш ContactDataByTypeTemplateSelector.

  5. Во время выполнения, когда коллекция меняет ContactDataByTypeTemplateSelector, выберите нам шаблон на основе элемента, и у нас может быть любое количество шаблонов для любого количества определенных функций.

Примечание: измените значение TestCustomTab на ваше пространство имен.

+0

Привет, спасибо за ответ. Кажется, я не объяснил себя на 100%. Я добавил свой XAML для списка, и мой код, что я не смог получить работу, был символом. Я понятия не имею, к чему это привязать. Я хотел бы добавить все предопределенное содержимое xml во внешний класс и использовать его для всех предопределенных привязок данных. Но как я могу связать combobox с 2 datacontexts в одно и то же время? Один для применения текущего выбранного индекса и один для заполнения выпадающего списка до его показания со значениями по умолчанию. – Patrick

1

За последний вопрос, вы можете использовать кнопку и шаблон его включить изображение.