2010-01-28 5 views
7

잠시 동안 WPF로 작업 해오고 있지만 도움이 필요합니다. 내가 탭 1에서 멀리 이동 한 다음 선택이 제거됩니다 다시에 올 때마다WPF ComboBox SelectedItem

<TabControl> 
    <TabItem Header="1"> 
     <ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding MyListSelection}"/> 
    </TabItem> 
    <TabItem Header="2"/> 
</TabControl> 

:

은 내가 ComboBox 아래와 같이 있습니다. 그 이유는 컨트롤이 범위를 벗어나서 다시 돌아올 때 컨트롤이 파괴된다는 것입니다.하지만 그 과정에서 SelectedItem은 null이되어 실제로 사용자가 원하는 것이 아니며 UI로 인한 이벤트입니다. 수명주기.

그래서 가장 좋은 경로는 무엇일까요? MVVM을 사용하여이 응용 프로그램을 빌드 중이므로 My ViewModel의 MyListSelection 속성에 대한 호출을 무시할 수 있지만 ComboBoxes가 모두 있고 WPF의 버그를 고려하여 ViewModel을 수정하는 것을 좋아하지 않습니다.

WPF ComboBox를 하위 클래스로 만들 수 있지만 SelectedItemChanging 이벤트가 없습니다. SelectedItem이 변경되었을 때만 처리기를 추가 할 수 있습니다.

아이디어가 있으십니까?

UPDATE :

좋아, 내 문제가 재현 얻을 수없는 이유를 내가 발견 벽에 내 머리를 구타 후. 어떤 이유로 목록 항목 유형이 클래스 인 경우 SelectedItem은 WPF에 의해 null로 설정되지만 값 유형 인 경우에는 그렇지 않습니다.

public class TestListViewModel : VMBase 
{ 
    public TestListViewModel() 
    { 
     TestList = new List<TestViewModel>(); 
     for (int i = 0; i < 10; i++) 
     { 
      TestList.Add(new TestViewModel(i.ToString())); 
     } 
    } 

    public List<TestViewModel> TestList { get; set; } 

    TestViewModel _SelectedTest; 
    public TestViewModel SelectedTest 
    { 
     get { return _SelectedTest; } 
     set 
     { 
      _SelectedTest = value; 
      OnPropertyChanged("SelectedTest"); 
     } 
    } 
} 

public class TestViewModel : VMBase 
{ 
    public string Name {get;set;} 
} 

내가 변경할 때 그래서 TestList가 int 형하고의 selectedItem은 동일하게 유지 앞뒤로 탭 사이 이동 :

여기 (VMBase가에서 INotifyPropertyChanged를 구현 단지 추상 클래스입니다) 내 테스트 클래스입니다. 그러나 유형이 TestViewModel 일 때 Tabitem이 초점이 맞지 않으면 SelectedTest가 null로 설정됩니다.

무슨 일 이니?

답변

10

나는 똑같은 문제를 겪었고, 지금까지는 문제가 무엇인지 알 수 없었다. 필자는 동일한 OS, .NET 버전 및 하드웨어 사양을 갖춘 4 대의 다른 컴퓨터에서 테스트를 수행했으며 그 중 두 제품에서 문제를 재현 할 수있었습니다. 다른 제품에서는 문제가 재현되었습니다. 나에게 맞는 해결 방법은 ItemsSource 앞에 SelectedItem 바인딩을 정의하는 것입니다. 이상하게도이 패턴을 따르면 모든 것이 예상대로 작동합니다. 말했다 , 당신은 다음을 수행해야합니다 :

<Window x:Class="ComboBoxInTabItemSpike.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"> 
    <StackPanel> 
     <TabControl> 
      <TabItem Header="1"> 
       <ComboBox SelectedItem="{Binding MySelect}" ItemsSource="{Binding MyList}"/> 
      </TabItem> 
      <TabItem Header="2"/> 
     </TabControl> 
     <TextBlock Text="{Binding MySelect}"/> 
    </StackPanel> 
</Window> 
0

OP 변경 후 편집 됨. 안녕하세요 호세, 내가 말한 오류를 재현 할 수 없습니다. 그래서 파괴되는 컨트롤에 대한 당신의 가정은 잘못된 것입니다. Combobox는 현재 참조 유형을 사용 중이라도 아래 코드와 함께 예상대로 작동합니다. TabItem을 변경하면 코드의 다른 일부가 시작되어야합니다.

<Window x:Class="ComboBoxInTabItemSpike.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"> 
    <StackPanel> 
     <TabControl> 
      <TabItem Header="1"> 
       <ComboBox ItemsSource="{Binding MyList}" 
          SelectedItem="{Binding MySelect}"/> 
      </TabItem> 
      <TabItem Header="2"/> 
     </TabControl> 
     <TextBlock Text="{Binding MySelect}"/> 
    </StackPanel> 
</Window> 

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

namespace ComboBoxInTabItemSpike 
{ 
    public partial class Window1 : Window, INotifyPropertyChanged 
    { 
     public Window1() 
     { 
      InitializeComponent(); 
      MyList=new ObservableCollection<TestObject>(
       new[]{new TestObject("1"),new TestObject("2"),new TestObject("3") }); 
      DataContext = this; 
     } 

     public ObservableCollection<TestObject> MyList { get; set; } 

     private TestObject mySelect; 
     public TestObject MySelect 
     { 
      get { return mySelect; } 
      set{ mySelect = value; 
      if(PropertyChanged!=null) 
       PropertyChanged(this,new PropertyChangedEventArgs("MySelect"));} 
     } 

     public TestObject MySelectedItem 
     { 
      get { return (TestObject)GetValue(MySelectedItemProperty); } 
      set { SetValue(MySelectedItemProperty, value); } 
     } 

     public static readonly DependencyProperty MySelectedItemProperty = 
      DependencyProperty.Register("MySelectedItem", 
           typeof(TestObject), 
           typeof(Window1), 
           new UIPropertyMetadata(null)); 

     public event PropertyChangedEventHandler PropertyChanged; 
    } 

    public class TestObject 
    { 
     public string Name { get; set; } 

     public TestObject(string name) 
     { 
      Name = name; 
     } 

     public override string ToString() 
     { 
      return Name; 
     } 
    } 
} 
+1

목록 형식이 참조 형식 인 경우 동일한 형식으로 동작하지 않습니다. 내 업데이트 된 게시물보기 – Jose

0

바인딩을 확인하는 것이 좋습니다. 앱의 다른 항목이 선택한 항목이나 항목 소스를 변경하면 바인딩이 중단됩니다. Visual Studio에서 출력 창을보고 오류가 있는지 확인할 수도 있습니다.

0

여기에 누락 된 부분은 SelectedItem의 TwoWay 바인딩입니다. MyList (바인딩 된 ItemsSource) 및 MyListSelection (귀하의 사례에서 SelectedItem에 본드)이 포함 된 ViewModel 클래스를 바인딩하면 다른 탭으로 갔음에도 불구하고 항상 이러한 정보를 갖게됩니다. 따라서이 탭으로 돌아 오면 MyListSelection은 ComboBoc.SelectedItem에 다시 바인드하므로 좋을 것입니다. 이걸 시도해보고 알려줘.

+1

SelectedItem 바인딩은 기본적으로 TwoWay입니다. –

0

간단한 null 검사로 해결할 수 있다고 생각합니다. 콤보 상자는 재활용 할 때의 selectedIndex의를 재설정하는 경향이 있기 때문에

public TestViewModel SelectedTest 
{ 
    get { return _SelectedTest; } 
    set 
    { 
     if(value != null) 
      _SelectedTest = value; 
     OnPropertyChanged("SelectedTest"); 
    } 
} 

이다. 이 간단한 널 검사는 마지막 유효한 항목으로 리 바인드하도록합니다.

+0

예, 제가 여러 번 고용했지만, 콤보 박스와리스트 뷰가 많이 있습니다. 매번 그렇게하는 것이 매우 짜증납니다. – Jose

+0

실제로 이것은 매우 성가시다. 그러나 모든 속성에서조차도 속성을 변경해야하는 것은 다시 성가시다. WPF는 완벽하지 않습니다. GL –

+1

Null 값이 때때로 컬렉션 내에서 유효한 값일 수 있으므로 항상 만족 스럽지는 않습니다. 또한 속성이 실제로 종속성 속성 인 경우는 어떻습니까? 그런 다음, 비슷한 일을하기 위해 Coerce 및 Change 알림 이벤트를 살펴보아야합니다. 제 의견으로는 이것은 일반적으로 수용 가능한 해결책이 아닙니다. – jpierson

0

내 목록에서 참조 유형과 정확히 같은 문제가되었다. 솔루션은 내 TestViewModel에서 Equals()를 재정 의하여 WPF가 어떤 개체가 SelectedItem인지를 결정하기 위해 개체간에 값 평등 검사 (참조 검사 대신)를 수행 할 수 있도록하는 것이 었습니다. 필자는 실제로 TestViewModel의 식별 기능인 ID 필드를 갖게되었습니다.

0

이 동작은 콤보 상자에 의해 컴파일러에서보다 나은 방식으로 구현되어야합니다 ... IE 컴파일러에서 확인해야하며 ItemsSource 및 해당 형식의 SelectedItem 이제까지 비교되는 값을 반환 할 수밖에 없다

그것은 당신이 같음을() 및 GetHashCode() 메소드를 오버라이드 (override) 고려할 수 있다고 경고한다 ...

이 오늘에 많은 시간을 낭비!