2013-08-15 2 views
0

В моей модели просмотра (VM) У меня есть ObservableCollection элементов. По моему мнению, я привязываюсь к коллекции. Я создал несколько пользовательских элементов управления, у которых есть свойство зависимости, которое я связываю с вызываемым STCode. Так, например, объект «Tag» будет иметь свойство «Name» типа String и свойство «value» типа integer.Привязать к определенному элементу в ObservableCollection, проверив значение свойства string

В моей ViewModel

Constructor 
Tags.Add(new Tag("Tag1",111)); 
Tags.Add(new Tag("Tag2",222)); 
Tags.Add(new Tag("Tag3",333)); 
Tags.Add(new Tag("Tag4",444)); 

public ObservableCollection<Tag> Tags 
{ 
    get 
    { 
     return _TagList; 
    } 
    set 
    { 
     if (value != _TagList) 
     { 
      _TagList = value; 
     } 
    } 
} 

На мой взгляд

<my:UserControl1 x:Name="control1" Margin="12,89,0,0" HorizontalAlignment="Left" Width="257" Height="249" VerticalAlignment="Top" STCode="{Binding Path=Value}"/> 

Это связывается со свойством первой штук значение в ObservableCollection (Показывается значение "tag1"). Есть ли в любом случае, что я могу получить конкретный объект «tag» из наблюдаемого набора, указав свойство имени строки? Таким образом, в основном, если у меня было 3 экземпляра моего usercontrol в представлении, на каждом элементе управления я хотел бы указать свойство «Name» объекта Tag как строку в XAML, а в ответ привязать этот конкретный элемент управления к этому конкретному тегу integer " Значение "свойство?

Я надеюсь, что это имеет смысл

Модель

public class Tag : ModelBase 
{ 
    private int _value; 
    public string Tagname { get; set; } 
    public int Value 
    { 
     get 
     { 
      return _value; 
     } 
     set 
     { 
      _value = value; 
      NotifyPropertyChanged("Value"); 
     } 
    } 
} 

ModelBase

public class ModelBase :INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public void NotifyPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    }  
} 
+0

Почему бы просто не создать свойство для каждого тега и не привязаться к нему? – metacircle

+0

Я не могу сделать это, так как могут быть сотни тегов – DLR

+0

Как насчет использования IValueConverter для привязки и настройки его Paramater в соответствии с вашими потребностями. http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx – metacircle

ответ

0

Поскольку ваши элементы управления UserControl связаны с самой коллекции, а не пункт о сборе (преобразователь делает это работа внутри), вы должны вызвать PropertyChanged во всей коллекции, если хотите обновить привязки в своих пользовательских элементах управления.

Edit: Полное решение

ViewModel:

public class MainWindowViewModel : INotifyPropertyChanged 
{ 
    public ObservableCollection<Tag> Tags { get; private set; } 

    public MainWindowViewModel() 
    { 
     Tags = new ObservableCollection<Tag>(); 
     Tags.Add(new Tag("Tag1", 111)); 
     Tags.Add(new Tag("Tag2", 222)); 
     Tags.Add(new Tag("Tag3", 333)); 
     Tags.Add(new Tag("Tag4", 444)); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    [NotifyPropertyChangedInvocator] 
    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    public void ChangeRandomTag() 
    { 
     var rand = new Random(); 

     var tag = Tags[rand.Next(0, Tags.Count - 1)]; 

     tag.Value = rand.Next(0, 1000); 

     OnPropertyChanged("Tags"); 
    } 
} 

Просмотр XAML:

<Window x:Class="WpfApplication1.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:wpfApplication1="clr-namespace:WpfApplication1" 
    Title="MainWindow" 
    Width="525" 
    Height="350"> 

<Window.Resources> 
    <wpfApplication1:MyConverter x:Key="MyConverter" /> 
</Window.Resources> 

<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="*" /> 
     <ColumnDefinition Width="*" /> 
    </Grid.ColumnDefinitions> 

    <ListBox ItemsSource="{Binding Tags}"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <Border Margin="1" 
         BorderBrush="Black" 
         BorderThickness="1" 
         CornerRadius="2"> 
        <StackPanel Orientation="Vertical"> 
         <TextBlock Text="{Binding Name}" /> 
         <TextBlock Text="{Binding Value}" /> 
        </StackPanel> 
       </Border> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 

    <StackPanel Grid.Column="1" Orientation="Vertical"> 
     <Button x:Name="buttonChangeRandomTag" 
       Click="ButtonChangeRandomTag_OnClick" 
       Content="Change Random Tag Value" /> 
     <TextBlock Text="{Binding Tags, Converter={StaticResource MyConverter}, ConverterParameter=Tag1}" /> 
     <TextBlock Text="{Binding Tags, Converter={StaticResource MyConverter}, ConverterParameter=Tag2}" /> 
     <TextBlock Text="{Binding Tags, Converter={StaticResource MyConverter}, ConverterParameter=Tag3}" /> 
     <TextBlock Text="{Binding Tags, Converter={StaticResource MyConverter}, ConverterParameter=Tag4}" /> 
    </StackPanel> 

</Grid> 

View Code позади:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     DataContext = new MainWindowViewModel(); 
     InitializeComponent(); 
    } 

    private void ButtonChangeRandomTag_OnClick(object sender, RoutedEventArgs e) 
    { 
     (DataContext as MainWindowViewModel).ChangeRandomTag(); 
    } 
} 

Преобразователь:

[ValueConversion(typeof(ObservableCollection<Tag>), typeof(int))] 
public class MyConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     var collection = value as ObservableCollection<Tag>; 
     var key = parameter as string; 

     if (collection == null || parameter == null) 
      return 0; 

     var result = collection.FirstOrDefault(item => item.Name.Equals(key)); 
     if (result == null) 
      return 0; 

     return result.Value; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Тэг Класс:

public class Tag : INotifyPropertyChanged 
{ 
    private string name; 
    private int value; 

    public string Name 
    { 
     get { return name; } 
     set 
     { 
      if (value == name) return; 
      name = value; 
      OnPropertyChanged("Name"); 
     } 
    } 

    public int Value 
    { 
     get { return value; } 
     set 
     { 
      if (value == this.value) return; 
      this.value = value; 
      OnPropertyChanged("Value"); 
     } 
    } 

    public Tag(string name, int value) 
    { 
     Value = value; 
     Name = name; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    [NotifyPropertyChangedInvocator] 
    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 
+0

Вы определили локальную локальную сеть IObservableCollection в своем приложении? – DLR

+0

Нет, это Типо. Я исправлю это в своем ответе – metacircle

+0

Прекрасное спасибо за ответ. Последнее, что не работает. Если я использую этот XAML: Значение value всегда равно нулю. Однако, если я использую это: Я получаю фактическое значение это изменение этого конкретного объекта тега. Есть идеи? – DLR

0

Вы можете использовать ValueConverter, чтобы сделать это для вас:

[ValueConversion(typeof(string), typeof(string))] 
public class StringToTagPropertyConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value == null || value != typeof(ObservableCollection<Tag>)) return 
DependencyProperty.UnsetValue; 
     if (parameter as string == null) return DependencyProperty.UnsetValue; 
     ObservableCollection<Tag> tagObject = (ObservableCollection<Tag>)value; 
     string returnValue = tagObject.Where(t => t.Name.ToLower() == 
parameter.ToString().ToLower()).FirstOrDefault(); 
     return returnValue ?? DependencyProperty.UnsetValue; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     return DependencyProperty.UnsetValue; 
    } 
} 

Вы бы использовать его как это:

<my:UserControl1 x:Name="control1" Margin="12,89,0,0" HorizontalAlignment="Left" 
Width="257" Height="249" VerticalAlignment="Top" STCode="{Binding Tags, 
Converter={StaticResource StringToTagPropertyConverter}, 
ConverterParameter="Name"}" /> 

Изменив значение ConverterParameter, вы можете получить ValueConverter для возврата различных свойств вашего объекта тега. Я предполагаю, что вы знаете, как добавить конвертер значений в XAML.

+0

Передача тэга в качестве параметра на один шаг ближе к решению. Теперь мне нужно сделать элемент в коллекции Observable с этим параметром в качестве свойства «Имя» и вернуть значение этого отдельного элемента в коллекции – DLR

+0

. Я отредактировал свой ответ соответственно. Обратите внимание, что вам нужно добавить 'using System.Linq ;' использовать Linq в классе' Конвертер'. – Sheridan