Двусторонняя ссылка на свойства всех SelectedItems ListView? - PullRequest
0 голосов
/ 21 мая 2019

У меня есть ListView, связанный с ObservableCollection объектов. Рядом с этим у меня есть куча TextBox и ComboBox, которые TwoWay связаны со свойствами SelectedItem этого ListView. Элементы в моем ListView имеют INotifyPropertyChanged. При этом пользователь может выбрать элемент из ListView и изменить его свойства.

Однако редактирование большого количества элементов занимает много времени, поэтому я хотел, чтобы пользователь мог выбрать несколько элементов и редактировать свойства всех выбранных элементов одновременно, используя элементы управления рядом с ListView.

Я уже пытался изменить DataContext на свойство SelectedItems объекта ListView, но это не сработало.

Может кто-нибудь сказать мне, как это сделать?

Edit: Чтобы уточнить, когда пользователь выбирает более одного элемента, я хочу, чтобы элементы редактирования рядом с ListView ничего не отображали, и только тогда, когда пользователь что-то изменяет в этих элементах управления, изменения переходят ко всем элементам SelectedItems, и изменение остается видимым в TextBox. или ComboBox, потому что тогда свойство одинаково во всех SelectedItems.

<StackPanel x:Name="EditPanel" Grid.Row="0" Grid.RowSpan="2" DataContext="{Binding SelectedItem, ElementName=LayersList}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" CanVerticallyScroll="True">
    <TextBlock FontSize="14" HorizontalAlignment="Stretch" Foreground="#FFD6D6D6" Margin="0,10,0,0"><Run Text="Name:"/></TextBlock>
    <TextBox x:Name="SelectedNameBox" HorizontalAlignment="Stretch" TextWrapping="NoWrap" Foreground="#FFD6D6D6" Text="{Binding Name, Mode=TwoWay}"/>
    <TextBlock FontSize="14" HorizontalAlignment="Stretch" Foreground="#FFD6D6D6" Margin="0,10,0,0"><Run Text="Hitsound info:"/></TextBlock>
    <ComboBox x:Name="SelectedSampleSetBox" Margin="0,10,0,0" HorizontalAlignment="Stretch" Text="{Binding SampleSetString, Mode=TwoWay}" Cursor="Hand">
        <ComboBoxItem Content="Normal" HorizontalAlignment="Left" Cursor="Hand"/>
        <ComboBoxItem Content="Soft" HorizontalAlignment="Left" Cursor="Hand"/>
        <ComboBoxItem Content="Drum" HorizontalAlignment="Left" Cursor="Hand"/>
    </ComboBox>
    <ComboBox x:Name="SelectedHitsoundBox" Margin="0,10,0,0" HorizontalAlignment="Stretch" Text="{Binding HitsoundString, Mode=TwoWay}" Cursor="Hand">
        <ComboBoxItem Content="Normal" HorizontalAlignment="Left" Cursor="Hand"/>
        <ComboBoxItem Content="Whistle" HorizontalAlignment="Left" Cursor="Hand"/>
        <ComboBoxItem Content="Finish" HorizontalAlignment="Left" Cursor="Hand"/>
        <ComboBoxItem Content="Clap" HorizontalAlignment="Left" Cursor="Hand"/>
    </ComboBox>
    ...
</StackPanel>

Ответы [ 2 ]

1 голос
/ 21 мая 2019

Как вы описали проблему, кажется, что вы не продумали это до конца.

Если у вас есть один список и набор элементов управления, которые отображают свойства выбранного элемента, где вы хотите свойстводанные для отображения при выборе нескольких элементов?Например, если у вас есть класс Person, например:

public class Person
{
    public string Name { get; set; }
    public string City { get; set; }
    public int Age { get; set; }
}

Когда пользователь выбирает из списка два разных экземпляра Person, вы хотите, чтобы текстовое поле, назначенное свойству Name, отображалосьвсе выбранные имена?Если нет, то если вы хотите, чтобы они были в разных текстовых полях, вам пришлось бы динамически создавать столько текстовых полей, сколько элементов было выбрано пользователем.Любое из которых, я чувствую, не может быть идеальным решением.

Вот альтернативное решение;вы отображаете свои данные в DataGrid.Я использовал самый простой DataGrid здесь с включенным AutoGeneratingColumns.

<DataGrid Grid.Row="0" Margin="4"
          Name="DataGridPersons"
          AutoGenerateColumns="True"
          ItemsSource="{Binding Persons}"/>

Затем, в вашем Code Behind (в идеале вы должны использовать MVVM скороговорку и в этом случае в вашем ViewModel) вы просто заполняете свой список данных.

public ObservableCollection<Person> Persons { get; set; }

public MainWindow()
{
    InitializeComponent();

    Persons = new ObservableCollection<Person>
    {
        new Person() { Name = "Jane", City = "NY", Age = 23 },
        new Person() { Name = "Chelsea", City = "LA", Age = 27 },
        new Person() { Name = "Chris", City = "Chicago", Age = 25 }
    };

    DataContext = this;
}

По умолчанию DataGrid является редактируемым и записывает сделанные вами изменения.

Редактируемый DataGrid:

enter image description here


РЕДАКТИРОВАТЬ:

После отредактированного вопроса ОП это новый ответ.

В этом случае я бы избавился от SelectedItem и вместо этого имел бы различные свойства string, соответствующие каждому свойству в вашем объекте класса.

Предположим, ваш класс Person таков:

public class Person
{
    public string Name { get; set; }
    public string City { get; set; }
}

Тогда у меня будет ObservableCollection и столько же string свойств, сколько у вас есть свойств в вашем классе;два в этом случае.

public ObservableCollection<Person> Persons { get; set; }

private string _editName = null;
public string EditName
{
    get { return _editName; }
    set
    {
        _editName = value;
        OnPropertyChanged("EditName");
    }
}

private string _editCity = null;
public string EditCity
{
    get { return _editCity; }
    set
    {
        _editCity = value;
        OnPropertyChanged("EditCity");
    }
}

Затем я бы привязал текстовые поля к этим свойствам:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <ListBox Grid.Column="0" Grid.Row="0" Grid.RowSpan="3"
             Margin="8" Name="ItemListBox"
             ItemsSource="{Binding Persons}"
             DisplayMemberPath="Name"/>

    <TextBox Grid.Column="1" Grid.Row="0"
             Margin="8" Name="TxtName"
             TextChanged="TxtName_TextChanged"
             Text="{Binding EditName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    <TextBox Grid.Column="1" Grid.Row="1"
             Margin="8" Name="TxtCity"
             TextChanged="TxtCity_TextChanged"
             Text="{Binding EditCity, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>

И в событии TextChanged каждого текстового поля я бы обновилваш ObservableCollection.

private void TxtName_TextChanged(object sender, TextChangedEventArgs e)
{
    foreach (var person in Persons)
    {
        person.Name = EditName;
    }
}

private void TxtCity_TextChanged(object sender, TextChangedEventArgs e)
{
    foreach (var person in Persons)
    {
        person.City = EditCity;
    }
}
0 голосов
/ 24 мая 2019

В итоге я не использовал привязки данных для элементов управления редактированием. Вместо этого я явно обновляю их в SelectionChangedEvent объекта ListView. Там также описывается логика отображения нескольких выбранных элементов одновременно.

suppressEvents = true;

if (selectedLayers.TrueForAll(o => o.Name == selectedLayer.Name)) {
    SelectedNameBox.Text = selectedLayer.Name;
} else {
    SelectedNameBox.Text = "";
}
...

suppressEvents = false;

Затем измененные события элементов управления редактирования обновляют все выбранные элементы.

private void SelectedNameBox_TextChanged(object sender, TextChangedEventArgs e) {
    if (suppressEvents) return;

    string t = (sender as TextBox).Text;
    foreach (HitsoundLayer hitsoundLayer in LayersList.SelectedItems) {
        hitsoundLayer.Name = t;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...