2009-04-28 5 views
22

Dictionary<string, int>ListView에 바인딩하고 싶습니다. 나는 이 Dictionary에있는 데이터 바인딩 메커니즘을 통해 업데이트되는 방식으로이 작업을 수행하려고합니다. 을 Values으로 변경하고 싶지 않습니다. 또한 Dictionary에 새 매핑을 추가하는 것에 신경 쓰지 않아도됩니다. 난 그냥 기존의 것들을 업데이 트하고 싶습니다.WPF에서 사전을 사용하여 양방향 데이터 바인딩

ItemsSource (ListView)으로 사전을 설정하면이 작업이 수행되지 않습니다. ListView이 열거자를 사용하여 Dictionary의 내용에 액세스하고 그 열거 형의 요소가 변경 불가능하기 때문에 작동하지 않습니다 KeyValuePair 개체입니다.

내 현재 조사 라인에서 Keys 속성을 사용하려고합니다. 내 ListViewItemsSource 속성에 할당합니다. 이것은 내가 Keys을 표시 할 수있게 해주지 만, 에있는 Values에 액세스하는 WPF의 데이터 바인딩 메커니즘에 대해서는 충분히 알지 못합니다.

나는이 질문을 발견했다 : Access codebehind variable in XAML 그러나 여전히 그 격차를 줄이는 것처럼 보이지 않는다.

이 접근 방식을 만드는 방법을 아는 사람이 있습니까? 누구나 더 좋은 방법이 있습니까?

마지막 수단으로 사용자 지정 개체를 만들고 을 다시 작성/업데이트하는 List에 붙여 넣을 수 있지만 기본 제공 데이터 바인딩 기능을 우회하는 방법처럼 보입니다. 효과적으로 활용하십시오.

+1

의 자신의 버전을 구현할 수있다? – Rauhotz

+0

어떻게 그것을 두 가지 방식으로 만들려고합니까? 값이 TextBox에 표시됩니까? – Ray

+0

@ 레이 내 값을위한 사용자 지정 편집기가 있습니다. TextBox를 사용한 예가 있다면, 필자의 요구를 충족시킬 수있을 것이라고 확신합니다. –

답변

17

나는 사전으로 원하는 것을 할 수 없을 것이라고 생각합니다.

  1. 당신이 원하는 것처럼이 방법은 바인딩을 허용하지 않을 것 때문에 사전에서 INotifyPropertyChanged 또는 INotifyCollectionChanged
  2. 를 구현하지 않기 때문에

    .

정확한 요구 사항에 맞는지 확실하지 않지만 ObservableCollection 및 맞춤 클래스를 사용합니다.

값에 대한 바인딩을 두 가지 방법으로 만드는 방법을 보여주기 위해 DataTemplate을 사용하고 있습니다. 당신은 단지 ObservableCollection<int>

사용자 정의 클래스

public class MyCustomClass 
{ 
    public string Key { get; set; } 
    public int Value { get; set; } 
} 

설정 ItemsSource

ObservableCollection<MyCustomClass> dict = new ObservableCollection<MyCustomClass>(); 
dict.Add(new MyCustomClass{Key = "test", Value = 1}); 
dict.Add(new MyCustomClass{ Key = "test2", Value = 2 }); 
listView.ItemsSource = dict; 

XAML

<Window.Resources> 
    <DataTemplate x:Key="ValueTemplate"> 
     <TextBox Text="{Binding Value}" /> 
    </DataTemplate> 
</Window.Resources> 
<ListView Name="listView"> 
    <ListView.View> 
     <GridView> 
      <GridViewColumn CellTemplate="{StaticResource ValueTemplate}"/> 
     </GridView> 
    </ListView.View> 
</ListView> 
을 사용할 수 있도록이 구현 키 물론

는 사용되지 않습니다
+1

사실 ListView에서 사전에 변경 내용을 전파하는 것보다 Dictionary에서 ListView로 변경 내용을 전파하는 것이 덜 걱정입니다. Inotify 인터페이스는 주로 이전 인터페이스와 관련이있는 것처럼 보입니다. –

+0

네, 맞습니다. 그러나 사전 바인딩을 올바르게 시도했는데 할 수 없었던 것처럼 제대로 작동하지 못했습니다. 다른 사람에게 제안이 있는지 확인합니다. – Ray

+0

MyCustomClass는 INotifyPropertyChanged를 구현해야합니다. – MikeT

6

이것은 약간 해키지만, 나는 그것이 당신이 원하는 것을 이해한다고 가정 할 때 작동하도록했습니다.XAML에서

class ViewModel : INotifyPropertyChanged 
{ 
    public ViewModel() 
    { 
     this.data.Add(1, "One"); 
     this.data.Add(2, "Two"); 
     this.data.Add(3, "Three"); 
    } 

    Dictionary<int, string> data = new Dictionary<int, string>(); 
    public IDictionary<int, string> Data 
    { 
     get { return this.data; } 
    } 

    private KeyValuePair<int, string>? selectedKey = null; 
    public KeyValuePair<int, string>? SelectedKey 
    { 
     get { return this.selectedKey; } 
     set 
     { 
      this.selectedKey = value; 
      this.OnPropertyChanged("SelectedKey"); 
      this.OnPropertyChanged("SelectedValue"); 
     } 
    } 

    public string SelectedValue 
    { 
     get 
     { 
      if(null == this.SelectedKey) 
      { 
       return string.Empty; 
      } 

      return this.data[this.SelectedKey.Value.Key]; 
     } 
     set 
     { 
      this.data[this.SelectedKey.Value.Key] = value; 
      this.OnPropertyChanged("SelectedValue"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propName) 
    { 
     var eh = this.PropertyChanged; 
     if(null != eh) 
     { 
      eh(this, new PropertyChangedEventArgs(propName)); 
     } 
    } 
} 

그리고 :

<Window x:Class="WpfApplication1.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition /> 
      <RowDefinition Height="Auto" /> 
     </Grid.RowDefinitions> 
     <ListBox x:Name="ItemsListBox" Grid.Row="0" 
      ItemsSource="{Binding Path=Data}" 
      DisplayMemberPath="Key" 
      SelectedItem="{Binding Path=SelectedKey}"> 
     </ListBox> 
     <TextBox Grid.Row="1" 
      Text="{Binding Path=SelectedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 
    </Grid> 
</Window> 

Data 속성의 값이 ListBoxItemsSource에 바인딩

내가 먼저 뷰 모델 클래스를 만들었습니다. 질문을 올리면 의 인스턴스가 ListBox 뒤에있는 데이터로 사용됩니다. DisplayMemberPathKey으로 설정하여 키 값이 ListBox의 각 항목에 대해 표시된 값으로 사용됩니다. 당신이 발견 즉 읽기 전용되기 때문에

, 당신은 단지의 TextBox에 대한 데이터로 KeyValuePairValue을 사용할 수 없습니다. 대신 TextBox은보기 모델의 속성에 바인딩되어 현재 선택된 키의 값을 가져 와서 설정할 수 있습니다. SelectedItem 속성 (ListBox)을보기 모델의 다른 속성에 바인딩하여 업데이트됩니다. 이 속성을 nullable (KeyValuePair는 구조체이기 때문에)로 만들어야 만 선택 사항이 없을 때 코드가 감지 할 수있었습니다.

내 테스트 앱에서는보기 모델의 Dictionary으로 전파되는 TextBox을 수정 한 것으로 보입니다.

당신이 가고있는 것이 더 많거나 적습니까? 조금 깨끗해야 할 것 같지만 그렇게 할 방법이 있는지 확실하지 않습니다. 대신

Dictionary<string, int> 

+0

내 상황이 약간 다릅니다.Dictionary 항목을 Label 및 Textbox의 여러 쌍으로 표시하려고합니다. 너는 어떤 생각을 가지고 있니? – YukiSakura

+0

@YukiSakura 사전에있는 ItemsControl부터 시작하여 적절한 속성에 바인딩 된 Label 및 TextBox를 갖도록 항목 템플릿을 설정합니다. – Andy

+0

시도했지만, 런타임에 '읽기 전용 KeyValuePair ...에 TwoWay를 사용할 수 없습니다 ...'라는 오류가 발생했습니다. – YukiSakura

0

, 당신은

Dictionary<string, IntWrapperClass>? 

유무 IntWrapperClass가에서 INotifyPropertyChanged를 구현 할 수 있습니다. 그런 다음 Listview/Listbox를 사전의 항목에 양방향으로 바인딩 할 수 있습니다.

0

위의 내용을 게시했습니다. 당신은 아래에 a를 둘 수 있습니다 ObservableCollection<ObservableKvp<MyKeyObject, MyValueObject>>

키는 읽기 전용이므로 키를 변경해서는 안됩니다. 이 일을 프리즘을 필요로 - 또는 당신은 더 나은 WPF와의 ObservableDictionary 같은 것을 사용하지 않을까요 INotifyPropertyChanged 대신

public class ObservableKvp<K, V> : BindableBase 
{ 
    public K Key { get; } 

    private V _value; 
    public V Value 
    { 
     get { return _value; } 
     set { SetProperty(ref _value, value); } 
    } 

    public ObservableKvp(K key, V value) 
    { 
     Key = key; 
     Value = value; 
    } 
} 
관련 문제