Pregunta

En una página de WPF que estoy diseñando para mi iglesia, tengo dos controles ListBox vinculados a los resultados de dos consultas de Linq-to-Entities: el primer cuadro de lista / consulta contiene todas las personas que aún no se han comprometido En el año, el segundo cuadro de lista / consulta contiene todas las personas que se han comprometido (y sus compromisos asociados). Específicamente:

var familiesWithNoPledges = from family in entities.Family.Include("Pledge")
    where !family.Pledge.Where(p => p.PledgeYearID == pledgeYear).Any()
    select family;

var familiesWithPledges = from family in entities.Family
    join pledge in entities.Pledge.Include("PledgeFrequency").Where(p => p.PledgeYearID == pledgeYear) on family equals pledge.Family
    select new { family, pledge };

Cuando el usuario de la aplicación selecciona una familia del primer ListBox, el elemento ListBox se expande ligeramente para mostrar los campos de un compromiso, de modo que es fácil agregar los detalles del compromiso al segundo ListBox. Se ve algo como esto:

http://wouldbetheologian.com/images/PledgeManager.jpg (Imagen externa)

La base de datos subyacente (entre otras cosas) tiene una " Familia " tabla con una relación 1: muchos con un " Compromiso " mesa. Y cuando el usuario hace clic en el botón " Agregar compromiso " botón, me gustaría crear la nueva instancia de Compromiso, guardarla en la base de datos y luego actualizar los dos controles.

Pero no puedo averiguar cómo hacer eso. Si trato de hacerlo en el código subyacente, no parece ser el controlador de eventos para las (n-instancias de) " Agregar compromiso " botón puede hacer referencia a los controles en cuestión; y en XAML, si intento vincular los controles ListBoxItem DataTemplate a los campos Family.Pledge (o Family.Pledge.FirstOrDefault ()), esos campos aún están vacíos cuando veo el objeto Family actual en el controlador de eventos para el Agregar Botón de compromiso.

¿Alguna idea sobre cómo resolver esto? ¿O hay un mejor modelo de interfaz de usuario que debería ver en conjunto?

Gracias de antemano.

¿Fue útil?

Solución 2

Gracias, Andrew, eso lo hizo. La clave fue que tuve que crear un DataContext separado para el DockPanel en cuestión, y luego lo vinculé a una nueva instancia del objeto Pledge creado más arriba en la plantilla.

<ListBox>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.Resources>
                    <local:Pledge x:Key="pledge" />
                </Grid.Resources>

                <DockPanel DataContext="{Binding Source={StaticResource pledge}}" >
                    <TextBox Name="txtAmount" Text="{Binding Path=Amount}" />
                    <TextBox Name="txtEnvelopeID" Text="{Binding Path=EnvelopeID}" />
                    <!-- Bind the Tag property of the Button to the DataContext of the ListBoxItem, i.e.  the current Family object -->
                    <Button Tag="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}" Name="addPledge" Click="addPledge_Click"  >
                        Add Pledge -->
                    </Button>
                </DockPanel>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Todavía necesitaba saber más detalles para configurar el objeto de Compromiso de manera adecuada, pero pude obtenerlos vinculando la propiedad Etiqueta del Botón al DataContext de su padre con plantilla:

<Button 
    Tag="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}" 
    Name="addPledge" 
    Click="addPledge_Click" 
/>

Y a partir de ahí, pude manejar el resto en el código subyacente:

    private void addPledge_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            // Set any additional necessary properties.
            Button button = (Button)sender;
            Pledge pledge = (Pledge)button.DataContext;
            pledge.PledgeYear = (PledgeYear)cboYear.SelectedItem;
            pledge.Family = (Family)button.Tag;

            // Update the database and refresh the Listboxes.
            entities.AddToPledge(pledge);
            entities.SaveChanges();
            LoadUnpledgedListBox();
            LoadPledgedListBox();
        }
        catch (System.Data.UpdateException ex)
        {
            MessageBox.Show("Error updating database: " + ex.Message);
        }
        catch (System.Exception ex)
        {
            Classes.Utils.HandleGenericError(ex);
        }
    }

Muchas gracias, eso me apuntó en la dirección correcta.

Otros consejos

La forma más fácil de hacerlo es tener la clase que representa los elementos en su ListBox ItemsSource para tener todos los campos a los que hace referencia en su DataTemplate. Luego, en el controlador de botones, puede acceder a la nueva información de compromiso utilizando el contexto de datos del botón.

    private void AddPledge_Click(object sender, RoutedEventArgs e)
    {
        Button b = sender as Button;
        PotentialPledge p = b.DataContext as PotentialPledge;

        //do stuff with pledge
    }

Puede haber una manera de hacer esto sin que los campos con plantilla formen parte de la clase que compone el ItemsSource para el ListBox (solo aprendiendo WPF), pero esto funciona. Si eso no ayuda, miraré hacia atrás más tarde (listo para trabajar ahora).

De todos modos, un trabajo increíble haciendo una aplicación para tu iglesia, se ve bastante bien.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top