2014-07-25 1 views
0

사용자 인터페이스의 일부로 ListBox가있는 C# 프로젝트가 있습니다. 이 ListBox는 여러 프로젝트 이름을 표시하는 데 사용됩니다. 또한 데이터베이스 (모든 프로젝트, 불완전, 완료 등)에 대한 쿼리를 기반으로이 ListBox의 크기를 변경하는 옵션이 있습니다.변경 될 때마다 ListBox의 항목 수를 동적으로 어떻게 표시 할 수 있습니까?

또한 ListBox 내에있는 결과의 개수를 표시하는 레이블이 있습니다. 목록을 변경하는 코드 줄마다가 아닌 목록이 변경 될 때마다 자동으로이 작업을 수행 할 수있는 방법을 찾고자했습니다.

DataSourceChanged 이벤트를 사용해 보았지만 정말 흥미로운 문제입니다. ListBox가 실제로 새 값으로 채워지기 전에 이벤트가 발생합니다. 예를 들어, 프로그램 시작 부분에 ListBox의 데이터 소스를 100 개의 프로젝트 그룹으로 설정했습니다. 그런 다음 DataSourceChanged 이벤트가 발생하고 값을 얻으려면 listBox1.Items.Count.ToString() 호출하고 0을 반환합니다. 다시 목록 상자가 채워지기 때문에 다시. 따라서 레이블을 0으로 표시하고 목록 상자에 100 개 항목을 표시합니다.

이제 불완전한 프로젝트 (예 : 50이 계산 됨)로 범위를 좁히면 이벤트가 발생하면 100이라는 값이 반환됩니다. 이는 불완전 프로젝트가 존재하지 않기 때문입니다 데이터 소스가 변경된 이후 아직 채워지지 않았습니다. 그래서 저는 100이라고 쓰여지는 레이블을 갖지만 50 개의 항목 만있는 목록 상자를 갖습니다.

사용할 수있는 다른 이벤트가 있습니까? DataSourceChanged 이벤트에 보류중인 데이터 소스를 볼 수있는 매개 변수가 있습니까? 또는 실제로 코드에서 목록 상자를 변경하고 레이블을 업데이트하는 모든 인스턴스를 찾아야합니다.

+3

사용'ObservableCollection에 는'자동 업데이트 UI에 대한 알림을 제공 ItemsSource에 바인딩합니다. –

+0

'DataSourceChanged'에서'listBox1.Items.Count.ToString()'을 실행하는 대신 목록에 항목을 추가하거나 DataSet을 Listbox에 바인딩하는 함수에 추가하려고 할 수 있습니다. – CularBytes

+1

WPF는 이벤트와 관련이 없습니다. 당신은 완전히 잘못된 접근법을 사용하고 있습니다. WPF는 절차 적 코드가 아니라 XAML 및 DataBinding에 대한 것입니다. 단순히''바인딩하면됩니다. 끔찍한 winforms와 같은 해킹이 필요 없습니다. –

답변

1

ICollectionView 인터페이스를 사용하면 항목 소스를 그대로 유지할 수도 있습니다 (DB를 일부 작업 부하로 저장하고 혼란스럽게 만듭니다). 또한 여기에있는 다른 설명에서 언급 한대로 항목 소스에 ObservableCollection을 사용해야합니다. WPF의 이벤트에 집중하는 대신 바인딩, 명령 및 작업을 사용해야합니다. 불쾌한 코드 숨김은 오래된 MVVM 베테랑의 아픈 눈을주고 작은 새끼 고양이를 울게 만듭니다.)

"데이터 소스"의 전체 변경 사항에서 Stuffs 컬렉션을 변경하기 만하면 필터를 사용할 수 있습니다. 실례합니다. 가능한 한 쉽게 예제를 만들려고했습니다.

XAML :

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

    <Window.DataContext> 
     <custtest:MainViewModel/> 
    </Window.DataContext> 

    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="*"></RowDefinition> 
      <RowDefinition Height="Auto"></RowDefinition> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*"></ColumnDefinition> 
      <ColumnDefinition Width="Auto" MinWidth="100"></ColumnDefinition> 
     </Grid.ColumnDefinitions> 
     <ListBox ItemsSource="{Binding Stuffs}" Grid.Row="0" Grid.Column="0"></ListBox> 
     <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding StuffFilterView.Count}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock> 
     <TextBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ></TextBox> 
    </Grid> 
</Window> 

뷰 모델 :

아래의 코드는 매우 간단합니다, 당신은 내가 ctor에 거기에 할 일을해서는 안됩니다! 그것은 단지 단순함을위한 것입니다.

public class MainViewModel : INotifyPropertyChanged 
{ 
    private ObservableCollection<string> stuffs; 
    private string searchText; 
    private ICollectionView stuffFilterView; 

    public ICollectionView StuffFilterView 
    { 
     get { return stuffFilterView; } 
     set 
     { 
      if (Equals(value, stuffFilterView)) return; 
      stuffFilterView = value; 
      OnPropertyChanged(); 
     } 
    } 

    public ObservableCollection<String> Stuffs 
    { 
     get { return stuffs; } 
     set 
     { 
      if (Equals(value, stuffs)) return; 
      stuffs = value; 
      OnPropertyChanged(); 
     } 
    } 

    public String SearchText 
    { 
     get { return searchText; } 
     set 
     { 
      if (value == searchText) return; 
      searchText = value; 
      OnPropertyChanged(); 
      OnSearchTextChanged(); 
     } 
    } 

    private void OnSearchTextChanged() 
    { 
     StuffFilterView.Refresh(); // Refresheses content in your ICollectionView when text changes    
    } 

    public MainViewModel() 
    { 
     // Bad pie! 
     Stuffs = new ObservableCollection<string> {"jall", "b", "c", "d", "blabla"}; 
     StuffFilterView = CollectionViewSource.GetDefaultView(Stuffs); 
     StuffFilterView.Filter = FilterStuff; 
    } 

    private bool FilterStuff(object obj) 
    { 
     String str = obj.ToString(); 
     if (String.IsNullOrEmpty(SearchText)) 
      return true; 

     return str.Contains(SearchText); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    [NotifyPropertyChangedInvocator] // R# remove if you don't have it 
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

희망 하시겠습니까?

건배, 스티

+0

아이디어를 제공해 주셔서 감사합니다. 나는이 프로젝트를 휴가로 인해 일주일 동안 지낼 예정이지만, 나는 8 월에 내 결과와 함께 다시 올 것이다. 나는 이것이 마치 무시당하는 것처럼 보이기를 원하지 않았습니다. – AdamMc331

+0

당신은 바로 거기에 필요한 모든 것을 가지고 있습니다. 멋진 휴가를 보내십시오! 실제로 그렇게 복잡하지는 않지만 INot을 포함해야한다고 명시되어 있습니다. 중첩 된 모든 클래스에서 시작하여 실행 중입니다. 위의 코드는 자신을 위해 테스트하면 실행됩니다. 나는 나의 친척들을 찾아 다닐 때 rdp를 통해 정말 빠른 앱을 만들었다. ;) –

+0

나의 무지를 용서해라. 그러나 이것은 xaml 파일을 다루는 나의 첫번째 시간이다. 그리고 나는 그것을 발견하는 것처럼 보이지 않는다. 이 파일은 이미 Visual Studio의 어딘가에 존재해야합니까, 아니면 내가 만들어야하는 파일입니까? – AdamMc331

관련 문제