2017-11-18 14 views
0

내 MVVM 양식의 콤보 상자에서 현재 선택한 항목과 현재의 드롭 다운 목록 항목을 모두 표시하는 선택 상자를 새로 고치고 싶습니다. 바운드 데이터가 변경되자 마자 선택된 항목. 나는이 일이 일어날 수 없습니다. 사진을 새로 고치는 것도 중요합니다.WPF가 콤보 상자 선택 상자 및 드롭 다운 목록 항목을 동기화하지 않고 즉시 새로 고치지 않음을 알립니다.

예제 양식에는 미리로드 된 사람을 보여주는 2 개의 콤보 상자와 사람을 추가하는 단추와 기존 사람의 일부 데이터를 변경하는 단추가 있습니다. 이 버튼을 클릭하면 Person.Type 필드가 조금씩 임의로 변경되고 다른 그림 파일 문자열은 Person.PicFullPath에 저장됩니다.

<Window x:Class="combobox_test__01.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:combobox_test__01" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="600" Width="420" WindowStartupLocation="CenterScreen"> 
    <Window.Resources> 
     <local:VM x:Key="vm" /> 

     <DataTemplate x:Key="cboTemplate" > 
      <StackPanel Orientation="Horizontal"> 
       <Border Height="80" Width="80" > 
        <Image> 
         <Image.Source> 
          <PriorityBinding> 
           <Binding Path="PicFullPath" Mode="TwoWay"/> 
          </PriorityBinding> 
         </Image.Source> 
        </Image> 
       </Border> 
       <Canvas Height="80" Width="160" > 
        <StackPanel> 
         <TextBlock HorizontalAlignment="Left" Height="16" Text="{Binding Path=Name, Mode=TwoWay}" /> 
         <TextBlock HorizontalAlignment="Left" Height="16" Text="{Binding Path=Type, Mode=TwoWay}" /> 
        </StackPanel> 
       </Canvas> 
      </StackPanel> 
     </DataTemplate> 

    </Window.Resources> 
    <Window.DataContext> 
     <Binding Source="{StaticResource vm}" /> 
    </Window.DataContext> 
    <Grid> 
     <ComboBox Name="cbo1" IsSynchronizedWithCurrentItem="True" HorizontalAlignment="Left" Margin="19,11,0,0" VerticalAlignment="Top" Width="159" 
       ItemsSource="{Binding People}" 
       SelectedItem="{Binding SelectedPerson}" 
       DisplayMemberPath="Type" /> 
     <Button Content="New Row" HorizontalAlignment="Left" Margin="224,11,0,0" VerticalAlignment="Top" Width="142" 
       Command="{Binding NewRowCommand}" /> 
     <Button Content="Change current row data" HorizontalAlignment="Left" Margin="224,48,0,0" VerticalAlignment="Top" Width="142" 
       Command="{Binding AlterRowCommand}" /> 
     <ComboBox Name="cbo2" IsSynchronizedWithCurrentItem="True" HorizontalAlignment="Left" Margin="19,130,0,0" VerticalAlignment="Top" Width="159" Height="82" 
      ItemsSource="{Binding People}" 
      SelectedItem="{Binding SelectedPerson}" 
      ItemTemplate="{StaticResource cboTemplate}" /> 
    </Grid> 
</Window> 

using myAssemblies; 
using System; 
using System.Collections.ObjectModel; 
using System.Windows.Input; 
using System.ComponentModel; 

namespace combobox_test__01 
{ 
    public class VM : INotifyPropertyChanged 
    { 
     private ObservableCollection<Person> people; 
     public ObservableCollection<Person> People 
     { 
      get { return people; } 
      set 
      { 
       people = value; 
       OnPropertyChanged("People"); 
      } 
     } 

     private Person selectedPerson; 
     public Person SelectedPerson 
     { 
      get { return selectedPerson; } 
      set 
      { 
       selectedPerson = value; 
       OnPropertyChanged("SelectedPerson"); 
       People = People; 
      } 
     } 

     private int idx = 0; 
     private string[,] newP; 
     private string DefaultPic = @"D:\Visual Studio Testing\Icons\user-icon.png", 
      NewPic = @"D:\Visual Studio Testing\Small size pictures\mugshot"; 
     private Random random = new Random(); 

     public event PropertyChangedEventHandler PropertyChanged; 
     protected void OnPropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, 
        new PropertyChangedEventArgs(propertyName)); 
      } 
     } 

     public VM() 
     { 
      People = new ObservableCollection<Person>() 
      { 
       new Person() {Name="Aa", Type="Taa", PicFullPath=DefaultPic}, 
       new Person() {Name="Bb", Type="Tbb", PicFullPath=DefaultPic}, 
       new Person() {Name="Cc", Type="Tcc", PicFullPath=DefaultPic} 
      }; 

      newP = new string[4, 3] { { "Dd", "Tdd", "" }, { "Ee", "Tee", "" }, { "Ff", "Tff", "" }, { "Gg", "Tgg", "" } }; 
     } 

     public ICommand AlterRowCommand => new RelayCommandBase(AlterRow); 
     private void AlterRow(object parameter) 
     { 
      //Make SelectedPerson.Type into a string ending with 2 randomish digits 
      string fmts, picChoice; 
      GetDifferentData(out fmts, out picChoice); 
      string s = SelectedPerson.Type.Substring(0,3).PadRight(5); 
      SelectedPerson.Type = s + fmts; 

      // Use those 2 randomish digits to choose a picture from existing ones 
      SelectedPerson.PicFullPath = NewPic + picChoice; 

      // Force both setters to execute 
      SelectedPerson = SelectedPerson; 
     } 

     public ICommand NewRowCommand => new RelayCommandBase(NewRow); 
     private void NewRow(object parameter) 
     { 
      string fmts, picChoice; 
      GetDifferentData(out fmts, out picChoice); 
      People.Add(new Person() { Name = newP[idx, 0], Type = newP[idx++, 1], PicFullPath = NewPic + picChoice }); 
     } 

     private void GetDifferentData(out string fmts, out string picChoice) 
     { 
      int randomi = random.Next(1, 35); 
      fmts = randomi.ToString("D2"); 
      picChoice = fmts + ".jpg"; 
     } 
    } 

    public class Person 
    { 
     public string Name { get; set; } 
     public string Type { get; set; } 
     public string PicFullPath { get; set; } 
    } 
} 

는 동작입니다 :

응용 프로그램을 실행 뷰 모델은 1
클릭
뷰 모델 주에 '현재 행 데이터 변경'이 국가에
2
눈에 띄는에게 변경 : 선택 상자에 변경된 Type 데이터와 다른 그림을 표시하려면

콤보 상자를 클릭하십시오. cbo1
드롭 다운 목록에 People.Type의 변경 사항이 표시됩니다. 선택 상자에는 여전히 이전 데이터가 표시됩니다.

클릭 콤보 상자 cbo2
드롭 다운 목록에 변경 People.Type과 다른 그림이 표시됩니다. 선택 상자에는 여전히 이전 데이터가 표시됩니다.

선택한 항목을 이동하지 않고 '현재 행 데이터 변경'을 다시 클릭하십시오.

뷰 모델의 상태는 3입니다.
눈에 띄는 변경 없음 : 드롭 다운 목록을 축소하면 양식이 초기화시와 동일하게 보입니다.

클릭 콤보 상자 cbo1
드롭 다운 목록은 여전히 ​​People.Type의 첫 번째 변화를 보여 주지만, People.Type 다시 변경되었습니다. 선택 상자에는 여전히 원래 데이터가 표시됩니다.

클릭 콤보 상자 cbo2
마지막으로 떨어 뜨린 후 드롭 다운 목록이 변경되지 않았습니다. 선택 상자에는 여전히 원래 데이터가 표시됩니다.

뷰 모델에서 상태가 3 가지 변경되었지만 콤보 상자의 상태 상자는 선택 상자에 표시되고 상태 2는 드롭 다운 목록에 표시됩니다. 나는 그들에게 두 곳 모두에서 주 3을 보여주기를 바랍니다.

콤보 상자 cbo1을 클릭하고 다른 항목을 선택한 다음 첫 번째 항목을 선택하십시오. 그래서 우리는 선택된 항목을 옮기고 그것을 옮겼습니다.
두 콤보 상자 모두 선택 상자
의 최신 데이터를 표시합니다. 드롭 다운 목록의 유효 기간이 만료되었습니다. 둘 다 상태 2를 표시하므로 선택을 변경하고 다시 변경하면 드롭 다운 목록에 표시된 데이터가 변경되지 않습니다.

클릭 '새 행'
뷰 모델은 주 4
눈에 띄는 변화입니다 : 예상대로 - 눈에 띄는 변화가 없을 것이다, 그래서 새로운 사람이 선택되어 있지 않습니다.

드롭 다운 목록에서 콤보 상자를
새로운 사람 표시를 클릭하지만 첫 번째 항목은 아직 없음을 클릭하면 드롭 다운 목록이 첫 번째 변경 후 변경 내용을 표시 할 것 2.

상태를 보여줍니다 - 그들은 상태 2가 표시됩니다.

선택 상자를 만들고 드롭 다운 목록에 항상 최신 데이터를 표시하려면 어떻게합니까?

답변

0

나는 해결책이있다. 그것은 매우 깨끗하지는 않지만 간단하고 작동합니다. 그래서 선택 상자 정의에

SelectedIndex="{Binding CboPeopleSelectedIndex}" 

를 추가

using npAssemblies; 
using System; 
using System.Collections.ObjectModel; 
using System.Windows.Input; 
using System.ComponentModel; 

namespace combobox_test__01 
{ 
    public class VM : INotifyPropertyChanged 
    { 
     private ObservableCollection<Person> people; 
     public ObservableCollection<Person> People 
     { 
      get { return people; } 
      set 
      { 
       people = value; 
       OnPropertyChanged("People"); 
      } 
     } 

     private Person selectedPerson; 
     public Person SelectedPerson 
     { 
      get { return selectedPerson; } 
      set 
      { 
       selectedPerson = value; 
       OnPropertyChanged("SelectedPerson"); 
      } 
     } 

     private int cboPeopleSelectedIndex; 
     public int CboPeopleSelectedIndex 
     { 
      get { return cboPeopleSelectedIndex; } 
      set 
      { 
       cboPeopleSelectedIndex = value; 
       OnPropertyChanged("CboPeopleSelectedIndex"); 
      } 
     } 

     private int newPidx = 0; 
     private string[,] newP; 
     private string DefaultPic = @"D:\Visual Studio Testing\Icons\user-icon.png", 
      NewPic = @"D:\Visual Studio Testing\Small size pictures\mugshot"; 
     private Random random = new Random(); 

     public event PropertyChangedEventHandler PropertyChanged; 
     protected void OnPropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, 
        new PropertyChangedEventArgs(propertyName)); 
      } 
     } 

     public VM() 
     { 
      People = new ObservableCollection<Person>() 
      { 
       new Person() {Name="Aa", Type="Taa", PicFullPath=DefaultPic}, 
       new Person() {Name="Bb", Type="Tbb", PicFullPath=DefaultPic}, 
       new Person() {Name="Cc", Type="Tcc", PicFullPath=DefaultPic} 
      }; 

      newP = new string[4, 3] { { "Dd", "Tdd", "" }, { "Ee", "Tee", "" }, { "Ff", "Tff", "" }, { "Gg", "Tgg", "" } }; 
     } 

     public ICommand AlterRowCommand => new RelayCommandBase(AlterRow); 
     private void AlterRow(object parameter) 
     { 
      //Make SelectedPerson.Type into a string ending with 2 randomish digits 
      string fmts, picChoice; 
      GetDifferentData(out fmts, out picChoice); 
      string s = SelectedPerson.Type.Substring(0,3).PadRight(5); 
      SelectedPerson.Type = s + fmts; 
      // Use those 2 randomish digits to choose a picture from existing ones 
      SelectedPerson.PicFullPath = NewPic + picChoice; 
      // refresh the control the collection is bound to 
      ResetBoundItems(SelectedPerson); 
     } 

     public ICommand NewRowCommand => new RelayCommandBase(NewRow); 
     private void NewRow(object parameter) 
     { 
      string fmts, picChoice; 
      int highIdx = People.Count; 
      GetDifferentData(out fmts, out picChoice); 
      Person newPerson = new Person() { Name = newP[newPidx, 0], Type = newP[newPidx++, 1], PicFullPath = NewPic + picChoice }; 
      People.Add(newPerson); 
      // refresh the control the collection is bound to and select the new row 
      ResetBoundItems(newPerson, highIdx); 
     } 

     private void GetDifferentData(out string fmts, out string picChoice) 
     { 
      int randomi = random.Next(1, 35); 
      fmts = randomi.ToString("D2"); 
      picChoice = fmts + ".jpg"; 
     } 

     private void ResetBoundItems(Person inPerson, int gotoIndex = -1) 
     { 
      // refreshes the display of the combobox otherwise it is visually stale 
      int idx = gotoIndex; 
      if (gotoIndex == -1) 
      { 
       // a preferred index was not supplied; use the currently selected index 
       idx = CboPeopleSelectedIndex; 
      } 
      // save a copy of the current selected person 
      Person tmpP = (Person)inPerson.Clone(); 
      // save the current ItemsSource 
      ObservableCollection<Person> refPC = new ObservableCollection<Person>(); 
      refPC = People; 
      // reset the ItemsSource 
      ObservableCollection<Person> tmpPC = new ObservableCollection<Person>(); 
      People = tmpPC; 
      // set it back 
      People = refPC; 
      // restore the selected person 
      SelectedPerson = (Person)tmpP.Clone(); 
      // select the relevant row 
      CboPeopleSelectedIndex = idx; 
     } 
    } 

    public class Person 
    { 
     public string Name { get; set; } 
     public string Type { get; set; } 
     public string PicFullPath { get; set; } 

     public Person Clone() 
     { 
      return (Person)this.MemberwiseClone(); 
     } 
    } 
} 

뷰가 바운드 selectedIndex의를 위해 선택 상자를 필요 : 이것은 몇 가지 작은 변화와 새로운 방법으로 업데이트 된보기 모델 코드입니다.

새로운 방법 ResetBoundItems()은 새로 고침을 처리합니다. Person 클래스에는 Clone() 메소드가 필요합니다. 추가 할 때 ComboBox를 새 행으로 선택했습니다. 이 솔루션은 ListBox에도 적용됩니다.