Dynamiczne dodawanie elementów do UI

0

Cześć, potrzebóję dodawać różne elementy do UI w trakcie działania programu. Aplikacje piszę z wykorzystniem MVVM. Znalazłem kilka podobnym rozwiązań niestety żadnego które spełnia moje wymagania - dodanie różnych kontrolek w konkretym położeniu.

            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Left" Value="{Binding X}"/>
                    <Setter Property="Canvas.Top" Value="{Binding Y}"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Rectangle Width="{Binding Width}" Height="{Binding Height}" Fill="Black"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

Taki kod widoku wraz z zastosowaniem ObservableCollection pozwala dodawać elementy w kontretnym miejscu, ale tylko jednego typu zdefiniowanego w DataTemplate. Czy jest jakiś sposób, żeby dodwać różne elementy bez tworzenia nowego* ItemsControl *dla każdego typu?

2

DataTemplateSelector? Daje ci możliwość wstawiania różnych kontrolek w zależności od tego, np. jakiego typu jest zbindowany element z ItemsSource.

Na przykład ja mam listę obiektów typu FakeDevice, z którego dziedziczą FakeScale i FakeBarcodeReader, a potem w zależności od tego jaki to faktycznie jest obiekt pojawiają się różne rzeczy.

<Window.Resources>
	<DataTemplate DataType="{x:Type local:FakeScale}" x:Key="FakeScaleTemplate">
		<StackPanel>
			<TextBlock Text="{Binding DeviceId}" />
			<TextBlock Text="{Binding CurrentWeight}" />

			<TextBox Text="{Binding Data, Mode=TwoWay}" />
			<Button Content="Add item" Click="AddItem_Click" />
			<Button Content="Remove item" Click="RemoveItem_Click" />
		</StackPanel>

	</DataTemplate>

	<DataTemplate DataType="{x:Type local:FakeBarcode}" x:Key="FakeBarcodeTemplate">
		<StackPanel>
			<TextBlock Text="{Binding DeviceId}" Background="Beige"></TextBlock>
			<TextBox Text="{Binding Data, Mode=TwoWay}" />
			<Button Content="Send barcode" Click="SendBarcode_Click" />
		</StackPanel>
	</DataTemplate>

	<local:PropertyDataTemplateSelector 
		FakeBarcodeTemplate="{StaticResource FakeBarcodeTemplate}" 
		FakeScaleTemplate="{StaticResource FakeScaleTemplate}"
		x:Key="TemplateSelector"
		/>
</Window.Resources>

<ListView VerticalAlignment="Stretch" x:Name="devices" Grid.Column="1" ItemTemplateSelector="{StaticResource TemplateSelector}">
</ListView>

natomiast sam PropertyDateTemplateSelector wygląda tak:

public class PropertyDataTemplateSelector : DataTemplateSelector
{
	public DataTemplate FakeScaleTemplate { get; set; }
	public DataTemplate FakeBarcodeTemplate { get; set; }        

	public override DataTemplate SelectTemplate(object item,
			   DependencyObject container)
	{
		if (item is FakeScale)
			return FakeScaleTemplate;
		else
			return FakeBarcodeTemplate;            
	}
}
0

Zapomniałem odpisać :) Znalazłem inne rozwiązanie - dużo prostsze i chyba bardziej oczywiste. Tak to jest jak się jest amotorem i się zaczyna kombinować.

W widoku wystarczy napisać:

        <ItemsControl ItemsSource="{Binding Path=Items}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>

I w VM dodajemy tylko:

public ObservableCollection<FrameworkElement> Items { get; set; }

I teraz możemy dodawać dowolną kontrolkę z poziomu VM i modyfikować jej położenie - czyli dokładnie to co potrzebuję.

0
uniqa napisał(a):

Zapomniałem odpisać :) Znalazłem inne rozwiązanie - dużo prostsze i chyba bardziej oczywiste. Tak to jest jak się jest amotorem i się zaczyna kombinować.

Napisałeś że piszesz zgodnie z MVVM to dostałeś powyżej rozwiązaniem z nim zgodne. To co znalazłeś nie jest zgodne z MVVM, skoro VM bezpośrednio ma w sobie kontrolki widoku ;)

0

Chyba nie do końca dobrze opisałem o co mi chodzi. Użytkownik może dodawać i modyfikować kontrolki jedynie na zdeinowanym obszarze roboczym. Coś podobnego do drawo.io tylko zamiast symboli użytkownik może dodawać kontroliki. Czy w takim przypadku nadal nie jest to zgodne z MVVM?

0

kazda referencja do elementow UI w modelu lub view modelu jest zlamaniem wzorca projektowego MVVM

1 użytkowników online, w tym zalogowanych: 0, gości: 1