WPF Create user control dynamically on change of observablecollection OR Visualize nested ObservableCollections by using nested User controls

StackOverflow https://stackoverflow.com/questions/16281082

سؤال

I am new to WPF, and I can't find a solution to my problem.

I've got an Observable Collection in my ViewModel:

ObservableCollection<Process>

Within the Process class is another ObervableCollection:

ObservableCollection<BurstTime>

I want to add a new User control (what can vizualize the actual state of Process data, and it's burst times) dynamically to one of my StackPanel in my view each time, when a new Process is activated, and remove it when the process is ended (when the observable collection changes).. During it's run, I want to diplay it's Burst Time collection, what can change in time..

I've tried to subscribe to the CollectionChanged event in my user control's codebehind and use a User Control inside another User Control and dynamicalli create required TextBlocks when my event handler runs, but I always get a System.Reflection.TargetInvocationException (inner exception: System.NullReferenceException) when my outer InitializeComponent() is running..

public ResourceUseView()
{
    InitializeComponent();
    ((ObservableCollection<Process>)DataContext).CollectionChanged += ResourceUseView_CollectionChanged;
}

Is it possible to do it? Is it possible to create or remove User controls in my outer UserControl's codebehind while reacting to ObservableCollection's element changes, and update the outer when an element changes in the inner ObservableCollection? Are there other ways than instantiate a UserControl inside another User Control dynamically? Is there any special control, what can display ObservableCollection in ObservableCollection?

(If it'is possible, I would like to have different user controls as much as elements my ObservableCollection have..)

Thanks for your help!

هل كانت مفيدة؟

المحلول

The constructor runs before the data binding, so you are probably seeing that error because the DataContext is null at the time the constructor runes.

To bind to a collection, use a control that contains an ItemsSource property. And if you want to bind to a nested collection, modify the ItemTemplate of the control to use another control with an ItemsSource property for the nested collection.

Here's an example using an ItemsControl

<ItemsControl ItemsSource="{Binding Processes}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ItemsControl ItemsSource="{Binding BurstTimes}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

I have some examples of the ItemsControl on my blog if you're interested.

If you want to specify a UserControl for each object, then set the ItemTemplate for the first ItemsControl to be the ProcessUserControl, and inside the ProcessUserControl have an ItemsControl bound to BurstTimes and use a BurstTimeUserControl for it's ItemTemplate

<ItemsControl ItemsSource="{Binding Processes}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <local:ProcessUserControl />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

...

<UserControl x:Class="MyNamespace.ProcessUserControl ...>
    ...
    <ItemsControl ItemsSource="{Binding BurstTimes}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <local:BurstTimeUserControl />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    ...
</UserControl> 
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top