2010-05-10 5 views
0

WPF ListBox에 항목 목록이 있습니다. 사용자가 이러한 항목을 여러 개 선택하고 제거 단추를 클릭하여 목록에서 이러한 항목을 제거 할 수있게하려고합니다. 이 같은MVVM RelayCommand를 통해 ListBox에서 SelectedItems 제거

내보기에서
public RelayCommand<IList> RemoveTagsCommand { get; private set; } 

, 내가 묶을 내 RemoveTagsCommand :

<DockPanel> 
<Button DockPanel.Dock="Right" Command="{Binding RemoveTagsCommand}" CommandParameter="{Binding ElementName=TagList, Path=SelectedItems}">Remove tags</Button> 
<ListBox x:Name="TagList" ItemsSource="{Binding Tags}" SelectionMode="Extended"> 
    <ListBox.ItemsPanel> 
     <ItemsPanelTemplate> 
      <StackPanel Orientation="Horizontal"/> 
     </ItemsPanelTemplate> 
    </ListBox.ItemsPanel> 
    <ListBox.Resources> 
     <DataTemplate DataType="{x:Type Model:Tag}"> 
      ... 
     </DataTemplate> 
    </ListBox.Resources> 
</ListBox> 
</DockPanel> 

내 뷰 모델의 생성자 MVVM RelayCommand 패턴을 사용하여

, 나는 다음과 같은 서명 명령을 만들었습니다 다음 명령의 인스턴스를 설정합니다.

RemoveTagsCommand = new RelayCommand<IList>(RemoveTags, CanRemoveTags); 

현재 구현 중입니다. RemoveTags의 기능은 캐스트 및 복사 기능과 함께 거추장 스럽습니다. 이것을 구현하는 더 좋은 방법이 있습니까? 그게 당신이 어쨌든 얻기 위하여려고하고있는 무슨이기 때문에

public void RemoveTags(IList toRemove) 
    { 
     var collection = toRemove.Cast<Tag>(); 
     List<Tag> copy = new List<Tag>(collection); 

     foreach (Tag tag in copy) 
     { 
      Tags.Remove(tag); 
     } 
    } 

답변

2

ModeIt = OneWayToSource를 사용하여 SelectedItems를 VM의 속성에 바인딩 한 다음 RemoveTags의 바인딩 된 컬렉션 속성을 사용할 수도 있지만 상당히 깨끗해 보입니다. 완전히 확신 할 수는 없지만이 경우 강력하게 형식화 된 IList 컬렉션을 사용할 수 있습니다.

+0

불행히도 강력한 형식의 IList를 사용할 수 없습니다. 이것이 WPF에 의해 반환 된 SelectedItemCollection의 한계라고 생각하지만, RelayCommand의 특정 풍미 때문일 수도 있습니다. – dthrasher

+0

이 부분을 다시 한 번 살펴보면, 제거의 결과로 SelectedItems 목록이 변경 될 수 있다는 사실이 우려됩니다. 그렇다면이 코드는 당신이 얻는만큼 깨끗하다고 ​​생각합니다. RelayCommand가 Cast를 내부적으로 지원하도록하고 싶지 않다면 캐스트는 피할 수 없습니다 ('IList'를'IList '에 적용하는 암시적인'Cast '을 가진'RelayListCommand '과 같은 것). –

+0

고마워, 댄. 당신 말이 맞아요. 복사와 주조가 약간 어색해 보이지만 일이 끝납니다. – dthrasher

0

왜 당신은 List<Tag>가되도록 RelayCommand의 형식 인수를 지정하지? 실행 된 핸들러가 Tag 오브젝트 목록으로 작업하기 위해 하드 코딩 되었기 때문에보다 일반적인 유형을 지정하는 포인트가 없습니다. 이미 거기에 의존성을 만들었으므로 유형 인수에서도 사용할 수 있습니다. 그런 다음 실행 된 핸들러는 캐스트 또는 복사가 필요하지 않습니다.

+1

Tag 인스턴스 만 추가 했어도 SelectedItems가 List 이 될 것으로 생각하지 않습니다. –

+0

@ Dan이 맞습니다. 목록 을 사용할 수 없습니다. SelectedItems 속성이 아닌 일반 SelectedItemsCollection 개체를 반환합니다 생각합니다. – dthrasher

4

내가 (모델을 볼 수 없습니다) 모델에 플래그에 아이템 'IsSelected 속성을 바인딩 할 ListBoxItemContainerStyle를 사용하는 것, 예를 들면 :

다음
<ListBox.ItemContainerStyle> 
    <Style TargetType="{x:Type ListBoxItem}"> 
     <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/> 
    </Style> 
</ListBox.ItemContainerStyle> 

당신에 대해 걱정할 필요가 없습니다 당신이 당신의 명령에 어떤 주장을 전가했는지. 또한 내 경험에 비추어 볼 때 뷰 모델의 객체가 사용자가 선택한 것을 알면 그 정보를 다른 용도로 사용할 수 있습니다.

foreach (Tag t in Tags.Where(x => x.IsSelected).ToList()) 
{ 
    Tags.Remove(t); 
} 
+0

흠을 지원합니다. 이것은 매우 흥미로운 접근 방법입니다. 그래도 내 ViewModel에 UI 상태가 유출되는 것은 확실하지 않습니다. – dthrasher

+1

그건 나에게 이해가되지 않는다. 뷰 모델은 뷰의 모델입니다. UI 상태에 대해 알고있는 것이 전적으로 적합합니다. 선택한 항목을 제거하는 명령이 표시되면 선택한 항목이 무엇인지 알아야합니다. ListBox 대신에'ListView'를 사용하도록 뷰를 재 스타일 할 수도 있지만, 사용자가 제거 할 항목을 선택할 수 없도록 스타일을 변경하지 않을 것입니다. –

+1

나는 이것이 정답으로 투표되어야한다고 생각한다. – webe0316

0

1.) 당신의 ViewModel에 제거 버튼을 명령 바인딩 : 명령에

코드는 무언가 같이 될 것입니다. 당신은 당신이 당신의 목록 상자에 이름을주는 경우 ElementName = NameOfListBox를 사용하여 경로 = selectedItems를하여 목록 상자에서 selectedItems를을 위해 CommandParameter를 사용하여 바인딩을 설정하면

2)

3) 당신의 명령 확인 ViewModel에서 인수를 전달합니다. IList로 캐스팅 할 수있는 객체를 얻습니다.

다음은 간단한 예입니다. 구조를 설정하는 데 도움이됩니다.보기에서

:

<Button Command="{Binding CommandInViewModelForRemove}" 
     CommandParameter="{Binding ElementName=blah,Path=SelectedItems}" 

<ListBox x:Name="blah" .... /> 

뷰 모델에서 :이 도움이

public ViewModel(){ 
    RemoveCommand = new RelayCommand<object>(Remove, CanRemove); 
} 

private void Remove(object selectedItems){ 
    var list = (IList)selectedItems; 
    //do some work, cast to view models that represent list items, etc 
} 

희망!

+0

나는 당신이 이미 제안한 것들을 실제로하고있었습니다. 제 질문은 샘플의 "do some work"비트에 관한 것입니다. 각 항목을 전송하고 selectedItem을 새 목록에 복사하지 않고 목록에서 항목을 제거하는 더 깔끔하고 좋은 방법이 있습니까? – dthrasher

+0

와우, 나는 완전히 그것을 놓쳤다 - 그것에 관해 유감스럽게 생각해 라! 다시 드로잉 보드로 돌아가서 내가 무엇을 생각해 내는지 보도록하겠습니다. 건배! –