قم بإزالة SelectItems من صندوق القائمة عبر MVVM RelayCommand

StackOverflow https://stackoverflow.com/questions/2803672

  •  25-09-2019
  •  | 
  •  

سؤال

لدي قائمة بالعناصر في صندوق WPF. أريد السماح للمستخدم بتحديد العديد من هذه العناصر والنقر فوق زر إزالة لإزالة هذه العناصر من القائمة.

باستخدام نمط MVVM RelayCommand ، قمت بإنشاء أمر مع التوقيع التالي:

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>

يقوم مُنشئ ViewModel بإعداد مثيل للأمر:

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

إن تنفيذي الحالي لـ removetags يشعر بأنه clunky ، مع القوالب والنسخ. هل هناك طريقة أفضل لتنفيذ هذا؟

    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);
        }
    }
هل كانت مفيدة؟

المحلول

هذا يبدو نظيفًا إلى حد ما بالنسبة لي ، على الرغم من أنك قد تكون قادرًا على الربط SelectedItems إلى خاصية على VM الخاص بك باستخدام Mode=OneWayToSource ثم استخدم خاصية Constain Collection من RemoveTags.
لست متأكدًا تمامًا ، لكنك قد تكون قادرًا على استخدام مجموعة Ilist بقوة في هذه الحالة.

نصائح أخرى

سأستخدم ItemContainerStyle على ال ListBox لربط العناصر IsSelected خاصية للعلم في النموذج (لا عرض النموذج) ، على سبيل المثال:

 <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);
}

لماذا لا تحدد وسيطة نوع RelayCommand ليكون List<Tag>, ، بما أن هذا ما ستحصل عليه على أي حال؟ لا يوجد أي فائدة من تحديد نوع عام أكثر من ذلك لأن المعالج المنفذ يتم ترميزه بقوة للعمل مع قائمة من Tag أشياء. نظرًا لأنك قد قمت بالفعل بالاعتماد هناك ، فقد تقوم أيضًا بتجميعها على حجة النوع أيضًا. ثم لن يحتاج معالجك المنفذ إلى أي طاقم أو نسخ.

1.) ربط زر إزالة الخاص بك في أمر ViewModel الخاص بك.

2.) عندما تقوم بإعداد الربط الخاص بك ، استخدم commandarameter لأخذ selectItems من قائمة القائمة الخاصة بك عن طريق إعطاء اسم ListBox الخاص بك واستخدام elementName = nameOfListbox ، path = selecteMs

3.) تأكد من أن الأمر في ViewModel الخاص بك يمر على طول الوسيطات. ستحصل على كائن يمكنك إلقاؤه باعتباره ilist.

فيما يلي مثال بسيط ، يجب أن يساعدك ذلك في إعداد هيكلك.

في المنظر:

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

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

في ViewModel:

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
}

أتمنى أن يساعدك هذا!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top