Dynamiczne dodawanie elementów do UI

Dynamiczne dodawanie elementów do UI
UN
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 3 lata
  • Postów:18
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.

Kopiuj
            <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?

edytowany 1x, ostatnio: uniqa
Ktos
Moderator
  • Rejestracja:prawie 23 lata
  • Ostatnio:około 4 godziny
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.

Kopiuj
<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:

Kopiuj
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;            
	}
}
UN
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 3 lata
  • Postów:18
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ć:

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

I w VM dodajemy tylko:

Kopiuj
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ę.

neves
  • Rejestracja:prawie 22 lata
  • Ostatnio:około 3 godziny
  • Lokalizacja:Kraków
  • Postów:1114
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 ;)


UN
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 3 lata
  • Postów:18
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

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.