.net - Opret manuelt ubundet datagrid

Indlæg af Hanne Mølgaard Plasc

Problem



Kan nogen fortælle mig, om det er muligt at oprette og tilføje data til et ubundet WPF Toolkit datagrid.


Hvis det faktisk er muligt at gøre, kan nogen venligst give et eksempel på følgende:


programmatisk:
opret en datagrid
opret en datagridtextkolonne
Tilføj datagridtextkolonnen til datagrid
opret en datagridrow
sæt teksten i datagridtekolonnen for rækken for at 'teste'
Tilføj datagridrow til datagrid


Jeg vil gerne oprette en datagrid, der er ubundet. Min grund er, at jeg gerne vil oprette en skabelonsøjle med flere kontroller af forskellige typer og tal - 2 afkrydsningsfelter, 4 radiobuttoner, 5 afkrydsningsfelter osv. - som dynamisk tilføjes ved kørselstidspunktet, og da typen og nummeret er ukendte, kan man ikke tænke på en måde at databind dem på. Jeg er glad for at arbejde ubundet.


Tak på forhånd!


[[Rediger: Jeg har endnu ikke fundet et passende svar på dette spørgsmål, og jeg har startet en gevinst]]

Bedste reference


Du kan bruge UserControl, der vil skabe ønskede kontroller.


Window1.xaml (uddrag)


<dg:DataGrid ItemsSource="{Binding}" CanUserAddRows="False" AutoGenerateColumns="False">
    <dg:DataGrid.Columns>

       <dg:DataGridTemplateColumn Header="Test" MinWidth="100">
            <dg:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <my:ControlA Foo="{Binding}"></my:ControlA>
                </DataTemplate>
            </dg:DataGridTemplateColumn.CellTemplate>
        </dg:DataGridTemplateColumn>

    </dg:DataGrid.Columns>
</dg:DataGrid>


Window1.xaml.cs


public partial class Window1 : Window
{
    List<Foo> \_items = new List<Foo>();

    public Window1()
    {
        InitializeComponent();

        \_items.Add(new Foo { CheckBoxCount = 2, TextBoxCount = 1 });
        \_items.Add(new Foo { CheckBoxCount = 3, TextBoxCount = 0 });

        DataContext = \_items;
    }
}


ControlA.xaml


<UserControl x:Class="Demo.ControlA"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel x:Name="\_placeHolder">
    </StackPanel>
</UserControl>


ControlA.xaml.cs


public partial class ControlA : UserControl
{
    public ControlA()
    {
        InitializeComponent();

        Loaded += new RoutedEventHandler(ControlA\_Loaded);
    }

    void ControlA\_Loaded(object sender, RoutedEventArgs e)
    {
        if (Foo != null)
        {
            for (int it = 0; it < Foo.CheckBoxCount; it++)
                \_placeHolder.Children.Add(new CheckBox());

            for (int it = 0; it < Foo.TextBoxCount; it++)
                \_placeHolder.Children.Add(new TextBox());
        }
    }

    public static readonly DependencyProperty FooProperty =
        DependencyProperty.Register("Foo", typeof(Foo), typeof(ControlA));

    public Foo Foo
    {
        get { return (Foo)GetValue(FooProperty); }
        set { SetValue(FooProperty, value); }
    }
}


Foo.cs


public class Foo
{
    public int TextBoxCount { get; set; }
    public int CheckBoxCount { get; set; }
}


Håber dette hjælper.


P.S. Det skal være muligt at refactor DataGridTemplateColumn i separate UserControl.

Andre referencer 1


Jeg har aldrig brugt et gitter uden at binde det til noget.


MEN kigger på den underliggende årsag, der kan løses, mens du stadig bruger databinding.


For eksempel:
Hvis du bruger en ViewModel klasse til dig objekt, som nettet er bundet til, så kan du gøre et aspekt af den klasse være synlighedssætene til de forskellige kontroller.


I objektet har du det her:


Public ReadOnly Property CheckboxAVisibility As Windows.Visibility
   Get
     ' Do Logic 
     Return Visiblity 
   End Get
End Property


Og i XAML gør du det:


<CheckBox IsChecked="{Binding IsBoxAChecked}" Visibility={Binding CheckboxAVisibility}" />


Dette gør også tingene nemmere, da du kan ændre synligheden af ​​forskellige kontroller ved at ændre andre kontroller inden for rækken (fx: fjernelse af afkrydsningsfeltet CheckboxA forårsager, at RadioButtons B, C &D vises).


En anden mulighed ville være at nævne kun 'Header' -information i gitteret, og når brugeren dobbeltklikker en række, vil du vise en editor med de redigerbare aspekter i et sekundært panel eller et vindue (svarende til, hvordan MVC-redigering fungerer).


Rediger som følge af kommentar


Her er et andet forslag, snarere end en datagrid, brug af en StackPanel. For hver række du har brug for, kan du tilføje et gitterpanel eller stakpanel eller noget lignende, der er oprettet på runtime i henhold til dine regler. For eksempel:


XAML:


<StackPanel Name="stkItems" Orientation="Vertical" />


Kode:


Public Sub AddItems(dt as DataTable)
   For Each row As DataRow in dt.Rows
     Select Case row("Which")
          Case 1:
             Dim i As New Checkbox
             i.Content = "Foo"
             i.IsChecked = row("Content")
             stkItems.Children.Add(i)
          Case 2:
              Dim i as New TextBox
              i.Text = row("Content")
              stkItems.Children.Add(i)
     End Select
   Next
End Sub


Dette er meget forenklet, og du kan gøre ting som f.eks. Foruddefinerede brugerkontroller, som du kan bruge, eller bare opbygge en masse kontrolelementer i en programmæssigt defineret container og derefter tilføje det til StackPanel

Andre referencer 2


Jeg har oprettet en simpel DataGridUnboundedColumn klasse, der er afledt af DataGridBoundColumn og kan bruges til at levere brugerdefineret tekst af FrameworkElement til cellen.


Du abonnerer simpelthen på CellFormating-arrangementet og indstiller CellElement i EventArgs til det brugerdefinerede element, der vil blive vist. Det er også muligt at indstille kun CellText i EventArgs - i dette tilfælde vil TextBlock med CellText blive vist i Gitteret.


Følgende eksempler viser, hvordan man bruger det:


XAML:


<dg:DataGrid Name="DataGrid1" AutoGenerateColumns="False">
    <dg:DataGrid.Columns>
        <dg:DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
        <myColumn:DataGridUnboundedColumn x:Name="AddressColumn" Header="Address" />
    </dg:DataGrid.Columns>
</dg:DataGrid>


KODE:


   public MyPage()
    {
        InitializeComponent();

        AddressColumn.CellFormating += new UnboundedColumnEventHandler(AddressColumn\_CellFormating);
    }

    void AddressColumn\_CellFormating(object sender, UnboundedColumnEventArgs e)
    {
        IPerson person;

        person= e.DataItem as IPerson;

        if (person!= null)
            e.CellText = string.Format("{0}, {1} {2}", person.Address, person.PostalCode, person.City);
    }


Implementeringen af ​​DataGridUnboundedColumn er her:


class DataGridUnboundedColumn : DataGridBoundColumn
{
    public event UnboundedColumnEventHandler CellFormating;

    public DataGridUnboundedColumn()
    {
        this.IsReadOnly = true;
    }

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    {
        return null;
    }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        FrameworkElement shownElement;
        UnboundedColumnEventArgs eventArgs;

        if (CellFormating == null)
            return null;


        eventArgs = new UnboundedColumnEventArgs(cell, dataItem);

        // call the event
        CellFormating(this, eventArgs);

        shownElement = null;

        // check the data set in the eventArgs
        if (eventArgs.CellElement != null)
        {
            // show the set eventArgs.CellElement
            shownElement = eventArgs.CellElement;
        }
        else if (eventArgs.CellText != null)
        {
            // show the CellText in TextBlock
            TextBlock textBlock = new TextBlock();
            textBlock.Text = eventArgs.CellText;

            shownElement = textBlock;
        }
        else
        {
            // nothing set
        }

        return shownElement;
    }
}

public delegate void UnboundedColumnEventHandler(object sender, UnboundedColumnEventArgs e);

public class UnboundedColumnEventArgs : EventArgs
{
    public DataGridCell Cell { get; set; }
    public object DataItem { get; set; }

    /// <summary>
    /// The subscriber of the event can set the CellText.
    /// In this case the TextBlock is used to display the text.
    /// NOTE that if CellElement is not null, the CellText will not be used but insted a CellElement will be shown
    /// </summary>
    public string CellText { get; set; }

    /// <summary>
    /// The subscribed can set the FrameworkElement that will be shown for this cell.
    /// If the CellElement is null, the CellText will be used to show the TextBlock
    /// </summary>
    public FrameworkElement CellElement { get; set; }

    public UnboundedColumnEventArgs()
        : base()
    { }

    public UnboundedColumnEventArgs(DataGridCell cell, object dataItem)
        : base()
    {
        Cell = cell;
        DataItem = dataItem;
    }
}