2010-11-18 23 views
6

He estado leyendo mucho sobre MVVM (usando la biblioteca de Laurent Bugnion en concreto) y estoy luchando constantemente para determinar cómo hacer las cosas en MVVM que eran de otra forma fácil con código detrás.MVVM cuadro de lista de actualización de contenido Mantener el elemento seleccionado Silverlight

Aquí hay solo un ejemplo en el que sospecho que estoy haciendo las cosas de la manera difícil. Si alguien tiene tiempo para leer todo esto, quizás puedan comentar sobre la cordura de mi enfoque. :)

I tienen un cuadro de lista unido a un ViewModel como tan:

<ListBox x:Name="lstFruitBasketLeft" ItemsSource="{Binding FruitBasket}" 
    SelectedItem="{Binding SelectedFruit, Mode=TwoWay}" Width="150"> 
<ListBox.ItemTemplate> 
    <DataTemplate> 
     <StackPanel Orientation="Horizontal" VerticalAlignment="Center" 
        HorizontalAlignment="Left" Margin="2"> 
      <TextBlock Text="{Binding Name}" /> 
      <TextBlock Text=":" /> 
      <TextBlock Text="{Binding Quantity}" /> 
     </StackPanel> 
    </DataTemplate> 
</ListBox.ItemTemplate> 

El ItemSource es un ObservableCollection de objetos de frutas:

public class Fruit 
{ 
    public string Name { get; set; } 
    public int Quantity { get; set; } 

    public Fruit() { } 
    public Fruit(string name, int quantity) 
    { 
     this.Name = name; 
     this.Quantity = quantity; 
    } 
    } 

Se define en la ViewModel como:

// Property FruitBasket 
public const string FruitBasketPropertyName = "FruitBasket"; 
private ObservableCollection<Fruit> _fruitBasket = null; 
public ObservableCollection<Fruit> FruitBasket 
{ 
    get { return _fruitBasket; } 
    set 
    { 
    if (_fruitBasket == value) 
     return; 

    _fruitBasket = value; 

    // Update bindings, no broadcast 
    RaisePropertyChanged(FruitBasketPropertyName); 
    } 
} 

La propiedad SelectedItem ligados es como tal:

//Property SelectedFruit 
public const string SelectedFruitPropertyName = "SelectedFruit"; 

private Fruit _selectedFruit = null; 

public Fruit SelectedFruit 
{ 
    get { return _selectedFruit; } 
    set 
    { 
    if (_selectedFruit == value) 
     return; 

    var oldValue = _selectedFruit; 
    _selectedFruit = value; 

    // Update bindings, no broadcast 
    RaisePropertyChanged(SelectedFruitPropertyName); 
    } 
} 

A continuación, la lista se rellena en la construcción del modelo de vista.

Ahora, agrego un RelayCommand a un botón en la página de presentación que ejecuta un método que incrementa la cantidad del elemento seleccionado. Tenga en cuenta que todavía no estoy usando el parámetro, pero "Bob" es un marcador de posición para algunos cambios para más adelante.

<Button x:Name="butMore" Content="More!" HorizontalAlignment="Right" Height="25" Width="75" Margin="4"> 
    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="Click"> 
      <cmd:EventToCommand 
       Command="{Binding addMoreCommand}" 
       CommandParameter="Bob" /> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 
</Button> 

Aquí está el código para el comando:

// Property addMoreCommand 
public RelayCommand addMoreCommand 
{ 
    get; 
    private set; 
} 

...

//Init relays (this is in the constructor) 
    addMoreCommand = new RelayCommand(AddFruit, CanExecute); 

...

public void AddFruit() 
{ 
    //Increment the fruit 
    SelectedFruit.Quantity++; 

    //Save the previous selected item 
    Fruit oldSelectedItem = SelectedFruit; 

    //We have to have a new list in order to get the list box to refresh 
    FruitBasket = new ObservableCollection<Fruit>(FruitBasket); 

    //Reselect 
    SelectedFruit = oldSelectedItem; 
} 


public bool CanExecute() 
{ 
    return true; //for now 
} 

Ahora bien, esto funciona, pero tengo un poco problemas con él:

Primero, siento que hay muchas condiciones que se deben unir para que esto funcione y me pregunto si tendré tanta suerte tratando de mover algún código Telerik Drag and Drop en MVVM.

En segundo lugar, parece un enfoque de rendimiento bastante pobre para recrear la lista de esa manera.

Por último, parece que esto sería más fácil en código detrás (aunque no estoy 100% seguro de que todavía no tenga que reconstruir esa lista).

¿Alguien tiene alguna idea sobre mi enfoque o tal vez incluso ... sugerencias para facilitar las cosas? ¿Me estoy perdiendo algo obvio aquí?

Gracias

-Driodilate:]

Respuesta

2

maulkye,

Hay algo va mal si tiene que actualizar su ObservableCollection.Por lo general, no debería necesitarlo porque el ObservableCollection le notificará sobre cambios en los artículos.

Nunca haga esto:

FruitBasket = new ObservableCollection<Fruit>(FruitBasket); 

Su public ObservableCollection<Fruit> FruitBasket debería tener ningún colocador pública, debe ser de sólo lectura. Solo Add o Remove Elementos a/de la lista.

Si desea manejar selecciones múltiples, es probable que necesite una extensión CollectionView que pueda manejar esto, obtenga más sugerencias here.

espero que esto ayude un poco, aunque probablemente no respondió a todas las preguntas:)

EDIT: Ok, supongo que tengo algunas cosas mal. Ahora supongo que entiendo completamente lo que estás tratando de lograr. Usted es no recibiendo una notificación cuando se cambie su propiedad, ¿verdad? Bueno, por este motivo, hemos adaptado "BindableLinq" en uno de nuestros proyectos, que puede compilar en Silverlight sin problemas. (hay soluciones similares disponibles, llamadas Continuous Linq o Obtics, haga su elección).

Usando BindableLinq, usted puede transformar su ObservableCollection a un BindableCollection utilizando un método de extensión única. El BindableCollection reflejará todos los cambios correctamente. Darle una oportunidad.

Edit2: para implementar un modelo de vista adecuada, por favor considere los siguientes cambios.

1) Fruit es su modelo. Como no implementa INotifyPropertyChanged, no propagará ningún cambio. Cree un , incorporando su modelo Fruit e invoque RaisePropertyChanged para cada conjunto de propiedades.

2) Cambie su FruitBasket para ser un ObservableCollection de . Poco a poco comienza a tener sentido :)

3) SelectedFruit tiene que ser un también. Ahora tiene aún más sentido.

4) Ahora ya funciona para mí, incluso sin BindableLinq. ¿Tuviste algún éxito?

HTH

mejores deseos,
Thomas

+0

Bueno, eso no ayuda, pero me deja en la situación de no saber cómo conseguir el control enlazado a actualizar correctamente. Tenga en cuenta que no estoy agregando o eliminando elementos (eso funciona perfectamente sin el código adicional). Mi problema ocurre cuando estoy actualizando una propiedad en uno de los objetos que está en el ObservableCollection. – maulkye

+0

Hmmmm, aunque me hiciste pensar. Podría simplemente eliminar el elemento seleccionado, actualizarlo y luego volver a agregarlo para que las actualizaciones automáticas funcionen. Aunque no estoy seguro de cómo afectará esto a la clasificación. – maulkye

+0

Compruebe mi EDIT, hay otra pista que podría seguir :) – thmshd

Cuestiones relacionadas