Как отобразить номера строк в ListView?

Я рекомендую прочитать этот вопрос , в котором содержится много полезной информации о том, почему вы не можете использовать дженерики с методами черты, если хотите использовать их в качестве объектов.

Короткий ответ: вы не можете делать то, что пытаетесь сделать: иметь функцию, которая принимает итератор любого типа (которая является связанной универсальной функцией), и при этом эта черта является объектобезопасной. [ 1118]

Есть несколько трюков, которые вы можете использовать , однако, это позволит вам манипулировать итераторами строк с помощью объекта-черты. Я рассмотрю каждый метод.

1. Используйте несколько методов в своей черте

В Rust есть только два типа строк: String и &str. Как вы указали в своем ответе, вы хотите работать с обоими. В этом случае все, что вам нужно сделать, это сделать два разных метода:

pub trait Store {
    fn query_valid_paths_str(&mut self, paths: &mut dyn Iterator) -> Vec;
    fn query_valid_paths_string(&mut self, paths: &mut dyn Iterator) -> Vec;
}

Теперь, это становится нелогичным в определенный момент, если у вас слишком много типов, с которыми вы имеете дело. Но если есть только два, это самый простой вариант.

Если вы хотите использовать вместо этого IntoIterator, сигнатуры функций будут выглядеть следующим образом:

pub trait Store {
    fn query_valid_paths_str(&mut self, paths: &mut dyn IntoIterator, Item = &str>) -> Vec;
    fn query_valid_paths_string(&mut self, paths: &mut dyn IntoIterator, Item = String>) -> Vec;
}

2. Используйте Box и динамическую диспетчеризацию

Этот подход гораздо более сложный и, вероятно, не стоит усилий, но я приведу его здесь в качестве доказательства концепции.

pub trait Store {
    fn query_valid_paths(&mut self, paths: &mut dyn Iterator>) -> Vec;
}

Здесь paths - итератор над блоком, которому принадлежит объект черты AsRef.

Это (насколько я знаю) единственный способ создать действительно полиморфное решение. Но какой ценой? Чтобы это работало, вам нужно не только явно объявить список, который вы передали как Vec>>, это добавляет много накладных расходов при динамической диспетчеризации из указателей блока. Просто чтобы показать, насколько громоздким это может быть:

let mut str_vec: Vec>> = vec!(Box::new("string one"), Box::new("string two".to_string()));
some_store_object.query_valid_paths(&mut str_vec.iter());

Я не рекомендую этот метод, если вам абсолютно не нужны эти функции. Вместо этого используйте первый метод.

Если вы используете этот метод, но хотите использовать его с IntoIterator, он будет выглядеть так:

pub trait Store {
    fn query_valid_paths(&mut self, paths: &mut dyn IntoIterator>>, Item = Box>>) -> Vec;
}

26
задан Dave Clemmer 29 July 2011 в 16:01
поделиться

1 ответ

Я думаю, что Вы имеете изящное решение, но это работает.

XAML:

<ListView Name="listviewNames">
  <ListView.View>
    <GridView>
      <GridView.Columns>
        <GridViewColumn
          Header="Number"
          DisplayMemberBinding="{Binding RelativeSource={RelativeSource FindAncestor, 
                                         AncestorType={x:Type ListViewItem}}, 
                                         Converter={StaticResource IndexConverter}}" />
        <GridViewColumn
          Header="Name"
          DisplayMemberBinding="{Binding Path=Name}" />
      </GridView.Columns>
    </GridView>
  </ListView.View>
</ListView>

ValueConverter:

public class IndexConverter : IValueConverter
{
    public object Convert(object value, Type TargetType, object parameter, CultureInfo culture)
    {
        ListViewItem item = (ListViewItem) value;
        ListView listView = ItemsControl.ItemsControlFromItemContainer(item) as ListView;
        int index = listView.ItemContainerGenerator.IndexFromContainer(item);
        return index.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
42
ответ дан MoonKnight 28 November 2019 в 06:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: